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