home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 12 Font / 12-Font.zip / T1FONT.ZIP / t1font.c next >
Text File  |  1991-10-14  |  35KB  |  1,164 lines

  1. /********************************************************************
  2.  *                                                                  *
  3.  *  Title:  t1font - Adobe Type 1 Font Utility                      *
  4.  *                                                                  *
  5.  *  Author: Ken Borgendale   14 OCT 91                              *
  6.  *                                                                  *
  7.  *  Copyright:                                                      *
  8.  *      t1font Copyright (C) IBM Corp., 1991                        *
  9.  *                                                                  *
  10.  *  Function:                                                       *
  11.  *      This utility does encode and decode functions against       *
  12.  *      Adobe type 1 fonts.  The font can be in one of 3 forms:     *
  13.  *                                                                  *
  14.  *      1. binary  - (.pfb format)  This form is used on the IBM    *
  15.  *                   PC and keeps the eexec information in binary.  *
  16.  *      2. ascii   - (.pfa format)  This form is used in Unix and   *
  17.  *                   to download to PostScript.  It keeps eexec     *
  18.  *                   information in hex.                            *
  19.  *      3. expanded- (.pfx format)  This form is private to t1font  *
  20.  *                   and decodes the eexec information so humans    *
  21.  *                   can read and modify it.                        *
  22.  *                                                                  *
  23.  *      t1font allows the font to be converted between these forms. *
  24.  *      The default action is to convert decoded and ascii fonts to *
  25.  *      binary, and to convert binary fonts to ascii.               *
  26.  *                                                                  *
  27.  *  Syntax:                                                         *
  28.  *      t1font  infile  outfile  -abxdq                             *
  29.  *      -a = Output ascii (hex) font                                *
  30.  *      -b = Output binary (compressed) font                        *
  31.  *      -x = Output expanded (decrypted) font                       *
  32.  *      -d = Show debug information                                 *
  33.  *      -q = Quiet mode (no info messages)                          *
  34.  *                                                                  *
  35.  *  Compile Options:                                                *
  36.  *      OS/2:     -G2srm -W3 -AL t1font.def                         *
  37.  *      DOS:      -Gsrm  -W3 -AL                                    *
  38.  *      RS/6000:  -DXLC                                             *
  39.  *                                                                  *
  40.  *  Notes:                                                          *
  41.  *      1. The fact that this code allows you to decrypt and modify *
  42.  *         type 1 fonts does not mean you have the legal right to   *
  43.  *         do so.  You should check the licence agreements for the  *
  44.  *         font to determine if this is a valid thing to do.        *
  45.  *                                                                  *
  46.  *      2. The information about what the font means is derived from*
  47.  *         "Adobe Type 1 Font Format", available at your local book *
  48.  *         store.                                                   *
  49.  *                                                                  *
  50.  *      3. The only real way to parse a type 1 font is with a       *
  51.  *         PostScript (forth) parser.  This is a simplistic parser, *
  52.  *         but it matches the ATM parser for the most part.         *
  53.  *                                                                  *
  54.  *      4. The resulting files are mixed between Unix and DOS rules *
  55.  *         for CR and LF.  There is an LF is all cases which should *
  56.  *         make all DOS C programs work.  A CR in the binary ASCII  *
  57.  *         section is expanded to CRLF.  An LF in the input is just *
  58.  *         left that way.                                           *
  59.  *                                                                  *
  60.  *      5. The expanded mode parser corrects charstring lengths,    *
  61.  *         but does very little other checking.  The fact that the  *
  62.  *         conversion works does not mean the font is any good.     *
  63.  *                                                                  *
  64.  ********************************************************************/
  65. #include <stdio.h>
  66. #include <string.h>
  67. #include <stdlib.h>
  68.  
  69. /*
  70.  *  Define unsigned types and other compiler sensitive stuff
  71.  */
  72. #ifdef XLC         /* RS/6000 */
  73. #define NEAR
  74. #define MAINENT
  75. #define OPTSEP  '-'
  76. #else              /* Microsoft C 6.0 */
  77. typedef unsigned char   uchar;
  78. typedef unsigned short  ushort;
  79. typedef unsigned long   ulong;
  80. typedef unsigned int    uint;
  81. #define NEAR near
  82. #define MAINENT _cdecl
  83. #define OPTSEP  '/'
  84. #endif
  85.  
  86. #define MAXCHARSTR 32700
  87. /*
  88.  *  Define section headers for pfb files
  89.  */
  90. typedef struct {
  91.     uchar   id;              /* Always 0x80 */
  92.     uchar   type;            /* 1=ASCII, 2=binary, 3=eof */
  93.     long    len;             /* Section length */
  94. } PFBHDR;
  95. PFBHDR  pfb;
  96.  
  97. /*
  98.  *  Charstring command table
  99.  */
  100. struct cstable {
  101.     ushort       val;        /* Value - escape command are val+32 */
  102.     uchar NEAR * name;
  103. } CSTable[] = {
  104.     1,     "hstem",                /* Single byte commands */
  105.     3,     "vstem",
  106.     4,     "vmoveto",
  107.     5,     "rlineto",
  108.     6,     "hlineto",
  109.     7,     "vlineto",
  110.     8,     "rrcurveto",
  111.     9,     "closepath",
  112.     10,    "callsubr",
  113.     11,    "return",
  114.     13,    "hsbw",
  115.     14,    "endchar",
  116.     21,    "rmoveto",
  117.     22,    "hmoveto",
  118.     30,    "vhcurveto",
  119.     31,    "hvcurveto",
  120.     32+0,  "dotsection",           /* Escapes */
  121.     32+1,  "vstem3",
  122.     32+2,  "hstem3",
  123.     32+6,  "seac",
  124.     32+7,  "sbw",
  125.     32+12, "div",
  126.     32+16, "callothersub",
  127.     32+17, "pop",
  128.     32+33, "setcurrentpoint",
  129.     100+0, "|-",                   /* Terminators */
  130.     100+0, "ND",
  131.     100+1, "|",
  132.     100+1, "NP",
  133.     100+3, "noaccess",
  134.     100+1, "put",
  135.     100+0, "def",
  136.     0,     "ERROR",
  137. };
  138.  
  139.  
  140. /*
  141.  *  Defines and constants
  142.  */
  143. const uchar hexdig[] = {"0123456789abcdef"};
  144. const uint  c1 = 52845;
  145. const uint  c2 = 22719;
  146.  
  147. /*
  148.  *  Function prototypes
  149.  */
  150. void  help (void);                 /* Show simple help */
  151. void  parseargs (int argc, uchar * * argv);
  152. void  binaryfile (void);           /* Input file is binary */
  153. void  outchar (uchar ch);          /* Output character */
  154. void  asciifile (void);            /* Input file is ascii */
  155. void  expandfile (void);           /* Input file is expanded */
  156. void  putonechar(uchar ch);        /* Put one char from expanded mode */
  157. void  expeexec(uchar ch);          /* Expanded mode eexec */
  158. void  expcharstr(uchar ch);        /* Expanded mode charstring */
  159. void  encryptnum(long num);        /* Output number to encryption */
  160. void  charstrnum(long v);          /* Put out number in charstring */
  161. void  setbinary(uchar type);       /* Write binary mode header */
  162. void  eexec (uchar ch);            /* Process one eexec char */
  163. void  normchar (uchar ch);         /* Process normal eexec char */
  164. void  charstr (uchar ch);          /* Process one charstring char */
  165. uchar decrypt (uchar cipher);      /* eexec decrypt */
  166. uchar decryptch (uchar cipher);    /* Charstring decrypt */
  167. uchar encrypt(uchar cipher);       /* eexec encrypt */
  168. uchar encryptch(uchar plain);      /* Charstring encrypt */
  169. void  outhexchar (uchar ch);       /* Output a hex byte */
  170. void  outval (long v);             /* Output number */
  171. void  outcmd (uchar ch);           /* Output command */
  172. void  maxcol(void);                /* Check for end of line */
  173. void  warning(uchar * warn);       /* Output a warning */
  174.  
  175. /*
  176.  *  Global variables.  A number of these global variables come from
  177.  *  the fact that much of the parse is a state machine, where the
  178.  *  functions are called for each character parsed.
  179.  */
  180. FILE   * inf;                /* Input file */
  181. FILE   * outf;               /* Output file */
  182. uchar  * infname;            /* Input file name */
  183. uchar  * outfname;           /* Output file name */
  184. uint    rdn, rch;            /* random number current values */
  185. long    thisval, oldval;     /* evaluate numbers as they pass by */
  186. long    cscnt;               /* Charstring count  */
  187. int     col;                 /* current output column */
  188. uchar   mode;                /* eexec mode */
  189. uchar   cmode;               /* charstring mode */
  190. uchar   xmode;               /* expansion mode */
  191. uchar   deflenIV;            /* Defining lenIV */
  192. int     lenIV;               /* ignore length for charstrings */
  193. int     ignore;              /* Current ignore state */
  194. uchar   token[512];          /* Current token */
  195. uchar   line[512];           /* Input line */
  196. int     tokenpos;            /* Token position */
  197. long    bytecnt;             /* Byte count for binary mode */
  198. long    cntloc;              /* Where to update count */
  199.  
  200. uchar   debugflag;           /* -d option */
  201. uchar   quietflag;           /* -q option */
  202. uchar   outtype;             /* Do only hex output */
  203. uchar   inform;              /* Format of input */
  204. uchar   justnl;              /* Just stuffed nl */
  205. uchar   hexval;              /* Current hex value */
  206. uchar   oddnib;              /* Currently at odd nibble */
  207. uchar   RDtype;              /* font uses RD instead of -| */
  208. uchar   negflag;             /* Number is negative */
  209.  
  210. uchar * CharStr;             /* Charstring build buffer */
  211. int     CharPos;             /* Charstring current length */
  212. uchar   glyph[32];           /* Glyph or Subr name */
  213.  
  214. #define PFASCII  0
  215. #define PFBINARY 1
  216. #define PFEXPAND 2
  217. #define PFUNDEF  3
  218.  
  219. #define XMOUTSIDE 0
  220. #define XMSUBRS   1
  221. #define XMCHARS   2
  222.  
  223. /*
  224.  *  Put out short help
  225.  */
  226. void  help (void) {
  227.     puts("\nt1font - Adobe Type 1 Font Utility     Version 1.0   14 Oct 1991\n");
  228.     puts("t1font  infile  outfile  -abx");
  229.     puts("-a = Output ascii (hex) font");
  230.     puts("-b = Output binary (compressed) font");
  231.     puts("-x = Output expanded (decrypted) font");
  232.     puts("\nThis utility converts between three forms of the Adobe type 1");
  233.     puts("fonts.  The binary form is used on the PC, the ascii form is sent");
  234.     puts("to PostScript and used in Unix.  The expanded form allows some");
  235.     puts("editing of the decrypted font.");
  236.     puts("\nKen Borgendale - kwb@betasvm2.vnet.ibm.com");
  237.     exit (1);
  238. }
  239.  
  240. /*
  241.  *  Main function of Adobe Type 1 Font Utility
  242.  */
  243. MAINENT  main(int argc, uchar ** argv) {
  244.     uchar ch;
  245.  
  246.     /*
  247.      *  Parse arguments
  248.      */
  249.     parseargs(argc, argv);
  250.  
  251.     inf = fopen(infname, "rb");
  252.     if (!inf) {
  253.         fputs("Input file open error - ", stderr);
  254.         fputs(infname, stderr);
  255.         fputc('\n', stderr);
  256.         exit (5);
  257.     }
  258.  
  259.     /*
  260.      *  Look at the first character to decide what type the input is
  261.      */
  262.     ch = (uchar)fgetc(inf);         /* Peek at the first character */
  263.     switch (ch) {
  264.     case '%':
  265.         inform = PFASCII;
  266.         ungetc(ch, inf);             /* Position back */
  267.         break;
  268.     case '#':
  269.         inform = PFEXPAND;
  270.         break;
  271.     case 0x80:
  272.         inform = PFBINARY;
  273.         ungetc(ch, inf);             /* Position back */
  274.         break;
  275.     default:
  276.         fputs("Unknown input file type - ", stderr);
  277.         fputs(infname, stderr);
  278.         fputc('\n', stderr);
  279.         exit (9);
  280.     } /* endswitch */
  281.  
  282.     /*
  283.      *  Default output type
  284.      */
  285.     if (outtype==PFUNDEF) {
  286.         if (inform==PFBINARY)
  287.               outtype = PFASCII;
  288.         else  outtype = PFBINARY;
  289.     }
  290.  
  291.     if (inform == outtype) {
  292.         fputs("Input file already in desired output format\n", stderr);
  293.         exit (10);
  294.     }
  295.  
  296.     /*
  297.      *  Open output file
  298.      */
  299.     outf = fopen(outfname, "wb");
  300.     if (!outf) {
  301.         fputs("Output file open error - ", stderr);
  302.         fputs(outfname, stderr);
  303.         fputc('\n', stderr);
  304.         exit (6);
  305.     }
  306.     if (outtype==PFEXPAND) {        /* Put out marker for expanded font */
  307.         fputc('#', outf);
  308.     }
  309.     if (outtype==PFBINARY) {        /* Put out text section start */
  310.         fwrite("\x80\1\0\0\0\0", 6, 1, outf);
  311.         cntloc = 2;
  312.     }
  313.  
  314.     /*
  315.      *  Initialize global variables
  316.      */
  317.     col = 0;
  318.     ignore = 4;
  319.     mode = 4;
  320.     cmode = 0;
  321.     rdn  = 55665;
  322.     lenIV = 4;
  323.  
  324.     /*
  325.      *  Call the routine based on the input file type
  326.      */
  327.     switch (inform) {
  328.     case PFASCII:            /* Ascii input */
  329.         asciifile();
  330.         break;
  331.     case PFBINARY:           /* Binary input */
  332.         binaryfile();
  333.         break;
  334.     case PFEXPAND:           /* Expanded input */
  335.         expandfile();
  336.         break;
  337.     } /* endswitch */
  338.  
  339.     /*
  340.      *  Finish up
  341.      */
  342.     if (outtype==PFBINARY) {        /* Put out eof  */
  343.         setbinary(3);
  344.     }
  345.     fclose(inf);
  346.     fclose(outf);
  347.     return 0;
  348. }
  349.  
  350. /*
  351.  *  Parse arguments
  352.  */
  353. void  parseargs (int argc, uchar * * argv) {
  354.     uchar  swchar;
  355.     int    argcnt;
  356.     int    filecnt;
  357.     uchar * argp;
  358.  
  359.     argcnt = 1;
  360.     filecnt = 0;
  361.     outtype = PFUNDEF;
  362.     /* Read the arguments and decide what we are doing */
  363.     while (argcnt<argc) {
  364.         argp = argv[argcnt];
  365.         /* Check for switches.  Files may not start with - or / */
  366.         if (*argp == '-' || *argp == OPTSEP) {
  367.             /* Process switches */
  368.             swchar = (uchar)tolower(argp[1]);
  369.             argp += 2;
  370.             switch (swchar) {
  371.             case '?':
  372.                 help();      /* Does not return */
  373.  
  374.             /* Hex output mode */
  375.             case 'a':
  376.                 outtype = PFASCII;
  377.                 break;
  378.  
  379.             /* Binary output mode */
  380.             case 'b':
  381.                 outtype = PFBINARY;
  382.                 break;
  383.  
  384.             /* Debug option - currently undocumented */
  385.             case 'd':
  386.                 debugflag = 1;
  387.                 break;
  388.  
  389.             /* Quiet option - currently undocumented */
  390.             case 'q':
  391.                 quietflag = 1;
  392.                 break;
  393.  
  394.             /* Expansion mode option */
  395.             case 'x':
  396.                 outtype = PFEXPAND;
  397.                 break;
  398.  
  399.             default:
  400.                 fputs("Unknown options: ", stderr);
  401.                 fputs(argp-2, stderr);
  402.                 fputc('\n', stderr);
  403.             }
  404.         } else {
  405.             if (*argp=='?') {
  406.                 help();      /* Does not return */
  407.             }
  408.             switch(++filecnt) {
  409.             case 1:
  410.                 infname = argp;
  411.                 break;
  412.             case 2:
  413.                 outfname = argp;
  414.                 break;
  415.             default:
  416.                 fputs("Extra parameter ignored: ", stderr);
  417.                 fputs(argp, stderr);
  418.                 fputc('\n', stderr);
  419.             }
  420.         }
  421.         argcnt++;
  422.     }
  423.     /*
  424.      *  Make sure two files were specified.  The extensions and output
  425.      *  file name could be defaulted, but this routine is not used often
  426.      *  enough to be a big problem.
  427.      */
  428.     if (filecnt<2) {
  429.         fputs("Two files must be specified.\n", stderr);
  430.         help();
  431.     }
  432. }
  433.  
  434. /*
  435.  *  Process a binary input file
  436.  */
  437. void  binaryfile(void) {
  438.     long  len;
  439.     uchar ch;
  440.  
  441.     while (!feof(inf)) {
  442.         pfb.id = 0;
  443.         fread(&pfb, 6, 1, inf);
  444.         if (pfb.id!=0x80) {      /* Check for .pfb file */
  445.             fputs("Bad input file - ", stderr);
  446.             fputs(infname, stderr);
  447.             fputc('\n', stderr);
  448.             exit(7);
  449.         }
  450.         len = pfb.len;
  451.  
  452.         if (pfb.type==3) break;   /* eof   */
  453.         switch (pfb.type) {
  454.         case 1:                   /* ascii */
  455.             while (len) {
  456.                 ch = (uchar) fgetc(inf);
  457.                 outchar(ch);
  458.                 len--;
  459.             }
  460.             break;
  461.         case 2:                   /* binary */
  462.             while (len) {
  463.                 ch = (uchar) fgetc(inf);
  464.                 if (outtype) {
  465.                     eexec(ch);
  466.                 } else {
  467.                     outhexchar(ch);
  468.                 }
  469.                 len--;
  470.             }
  471.             if (outtype==PFASCII)
  472.                 outchar('\n');
  473.             break;
  474.         default:
  475.             fputs("Bad header type - ", stderr);
  476.             fputs(infname, stderr);
  477.             fputc('\n', stderr);
  478.             exit (8);
  479.         } /* endswitch */
  480.     }
  481. }
  482.  
  483. /*
  484.  *  Output a character keeping track of tokens
  485.  */
  486. void  outchar (uchar ch) {
  487.     if (ch==' ' || ch=='\t' || ch=='\r' || ch=='\n') {
  488.         /* check tokens */
  489.         if (tokenpos) {
  490.             token[tokenpos]=0;
  491.             switch (tokenpos) {
  492.             case 3:
  493.                 if (!strcmp(token, "def")) {
  494.                     if (deflenIV) {
  495.                         if (thisval<8)
  496.                             lenIV = (int)thisval;
  497.                         deflenIV = 0;
  498.                     }
  499.                 }
  500.                 break;
  501.             case 5:
  502.                 if (!strcmp(token, "eexec")) {
  503.                     mode = 0;
  504.                 }
  505.                 break;
  506.             case 6:
  507.                 if (!strcmp(token, "/lenIV")) {
  508.                     deflenIV = 1;
  509.                 }
  510.                 break;
  511.             }
  512.         }
  513.         thisval = 0;
  514.         tokenpos = 0;
  515.     } else {
  516.         if (ch>='0' && ch<='9') {
  517.             tokenpos = 0;
  518.             thisval *= 10;
  519.             thisval += (ch-'0');
  520.         } else {
  521.             token[tokenpos++] = ch;
  522.         }
  523.     }
  524.     if (justnl) {              /* Ignore LF if we just stuffed one */
  525.         justnl = 0;
  526.         if (ch==0x0a) return;
  527.     }
  528.     fputc(ch, outf);           /* Output the character */
  529.     bytecnt++;
  530.     if (ch==0x0d) {            /* Stuff LF for all CRs */
  531.         fputc(0x0a, outf);
  532.         bytecnt++;
  533.         justnl = 1;
  534.     }
  535. }
  536.  
  537. /*
  538.  *  Process an ascii input file
  539.  */
  540. void  asciifile(void) {
  541.     uchar   ch;
  542.     uchar * lp;
  543.     int     i, val;
  544.  
  545.     while (!feof(inf)) {
  546.         lp = fgets(line, 511, inf);
  547.         if (!lp) break;
  548.     reloop:
  549.         if (mode==4) {       /* Outside of eexec */
  550.             while (*lp) outchar(*lp++);
  551.         } else {
  552.             if (!mode && outtype==PFBINARY) {
  553.                 setbinary(2);
  554.                 mode = 1;
  555.             }
  556.             /*
  557.              *  Check for end of eexec mode
  558.              */
  559.             i = strspn(line, "0\r\n");
  560.             if (i>16 && !line[i]) {
  561.                 mode = 4;
  562.                 tokenpos = 0;
  563.                 if (outtype==PFBINARY)
  564.                     setbinary(1);
  565.                 goto reloop;
  566.             }
  567.  
  568.             /*
  569.              *  Process an eexec line
  570.              */
  571.             while (*lp) {
  572.                 if (*lp>='0' && *lp <= '9') {
  573.                     val = *lp - '0';
  574.                 } else {
  575.                     ch = (uchar) tolower(*lp);
  576.                     if (ch>='a' && ch<='f') {
  577.                        val = ch-'a'+10;
  578.                     } else {
  579.                         lp++;
  580.                         continue;
  581.                     }
  582.                 }
  583.                 /*
  584.                  *  Accumulate digits
  585.                  */
  586.                 if (oddnib) {
  587.                     hexval |= val;
  588.                     if (outtype==PFEXPAND) {
  589.                         eexec(hexval);
  590.                     } else {
  591.                         fputc(hexval, outf);
  592.                         bytecnt++;
  593.                     }
  594.                 } else {
  595.                     hexval = (uchar)(val<<4);
  596.                 }
  597.                 oddnib ^= 1;
  598.                 lp++;
  599.             }
  600.         }
  601.     }
  602. }
  603.  
  604.  
  605. /*
  606.  *  Process an expanded input file
  607.  */
  608. void  expandfile(void) {
  609.     uchar * lp;
  610.     int     i;
  611.  
  612.     /* Allocate space for charstring build */
  613.     CharStr = malloc(MAXCHARSTR);
  614.     xmode = XMOUTSIDE;
  615.     cmode = 0;
  616.  
  617.     /* Loop for all input */
  618.     while (!feof(inf)) {
  619.         lp = fgets(line, 511, inf);
  620.         if (!lp) break;
  621.     reloopx:
  622.         if (mode==4) {               /* Outside eexec */
  623.             while (*lp) outchar(*lp++);
  624.         } else {
  625.             /* eexec start */
  626.             if (!mode) {
  627.                 if (outtype==PFBINARY)
  628.                     setbinary(2);
  629.                 mode = 1;
  630.                 for (i=0; i<4; i++) {
  631.                     putonechar('x');
  632.                 }
  633.             }
  634.             /* Check eexec end condition */
  635.             i = strspn(line, "0\r\n");
  636.             if (i>16 && !line[i]) {
  637.                 mode = 4;
  638.                 tokenpos = 0;
  639.                 if (outtype==PFBINARY)
  640.                     setbinary(1);
  641.                 if (outtype==PFASCII) {
  642.                     outchar('\n');
  643.                 }
  644.                 goto reloopx;
  645.             }
  646.             while (*lp) {
  647.                 /* process chars */
  648.                 switch (mode) {
  649.                 case 1:       /* Outside charstring */
  650.                     expeexec(*lp);
  651.                     break;
  652.                 case 2:       /* Inside charstring */
  653.                     expcharstr(*lp);
  654.                     break;
  655.                 } /* endswitch */
  656.                 lp++;
  657.             }
  658.         }
  659.     }
  660. }
  661.  
  662. /*
  663.  *  Put out one character from expanded mode
  664.  */
  665. void  putonechar(uchar ch) {
  666.     uchar  x;
  667.  
  668.     x = encrypt(ch);
  669.     if (outtype==PFBINARY) {
  670.         fputc(x, outf);
  671.         bytecnt++;
  672.     } else {
  673.         outhexchar(x);
  674.     }
  675. }
  676.  
  677. /*
  678.  *  Parse one character in expanded eexec mode.
  679.  *
  680.  *  This is basically a parse for the start of an charstring.
  681.  *  We have to be careful not to output the length field of a charstring
  682.  *  until we have parsed the charstring to find its actual length.
  683.  */
  684. void  expeexec(uchar ch) {
  685.     if (ch==' ' || ch=='\t' || ch=='\r' || ch=='\n') {
  686.         if (tokenpos==2 &&
  687.            ((token[0]=='-' && token[1]=='|') ||
  688.             (token[0]=='R' && token[1]=='D')) ) {
  689.             mode=2;
  690.             if (token[0]=='R') RDtype = 1;
  691.             else RDtype = 0;
  692.             rch = 4330;
  693.             cscnt = oldval;
  694.             memset(CharStr, 'y', lenIV);
  695.             CharPos = lenIV;
  696.         }
  697.         if (tokenpos) {          /* Allow multiple blanks */
  698.             if (tokenpos>0) {
  699.                 token[tokenpos] = 0;
  700.                 if (*token=='/') {
  701.                     strncpy(glyph, token, 31);
  702.                     if (xmode==XMCHARS) {
  703.                         cmode = 1;     /* Buffer charstring */
  704.                     }
  705.                     if (!strcmp(token, "/Subrs")) {
  706.                         xmode = XMSUBRS;
  707.                     }
  708.                     if (!strcmp(token, "/CharStrings")) {
  709.                         xmode = XMCHARS;
  710.                     }
  711.                 } else {
  712.                     if (tokenpos==3) {
  713.                         if (!strcmp(token, "end")) {
  714.                             xmode = XMOUTSIDE;
  715.                         }
  716.                         if (!strcmp(token, "dup")) {
  717.                             if (xmode==XMSUBRS) {
  718.                                 cmode = 2;
  719.                             }
  720.                         }
  721.                     }
  722.                 }
  723.             }
  724.             /* Start delayed mode for subr tokens */
  725.             if (cmode==2 && tokenpos<0) {
  726.                 strcpy(glyph, "Subr ");       /* Keep for errors */
  727.                 ltoa(thisval, glyph+5, 10);
  728.                 cmode = 1;
  729.             }
  730.             oldval = thisval;
  731.             thisval = 0;
  732.             tokenpos = 0;
  733.         }
  734.     } else {
  735.         if (tokenpos<=0 && ch>='0' && ch<='9') {
  736.             tokenpos = -1;
  737.             thisval *= 10;
  738.             thisval += (ch-'0');
  739.         } else {
  740.             /* Slash starts a new token */
  741.             if (ch=='/') tokenpos = 0;
  742.             token[tokenpos++] = ch;
  743.         }
  744.     }
  745.     if (cmode != 1) {      /* Delay if might be charstring */
  746.         if (ch!=0x0a || !justnl)
  747.             putonechar(ch);
  748.     }
  749.     justnl = 0;
  750. }
  751.  
  752.  
  753. /*
  754.  * Output an encrypted number with a leading space
  755.  */
  756. void  encryptnum(long num) {
  757.     uchar chx[16];
  758.     uchar *cp;
  759.  
  760.     ltoa(num, chx, 10);
  761.     putonechar(' ');
  762.     cp = chx;
  763.     while (*cp) {
  764.         putonechar(*cp);
  765.         cp++;
  766.     }
  767. }
  768.  
  769. /*
  770.  *  Parse one character in expanded charstring mode
  771.  */
  772. void  expcharstr(uchar ch) {
  773.     uchar * cp;
  774.     int     i;
  775.     int     value;
  776.  
  777.     if (ch==' ' || ch=='\t' || ch=='\r' || ch=='\n') {
  778.         if (tokenpos<0) {
  779.             if (negflag)
  780.                 thisval = -thisval;
  781.             charstrnum(thisval);
  782.         }
  783.         if (tokenpos>0) {
  784.             token[tokenpos]=0;
  785.             i=0;
  786.             value = 200;
  787.             while (CSTable[i].val) {
  788.                 if (!strcmp(token, CSTable[i].name)) {
  789.                     value = CSTable[i].val;
  790.                     break;
  791.                 }
  792.                 i++;
  793.             }
  794.             if (value>199) {
  795.                 warning("Unknown readchar token, charstr ended");
  796.             }
  797.             /* Put operator into charstr */
  798.             if (value<100) {
  799.                 if (value>=32) {
  800.                     CharStr[CharPos] = 12;
  801.                     CharPos++;
  802.                     value -= 32;
  803.                 }
  804.                 CharStr[CharPos] = (uchar) value;
  805.                 CharPos++;
  806.             }
  807.  
  808.             /*
  809.              * End charstring - put whole charstring out
  810.              */
  811.             if (value>=100) {             /* End of charstr */
  812.                 if (CharPos != (int)cscnt) {
  813.                     warning("Incorrect charstring len");
  814.                 }
  815.                 encryptnum(CharPos);
  816.                 putonechar(' ');
  817.                 if (RDtype) {
  818.                     putonechar('R');
  819.                     putonechar('D');
  820.                 } else {
  821.                     putonechar('-');
  822.                     putonechar('|');
  823.                 }
  824.                 putonechar(' ');
  825.                 cp = CharStr;
  826.                 for (i=0; i<CharPos; i++) {
  827.                     putonechar(encryptch(*cp));
  828.                     cp++;
  829.                 }
  830.                 putonechar(' ');
  831.                 cp = token;
  832.                 while (*cp) {
  833.                     putonechar(*cp);
  834.                     cp++;
  835.                 }
  836.                 cmode = 0;
  837.                 mode = 1;
  838.                 putonechar('\n');
  839.                 justnl = 1;
  840.             }
  841.         }
  842.         tokenpos = 0;
  843.     } else {
  844.         if (tokenpos<=1 && ch>='0' && ch<='9') {
  845.             if (tokenpos>=0) {
  846.                 negflag = 0;
  847.                 if (tokenpos==1) {
  848.                     if (*token=='-')
  849.                         negflag=1;
  850.                     else goto notnum;
  851.                 }
  852.                 tokenpos = -1;
  853.                 thisval = 0;
  854.             }
  855.             thisval *= 10;
  856.             thisval += (ch-'0');
  857.         } else {
  858.         notnum:
  859.             token[tokenpos++] = ch;
  860.         }
  861.     }
  862. }
  863.  
  864. /*
  865.  *  Add a charstring number to the charstring buffer
  866.  */
  867. void  charstrnum(long v) {
  868.     short s;
  869.     long  val;
  870.     int   i;
  871.  
  872.     /*
  873.      * Single byte encoding
  874.      */
  875.     if (labs(v) <= 107) {
  876.         CharStr[CharPos] = (uchar)(v + 139);
  877.         CharPos++;
  878.         return;
  879.     }
  880.  
  881.     /*
  882.      * Double byte encoding
  883.      */
  884.     if (labs(v) <= 1131) {
  885.         s = (short) abs((short)v);
  886.         s -= 108;
  887.         if (v<0) {
  888.             CharStr[CharPos] = (uchar)((s>>8)+251);
  889.         } else {
  890.             CharStr[CharPos] = (uchar)((s>>8)+247);
  891.         }
  892.         CharStr[CharPos+1] = (uchar)s;
  893.         CharPos += 2;
  894.         return;
  895.     }
  896.  
  897.     /*
  898.      *  Four byte encoding.  Do this in a way that works for both
  899.      *  little-endian and big-endian.
  900.      */
  901.     CharStr[CharPos] = 255;
  902.     val = v;
  903.     for (i=1; i<=4; i++) {
  904.         CharStr[CharPos+i] = (uchar)val;
  905.         val >>= 8;
  906.     }
  907.     CharPos += 5;
  908. }
  909.  
  910.  
  911. /*
  912.  *  Update the length an write the next entry for binary mode
  913.  */
  914. void  setbinary(uchar type) {
  915.     fseek(outf, cntloc, SEEK_SET);
  916.     fwrite(&bytecnt, 4, 1, outf);
  917.     fseek(outf, 0L, SEEK_END);
  918.     bytecnt = 0;
  919.     fputc('\x80', outf);
  920.     fputc(type, outf);
  921.     cntloc = ftell(outf);
  922.     if (type != 3) {         /* Adobe does not put the len on EOF */
  923.         fwrite("\0\0\0\0", 4, 1, outf);
  924.     }
  925. }
  926.  
  927. /*
  928.  *  Process one eexec character.  This is a state machine.
  929.  */
  930. void  eexec(uchar ch) {
  931.     ch = decrypt(ch);
  932.     switch (mode) {
  933.     case 0:      /* Ignore at front */
  934.         if (!--ignore) mode=1;
  935.         break;
  936.     case 1:      /* In normal chars */
  937.         normchar(ch);
  938.         break;
  939.     case 2:      /* At front of charstring */
  940.         ch = decryptch(ch);
  941.         cscnt--;
  942.         if (!--ignore) mode=3;
  943.         break;
  944.     case 3:      /* Normal charstring */
  945.         charstr(ch);
  946.         if (!--cscnt) {
  947.             mode = 1;
  948.         }
  949.     }
  950. }
  951.  
  952. /*
  953.  *  Check if we should put out end of line
  954.  */
  955. void  maxcol(void) {
  956.     if (col>70) {
  957.         fputc(0x0d, outf);
  958.         fputc(0x0a, outf);
  959.         col = 0;
  960.     }
  961. }
  962.  
  963. /*
  964.  *  Output hex character.  Maintain column position and add line breaks
  965.  *  as necessary.
  966.  */
  967. void outhexchar(uchar ch) {
  968.     fputc(hexdig[ch>>4], outf);
  969.     fputc(hexdig[ch&15], outf);
  970.     col += 2;
  971.     if (col>=78) {
  972.         fputc(0x0d, outf);
  973.         fputc(0x0a, outf);
  974.         col = 0;
  975.     }
  976. }
  977.  
  978. /*
  979.  *  Normal character in eexec range.  This routine evaluates numeric
  980.  *  operands, and look for special tokens.
  981.  */
  982. void normchar(uchar ch) {
  983.     if (ch==' ' || ch=='\t' || ch=='\r' || ch=='\n') {
  984.         if (tokenpos==2 &&
  985.            ((token[0]=='-' && token[1]=='|') ||
  986.             (token[0]=='R' && token[1]=='D')) ) {
  987.             mode=2;
  988.             cmode = 0;
  989.             ignore = lenIV;
  990.             rch = 4330;
  991.             cscnt = oldval;
  992.         } else {
  993.             fputc(ch, outf);
  994.             col++;
  995.             if (ch=='\n' || ch=='\r') col = 0;
  996.             maxcol();
  997.         }
  998.         oldval = thisval;
  999.         thisval = 0;
  1000.         tokenpos = 0;
  1001.     } else {
  1002.         if (ch>='0' && ch<='9') {
  1003.             tokenpos = 0;
  1004.             thisval *= 10;
  1005.             thisval += (ch-'0');
  1006.         } else {
  1007.             token[tokenpos++] = ch;
  1008.         }
  1009.         fputc(ch, outf);
  1010.         col++;
  1011.     }
  1012. }
  1013.  
  1014. /*
  1015.  *  Character string character.  Within a character string, commands and
  1016.  *  integer operands are encoded so as to minimize memory usage.
  1017.  *  This routine is a state machine.
  1018.  */
  1019. void charstr(uchar ch) {
  1020.     long  temp;
  1021.  
  1022.     ch = decryptch(ch);         /* Do second decode */
  1023.     switch (cmode) {
  1024.     case 0:                     /* In base charstring processing */
  1025.         if (ch<32) {                   /* Process command */
  1026.             if (ch==12) cmode=1;       /* Escape */
  1027.             else        outcmd(ch);
  1028.         } else {
  1029.             if (ch<247) {       /* Single byte integer */
  1030.                 outval((long)ch-139);
  1031.             } else {
  1032.                 if (ch==255) {  /* Start four byte integer */
  1033.                     cmode = 4;
  1034.                     ignore = 4;
  1035.                     thisval = 0;
  1036.                 } else {        /* 2 byte integer */
  1037.                     if (ch<251) {
  1038.                         cmode = 2;
  1039.                         thisval = ch-247;
  1040.                     } else {
  1041.                         cmode = 3;
  1042.                         thisval = ch-251;
  1043.                     }
  1044.                     thisval <<= 8;
  1045.                 }
  1046.             }
  1047.         }
  1048.         break;
  1049.  
  1050.     case 1:                     /* Escape command */
  1051.         outcmd((uchar)(ch+32));
  1052.         cmode = 0;
  1053.         break;
  1054.  
  1055.     case 2:                     /* Two byte positive number */
  1056.         thisval += ch + 108;
  1057.         outval(thisval);
  1058.         cmode = 0;
  1059.         break;
  1060.  
  1061.     case 3:                     /* Two byte negative number */
  1062.         thisval = 0 - thisval - ch - 108;
  1063.         outval(thisval);
  1064.         cmode = 0;
  1065.         break;
  1066.  
  1067.     case 4:                     /* Long integer */
  1068.         temp = ch;
  1069.         temp <<= ((4-ignore)*8);
  1070.         thisval |= temp;
  1071.         if (!--ignore) {
  1072.             outval(thisval);
  1073.             cmode = 0;
  1074.         }
  1075.     }
  1076. }
  1077.  
  1078. /*
  1079.  *  Decrypt one byte of normal eexec data (Adobe algorithm)
  1080.  */
  1081. uchar decrypt(uchar cipher) {
  1082.     uchar plain;
  1083.  
  1084.     plain = (uchar)(cipher ^ (rdn>>8));
  1085.     rdn = (cipher+rdn) * c1 + c2;
  1086.     return plain;
  1087. }
  1088.  
  1089. /*
  1090.  *  Decrypt one byte in a charstring (Adobe algorithm)
  1091.  */
  1092. uchar decryptch(uchar cipher) {
  1093.     uchar plain;
  1094.  
  1095.     plain = (uchar)(cipher ^ (rch>>8));
  1096.     rch = (cipher+rch) * c1 + c2;
  1097.     return plain;
  1098. }
  1099.  
  1100. /*
  1101.  *  Encrypt one byte of normal eexec data (Adobe algorithm)
  1102.  */
  1103. uchar encrypt(uchar plain) {
  1104.     uchar cipher;
  1105.  
  1106.     cipher = (uchar)(plain ^ (rdn>>8));
  1107.     rdn = (cipher+rdn) * c1 + c2;
  1108.     return cipher;
  1109. }
  1110.  
  1111. /*
  1112.  *  Encrypt one byte in a charstring (Adobe algorithm)
  1113.  */
  1114. uchar encryptch(uchar plain) {
  1115.     uchar cipher;
  1116.  
  1117.     cipher = (uchar)(plain ^ (rch>>8));
  1118.     rch = (cipher+rch) * c1 + c2;
  1119.     return cipher;
  1120. }
  1121.  
  1122. /*
  1123.  *  Output a value.  Keep track of the size so we can put in line ends
  1124.  *  as necessary.
  1125.  */
  1126. void outval(long v) {
  1127.     char chx[16];
  1128.     ltoa(v, chx, 10);
  1129.     col += strlen(chx);
  1130.     col++;
  1131.     fputc(' ', outf);
  1132.     fputs(chx, outf);
  1133.     maxcol();
  1134. }
  1135.  
  1136. /*
  1137.  *  Output a charstring command.  Look up the name in the table.
  1138.  */
  1139. void outcmd(uchar ch) {
  1140.     uint    i;
  1141.  
  1142.     i=0;
  1143.     while (CSTable[i].val && CSTable[i].val!=ch) i++;
  1144.  
  1145.     fputc(' ', outf);
  1146.     fputs(CSTable[i].name, outf);
  1147.     col += strlen(CSTable[i].name);
  1148.     col++;
  1149.     maxcol();
  1150. }
  1151.  
  1152. /*
  1153.  *  Output a warning.  Put out the message and the name of the glyph
  1154.  *  or Subr number we are currently working on.
  1155.  */
  1156. void warning(uchar * warn) {
  1157.     if (!quietflag) {
  1158.         fputs(warn, stderr);
  1159.         fputs(" - ", stderr);
  1160.         fputs(glyph, stderr);       /* Last glyph we saw */
  1161.         fputc('\n', stderr);
  1162.     }
  1163. }
  1164.