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

  1. /* t1asm
  2.  *
  3.  * This program `assembles' Adobe Type-1 font programs in pseudo-PostScript
  4.  * form into either PFB or PFA format.  The human readable/editable input is
  5.  * charstring- and eexec-encrypted as specified in the `Adobe Type 1 Font
  6.  * Format' version 1.1 (the `black book').  There is a companion program,
  7.  * t1disasm, which `disassembles' PFB and PFA files into a pseudo-PostScript
  8.  * file.
  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:        t1asm.c,v $
  19.  * Revision 1.2  92/05/22  11:54:45  ilh
  20.  * Fixed bug where integers larger than 32000 could not be encoded in
  21.  * charstrings.  Now integer range is correct for four-byte
  22.  * twos-complement integers: -(1<<31) <= i <= (1<<31)-1.  Bug detected by
  23.  * Piet Tutelaers (rcpt@urc.tue.nl).
  24.  *
  25.  * Revision 1.1  92/05/22  11:48:46  ilh
  26.  * initial version
  27.  *
  28.  * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by
  29.  * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code
  30.  * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS
  31.  * ... #endif, where _MSDOS is an identifier, which is automatically
  32.  * defined, if you compile with the Microsoft C/C++ Compiler.
  33.  *
  34.  */
  35.  
  36. #ifndef lint
  37. static char rcsid[] =
  38.   "@(#) $Id: t1asm.c,v 1.2 92/05/22 11:54:45 ilh Exp Locker: ilh $";
  39. static char copyright[] =
  40.   "@(#) Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.";
  41. #ifdef _MSDOS
  42. static char portnotice[] =
  43.   "@(#) Ported to MS-DOS by Kai-Uwe Herbing (herbing@netmbx.netmbx.de).";
  44. #endif
  45. #endif
  46.  
  47. /* Note: this is ANSI C. */
  48.  
  49. #ifdef _MSDOS
  50.   #include <fcntl.h>
  51.   #include <getopt.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 MAXBLOCKLEN ((1L<<17)-6)
  75. #define MINBLOCKLEN ((1L<<8)-6)
  76.  
  77. #define MARKER   128
  78. #define ASCII    1
  79. #define BINARY   2
  80. #define DONE     3
  81.  
  82. typedef unsigned char byte;
  83.  
  84. static FILE *ifp = stdin;
  85. static FILE *ofp = stdout;
  86.  
  87. /* flags */
  88. static int pfb = 0;
  89. static int active = 0;
  90. static int start_charstring = 0;
  91. static int in_eexec = 0;
  92.  
  93. static char line[LINESIZE];
  94.  
  95. /* lenIV and charstring start command */
  96. static int lenIV = 4;
  97. static char cs_start[10];
  98.  
  99. /* for charstring buffering */
  100. static byte charstring_buf[65535];
  101. static byte *charstring_bp;
  102.  
  103. /* for PFB block buffering */
  104. static byte blockbuf[MAXBLOCKLEN];
  105. static int32 blocklen = MAXBLOCKLEN;
  106. static int32 blockpos = -1;
  107. static int blocktyp = ASCII;
  108.  
  109. /* decryption stuff */
  110. static uint16 er, cr;
  111. static uint16 c1 = 52845, c2 = 22719;
  112.  
  113. /* table of charstring commands */
  114. static struct command {
  115.   char *name;
  116.   int one, two;
  117. } command_table[] = {
  118.   { "callothersubr", 12, 16 },
  119.   { "callsubr", 10, -1 },
  120.   { "closepath", 9, -1 },
  121.   { "div", 12, 12 },
  122.   { "dotsection", 12, 0 },
  123.   { "endchar", 14, -1 },
  124.   { "hlineto", 6, -1 },
  125.   { "hmoveto", 22, -1 },
  126.   { "hsbw", 13, -1 },
  127.   { "hstem", 1, -1 },
  128.   { "hstem3", 12, 2 },
  129.   { "hvcurveto", 31, -1 },
  130.   { "pop", 12, 17 },
  131.   { "return", 11, -1 },
  132.   { "rlineto", 5, -1 },
  133.   { "rmoveto", 21, -1 },
  134.   { "rrcurveto", 8, -1 },
  135.   { "sbw", 12, 7 },
  136.   { "seac", 12, 6 },
  137.   { "setcurrentpoint", 12, 33 },
  138.   { "vhcurveto", 30, -1 },
  139.   { "vlineto", 7, -1 },
  140.   { "vmoveto", 4, -1 },
  141.   { "vstem", 3, -1 },
  142.   { "vstem3", 12, 1 },
  143. };                                                /* alphabetical */
  144.  
  145. /* Two separate encryption functions because eexec and charstring encryption
  146.    must proceed in parallel. */
  147.  
  148. static byte eencrypt(byte plain)
  149. {
  150.   byte cipher;
  151.  
  152.   cipher = (byte) (plain ^ (er >> 8));
  153.   er = (uint16) ((cipher + er) * c1 + c2);
  154.   return cipher;
  155. }
  156.  
  157. static byte cencrypt(byte plain)
  158. {
  159.   byte cipher;
  160.  
  161.   cipher = (byte) (plain ^ (cr >> 8));
  162.   cr = (uint16) ((cipher + cr) * c1 + c2);
  163.   return cipher;
  164. }
  165.  
  166. /* This function flushes a buffered PFB block. */
  167.  
  168. static void output_block()
  169. {
  170.   int32 i;
  171.  
  172.   /* output four-byte block length */
  173.   fputc((int) (blockpos & 0xff), ofp);
  174.   fputc((int) ((blockpos >> 8) & 0xff), ofp);
  175.   fputc((int) ((blockpos >> 16) & 0xff), ofp);
  176.   fputc((int) ((blockpos >> 24) & 0xff), ofp);
  177.  
  178.   /* output block data */
  179.   for (i = 0; i < blockpos; i++)
  180.     fputc(blockbuf[i], ofp);
  181.  
  182.   /* mark block buffer empty and uninitialized */
  183.   blockpos =  -1;
  184. }
  185.  
  186. /* This function outputs a single byte.  If output is in PFB format then output
  187.    is buffered through blockbuf[].  If output is in PFA format, then output
  188.    will be hexadecimal if in_eexec is set, ASCII otherwise. */
  189.  
  190. static void output_byte(byte b)
  191. {
  192.   static char *hexchar = "0123456789ABCDEF";
  193.   static int hexcol = 0;
  194.  
  195.   if (pfb) {
  196.     /* PFB */
  197.     if (blockpos < 0) {
  198.       fputc(MARKER, ofp);
  199.       fputc(blocktyp, ofp);
  200.       blockpos = 0;
  201.     }
  202.     blockbuf[blockpos++] = b;
  203.     if (blockpos == blocklen)
  204.       output_block();
  205.   } else {
  206.     /* PFA */
  207.     if (in_eexec) {
  208.       /* trim hexadecimal lines to 64 columns */
  209.       if (hexcol >= 64) {
  210.         fputc('\n', ofp);
  211.         hexcol = 0;
  212.       }
  213.       fputc(hexchar[(b >> 4) & 0xf], ofp);
  214.       fputc(hexchar[b & 0xf], ofp);
  215.       hexcol += 2;
  216.     } else {
  217.       fputc(b, ofp);
  218.     }
  219.   }
  220. }
  221.  
  222. /* This function outputs a byte through possible eexec encryption. */
  223.  
  224. static void eexec_byte(byte b)
  225. {
  226.   if (in_eexec)
  227.     output_byte(eencrypt(b));
  228.   else
  229.     output_byte(b);
  230. }
  231.  
  232. /* This function outputs a null-terminated string through possible eexec
  233.    encryption. */
  234.  
  235. static void eexec_string(char *string)
  236. {
  237.   while (*string)
  238.     eexec_byte((byte) *string++);
  239. }
  240.  
  241. /* This function gets ready for the eexec-encrypted data.  If output is in
  242.    PFB format then flush current ASCII block and get ready for binary block.
  243.    We start encryption with four random (zero) bytes. */
  244.  
  245. static void eexec_start()
  246. {
  247.   eexec_string(line);
  248.   if (pfb) {
  249.     output_block();
  250.     blocktyp = BINARY;
  251.   }
  252.  
  253.   in_eexec = 1;
  254.   er = 55665;
  255.   eexec_byte(0);
  256.   eexec_byte(0);
  257.   eexec_byte(0);
  258.   eexec_byte(0);
  259. }
  260.  
  261. /* This function wraps-up the eexec-encrypted data and writes ASCII trailer.
  262.    If output is in PFB format then this entails flushing binary block and
  263.    starting an ASCII block. */
  264.  
  265. static void eexec_end()
  266. {
  267.   int i, j;
  268.  
  269.   if (pfb) {
  270.     output_block();
  271.     blocktyp = ASCII;
  272.   } else {
  273.     fputc('\n', ofp);
  274.   }
  275.   in_eexec = 0;
  276.   for (i = 0; i < 8; i++) {
  277.     for (j = 0; j < 64; j++)
  278.       eexec_byte('0');
  279.     eexec_byte('\n');
  280.   }
  281.   eexec_string("cleartomark\n");
  282.   if (pfb) {
  283.     output_block();
  284.     fputc(MARKER, ofp);
  285.     fputc(DONE, ofp);
  286.   }
  287. }
  288.  
  289. /* This function returns an input line of characters.  A line is terminated by
  290.    length (including terminating null) greater than LINESIZE, a newline \n, or
  291.    when active (looking for charstrings) by '{'.  When terminated by a newline
  292.    the newline is put into line[].  When terminated by '{', the '{' is not put
  293.    into line[], and the flag start_charstring is set to 1. */
  294.  
  295. static void getline()
  296. {
  297.   int c;
  298.   char *p = line;
  299.   int comment = 0;
  300.  
  301.   start_charstring = 0;
  302.   while (p < line + LINESIZE) {
  303.     c = fgetc(ifp);
  304.     if (c == EOF)
  305.       break;
  306.     if (c == '%')
  307.       comment = 1;
  308.     if (active && !comment && c == '{') {
  309.       start_charstring = 1;
  310.       break;
  311.     }
  312.     *p++ = (char) c;
  313.     if (c == '\n')
  314.       break;
  315.   }
  316.   *p = '\0';
  317. }
  318.  
  319. /* This function is used by the binary search, bsearch(), for command names in
  320.    the command table. */
  321.  
  322. static int command_compare(const void *key, const void *item)
  323. {
  324.   return strcmp((char *) key, ((struct command *) item)->name);
  325. }
  326.  
  327. /* This function returns 1 if the string is an integer and 0 otherwise. */
  328.  
  329. static int is_integer(char *string)
  330. {
  331.   if (isdigit(string[0]) || string[0] == '-' || string[0] == '+') {
  332.     while (*++string && isdigit(*string))
  333.       ;                                           /* deliberately empty */
  334.     if (!*string)
  335.       return 1;
  336.   }
  337.   return 0;
  338. }
  339.  
  340. /* This function initializes charstring encryption.  Note that this is called
  341.    at the beginning of every charstring. */
  342.  
  343. static void charstring_start()
  344. {
  345.   int i;
  346.  
  347.   charstring_bp = charstring_buf;
  348.   cr = 4330;
  349.   for (i = 0; i < lenIV; i++)
  350.     *charstring_bp++ = cencrypt((byte) 0);
  351. }
  352.  
  353. /* This function encrypts and buffers a single byte of charstring data. */
  354.  
  355. static void charstring_byte(int v)
  356. {
  357.   byte b = (byte) (v & 0xff);
  358.  
  359.   if (charstring_bp - charstring_buf > sizeof(charstring_buf)) {
  360.     fprintf(stderr, "error: charstring_buf full (%d bytes)\n",
  361.             sizeof(charstring_buf));
  362.     exit(1);
  363.   }
  364.   *charstring_bp++ = cencrypt(b);
  365. }
  366.  
  367. /* This function outputs buffered, encrypted charstring data through possible
  368.    eexec encryption. */
  369.  
  370. static void charstring_end()
  371. {
  372.   byte *bp;
  373.  
  374.   sprintf(line, "%d ", charstring_bp - charstring_buf);
  375.   eexec_string(line);
  376.   sprintf(line, "%s ", cs_start);
  377.   eexec_string(line);
  378.   for (bp = charstring_buf; bp < charstring_bp; bp++)
  379.     eexec_byte(*bp);
  380. }
  381.  
  382. /* This function generates the charstring representation of an integer. */
  383.  
  384. static void charstring_int(int num)
  385. {
  386.   int x;
  387.  
  388.   if (num >= -107 && num <= 107) {
  389.     charstring_byte(num + 139);
  390.   } else if (num >= 108 && num <= 1131) {
  391.     x = num - 108;
  392.     charstring_byte(x / 256 + 247);
  393.     charstring_byte(x % 256);
  394.   } else if (num >= -1131 && num <= -108) {
  395.     x = abs(num) - 108;
  396.     charstring_byte(x / 256 + 251);
  397.     charstring_byte(x % 256);
  398.   } else if (num >= (-2147483647-1) && num <= 2147483647) {
  399.     charstring_byte(255);
  400.     charstring_byte(num >> 24);
  401.     charstring_byte(num >> 16);
  402.     charstring_byte(num >> 8);
  403.     charstring_byte(num);
  404.   } else {
  405.     fprintf(stderr,
  406.             "error: cannot format the integer %d, too large\n", num);
  407.     exit(1);
  408.   }
  409. }
  410.  
  411. /* This function parses an entire charstring into integers and commands,
  412.    outputting bytes through the charstring buffer. */
  413.  
  414. static void parse_charstring()
  415. {
  416.   struct command *cp;
  417.  
  418.   charstring_start();
  419.   while (fscanf(ifp, "%s", line) == 1) {
  420.     if (line[0] == '%') {
  421.       /* eat comment to end of line */
  422.       while (fgetc(ifp) != '\n' && !feof(ifp))
  423.         ;                                         /* deliberately empty */
  424.       continue;
  425.     }
  426.     if (line[0] == '}')
  427.       break;
  428.     if (is_integer(line)) {
  429.       charstring_int(atoi(line));
  430.     } else {
  431.       cp = (struct command *)
  432.         bsearch((void *) line, (void *) command_table,
  433.                 sizeof(command_table) / sizeof(struct command),
  434.                 sizeof(struct command),
  435.                 command_compare);
  436.       if (cp) {
  437.         charstring_byte(cp->one);
  438.         if (cp->two >= 0)
  439.           charstring_byte(cp->two);
  440.       } else {
  441.         fprintf(stderr, "error: cannot use `%s' in charstring\n");
  442.         exit(1);
  443.       }
  444.     }
  445.   }
  446.   charstring_end();
  447. }
  448.  
  449. static void usage()
  450. {
  451.   fprintf(stderr,
  452.           "usage: t1asm [-b] [-l block-length] [input [output]]\n");
  453.   fprintf(stderr,
  454.           "\n-b means output in PFB format, otherwise PFA format.\n");
  455.   fprintf(stderr,
  456.           "The block length applies to the length of blocks in the\n");
  457.   fprintf(stderr,
  458.           "PFB output file; the default is to use the largest possible.\n");
  459.   exit(1);
  460. }
  461.  
  462. static void print_banner()
  463. {
  464.   static char rcs_revision[] = "$Revision: 1.2 $";
  465.   static char revision[20];
  466.  
  467.   if (sscanf(rcs_revision, "$Revision: %19s", revision) != 1)
  468.     revision[0] = '\0';
  469.   fprintf(stderr, "This is t1asm %s.\n", revision);
  470. }
  471.  
  472. int main(int argc, char **argv)
  473. {
  474.   char *p, *q, *r;
  475.   int c;
  476.  
  477.   extern char *optarg;
  478.   extern int optind;
  479.   extern int getopt(int argc, char **argv, char *optstring);
  480.  
  481.   print_banner();
  482.  
  483.   /* interpret command line arguments using getopt */
  484.   while ((c = getopt(argc, argv, "bl:")) != -1)
  485.     switch (c) {
  486.     case 'b':
  487.       pfb = 1;
  488.       break;
  489.     case 'l':
  490.       blocklen = atoi(optarg);
  491.       if (blocklen < MINBLOCKLEN) {
  492.         blocklen = MINBLOCKLEN;
  493.         fprintf(stderr,
  494.                 "warning: using minimum block length of %d\n",
  495.                 blocklen);
  496.       } else if (blocklen > MAXBLOCKLEN) {
  497.         blocklen = MAXBLOCKLEN;
  498.         fprintf(stderr,
  499.                 "warning: using maximum block length of %d\n",
  500.                 blocklen);
  501.       }
  502.       break;
  503.     default:
  504.       usage();
  505.       break;
  506.     }
  507.   if (argc - optind > 2)
  508.     usage();
  509.  
  510.   /* possibly open input & output files */
  511.   if (argc - optind >= 1) {
  512.     ifp = fopen(argv[optind], "rb");
  513.     if (!ifp) {
  514.       fprintf(stderr, "error: cannot open %s for reading\n", argv[1]);
  515.       exit(1);
  516.     }
  517.   }
  518.   if (argc - optind >= 2) {
  519.     ofp = fopen(argv[optind + 1], "wb");
  520.     if (!ofp) {
  521.       fprintf(stderr, "error: cannot open %s for writing\n", argv[2]);
  522.       exit(1);
  523.     }
  524.   }
  525.  
  526.   #ifdef _MSDOS
  527.     /* If we are processing a PFB (binary) output */
  528.     /* file, we must set its file mode to binary. */
  529.     if (pfb)
  530.       _setmode(_fileno(ofp), _O_BINARY);
  531.   #endif
  532.  
  533.   /* Finally, we loop until no more input.  Some special things to look for
  534.      are the `currentfile eexec' line, the beginning of the `/Subrs'
  535.      definition, the definition of `/lenIV', and the definition of the
  536.      charstring start command which has `...string currentfile...' in it. */
  537.  
  538.   while (!feof(ifp) && !ferror(ifp)) {
  539.     getline();
  540.     if (strcmp(line, "currentfile eexec\n") == 0) {
  541.       eexec_start();
  542.       continue;
  543.     } else if (strstr(line, "/Subrs") && isspace(line[6])) {
  544.       active = 1;
  545.     } else if ((p = strstr(line, "/lenIV"))) {
  546.       sscanf(p, "%*s %d", &lenIV);
  547.     } else if ((p = strstr(line, "string currentfile"))) {
  548.       /* locate the name of the charstring start command */
  549.       *p = '\0';                                  /* damage line[] */
  550.       q = strrchr(line, '/');
  551.       if (q) {
  552.         r = cs_start;
  553.         ++q;
  554.         while (!isspace(*q) && *q != '{')
  555.           *r++ = *q++;
  556.         *r = '\0';
  557.       }
  558.       *p = 's';                                   /* repair line[] */
  559.     }
  560.     /* output line data */
  561.     eexec_string(line);
  562.     if (start_charstring) {
  563.       if (!cs_start[0]) {
  564.         fprintf(stderr, "error: couldn't find charstring start command\n");
  565.         exit(1);
  566.       }
  567.       parse_charstring();
  568.     }
  569.   }
  570.   eexec_end();
  571.  
  572.   fclose(ifp);
  573.   fclose(ofp);
  574.  
  575.   return 0;
  576. }
  577.