home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 12 Font / 12-Font.zip / FONTUTIL.ZIP / t1disasm.c < prev    next >
Text File  |  1992-07-06  |  13KB  |  505 lines

  1. /* t1disasm
  2.  *
  3.  * This program `disassembles' Adobe Type-1 font programs in either PFB or PFA
  4.  * format.  It produces a human readable/editable pseudo-PostScript file by
  5.  * performing eexec and charstring decryption as specified in the `Adobe Type 1
  6.  * Font Format' version 1.1 (the `black book').  There is a companion program,
  7.  * t1asm, which `assembles' such a pseudo-PostScript file into either PFB or
  8.  * PFA format.
  9.  *
  10.  * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.
  11.  *
  12.  * Permission is hereby granted to use, modify, and distribute this program
  13.  * for any purpose provided this copyright notice and the one below remain
  14.  * intact.
  15.  *
  16.  * I. Lee Hetherington (ilh@lcs.mit.edu)
  17.  *
  18.  * $Log:        t1disasm.c,v $
  19.  * Revision 1.2  92/05/22  12:05:33  ilh
  20.  * Fixed bug where we were counting on sprintf to return its first
  21.  * argument---not true in ANSI C.  This bug was detected by Piet
  22.  * Tutelaers (rcpt@urc.tue.nl).  Also, fixed (signed) integer overflow
  23.  * error when testing high-order bit of integer for possible
  24.  * sign-extension by making comparison between unsigned integers.
  25.  *
  26.  * Revision 1.1  92/05/22  12:04:07  ilh
  27.  * initial version
  28.  *
  29.  * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by
  30.  * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code
  31.  * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS
  32.  * ... #endif, where _MSDOS is an identifier, which is automatically
  33.  * defined, if you compile with the Microsoft C/C++ Compiler.
  34.  *
  35.  */
  36.  
  37. #ifndef lint
  38. static char rcsid[] =
  39.   "@(#) $Id: t1disasm.c,v 1.2 92/05/22 12:05:33 ilh Exp Locker: ilh $";
  40. static char copyright[] =
  41.   "@(#) Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.";
  42. #ifdef _MSDOS
  43. static char portnotice[] =
  44.   "@(#) Ported to MS-DOS by Kai-Uwe Herbing (herbing@netmbx.netmbx.de).";
  45. #endif
  46. #endif
  47.  
  48. /* Note: this is ANSI C. */
  49.  
  50. #ifdef _MSDOS
  51.   #include <fcntl.h>
  52.   #include <io.h>
  53. #endif
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. #include <string.h>
  57. #include <ctype.h>
  58. #include <limits.h>
  59.  
  60. /* int32 must be at least 32-bit and uint16 must be at least 16-bit */
  61. #if INT_MAX >= 0x7FFFFFFFUL
  62. typedef int int32;
  63. #else
  64. typedef long int32;
  65. #endif
  66. #if USHRT_MAX >= 0xFFFFUL
  67. typedef unsigned short uint16;
  68. #else
  69. typedef unsigned int uint16;
  70. #endif
  71.  
  72. #define LINESIZE 256
  73.  
  74. #define cgetc()  cdecrypt((byte) (egetc() & 0xff))
  75.  
  76. typedef unsigned char byte;
  77.  
  78. static FILE *ifp = stdin;
  79. static FILE *ofp = stdout;
  80. static char line[LINESIZE];
  81. static int start_charstring = 0;
  82. static int lenIV = 4;
  83.  
  84. /* decryption stuff */
  85. static uint16 er, cr;
  86. static uint16 c1 = 52845, c2 = 22719;
  87.  
  88. /* This function looks for `currentfile eexec' string and returns 1 once found.
  89.    If c == 0, then simply check the status. */
  90.  
  91. static int eexec_scanner(int c)
  92. {
  93.   static char *key = "currentfile eexec\n";
  94.   static char *p = 0;
  95.  
  96.   if (!p)
  97.     p = key;
  98.  
  99.   if (c && *p) {
  100.     if ((char) (c & 0xff) == *p)
  101.       ++p;
  102.     else
  103.       p = key;
  104.   }
  105.   return *p == '\0';
  106. }
  107.  
  108. /* This function returns the value of a single hex digit. */
  109.  
  110. static int hexval(char c)
  111. {
  112.   if (c >= 'A' && c <= 'F')
  113.     return c - 'A' + 10;
  114.   else if (c >= 'a' && c <= 'f')
  115.     return c - 'a' + 10;
  116.   else if (c >= '0' && c <= '9')
  117.     return c - '0';
  118.   else
  119.     return 0;
  120. }
  121.  
  122. /* This function returns a single character at a time from a PFA or PFB file.
  123.    This stream is mixed ASCII and binary bytes.  For PFB files, the section
  124.    headers are removed, and \r is replaced by \n in ASCII sections.  For PFA
  125.    files, the hexdecimal data is turned into binary bytes. */
  126.  
  127. static int bgetc()
  128. {
  129.   static int first_byte = 1;
  130.   static int is_pfa = 0;
  131.   static int is_pfb = 0;
  132.   static int32 pfb_remaining = 0;
  133.   int c, val;
  134.  
  135.   /* is_pfa == 1 means PFA initial ASCII section
  136.      is_pfa == 2 means PFA hexadecimal section
  137.      is_pfb == 1 means PFB ASCII section
  138.      is_pfB == 2 means PFB binary section */
  139.  
  140.   c = fgetc(ifp);
  141.  
  142.   if (c == EOF)
  143.     return EOF;
  144.  
  145.   if (first_byte) {
  146.     /* Determine if this is a PFA or PFB file by looking at first byte. */
  147.     if (c == 0x80) {
  148.       is_pfb = 1;
  149.       is_pfa = 0;
  150.  
  151.       #ifdef _MSDOS
  152.         /* If we are processing a PFB (binary) input  */
  153.         /* file, we must set its file mode to binary. */
  154.         _setmode(_fileno(ifp), _O_BINARY);
  155.       #endif
  156.  
  157.     } else {
  158.       is_pfb = 0;
  159.       is_pfa = 1;
  160.     }
  161.     first_byte = 0;
  162.   }
  163.  
  164.   if (is_pfb) {
  165.     /* PFB */
  166.     if (pfb_remaining == 0) {
  167.       /* beginning of block---we know c == 0x80 at this point */
  168.       switch (fgetc(ifp)) {
  169.       case 1:
  170.         is_pfb = 1;
  171.         break;
  172.       case 2:
  173.         is_pfb = 2;
  174.         break;
  175.       case 3:
  176.         return EOF;
  177.       default:
  178.         fprintf(stderr, "error: is this really a PFB file?\n");
  179.         exit(1);
  180.       }
  181.       /* get block length */
  182.       pfb_remaining = (int32) (fgetc(ifp) & 0xff);
  183.       pfb_remaining |= (int32) (fgetc(ifp) & 0xff) << 8;
  184.       pfb_remaining |= (int32) (fgetc(ifp) & 0xff) << 16;
  185.       pfb_remaining |= (int32) (fgetc(ifp) & 0xff) << 24;
  186.       /* get character */
  187.       c = fgetc(ifp);
  188.       if (c == EOF)
  189.         return EOF;
  190.     }
  191.     --pfb_remaining;
  192.     /* in ASCII section change return to newline */
  193.     if (is_pfb == 1 && c == '\r')
  194.       c = '\n';
  195.     (void) eexec_scanner(c);
  196.     return c;
  197.   } else {
  198.     /* PFA */
  199.     if (is_pfa == 1) {
  200.       /* in initial ASCII */
  201.       if (eexec_scanner(c))
  202.         is_pfa = 2;
  203.       return c;
  204.     } else {
  205.       /* in hexadecimal */
  206.       while (isspace(c))
  207.         c = fgetc(ifp);
  208.       val = hexval((char)c) << 4;
  209.       val |= hexval((char)(c = fgetc(ifp)));
  210.       if (c == EOF)
  211.         return EOF;
  212.       return val;
  213.     }
  214.   }
  215. }
  216.  
  217. /* Two separate decryption functions because eexec and charstring decryption
  218.    must proceed in parallel. */
  219.  
  220. static byte edecrypt(byte cipher)
  221. {
  222.   byte plain;
  223.  
  224.   plain = (byte) (cipher ^ (er >> 8));
  225.   er = (uint16) ((cipher + er) * c1 + c2);
  226.   return plain;
  227. }
  228.  
  229. static byte cdecrypt(byte cipher)
  230. {
  231.   byte plain;
  232.  
  233.   plain = (byte) (cipher ^ (cr >> 8));
  234.   cr = (uint16) ((cipher + cr) * c1 + c2);
  235.   return plain;
  236. }
  237.  
  238. /* This function returns 1 the first time the eexec_scanner returns 1. */
  239.  
  240. static int immediate_eexec()
  241. {
  242.   static int reported = 0;
  243.  
  244.   if (!reported && eexec_scanner(0)) {
  245.     reported = 1;
  246.     return 1;
  247.   } else {
  248.     return 0;
  249.   }
  250. }
  251.  
  252. /* This function returns a single byte at a time through (possible) eexec
  253.    decryption.  When immediate_eexec returns 1 it fires up the eexec decryption
  254.    machinery. */
  255.  
  256. static int egetc()
  257. {
  258.   static int in_eexec = 0;
  259.   int c;
  260.  
  261.   if ((c = bgetc()) == EOF)
  262.     return EOF;
  263.  
  264.   if (!in_eexec) {
  265.     if (immediate_eexec()) {
  266.       /* start eexec decryption */
  267.       in_eexec = 1;
  268.       er = 55665;
  269.       /* toss out four random bytes */
  270.       (void) edecrypt((byte) (bgetc() & 0xff));
  271.       (void) edecrypt((byte) (bgetc() & 0xff));
  272.       (void) edecrypt((byte) (bgetc() & 0xff));
  273.       (void) edecrypt((byte) (bgetc() & 0xff));
  274.     }
  275.     return c;
  276.   } else {
  277.     return (int) edecrypt((byte) (c & 0xff));
  278.   }
  279. }
  280.  
  281. /* This function returns a line of eexec decrypted characters.  A line is
  282.    terminated by length (including terminating null) greater than LINESIZE, a
  283.    newline \n, or one of the special charstring start sequences ` -| ' or
  284.    ` RD '.  The line, including the terminating newline or charstring start
  285.    sequence is put into line[].  If terminated by a charstring start sequence,
  286.    the flag start_charstring is set to 1. */
  287.  
  288. static void egetline()
  289. {
  290.   int c;
  291.   char *p = line;
  292.  
  293.   start_charstring = 0;
  294.   while (p < line + LINESIZE) {
  295.     c = egetc();
  296.     if (c == EOF)
  297.       break;
  298.     *p++ = (char) c;
  299.     if (p >= line + 4 && (strncmp(p - 4, " -| ", 4) == 0 ||
  300.                           strncmp(p - 4, " RD ", 4) == 0)) {
  301.       p -= 4;
  302.       start_charstring = 1;
  303.       break;
  304.     }
  305.     if (c == '\r') {                              /* map \r to \n */
  306.       p[-1] = '\n';
  307.       break;
  308.     }
  309.     if (c == '\n')
  310.       break;
  311.   }
  312.   *p = '\0';
  313. }
  314.  
  315. /* If the line contains an entry of the form `/lenIV <num>' then set the global
  316.    lenIV to <num>.  This indicates the number of random bytes at the beginning
  317.    of each charstring. */
  318.  
  319. static void set_lenIV()
  320. {
  321.   char *p = strstr(line, "/lenIV ");
  322.  
  323.   if (p && isdigit(p[7])) {
  324.     lenIV = atoi(p + 7);
  325.   }
  326. }
  327.  
  328. /* Subroutine to output strings. */
  329.  
  330. static void output(char *string)
  331. {
  332.   fprintf(ofp, "%s", string);
  333. }
  334.  
  335. /* Subroutine to neatly format output of charstring tokens.  If token = "\n",
  336.    then a newline is output.  If at start of line (start == 1), prefix token
  337.    with tab, otherwise a space. */
  338.  
  339. static void output_token(char *token)
  340. {
  341.   static int start = 1;
  342.  
  343.   if (strcmp(token, "\n") == 0) {
  344.     fprintf(ofp, "\n");
  345.     start = 1;
  346.   } else {
  347.     fprintf(ofp, "%s%s", start ? "\t" : " ", token);
  348.     start = 0;
  349.   }
  350. }
  351.  
  352. /* Subroutine to decrypt and ASCII-ify tokens in charstring data.  First, the
  353.    length (in bytes) of the charstring is determined from line[].  Then the
  354.    charstring decryption machinery is fired up, skipping the first lenIV bytes.
  355.    Finally, the decrypted tokens are expanded into human-readable form. */
  356.  
  357. static void do_charstring()
  358. {
  359.   int l = strlen(line);
  360.   char *p = line + l - 1;
  361.   int cs_len;
  362.   int i;
  363.   int b;
  364.   int32 val;
  365.   char buf[20];
  366.  
  367.   while (p >= line && *p != ' ' && *p != '\t')
  368.     --p;
  369.   cs_len = atoi(p);
  370.  
  371.   *p = '\0';
  372.   output(line);
  373.   output(" {\n");
  374.  
  375.   cr = 4330;
  376.   for (i = 0; i < lenIV; i++, cs_len--)
  377.     (void) cgetc();
  378.  
  379.   while (cs_len > 0) {
  380.     --cs_len;
  381.     b = cgetc();
  382.     if (b >= 32) {
  383.       if (b >= 32 && b <= 246) {
  384.         val = b - 139;
  385.       } else if (b >= 247 && b <= 250) {
  386.         --cs_len;
  387.         val = (b - 247)*256 + 108 + cgetc();
  388.       } else if (b >= 251 && b <= 254) {
  389.         --cs_len;
  390.         val = -(b - 251)*256 - 108 - cgetc();
  391.       } else {
  392.         cs_len -= 4;
  393.         val =  (cgetc() & 0xff) << 24;
  394.         val |= (cgetc() & 0xff) << 16;
  395.         val |= (cgetc() & 0xff) <<  8;
  396.         val |= (cgetc() & 0xff) <<  0;
  397.         /* in case an int32 is larger than four bytes---sign extend */
  398.         #if MAX_INT > 0x7FFFFFFFUL
  399.           for (i = 4; i < sizeof(int32); i++)
  400.             val |= 0xff << (i * 8);
  401.         #endif
  402.       }
  403.       sprintf(buf, "%d", val);
  404.       output_token(buf);
  405.     } else {
  406.       switch (b) {
  407.       case 1: output_token("hstem"); break;
  408.       case 3: output_token("vstem"); break;
  409.       case 4: output_token("vmoveto"); break;
  410.       case 5: output_token("rlineto"); break;
  411.       case 6: output_token("hlineto"); break;
  412.       case 7: output_token("vlineto"); break;
  413.       case 8: output_token("rrcurveto"); break;
  414.       case 9: output_token("closepath"); break;
  415.       case 10: output_token("callsubr"); break;
  416.       case 11: output_token("return"); break;
  417.       case 13: output_token("hsbw"); break;
  418.       case 14: output_token("endchar"); break;
  419.       case 21: output_token("rmoveto"); break;
  420.       case 22: output_token("hmoveto"); break;
  421.       case 30: output_token("vhcurveto"); break;
  422.       case 31: output_token("hvcurveto"); break;
  423.       case 12:
  424.         --cs_len;
  425.         switch (b = cgetc()) {
  426.         case 0: output_token("dotsection"); break;
  427.         case 1: output_token("vstem3"); break;
  428.         case 2: output_token("hstem3"); break;
  429.         case 6: output_token("seac"); break;
  430.         case 7: output_token("sbw"); break;
  431.         case 12: output_token("div"); break;
  432.         case 16: output_token("callothersubr"); break;
  433.         case 17: output_token("pop"); break;
  434.         case 33: output_token("setcurrentpoint"); break;
  435.         default:
  436.           sprintf(buf, "UNKNOWN_12_%d", b);
  437.           output_token(buf);
  438.           break;
  439.         }
  440.         break;
  441.       default:
  442.         sprintf(buf, "UNKNOWN_%d", b);
  443.         output_token(buf);
  444.         break;
  445.       }
  446.       output_token("\n");
  447.     }
  448.   }
  449.   output("\t}");
  450. }
  451.  
  452. static void print_banner()
  453. {
  454.   static char rcs_revision[] = "$Revision: 1.2 $";
  455.   static char revision[20];
  456.  
  457.   if (sscanf(rcs_revision, "$Revision: %19s", revision) != 1)
  458.     revision[0] = '\0';
  459.   fprintf(stderr, "This is t1disasm %s.\n", revision);
  460. }
  461.  
  462. int main(int argc, char **argv)
  463. {
  464.   print_banner();
  465.  
  466.   /* possibly open input & output files */
  467.   if (argc >= 2) {
  468. /* OS2 */
  469.     ifp = fopen(argv[1], "rb");
  470.     if (!ifp) {
  471.       fprintf(stderr, "error: cannot open %s for reading\n", argv[1]);
  472.       exit(1);
  473.     }
  474.   }
  475.   if (argc >= 3) {
  476. /* OS2 */
  477.     ofp = fopen(argv[2], "wb");
  478.     if (!ofp) {
  479.       fprintf(stderr, "error: cannot open %s for writing\n", argv[2]);
  480.       exit(1);
  481.     }
  482.   }
  483.  
  484.   /* main loop---normally done when reach `mark currentfile closefile' on
  485.      output (rest is garbage). */
  486.  
  487.   for (;;) {
  488.     egetline();
  489.     if (line[0] == '\0')
  490.       break;
  491.     set_lenIV();
  492.     if (start_charstring)
  493.       do_charstring();
  494.     else
  495.       output(line);
  496.     if (strcmp(line, "mark currentfile closefile\n") == 0)
  497.       break;
  498.     }
  499.  
  500.   fclose(ifp);
  501.   fclose(ofp);
  502.  
  503.   return 0;
  504. }
  505.