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