home *** CD-ROM | disk | FTP | other *** search
- /* t1disasm
- *
- * This program `disassembles' Adobe Type-1 font programs in either PFB or PFA
- * format. It produces a human readable/editable pseudo-PostScript file by
- * performing eexec and charstring decryption as specified in the `Adobe Type 1
- * Font Format' version 1.1 (the `black book'). There is a companion program,
- * t1asm, which `assembles' such a pseudo-PostScript file into either PFB or
- * PFA format.
- *
- * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.
- *
- * Permission is hereby granted to use, modify, and distribute this program
- * for any purpose provided this copyright notice and the one below remain
- * intact.
- *
- * I. Lee Hetherington (ilh@lcs.mit.edu)
- *
- * $Log: t1disasm.c,v $
- * Revision 1.2 92/05/22 12:05:33 ilh
- * Fixed bug where we were counting on sprintf to return its first
- * argument---not true in ANSI C. This bug was detected by Piet
- * Tutelaers (rcpt@urc.tue.nl). Also, fixed (signed) integer overflow
- * error when testing high-order bit of integer for possible
- * sign-extension by making comparison between unsigned integers.
- *
- * Revision 1.1 92/05/22 12:04:07 ilh
- * initial version
- *
- * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by
- * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code
- * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS
- * ... #endif, where _MSDOS is an identifier, which is automatically
- * defined, if you compile with the Microsoft C/C++ Compiler.
- *
- */
-
- #ifndef lint
- static char rcsid[] =
- "@(#) $Id: t1disasm.c,v 1.2 92/05/22 12:05:33 ilh Exp Locker: ilh $";
- static char copyright[] =
- "@(#) Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.";
- #ifdef _MSDOS
- static char portnotice[] =
- "@(#) Ported to MS-DOS by Kai-Uwe Herbing (herbing@netmbx.netmbx.de).";
- #endif
- #endif
-
- /* Note: this is ANSI C. */
-
- #ifdef _MSDOS
- #include <fcntl.h>
- #include <io.h>
- #endif
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <limits.h>
-
- /* int32 must be at least 32-bit and uint16 must be at least 16-bit */
- #if INT_MAX >= 0x7FFFFFFFUL
- typedef int int32;
- #else
- typedef long int32;
- #endif
- #if USHRT_MAX >= 0xFFFFUL
- typedef unsigned short uint16;
- #else
- typedef unsigned int uint16;
- #endif
-
- #define LINESIZE 256
-
- #define cgetc() cdecrypt((byte) (egetc() & 0xff))
-
- typedef unsigned char byte;
-
- static FILE *ifp = stdin;
- static FILE *ofp = stdout;
- static char line[LINESIZE];
- static int start_charstring = 0;
- static int lenIV = 4;
-
- /* decryption stuff */
- static uint16 er, cr;
- static uint16 c1 = 52845, c2 = 22719;
-
- /* This function looks for `currentfile eexec' string and returns 1 once found.
- If c == 0, then simply check the status. */
-
- static int eexec_scanner(int c)
- {
- static char *key = "currentfile eexec\n";
- static char *p = 0;
-
- if (!p)
- p = key;
-
- if (c && *p) {
- if ((char) (c & 0xff) == *p)
- ++p;
- else
- p = key;
- }
- return *p == '\0';
- }
-
- /* This function returns the value of a single hex digit. */
-
- static int hexval(char c)
- {
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
- else if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- else if (c >= '0' && c <= '9')
- return c - '0';
- else
- return 0;
- }
-
- /* This function returns a single character at a time from a PFA or PFB file.
- This stream is mixed ASCII and binary bytes. For PFB files, the section
- headers are removed, and \r is replaced by \n in ASCII sections. For PFA
- files, the hexdecimal data is turned into binary bytes. */
-
- static int bgetc()
- {
- static int first_byte = 1;
- static int is_pfa = 0;
- static int is_pfb = 0;
- static int32 pfb_remaining = 0;
- int c, val;
-
- /* is_pfa == 1 means PFA initial ASCII section
- is_pfa == 2 means PFA hexadecimal section
- is_pfb == 1 means PFB ASCII section
- is_pfB == 2 means PFB binary section */
-
- c = fgetc(ifp);
-
- if (c == EOF)
- return EOF;
-
- if (first_byte) {
- /* Determine if this is a PFA or PFB file by looking at first byte. */
- if (c == 0x80) {
- is_pfb = 1;
- is_pfa = 0;
-
- #ifdef _MSDOS
- /* If we are processing a PFB (binary) input */
- /* file, we must set its file mode to binary. */
- _setmode(_fileno(ifp), _O_BINARY);
- #endif
-
- } else {
- is_pfb = 0;
- is_pfa = 1;
- }
- first_byte = 0;
- }
-
- if (is_pfb) {
- /* PFB */
- if (pfb_remaining == 0) {
- /* beginning of block---we know c == 0x80 at this point */
- switch (fgetc(ifp)) {
- case 1:
- is_pfb = 1;
- break;
- case 2:
- is_pfb = 2;
- break;
- case 3:
- return EOF;
- default:
- fprintf(stderr, "error: is this really a PFB file?\n");
- exit(1);
- }
- /* get block length */
- pfb_remaining = (int32) (fgetc(ifp) & 0xff);
- pfb_remaining |= (int32) (fgetc(ifp) & 0xff) << 8;
- pfb_remaining |= (int32) (fgetc(ifp) & 0xff) << 16;
- pfb_remaining |= (int32) (fgetc(ifp) & 0xff) << 24;
- /* get character */
- c = fgetc(ifp);
- if (c == EOF)
- return EOF;
- }
- --pfb_remaining;
- /* in ASCII section change return to newline */
- if (is_pfb == 1 && c == '\r')
- c = '\n';
- (void) eexec_scanner(c);
- return c;
- } else {
- /* PFA */
- if (is_pfa == 1) {
- /* in initial ASCII */
- if (eexec_scanner(c))
- is_pfa = 2;
- return c;
- } else {
- /* in hexadecimal */
- while (isspace(c))
- c = fgetc(ifp);
- val = hexval((char)c) << 4;
- val |= hexval((char)(c = fgetc(ifp)));
- if (c == EOF)
- return EOF;
- return val;
- }
- }
- }
-
- /* Two separate decryption functions because eexec and charstring decryption
- must proceed in parallel. */
-
- static byte edecrypt(byte cipher)
- {
- byte plain;
-
- plain = (byte) (cipher ^ (er >> 8));
- er = (uint16) ((cipher + er) * c1 + c2);
- return plain;
- }
-
- static byte cdecrypt(byte cipher)
- {
- byte plain;
-
- plain = (byte) (cipher ^ (cr >> 8));
- cr = (uint16) ((cipher + cr) * c1 + c2);
- return plain;
- }
-
- /* This function returns 1 the first time the eexec_scanner returns 1. */
-
- static int immediate_eexec()
- {
- static int reported = 0;
-
- if (!reported && eexec_scanner(0)) {
- reported = 1;
- return 1;
- } else {
- return 0;
- }
- }
-
- /* This function returns a single byte at a time through (possible) eexec
- decryption. When immediate_eexec returns 1 it fires up the eexec decryption
- machinery. */
-
- static int egetc()
- {
- static int in_eexec = 0;
- int c;
-
- if ((c = bgetc()) == EOF)
- return EOF;
-
- if (!in_eexec) {
- if (immediate_eexec()) {
- /* start eexec decryption */
- in_eexec = 1;
- er = 55665;
- /* toss out four random bytes */
- (void) edecrypt((byte) (bgetc() & 0xff));
- (void) edecrypt((byte) (bgetc() & 0xff));
- (void) edecrypt((byte) (bgetc() & 0xff));
- (void) edecrypt((byte) (bgetc() & 0xff));
- }
- return c;
- } else {
- return (int) edecrypt((byte) (c & 0xff));
- }
- }
-
- /* This function returns a line of eexec decrypted characters. A line is
- terminated by length (including terminating null) greater than LINESIZE, a
- newline \n, or one of the special charstring start sequences ` -| ' or
- ` RD '. The line, including the terminating newline or charstring start
- sequence is put into line[]. If terminated by a charstring start sequence,
- the flag start_charstring is set to 1. */
-
- static void egetline()
- {
- int c;
- char *p = line;
-
- start_charstring = 0;
- while (p < line + LINESIZE) {
- c = egetc();
- if (c == EOF)
- break;
- *p++ = (char) c;
- if (p >= line + 4 && (strncmp(p - 4, " -| ", 4) == 0 ||
- strncmp(p - 4, " RD ", 4) == 0)) {
- p -= 4;
- start_charstring = 1;
- break;
- }
- if (c == '\r') { /* map \r to \n */
- p[-1] = '\n';
- break;
- }
- if (c == '\n')
- break;
- }
- *p = '\0';
- }
-
- /* If the line contains an entry of the form `/lenIV <num>' then set the global
- lenIV to <num>. This indicates the number of random bytes at the beginning
- of each charstring. */
-
- static void set_lenIV()
- {
- char *p = strstr(line, "/lenIV ");
-
- if (p && isdigit(p[7])) {
- lenIV = atoi(p + 7);
- }
- }
-
- /* Subroutine to output strings. */
-
- static void output(char *string)
- {
- fprintf(ofp, "%s", string);
- }
-
- /* Subroutine to neatly format output of charstring tokens. If token = "\n",
- then a newline is output. If at start of line (start == 1), prefix token
- with tab, otherwise a space. */
-
- static void output_token(char *token)
- {
- static int start = 1;
-
- if (strcmp(token, "\n") == 0) {
- fprintf(ofp, "\n");
- start = 1;
- } else {
- fprintf(ofp, "%s%s", start ? "\t" : " ", token);
- start = 0;
- }
- }
-
- /* Subroutine to decrypt and ASCII-ify tokens in charstring data. First, the
- length (in bytes) of the charstring is determined from line[]. Then the
- charstring decryption machinery is fired up, skipping the first lenIV bytes.
- Finally, the decrypted tokens are expanded into human-readable form. */
-
- static void do_charstring()
- {
- int l = strlen(line);
- char *p = line + l - 1;
- int cs_len;
- int i;
- int b;
- int32 val;
- char buf[20];
-
- while (p >= line && *p != ' ' && *p != '\t')
- --p;
- cs_len = atoi(p);
-
- *p = '\0';
- output(line);
- output(" {\n");
-
- cr = 4330;
- for (i = 0; i < lenIV; i++, cs_len--)
- (void) cgetc();
-
- while (cs_len > 0) {
- --cs_len;
- b = cgetc();
- if (b >= 32) {
- if (b >= 32 && b <= 246) {
- val = b - 139;
- } else if (b >= 247 && b <= 250) {
- --cs_len;
- val = (b - 247)*256 + 108 + cgetc();
- } else if (b >= 251 && b <= 254) {
- --cs_len;
- val = -(b - 251)*256 - 108 - cgetc();
- } else {
- cs_len -= 4;
- val = (cgetc() & 0xff) << 24;
- val |= (cgetc() & 0xff) << 16;
- val |= (cgetc() & 0xff) << 8;
- val |= (cgetc() & 0xff) << 0;
- /* in case an int32 is larger than four bytes---sign extend */
- #if MAX_INT > 0x7FFFFFFFUL
- for (i = 4; i < sizeof(int32); i++)
- val |= 0xff << (i * 8);
- #endif
- }
- sprintf(buf, "%d", val);
- output_token(buf);
- } else {
- switch (b) {
- case 1: output_token("hstem"); break;
- case 3: output_token("vstem"); break;
- case 4: output_token("vmoveto"); break;
- case 5: output_token("rlineto"); break;
- case 6: output_token("hlineto"); break;
- case 7: output_token("vlineto"); break;
- case 8: output_token("rrcurveto"); break;
- case 9: output_token("closepath"); break;
- case 10: output_token("callsubr"); break;
- case 11: output_token("return"); break;
- case 13: output_token("hsbw"); break;
- case 14: output_token("endchar"); break;
- case 21: output_token("rmoveto"); break;
- case 22: output_token("hmoveto"); break;
- case 30: output_token("vhcurveto"); break;
- case 31: output_token("hvcurveto"); break;
- case 12:
- --cs_len;
- switch (b = cgetc()) {
- case 0: output_token("dotsection"); break;
- case 1: output_token("vstem3"); break;
- case 2: output_token("hstem3"); break;
- case 6: output_token("seac"); break;
- case 7: output_token("sbw"); break;
- case 12: output_token("div"); break;
- case 16: output_token("callothersubr"); break;
- case 17: output_token("pop"); break;
- case 33: output_token("setcurrentpoint"); break;
- default:
- sprintf(buf, "UNKNOWN_12_%d", b);
- output_token(buf);
- break;
- }
- break;
- default:
- sprintf(buf, "UNKNOWN_%d", b);
- output_token(buf);
- break;
- }
- output_token("\n");
- }
- }
- output("\t}");
- }
-
- static void print_banner()
- {
- static char rcs_revision[] = "$Revision: 1.2 $";
- static char revision[20];
-
- if (sscanf(rcs_revision, "$Revision: %19s", revision) != 1)
- revision[0] = '\0';
- fprintf(stderr, "This is t1disasm %s.\n", revision);
- }
-
- int main(int argc, char **argv)
- {
- print_banner();
-
- /* possibly open input & output files */
- if (argc >= 2) {
- /* OS2 */
- ifp = fopen(argv[1], "rb");
- if (!ifp) {
- fprintf(stderr, "error: cannot open %s for reading\n", argv[1]);
- exit(1);
- }
- }
- if (argc >= 3) {
- /* OS2 */
- ofp = fopen(argv[2], "wb");
- if (!ofp) {
- fprintf(stderr, "error: cannot open %s for writing\n", argv[2]);
- exit(1);
- }
- }
-
- /* main loop---normally done when reach `mark currentfile closefile' on
- output (rest is garbage). */
-
- for (;;) {
- egetline();
- if (line[0] == '\0')
- break;
- set_lenIV();
- if (start_charstring)
- do_charstring();
- else
- output(line);
- if (strcmp(line, "mark currentfile closefile\n") == 0)
- break;
- }
-
- fclose(ifp);
- fclose(ofp);
-
- return 0;
- }