kevin@kosman.UUCP (Kevin O'Gorman) (12/04/90)
A little while ago, Chris Sears (sears@dungeon.enet.dec.com) posted a set of programs to decode eexec-ed type 1 font programs. I had some trouble with that version, especially on MSDOS, so I combined some stuff and made this version, which compiles on MSC 5.1 and 6.00A, as well as under gcc on my SYSV UNIX. It should be reasonably portable, since the machines differ in word-size and endianness. There are some SYSV-isms, but just in the names of include files, I think. Also, see NEED_STRSTR. This routine also can be used in a pipeline. Specify - for the standard input. Output is always on stdout. I HAVE been having some trouble with it though -- the resulting PostScript seems always to get a VMERROR on my LaserWriter Plus, on any real font. Ideas? The result is informative anyway. I tried sending this to Chris first, but email to the indicated address does not work. Chris, thanks for the original. This is a single source file, not in shar format. Beware the trailing signature. /* * untype1.c -- decrypt an Adobe font file encrypted for eexec * * original by Chris B. Sears (sears@dungeon.enet.dec.com) * * Modified for portability by Kevin O'Gorman (kosman!kevin), because MSDOS * had trouble with intermediate files that were mixed binary and text, and * because it's really all one task. (3 Dec 1990) * * The original was distributed without a copyright notice, and no comment * about the status. I take that to place it in the public domain. I * (Kevin O'Gorman) specifically place my modifications in the public domain * -- I assert no rights, and accept no responsibility. * * As a courtesy, I request that notices of authorship be kept honest and * complete (and don't forget your own). * * usage: * untype1 [-s] inputfile * * The optional -s switch causes the output to be truncated at the first line * containing the token "definefont". This is useful in conjunction with the * shell scripts distributed by Chris Sears. * * The font-related code assumes that the font is eexec encoded (they almost * always are); the copying loop for stuff outside of eexec does not check * for font-related things. Further, the RD and -| tokens are hardwired in. * * Inputfile may be specified as "-". * * The decoded result is placed on the standard output. * * Current status: the results get VMerrors on my LaserWriter Plus, even if * I setpacking to true. The results are nevertheless very informative. * * Things to do: * 1: directly turn a type1 into a type3 font. * 2: draw the font characters large, with the hints and control points * made visible. * 3: decode printer internal fonts (type 5). * 4: strip ^D (from some postscript files) and ^Z (from MSDOS) characters. */ #include <stdio.h> #include <string.h> #include <ctype.h> #define SEEK_SET 0 #define TRUE 1 #define FALSE 0 #define EEXEC_SKIP_BYTES 4 #define MAX_ESCAPE 33 int lenIV = 4; /* CharString salt length */ typedef struct { char *command; int value; } Command; #define BUFFERSIZE 4096 static int skip_salt = EEXEC_SKIP_BYTES + 1; static FILE *in; static char in_buff[BUFFERSIZE], out_buff[BUFFERSIZE]; static int in_size, in_ptr; static int o, obase; static unsigned short int cr, cc1, cc2, er, ec1, ec2; #define ER 55665 #define EC1 52845 #define EC2 22719 #define CR 4330 #define CC1 52845 #define CC2 22719 static int count, csalt; Command commands[] = { { "notdefined_c0", 0 }, { "hstem", 1 }, { "notdefined_c2", 2 }, { "vstem", 3 }, { "vmoveto", 4 }, { "chars_rlineto", 5 }, { "hlineto", 6 }, { "vlineto", 7 }, { "rrcurveto", 8 }, { "chars_closepath",9 }, { "callsubr", 10 }, { "return", 11 }, { "escape", 12 }, { "hsbw", 13 }, { "endchar", 14 }, { "notdefined_c15", 15 }, { "notdefined_c16", 16 }, { "notdefined_c17", 17 }, { "notdefined_c18", 18 }, { "notdefined_c19", 19 }, { "notdefined_c20", 20 }, { "chars_rmoveto", 21 }, { "hmoveto", 22 }, { "notdefined_c23", 23 }, { "notdefined_c24", 24 }, { "notdefined_c25", 25 }, { "notdefined_c26", 26 }, { "notdefined_c27", 27 }, { "notdefined_c28", 28 }, { "notdefined_c29", 29 }, { "vhcurveto", 30 }, { "hvcurveto", 31 } }; Command escapes[] = { { "dotsection", 0 }, { "vstem3", 1 }, { "hstem3", 2 }, { "notdefined_e3", 3 }, { "notdefined_e4", 4 }, { "notdefined_e5", 5 }, { "seac", 6 }, { "sbw", 7 }, { "notdefined_e8", 8 }, { "notdefined_e9", 9 }, { "notdefined_e10", 10 }, { "notdefined_e11", 11 }, { "chars_div", 12 }, { "notdefined_e13", 13 }, { "notdefined_e14", 14 }, { "notdefined_e15", 15 }, { "callothersubr", 16 }, { "chars_pop", 17 }, { "notdefined_e18", 18 }, { "notdefined_e19", 19 }, { "notdefined_e20", 20 }, { "notdefined_e21", 21 }, { "notdefined_e22", 22 }, { "notdefined_e23", 23 }, { "notdefined_e24", 24 }, { "notdefined_e25", 25 }, { "notdefined_e26", 26 }, { "notdefined_e27", 27 }, { "notdefined_e28", 28 }, { "notdefined_e29", 29 }, { "notdefined_e30", 30 }, { "notdefined_e31", 31 }, { "notdefined_e32", 32 }, { "setcurrentpoint",33 } }; unsigned char GetPlain() { if (in_ptr >= in_size) { if(fgets(in_buff, BUFSIZ, in) == NULL) { fprintf(stderr,"Errror -- end of file.\n"); exit(1); } in_size = strlen(in_buff) - 1; in_ptr = 0; } return in_buff[in_ptr++]; } unsigned int GetHexChar() { unsigned int byte; /* skip whitespace */ do { byte = GetPlain(); } while ((byte == '\n') || (byte == ' ') || (byte == '\t') || (byte == '\r') || (byte == '\f')); /* figure the digit */ if ( (byte >= '0') && (byte <= '9') ) return (byte - '0'); if ( (byte >= 'A') && (byte <= 'F') ) return (byte - 'A' + 10); if ( (byte >= 'a') && (byte <= 'f') ) return (byte - 'a' + 10); /* anything else is an error */ fprintf(stderr, "Illegal hex digit.\n"); exit (1); } unsigned char EDeCrypt() { unsigned char ch1, ch2, plain, cipher; /* * Decode cipher. */ do { ch1 = GetHexChar(); ch2 = GetHexChar(); cipher = (ch1 << 4) + ch2; plain = (cipher ^ (er >> 8)); er = (cipher + er) * ec1 + ec2; if (skip_salt) skip_salt--; } while (skip_salt); return plain; } unsigned char CDeCrypt() { unsigned char plain, cypher; if (count <= 0) { fprintf(stderr,"Reading too many bytes of charstring data.\n"); exit(1); } do { cypher = EDeCrypt(); count--; plain = (cypher ^ (cr >> 8)); cr = (cypher + cr) * cc1 + cc2; if (csalt) csalt--; } while (csalt); return plain; } #ifdef NEED_STRSTR char * strstr(char *string, char *target) { int slen, tlen, i; tlen = strlen(target); slen = strlen(string); for (i=0; i+tlen <= slen; i++) { if (!strncmp(target, &string[i],tlen)) return (&string[i]); } return NULL; } #endif void out_check() { out_buff[o] = '\0'; /* terminate the string */ /* mostly serves to help use CodeView */ if (o-obase > 78) { int ptr; unsigned char c; for (ptr=obase+78; ptr>obase; ptr--) { c = out_buff[ptr]; if(c==' ' || c=='\t') break; } if (ptr-obase < 10) return; for (; ptr>obase; ptr--) { c = out_buff[ptr]; if (isalpha(c)) break; } if (ptr-obase < 10) return; for (;; ptr++) { c = out_buff[ptr]; if(c==' ' || c=='\t') break; } out_buff[ptr] = '\0'; fputs(out_buff, stdout); strcpy(out_buff,"\n\t"); strcat(out_buff,&out_buff[ptr+1]); o = strlen(out_buff); obase = -6; } } void main(argc, argv) int argc; char **argv; { unsigned char plainchar; char *count_pos; int i; int line_pos; long value; #define DATA_STATE 0 #define CHAR_STATE 1 #define CINZ_STATE 2 int state = DATA_STATE; unsigned char byte; if ((argc != 2 && argc != 3) || (argc == 3 && strcmp(argv[1],"-s"))) { fprintf(stderr, "Usage: %s [-s] input\n", argv[0]); exit(0); } if (strcmp(argv[argc-1], "-")) { if ((in = fopen(argv[argc-1], "r")) == NULL) { fprintf(stderr, "%s: can't open %s\n", argv[0], argv[argc-1]); exit(0); } } else {in = stdin;} /* * Just copy to output until we see an eexec. */ COPYFILE: while (1) { if (fgets(in_buff, BUFSIZ, in) == NULL) goto fin; if (strcmp(in_buff, "currentfile eexec\n") == 0) break; fprintf(stdout, "%s", in_buff); } skip_salt = EEXEC_SKIP_BYTES + 1; er = ER; ec1 = EC1; ec2 = EC2; for (in_ptr = 999, in_size = 0, o=0, obase=0;;) { switch(state) { case CINZ_STATE: cr = CR; cc1 = CC1; cc2 = CC2; csalt = lenIV + 1; for (count_pos = &out_buff[o-5]; (count_pos >= out_buff) && (*count_pos != ' '); count_pos--) ; /* This can be at the beginning of a line */ if (*count_pos == ' ') count_pos++; count = atoi(count_pos); /* * Change "count RD" to "{" */ o = count_pos - out_buff; out_buff[o++] = '{'; out_buff[o] = '\0'; state = CHAR_STATE; case CHAR_STATE: for ( ; count > 0; i += 2) { /* * Translate the buffer. */ byte = CDeCrypt(); if (byte == 11) { /* return */ o += sprintf(&out_buff[o], " %s", commands[byte].command); out_check(); break; } else if (byte == 12) { /* escape */ byte = CDeCrypt(); if (byte > MAX_ESCAPE) { o += sprintf(&out_buff[o], " not_defined_e%d", byte); out_check(); } else { o += sprintf(&out_buff[o], " %s", escapes[byte].command); out_check(); } continue; } else if (byte < 32) { o += sprintf(&out_buff[o], " %s", commands[byte].command); out_check(); } if (byte >= 32) { if (byte <= 246) { o += sprintf(&out_buff[o], " %d", byte - 139); out_check(); } else if ((byte >= 247) && (byte <= 250)) { o += sprintf(&out_buff[o], " %d", (byte - 247) * 256 + CDeCrypt() + 108); out_check(); } else if ((byte >= 251) && (byte <= 254)) { o += sprintf(&out_buff[o], " %d", -((int)byte - 251) * 256 - (int)CDeCrypt() - 108); out_check(); } else if (byte == 255) { value = CDeCrypt(); value <<= 8; value += CDeCrypt(); value <<= 8; value += CDeCrypt(); value <<= 8; value += CDeCrypt(); o +=sprintf(&out_buff[o], /* NOTE: long value */ " %ld", value); out_check(); } } } o += sprintf(&out_buff[o], " }"); out_check(); state = DATA_STATE; case DATA_STATE: /* * Decrypt a line of hex. */ plainchar = EDeCrypt(); out_buff[o++] = plainchar; out_check(); if ((o >=4) && !strncmp(" RD ", &out_buff[o-4], 4)) { state = CINZ_STATE; break; } if ((o >=4) && !strncmp(" -| ", &out_buff[o-4], 4)) { state = CINZ_STATE; break; } if (plainchar == '\n') { if (argc==3 && strstr(out_buff,"definefont")) goto fin; if (strncmp("/lenIV", out_buff, 6) == 0) lenIV = atoi(out_buff + 7); if ((count_pos = strstr(out_buff,"currentfile closefile")) != NULL){ strcpy(count_pos, "\n"); fputs(out_buff, stdout); goto COPYFILE; } fputs(out_buff, stdout); o = 0; obase = 0; } } /* switch */ } /* for (reading file) */ fin: fclose(in); exit(0); } -- Kevin O'Gorman ( kevin@kosman.UUCP, kevin%kosman.uucp@nrc.com ) voice: 805-984-8042 Vital Computer Systems, 5115 Beachcomber, Oxnard, CA 93035 Non-Disclaimer: my boss is me, and he stands behind everything I say.