Main Page   Modules   Alphabetical List   Compound List   File List   Compound Members   File Members  

t1asm.c

Go to the documentation of this file.
00001 /*  $Id: t1asm.c,v 1.5 2000/11/30 07:37:40 dbryson Exp $ */
00002 
00003 /*
00004 **  Description:
00005 **  
00006 **    This file is part of libps
00007 **
00008 **
00009 **  Contact:
00010 **
00011 **      Mail:
00012 **
00013 **        Technology Associates, Inc.
00014 **        LIBPS Project
00015 **        1455 Deming Way #11
00016 **        Sparks, NV  89431
00017 **        USA
00018 **
00019 **      Email:
00020 **
00021 **        libps@techass.com
00022 **
00023 **      See our website at:
00024 **
00025 **        libps.sourceforge.net
00026 **
00027 */
00028 
00029 /* t1asm
00030  *
00031  * This program `assembles' Adobe Type-1 font programs in pseudo-PostScript
00032  * form into either PFB or PFA format.  The human readable/editable input is
00033  * charstring- and eexec-encrypted as specified in the `Adobe Type 1 Font
00034  * Format' version 1.1 (the `black book').  There is a companion program,
00035  * t1disasm, which `disassembles' PFB and PFA files into a pseudo-PostScript
00036  * file.
00037  *
00038  * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.
00039  *
00040  * Permission is hereby granted to use, modify, and distribute this program
00041  * for any purpose provided this copyright notice and the one below remain
00042  * intact.
00043  *
00044  * I. Lee Hetherington (ilh@lcs.mit.edu)
00045  *
00046  * 1.5 and later versions contain changes by, and are maintained by,
00047  * Eddie Kohler <eddietwo@lcs.mit.edu>.
00048  *
00049  * New change log in `NEWS'. Old change log:
00050  *
00051  * Revision 1.4  92/07/10  10:53:09  ilh
00052  * Added support for additional PostScript after the closefile command
00053  * (ie., some fonts have {restore}if after the cleartomark).
00054  * 
00055  * Revision 1.3  92/06/23  10:58:25  ilh
00056  * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de)
00057  * incoporated.
00058  * 
00059  * Revision 1.2  92/05/22  11:54:45  ilh
00060  * Fixed bug where integers larger than 32000 could not be encoded in
00061  * charstrings.  Now integer range is correct for four-byte
00062  * twos-complement integers: -(1<<31) <= i <= (1<<31)-1.  Bug detected by
00063  * Piet Tutelaers (rcpt@urc.tue.nl).
00064  *
00065  * Revision 1.1  92/05/22  11:48:46  ilh
00066  * initial version
00067  *
00068  * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by
00069  * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code
00070  * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS
00071  * ... #endif, where _MSDOS is an identifier, which is automatically
00072  * defined, if you compile with the Microsoft C/C++ Compiler.
00073  *
00074  *
00075  * libps
00076  *
00077  * Made various changes for inclusion in libps including modifying these
00078  * routines to use the PSStream stuff and various name changes and making
00079  * this a library function rather than a program.
00080  *
00081  * November 21, 2000 Derry Bryson <derry@techass.com>
00082  */
00083 
00084 /* Note: this is ANSI C. */
00085 
00089 #ifdef HAVE_CONFIG_H
00090 # include "psconfig.h"
00091 #endif
00092 
00093 #if defined(_MSDOS) || defined(_WIN32)
00094 # include <fcntl.h>
00095 # include <io.h>
00096 #endif
00097 #include <stdio.h>
00098 #include <stdlib.h>
00099 #include <string.h>
00100 #include <ctype.h>
00101 #include <limits.h>
00102 #include <stdarg.h>
00103 #include <errno.h>
00104 /*#include "clp.h"*/
00105 #include "ps/ps.h"
00106 #include "t1lib.h"
00107 
00108 /* int32 must be at least 32-bit and uint16 must be at least 16-bit */
00109 #if INT_MAX >= 0x7FFFFFFFUL
00110 typedef int int32;
00111 #else
00112 typedef long int32;
00113 #endif
00114 #if USHRT_MAX >= 0xFFFFUL
00115 typedef unsigned short uint16;
00116 #else
00117 typedef unsigned int uint16;
00118 #endif
00119 
00120 #define LINESIZE 512
00121 
00122 typedef unsigned char byte;
00123 
00124 #if 0
00125 static FILE *ifp;
00126 static FILE *ofp;
00127 #else
00128 PSStream
00129   *in,
00130   *out;
00131 #endif
00132 
00133 static struct pfb_writer w;
00134 static int blocklen = -1;
00135 
00136 /* flags */
00137 static int pfb = 1;
00138 static int active = 0;
00139 static int ever_active = 0;
00140 static int start_charstring = 0;
00141 static int in_eexec = 0;
00142 static int ever_eexec = 0;
00143 
00144 /* need to add 1 as space for \0 */
00145 static char line[LINESIZE + 1];
00146 
00147 /* lenIV and charstring start command */
00148 static int lenIV = 4;
00149 static char cs_start[10];
00150 
00151 /* for charstring buffering */
00152 static byte charstring_buf[65535];
00153 static byte *charstring_bp;
00154 
00155 /* decryption stuff */
00156 static uint16 er, cr;
00157 static uint16 c1 = 52845, c2 = 22719;
00158 
00159 /* table of charstring commands */
00160 static struct command {
00161   char *name;
00162   int one, two;
00163 } command_table[] = {
00164   { "abs", 12, 9 },             /* Type 2 */
00165   { "add", 12, 10 },            /* Type 2 */
00166   { "and", 12, 3 },             /* Type 2 */
00167   { "blend", 16, -1 },          /* Type 2 */
00168   { "callgsubr", 29, -1 },      /* Type 2 */
00169   { "callothersubr", 12, 16 },  /* Type 1 ONLY */
00170   { "callsubr", 10, -1 },
00171   { "closepath", 9, -1 },       /* Type 1 ONLY */
00172   { "cntrmask", 20, -1 },       /* Type 2 */
00173   { "div", 12, 12 },
00174   { "dotsection", 12, 0 },      /* Type 1 ONLY */
00175   { "drop", 12, 18 },           /* Type 2 */
00176   { "dup", 12, 27 },            /* Type 2 */
00177   { "endchar", 14, -1 },
00178   { "eq", 12, 15 },             /* Type 2 */
00179   { "error", 0, -1 },           /* special */
00180   { "escape", 12, -1 },         /* special */
00181   { "exch", 12, 28 },           /* Type 2 */
00182   { "flex", 12, 35 },           /* Type 2 */
00183   { "flex1", 12, 37 },          /* Type 2 */
00184   { "get", 12, 21 },            /* Type 2 */
00185   { "hflex", 12, 34 },          /* Type 2 */
00186   { "hflex1", 12, 36 },         /* Type 2 */
00187   { "hhcurveto", 27, -1 },      /* Type 2 */
00188   { "hintmask", 19, -1 },       /* Type 2 */
00189   { "hlineto", 6, -1 },
00190   { "hmoveto", 22, -1 },
00191   { "hsbw", 13, -1 },           /* Type 1 ONLY */
00192   { "hstem", 1, -1 },
00193   { "hstem3", 12, 2 },          /* Type 1 ONLY */
00194   { "hstemhm", 18, -1 },        /* Type 2 */
00195   { "hvcurveto", 31, -1 },
00196   { "ifelse", 12, 22 },         /* Type 2 */
00197   { "index", 12, 29 },          /* Type 2 */
00198   { "load", 12, 13 },           /* Type 2 */
00199   { "mul", 12, 24 },            /* Type 2 */
00200   { "neg", 12, 14 },            /* Type 2 */
00201   { "not", 12, 5 },             /* Type 2 */
00202   { "or", 12, 4 },              /* Type 2 */
00203   { "pop", 12, 17 },            /* Type 1 ONLY */
00204   { "put", 12, 20 },            /* Type 2 */
00205   { "random", 12, 23 },         /* Type 2 */
00206   { "rcurveline", 24, -1 },     /* Type 2 */
00207   { "return", 11, -1 },
00208   { "rlinecurve", 25, -1 },     /* Type 2 */
00209   { "rlineto", 5, -1 },
00210   { "rmoveto", 21, -1 },
00211   { "roll", 12, 30 },           /* Type 2 */
00212   { "rrcurveto", 8, -1 },
00213   { "sbw", 12, 7 },             /* Type 1 ONLY */
00214   { "seac", 12, 6 },            /* Type 1 ONLY */
00215   { "setcurrentpoint", 12, 33 }, /* Type 1 ONLY */
00216   { "sqrt", 12, 26 },           /* Type 2 */
00217   { "store", 12, 8 },           /* Type 2 */
00218   { "sub", 12, 11 },            /* Type 2 */
00219   { "vhcurveto", 30, -1 },
00220   { "vlineto", 7, -1 },
00221   { "vmoveto", 4, -1 },
00222   { "vstem", 3, -1 },
00223   { "vstem3", 12, 1 },          /* Type 1 ONLY */
00224   { "vstemhm", 23, -1 },        /* Type 2 */
00225   { "vvcurveto", 26, -1 },      /* Type 2 */
00226 };                                                /* alphabetical */
00227 
00228 /* Two separate encryption functions because eexec and charstring encryption
00229    must proceed in parallel. */
00230 
00231 static byte eencrypt(byte plain)
00232 {
00233   byte cipher;
00234 
00235   cipher = (byte)(plain ^ (er >> 8));
00236   er = (uint16)((cipher + er) * c1 + c2);
00237   return cipher;
00238 }
00239 
00240 static byte cencrypt(byte plain)
00241 {
00242   byte cipher;
00243   
00244   /* Thanks to Tom Kacvinsky <tjk@ams.org> who reported that lenIV == -1 means
00245      unencrypted charstrings. */
00246   if (lenIV < 0) return plain;
00247 
00248   cipher = (byte)(plain ^ (cr >> 8));
00249   cr = (uint16)((cipher + cr) * c1 + c2);
00250   return cipher;
00251 }
00252 
00253 /* This function outputs a single byte.  If output is in PFB format then output
00254    is buffered through blockbuf[].  If output is in PFA format, then output
00255    will be hexadecimal if in_eexec is set, ASCII otherwise. */
00256 
00257 static void output_byte(byte b)
00258 {
00259   static char *hexchar = "0123456789abcdef";
00260   static int hexcol = 0;
00261   
00262   if (pfb) {
00263     /* PFB */
00264     PFB_OUTPUT_BYTE(&w, b);
00265   } else {
00266     /* PFA */
00267     if (in_eexec) {
00268       /* trim hexadecimal lines to `blocklen' columns */
00269       if (hexcol >= blocklen) {
00270         psPutC('\n', out);
00271         hexcol = 0;
00272       }
00273       psPutC(hexchar[(b >> 4) & 0xf], out);
00274       psPutC(hexchar[b & 0xf], out);
00275       hexcol += 2;
00276     } else {
00277       psPutC(b, out);
00278     }
00279   }
00280 }
00281 
00282 /* This function outputs a byte through possible eexec encryption. */
00283 
00284 static void eexec_byte(byte b)
00285 {
00286   if (in_eexec)
00287     output_byte(eencrypt(b));
00288   else
00289     output_byte(b);
00290 }
00291 
00292 /* This function outputs a null-terminated string through possible eexec
00293    encryption. */
00294 
00295 static void eexec_string(char *string)
00296 {
00297   while (*string)
00298     eexec_byte(*string++);
00299 }
00300 
00301 /* This function gets ready for the eexec-encrypted data.  If output is in
00302    PFB format then flush current ASCII block and get ready for binary block.
00303    We start encryption with four random (zero) bytes. */
00304 
00305 static void eexec_start(void)
00306 {
00307   eexec_string(line);
00308   if (pfb && w.blocktyp != PFB_BINARY) {
00309     pfb_writer_output_block(&w);
00310     w.blocktyp = PFB_BINARY;
00311   }
00312   
00313   in_eexec = 1;
00314   ever_eexec = 1;
00315   er = 55665;
00316   eexec_byte(0);
00317   eexec_byte(0);
00318   eexec_byte(0);
00319   eexec_byte(0);
00320 }
00321 
00322 /* 25.Aug.1999 -- Return 1 if this line actually looks like the start of a
00323    charstring. We use the heuristic that it should start with `/' (a name) or
00324    `dup' (a subroutine). Previous heuristic caused killa bad output. */
00325 
00326 static int check_line_charstring()
00327 {
00328   char *p = line;
00329   while (isspace(*p))
00330     p++;
00331   return (*p == '/' || (p[0] == 'd' && p[1] == 'u' && p[2] == 'p'));
00332 }
00333 
00334 /* This function returns an input line of characters. A line is terminated by
00335    length (including terminating null) greater than LINESIZE, \r, \n, \r\n, or
00336    when active (looking for charstrings) by '{'. When terminated by a newline
00337    the newline is put into line[]. When terminated by '{', the '{' is not put
00338    into line[], and the flag start_charstring is set to 1. */
00339 
00340 static void getline()
00341 {
00342   int c;
00343   char *p = line;
00344   int comment = 0;
00345   start_charstring = 0;
00346   
00347   while (p < line + LINESIZE) {
00348     c = psGetC(in);
00349     
00350     if (c == EOF)
00351       break;
00352     else if (c == '%')
00353       comment = 1;
00354     else if (active && !comment && c == '{') {
00355       /* 25.Aug.1999 -- new check for whether we should stop be active */
00356       if (check_line_charstring()) {
00357         start_charstring = 1;
00358         break;
00359       } else
00360         active = 0;
00361     }
00362     
00363     *p++ = (char) c;
00364     
00365     /* end of line processing: change CR or CRLF into LF, and exit */
00366     if (c == '\r') {
00367       c = psGetC(in);
00368       if (c != '\n')
00369         psUngetC(c, in);
00370       p[-1] = '\n';
00371       break;
00372     } else if (c == '\n')
00373       break;
00374   }
00375   
00376   *p = '\0';
00377 }
00378 
00379 /* This function wraps-up the eexec-encrypted data and writes ASCII trailer.
00380    If output is in PFB format then this entails flushing binary block and
00381    starting an ASCII block. */
00382 
00383 static void eexec_end(void)
00384 {
00385   int i, j;
00386   
00387   if (!pfb)
00388     psPutC('\n', out);
00389   else if (w.blocktyp != PFB_ASCII) {
00390     pfb_writer_output_block(&w);
00391     w.blocktyp = PFB_ASCII;
00392   }
00393   
00394   in_eexec = active = 0;
00395   
00396   for (i = 0; i < 8; i++) {
00397     for (j = 0; j < 64; j++)
00398       eexec_byte('0');
00399     eexec_byte('\n');
00400   }
00401 }
00402 
00403 /* This function is used by the binary search, bsearch(), for command names in
00404    the command table. */
00405 
00406 static int command_compare(const void *key, const void *item)
00407 {
00408   return strcmp((char *) key, ((struct command *) item)->name);
00409 }
00410 
00411 /* This function returns 1 if the string is an integer and 0 otherwise. */
00412 
00413 static int is_integer(char *string)
00414 {
00415   if (isdigit(string[0]) || string[0] == '-' || string[0] == '+') {
00416     while (*++string && isdigit(*string))
00417       ;                                           /* deliberately empty */
00418     if (!*string)
00419       return 1;
00420   }
00421   return 0;
00422 }
00423 
00424 /* This function initializes charstring encryption.  Note that this is called
00425    at the beginning of every charstring. */
00426 
00427 static void charstring_start()
00428 {
00429   int i;
00430 
00431   charstring_bp = charstring_buf;
00432   cr = 4330;
00433   for (i = 0; i < lenIV; i++)
00434     *charstring_bp++ = cencrypt((byte) 0);
00435 }
00436 
00437 /* This function encrypts and buffers a single byte of charstring data. */
00438 
00439 static void charstring_byte(int v)
00440 {
00441   byte b = (byte)(v & 0xff);
00442   if (charstring_bp - charstring_buf > sizeof(charstring_buf))
00443   {
00444 /*    fatal_error("charstring buffer overflow");*/
00445     printf("charstring buffer overflow!\n");
00446     exit(1);
00447   }
00448   *charstring_bp++ = cencrypt(b);
00449 }
00450 
00451 /* This function outputs buffered, encrypted charstring data through possible
00452    eexec encryption. */
00453 
00454 static void charstring_end()
00455 {
00456   byte *bp;
00457 
00458   sprintf(line, "%d ", charstring_bp - charstring_buf);
00459   eexec_string(line);
00460   sprintf(line, "%s ", cs_start);
00461   eexec_string(line);
00462   for (bp = charstring_buf; bp < charstring_bp; bp++)
00463     eexec_byte(*bp);
00464 }
00465 
00466 /* This function generates the charstring representation of an integer. */
00467 
00468 static void charstring_int(int num)
00469 {
00470   int x;
00471 
00472   if (num >= -107 && num <= 107) {
00473     charstring_byte(num + 139);
00474   } else if (num >= 108 && num <= 1131) {
00475     x = num - 108;
00476     charstring_byte(x / 256 + 247);
00477     charstring_byte(x % 256);
00478   } else if (num >= -1131 && num <= -108) {
00479     x = abs(num) - 108;
00480     charstring_byte(x / 256 + 251);
00481     charstring_byte(x % 256);
00482   } else if (num >= (-2147483647-1) && num <= 2147483647) {
00483     charstring_byte(255);
00484     charstring_byte(num >> 24);
00485     charstring_byte(num >> 16);
00486     charstring_byte(num >> 8);
00487     charstring_byte(num);
00488   } else {
00489 /*    error("can't format huge number `%d'", num);*/
00490     /* output 0 instead */
00491     charstring_byte(139);
00492   }
00493 }
00494 
00495 /* This function returns one charstring token. It ignores comments. */
00496 
00497 static void get_charstring_token()
00498 {
00499   int c = psGetC(in);
00500   while (isspace(c))
00501     c = psGetC(in);
00502   
00503   if (c == '%') {
00504     while (c != EOF && c != '\r' && c != '\n')
00505       c = psGetC(in);
00506     get_charstring_token();
00507     
00508   } else if (c == '}') {
00509     line[0] = '}';
00510     line[1] = 0;
00511     
00512   } else {
00513     char *p = line;
00514     while (p < line + LINESIZE) {
00515       *p++ = c;
00516       c = psGetC(in);
00517       if (c == EOF || isspace(c) || c == '%' || c == '}') {
00518         psUngetC(c, in);
00519         break;
00520       }
00521     }
00522     *p = 0;
00523   }
00524 }
00525 
00526 
00527 /* This function parses an entire charstring into integers and commands,
00528    outputting bytes through the charstring buffer. */
00529 
00530 static void parse_charstring()
00531 {
00532   struct command *cp;
00533 
00534   charstring_start();
00535   while (!psEof(in)) {
00536     get_charstring_token();
00537     if (line[0] == '}')
00538       break;
00539     if (is_integer(line)) {
00540       charstring_int(atoi(line));
00541     } else {
00542       int one;
00543       int two;
00544       int ok = 0;
00545       
00546       cp = (struct command *)
00547         bsearch((void *) line, (void *) command_table,
00548                 sizeof(command_table) / sizeof(struct command),
00549                 sizeof(struct command),
00550                 command_compare);
00551       
00552       if (cp) {
00553         one = cp->one;
00554         two = cp->two;
00555         ok = 1;
00556 
00557       } else if (strncmp(line, "escape_", 7) == 0) {
00558         /* Parse the `escape' keyword requested by Lee Chun-Yu and Werner
00559            Lemberg */
00560         one = 12;
00561         if (sscanf(line + 7, "%d", &two) == 1)
00562           ok = 1;
00563 
00564       } else if (strncmp(line, "UNKNOWN_", 8) == 0) {
00565         /* Allow unanticipated UNKNOWN commands. */
00566         one = 12;
00567         if (sscanf(line + 8, "12_%d", &two) == 1) 
00568           ok = 1;
00569         else if (sscanf(line + 8, "%d", &one) == 1) {
00570           two = -1;
00571           ok = 1;
00572         }
00573       }
00574 
00575       if (!ok)
00576         /*error("unknown charstring command `%s'", line)*/;
00577       else if (one < 0 || one > 255)
00578         /*error("bad charstring command number `%d'", one)*/;
00579       else if (two > 255)
00580         /*error("bad charstring command number `%d'", two)*/;
00581       else if (two < 0)
00582         charstring_byte(one);
00583       else {
00584         charstring_byte(one);
00585         charstring_byte(two);
00586       }
00587     }
00588   }
00589   charstring_end();
00590 }
00591 
00592 static void
00593 InitStatics(int npfb, PSStream* in, PSStream* out, int len)
00594 {
00595   pfb = npfb;
00596   
00597   blocklen = len;
00598 
00599   active = 0;
00600   ever_active = 0;
00601   start_charstring = 0;  
00602   in_eexec = 0;
00603   ever_eexec = 0;
00604 
00605   lenIV = 4;
00606   c1 = 52845;
00607   c2 = 22719;
00608 
00609   if(pfb)
00610     init_pfb_writer(&w, blocklen, out);
00611 }
00612 
00613 static int
00614 Assemble(void)
00615 {
00616   char 
00617     *p, 
00618     *q, 
00619     *r;
00620     
00621   while (!psEof(in) /*&& !ferror(ifp)*/) {
00622     getline();
00623     
00624     if (!ever_active) {
00625       if (strncmp(line, "currentfile eexec", 17) == 0) {
00626         /* Allow arbitrary whitespace after "currentfile eexec".
00627            Thanks to Tom Kacvinsky <tjk@ams.org> for reporting this.
00628            Note: strlen("currentfile eexec") == 17. */
00629         for (p = line + 17; isspace(*p); p++) ;
00630         if (!*p) {
00631           eexec_start();
00632           continue;
00633         }
00634       } else if (strncmp(line, "/lenIV", 6) == 0) {
00635         lenIV = atoi(line + 6);
00636       } else if ((p = strstr(line, "string currentfile"))
00637                  && strstr(line, "readstring")) { /* enforce `readstring' */
00638         /* locate the name of the charstring start command */
00639         *p = '\0';                                  /* damage line[] */
00640         q = strrchr(line, '/');
00641         if (q) {
00642           r = cs_start;
00643           ++q;
00644           while (!isspace(*q) && *q != '{')
00645             *r++ = *q++;
00646           *r = '\0';
00647         }
00648         *p = 's';                                   /* repair line[] */
00649       }
00650     }
00651 
00652     if (!active) {
00653       if ((p = strstr(line, "/Subrs")) && isdigit(p[7]))
00654         ever_active = active = 1;
00655       else if ((p = strstr(line, "/CharStrings")) && isdigit(p[13]))
00656         ever_active = active = 1;
00657     }
00658     if (strstr(line, "currentfile closefile")) {
00659       /* 2/14/99 -- happy Valentine's day! -- don't look for `mark
00660          currentfile closefile'; the `mark' might be on a different line */
00661       eexec_string(line);
00662       break;
00663     }
00664     
00665     eexec_string(line);
00666     
00667     /* output line data */
00668     if (start_charstring) {
00669       if (!cs_start[0])
00670 /*      fatal_error("couldn't find charstring start command");*/
00671         return PSERR_NOCHARSTRINGSTART;
00672       parse_charstring();
00673     }
00674   }
00675   
00676   /* Handle remaining PostScript after the eexec section */
00677   if (in_eexec)
00678     eexec_end();
00679   
00680   /* There may be additional code. */
00681   while (!psEof(in) /*&& !ferror(ifp)*/) {
00682     getline();
00683     eexec_string(line);
00684   }
00685   
00686   if (pfb)
00687     pfb_writer_end(&w);
00688 
00689   /* the end! */
00690 #if 0  
00691   if (!ever_active)
00692     error("warning: no charstrings found in input file");
00693 #endif
00694 
00695   return pserrno;    
00696 }
00697 
00709 int
00710 psAssembleToPFA(PSStream *in, PSStream* out, int lineLength)
00711 {
00712   pserrno = PSERR_NONE;
00713   
00714   if(!lineLength)
00715     lineLength = 64;
00716 
00717   InitStatics(0, in, out, lineLength);
00718   return Assemble();
00719 }
00720 
00732 int
00733 psAssembleToPFB(PSStream *in, PSStream* out, int maxBlockLen)
00734 {
00735   pserrno = PSERR_NONE;
00736   
00737   InitStatics(1, in, out, maxBlockLen);
00738   return Assemble();
00739 }                  
00740 
00741 #if 0 /* removed for libps */
00742 /*****
00743  * Command line
00744  **/
00745 
00746 #define BLOCK_LEN_OPT   300
00747 #define OUTPUT_OPT      301
00748 #define VERSION_OPT     302
00749 #define HELP_OPT        303
00750 #define PFB_OPT         304
00751 #define PFA_OPT         305
00752 
00753 static Clp_Option options[] = {
00754   { "block-length", 'l', BLOCK_LEN_OPT, Clp_ArgInt, 0 },
00755   { "help", 0, HELP_OPT, 0, 0 },
00756   { "line-length", 0, BLOCK_LEN_OPT, Clp_ArgInt, 0 },
00757   { "output", 'o', OUTPUT_OPT, Clp_ArgString, 0 },
00758   { "pfa", 'a', PFA_OPT, 0, 0 },
00759   { "pfb", 'b', PFB_OPT, 0, 0 },
00760   { "version", 0, VERSION_OPT, 0, 0 },
00761 };
00762 static char *program_name;
00763 
00764 void
00765 fatal_error(const char *message, ...)
00766 {
00767   va_list val;
00768   va_start(val, message);
00769   fprintf(stderr, "%s: ", program_name);
00770   vfprintf(stderr, message, val);
00771   putc('\n', stderr);
00772   exit(1);
00773 }
00774 
00775 void
00776 error(const char *message, ...)
00777 {
00778   va_list val;
00779   va_start(val, message);
00780   fprintf(stderr, "%s: ", program_name);
00781   vfprintf(stderr, message, val);
00782   putc('\n', stderr);
00783 }
00784 
00785 void
00786 short_usage(void)
00787 {
00788   fprintf(stderr, "Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\
00789 Try `%s --help' for more information.\n",
00790           program_name, program_name);
00791 }
00792 
00793 void
00794 usage(void)
00795 {
00796   printf("\
00797 `T1asm' translates a human-readable version of a PostScript Type 1 font into\n\
00798 standard PFB or PFA format. The result is written to the standard output\n\
00799 unless an OUTPUT file is given.\n\
00800 \n\
00801 Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\
00802 \n\
00803 Options:\n\
00804   -a, --pfa                   Output font in ASCII (PFA) format.\n\
00805   -b, --pfb                   Output font in binary (PFB) format. This is\n\
00806                               the default.\n\
00807   -l, --block-length NUM      Set max block length for PFB output.\n\
00808   -l, --line-length NUM       Set max encrypted line length for PFA output.\n\
00809   -o, --output=FILE           Write output to FILE.\n\
00810   -h, --help                  Print this message and exit.\n\
00811       --version               Print version number and warranty and exit.\n\
00812 \n\
00813 Report bugs to <eddietwo@lcs.mit.edu>.\n", program_name);
00814 }
00815 
00816 
00817 int main(int argc, char **argv)
00818 {
00819   char *p, *q, *r;
00820   
00821   Clp_Parser *clp =
00822     Clp_NewParser(argc, argv, sizeof(options) / sizeof(options[0]), options);
00823   program_name = (char *)Clp_ProgramName(clp);
00824   
00825   /* interpret command line arguments using CLP */
00826   while (1) {
00827     int opt = Clp_Next(clp);
00828     switch (opt) {
00829       
00830      case BLOCK_LEN_OPT:
00831       blocklen = clp->val.i;
00832       break;
00833       
00834      output_file:
00835      case OUTPUT_OPT:
00836       if (ofp)
00837         fatal_error("output file already specified");
00838       if (strcmp(clp->arg, "-") == 0)
00839         ofp = stdout;
00840       else {
00841         ofp = fopen(clp->arg, "w");
00842         if (!ofp) fatal_error("%s: %s", clp->arg, strerror(errno));
00843       }
00844       break;
00845       
00846      case PFB_OPT:
00847       pfb = 1;
00848       break;
00849       
00850      case PFA_OPT:
00851       pfb = 0;
00852       break;
00853       
00854      case HELP_OPT:
00855       usage();
00856       exit(0);
00857       break;
00858       
00859      case VERSION_OPT:
00860       printf("t1asm (LCDF t1utils) %s\n", VERSION);
00861       printf("Copyright (C) 1992-2000 I. Lee Hetherington, Eddie Kohler et al.\n\
00862 This is free software; see the source for copying conditions.\n\
00863 There is NO warranty, not even for merchantability or fitness for a\n\
00864 particular purpose.\n");
00865       exit(0);
00866       break;
00867       
00868      case Clp_NotOption:
00869       if (ifp && ofp)
00870         fatal_error("too many arguments");
00871       else if (ifp)
00872         goto output_file;
00873       if (strcmp(clp->arg, "-") == 0)
00874         ifp = stdin;
00875       else {
00876         ifp = fopen(clp->arg, "r");
00877         if (!ifp) fatal_error("%s: %s", clp->arg, strerror(errno));
00878       }
00879       break;
00880       
00881      case Clp_Done:
00882       goto done;
00883       
00884      case Clp_BadOption:
00885       short_usage();
00886       exit(1);
00887       break;
00888       
00889     }
00890   }
00891   
00892  done:
00893   if (!pfb) {
00894     if (blocklen == -1)
00895       blocklen = 64;
00896     else if (blocklen < 4) {
00897       blocklen = 4;
00898       error("warning: line length raised to %d", blocklen);
00899     } else if (blocklen > 1024) {
00900       blocklen = 1024;
00901       error("warning: line length lowered to %d", blocklen);
00902     }
00903   }
00904   
00905   if (!ifp) ifp = stdin;
00906   if (!ofp) ofp = stdout;
00907 
00908   if (pfb)
00909     init_pfb_writer(&w, blocklen, ofp);
00910   
00911 #if defined(_MSDOS) || defined(_WIN32)
00912   /* If we are processing a PFB (binary) output */
00913   /* file, we must set its file mode to binary. */
00914   if (pfb)
00915     _setmode(_fileno(ofp), _O_BINARY);
00916 #endif
00917   
00918   /* Finally, we loop until no more input. Some special things to look for are
00919      the `currentfile eexec' line, the beginning of the `/Subrs' or
00920      `/CharStrings' definition, the definition of `/lenIV', and the definition
00921      of the charstring start command which has `...string currentfile...' in
00922      it.
00923      
00924      Being careful: Check with `/Subrs' and `/CharStrings' to see that a
00925      number follows the token -- otherwise, the token is probably nested in a
00926      subroutine a la Adobe Jenson, and we shouldn't pay attention to it.
00927      
00928      Bugs: Occurrence of `/Subrs 9' in a comment will fool t1asm.
00929      
00930      Thanks to Tom Kacvinsky <tjk@ams.org> who reported that some fonts come
00931      without /Subrs sections and provided a patch. */
00932   
00933   while (!feof(ifp) && !ferror(ifp)) {
00934     getline();
00935     
00936     if (!ever_active) {
00937       if (strncmp(line, "currentfile eexec", 17) == 0) {
00938         /* Allow arbitrary whitespace after "currentfile eexec".
00939            Thanks to Tom Kacvinsky <tjk@ams.org> for reporting this.
00940            Note: strlen("currentfile eexec") == 17. */
00941         for (p = line + 17; isspace(*p); p++) ;
00942         if (!*p) {
00943           eexec_start();
00944           continue;
00945         }
00946       } else if (strncmp(line, "/lenIV", 6) == 0) {
00947         lenIV = atoi(line + 6);
00948       } else if ((p = strstr(line, "string currentfile"))
00949                  && strstr(line, "readstring")) { /* enforce `readstring' */
00950         /* locate the name of the charstring start command */
00951         *p = '\0';                                  /* damage line[] */
00952         q = strrchr(line, '/');
00953         if (q) {
00954           r = cs_start;
00955           ++q;
00956           while (!isspace(*q) && *q != '{')
00957             *r++ = *q++;
00958           *r = '\0';
00959         }
00960         *p = 's';                                   /* repair line[] */
00961       }
00962     }
00963 
00964     if (!active) {
00965       if ((p = strstr(line, "/Subrs")) && isdigit(p[7]))
00966         ever_active = active = 1;
00967       else if ((p = strstr(line, "/CharStrings")) && isdigit(p[13]))
00968         ever_active = active = 1;
00969     }
00970     if (strstr(line, "currentfile closefile")) {
00971       /* 2/14/99 -- happy Valentine's day! -- don't look for `mark
00972          currentfile closefile'; the `mark' might be on a different line */
00973       eexec_string(line);
00974       break;
00975     }
00976     
00977     eexec_string(line);
00978     
00979     /* output line data */
00980     if (start_charstring) {
00981       if (!cs_start[0])
00982         fatal_error("couldn't find charstring start command");
00983       parse_charstring();
00984     }
00985   }
00986   
00987   /* Handle remaining PostScript after the eexec section */
00988   if (in_eexec)
00989     eexec_end();
00990   
00991   /* There may be additional code. */
00992   while (!feof(ifp) && !ferror(ifp)) {
00993     getline();
00994     eexec_string(line);
00995   }
00996   
00997   if (pfb)
00998     pfb_writer_end(&w);
00999 
01000   /* the end! */
01001   if (!ever_active)
01002     error("warning: no charstrings found in input file");
01003   fclose(ifp);
01004   fclose(ofp);
01005   return 0;
01006 }
01007 
01008 #endif

Generated at Mon Dec 11 22:46:27 2000 for Postscript Utility Library by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000