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

t1disasm.c

Go to the documentation of this file.
00001 /*  $Id: t1disasm.c,v 1.6 2000/12/06 18:42:30 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 /* t1disasm
00030  *
00031  * This program `disassembles' Adobe Type-1 font programs in either PFB or PFA
00032  * format.  It produces a human readable/editable pseudo-PostScript file by
00033  * performing eexec and charstring decryption as specified in the `Adobe Type 1
00034  * Font Format' version 1.1 (the `black book').  There is a companion program,
00035  * t1asm, which `assembles' such a pseudo-PostScript file into either PFB or
00036  * PFA format.
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:55:08  ilh
00052  * Added support for additional PostScript after the closefile command
00053  * (ie., some fonts have {restore}if' after the cleartomark).  Also,
00054  * removed hardwired charstring start command (-| or RD) in favor of
00055  * automatically determining it.
00056  * 
00057  * Revision 1.3  92/06/23  10:57:53  ilh
00058  * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de)
00059  * incoporated.
00060  * 
00061  * Revision 1.2  92/05/22  12:05:33  ilh
00062  * Fixed bug where we were counting on sprintf to return its first
00063  * argument---not true in ANSI C.  This bug was detected by Piet
00064  * Tutelaers (rcpt@urc.tue.nl).  Also, fixed (signed) integer overflow
00065  * error when testing high-order bit of integer for possible
00066  * sign-extension by making comparison between unsigned integers.
00067  *
00068  * Revision 1.1  92/05/22  12:04:07  ilh
00069  * initial version
00070  *
00071  * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by
00072  * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code
00073  * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS
00074  * ... #endif, where _MSDOS is an identifier, which is automatically
00075  * defined, if you compile with the Microsoft C/C++ Compiler.
00076  *
00077  *
00078  * libps
00079  *
00080  * Made various changes for inclusion in libps including modifying these
00081  * routines to use the PSStream stuff and various name changes and making
00082  * this a library function rather than a program.
00083  *
00084  * November 21, 2000 Derry Bryson <derry@techass.com>
00085  */
00086 
00087 /* Note: this is ANSI C. */
00088 
00092 #ifdef HAVE_CONFIG_H
00093 # include "psconfig.h"
00094 #endif
00095 
00096 #if defined(_MSDOS) || defined(_WIN32)
00097 # include <fcntl.h>
00098 # include <io.h>
00099 #endif
00100 #include <stdio.h>
00101 #include <stdlib.h>
00102 #include <string.h>
00103 #include <ctype.h>
00104 #include <limits.h>
00105 #include <stdarg.h>
00106 #include <errno.h>
00107 /*#include "clp.h"*/
00108 #include "ps/ps.h"
00109 #include "t1lib.h"
00110 
00111 /* int32 must be at least 32-bit and uint16 must be at least 16-bit */
00112 #if INT_MAX >= 0x7FFFFFFFUL
00113 typedef int int32;
00114 #else
00115 typedef long int32;
00116 #endif
00117 #if USHRT_MAX >= 0xFFFFUL
00118 typedef unsigned short uint16;
00119 #else
00120 typedef unsigned int uint16;
00121 #endif
00122 
00123 typedef unsigned char byte;
00124 
00125 #if 0
00126 static FILE *ofp;
00127 #else
00128 static PSStream
00129   *out;
00130 #endif
00131 static int lenIV = 4;
00132 static char cs_start[10];
00133 static int unknown = 0;
00134 
00135 /* decryption stuff */
00136 static uint16 c1 = 52845, c2 = 22719;
00137 static uint16 cr_default = 4330;
00138 static uint16 er_default = 55665;
00139 
00140 #if 0
00141 static int error_count = 0;
00142 void fatal_error(const char *message, ...);
00143 void error(const char *message, ...);
00144 #endif
00145 
00146 /* If the line contains an entry of the form `/lenIV <num>' then set the global
00147    lenIV to <num>.  This indicates the number of random bytes at the beginning
00148    of each charstring. */
00149 
00150 static void
00151 set_lenIV(char *line)
00152 {
00153   char *p = strstr(line, "/lenIV ");
00154 
00155   /* Allow lenIV to be negative. Thanks to Tom Kacvinsky <tjk@ams.org> */
00156   if (p && (isdigit(p[7]) || p[7] == '+' || p[7] == '-')) {
00157     lenIV = atoi(p + 7);
00158   }
00159 }
00160 
00161 static void
00162 set_cs_start(char *line)
00163 {
00164   char *p, *q, *r;
00165 
00166   if ((p = strstr(line, "string currentfile"))) {
00167     /* enforce presence of `readstring' -- 5/29/99 */
00168     if (!strstr(line, "readstring"))
00169       return;
00170     /* locate the name of the charstring start command */
00171     *p = '\0';                                    /* damage line[] */
00172     q = strrchr(line, '/');
00173     if (q) {
00174       r = cs_start;
00175       ++q;
00176       while (!isspace(*q) && *q != '{')
00177         *r++ = *q++;
00178       *r = '\0';
00179     }
00180     *p = 's';                                     /* repair line[] */
00181   }
00182 }
00183 
00184 /* Subroutine to output strings. */
00185 
00186 static void
00187 output(char *string)
00188 {
00189   psPrintf(out, "%s", string);
00190 }
00191 
00192 /* Subroutine to neatly format output of charstring tokens.  If token = "\n",
00193    then a newline is output.  If at start of line (start == 1), prefix token
00194    with tab, otherwise a space. */
00195 
00196 static void
00197 output_token(char *token)
00198 {
00199   static int start = 1;
00200   
00201   if (strcmp(token, "\n") == 0) {
00202     psPrintf(out, "\n");
00203     start = 1;
00204   } else {
00205     psPrintf(out, "%s%s", start ? "\t" : " ", token);
00206     start = 0;
00207   }
00208 }
00209 
00210 /* Subroutine to decrypt and ASCII-ify tokens in charstring data. The
00211    charstring decryption machinery is fired up, skipping the first lenIV
00212    bytes, and the decrypted tokens are expanded into human-readable form. */
00213 
00214 static int
00215 decrypt_charstring(unsigned char *line, int len)
00216 {
00217   int i;
00218   int32 val;
00219   char buf[20];
00220 
00221   pserrno = PSERR_NONE;
00222   
00223   /* decrypt charstring */
00224   if (lenIV >= 0) {
00225     /* only decrypt if lenIV >= 0 -- negative lenIV means unencrypted
00226        charstring. Thanks to Tom Kacvinsky <tjk@ams.org> */
00227     int i;
00228     uint16 cr = cr_default;
00229     byte plain;
00230     for (i = 0; i < len; i++) {
00231       byte cipher = line[i];
00232       plain = (byte)(cipher ^ (cr >> 8));
00233       cr = (uint16)((cipher + cr) * c1 + c2);
00234       line[i] = plain;
00235     }
00236     line += lenIV;
00237     len -= lenIV;
00238   }
00239 
00240   /* handle each charstring command */
00241   for (i = 0; i < len; i++) {
00242     byte b = line[i];
00243     
00244     if (b >= 32) {
00245       if (b >= 32 && b <= 246)
00246         val = b - 139;
00247       else if (b >= 247 && b <= 250) {
00248         i++;
00249         val = (b - 247)*256 + 108 + line[i];
00250       } else if (b >= 251 && b <= 254) {
00251         i++;
00252         val = -(b - 251)*256 - 108 - line[i];
00253       } else {
00254         val =  (line[i+1] & 0xff) << 24;
00255         val |= (line[i+2] & 0xff) << 16;
00256         val |= (line[i+3] & 0xff) <<  8;
00257         val |= (line[i+4] & 0xff) <<  0;
00258         /* in case an int32 is larger than four bytes---sign extend */
00259 #if INT_MAX > 0x7FFFFFFFUL
00260         if (val & 0x80000000)
00261           val |= ~0x7FFFFFFF;
00262 #endif
00263         i += 4;
00264       }
00265       sprintf(buf, "%d", val);
00266       output_token(buf);
00267       
00268     } else {
00269       switch (b) {
00270       case 0: output_token("error"); break;             /* special */
00271       case 1: output_token("hstem"); break;
00272       case 3: output_token("vstem"); break;
00273       case 4: output_token("vmoveto"); break;
00274       case 5: output_token("rlineto"); break;
00275       case 6: output_token("hlineto"); break;
00276       case 7: output_token("vlineto"); break;
00277       case 8: output_token("rrcurveto"); break;
00278       case 9: output_token("closepath"); break;         /* Type 1 ONLY */
00279       case 10: output_token("callsubr"); break;
00280       case 11: output_token("return"); break;
00281       case 13: output_token("hsbw"); break;             /* Type 1 ONLY */
00282       case 14: output_token("endchar"); break;
00283       case 16: output_token("blend"); break;            /* Type 2 */
00284       case 18: output_token("hstemhm"); break;          /* Type 2 */
00285       case 19: output_token("hintmask"); break;         /* Type 2 */
00286       case 20: output_token("cntrmask"); break;         /* Type 2 */
00287       case 21: output_token("rmoveto"); break;
00288       case 22: output_token("hmoveto"); break;
00289       case 23: output_token("vstemhm"); break;          /* Type 2 */
00290       case 24: output_token("rcurveline"); break;       /* Type 2 */
00291       case 25: output_token("rlinecurve"); break;       /* Type 2 */
00292       case 26: output_token("vvcurveto"); break;        /* Type 2 */
00293       case 27: output_token("hhcurveto"); break;        /* Type 2 */
00294       case 28: {                /* Type 2 */
00295         /* short integer */
00296         val =  (line[i+1] & 0xff) << 8;
00297         val |= (line[i+2] & 0xff);
00298         i += 2;
00299         if (val & 0x8000)
00300           val |= ~0x7FFF;
00301         sprintf(buf, "%d", val);
00302         output_token(buf);
00303       }
00304       case 29: output_token("callgsubr"); break;        /* Type 2 */
00305       case 30: output_token("vhcurveto"); break;
00306       case 31: output_token("hvcurveto"); break;
00307       case 12:
00308         i++;
00309         b = line[i];
00310         switch (b) {
00311         case 0: output_token("dotsection"); break;      /* Type 1 ONLY */
00312         case 1: output_token("vstem3"); break;          /* Type 1 ONLY */
00313         case 2: output_token("hstem3"); break;          /* Type 1 ONLY */
00314         case 3: output_token("and"); break;             /* Type 2 */
00315         case 4: output_token("or"); break;              /* Type 2 */
00316         case 5: output_token("not"); break;             /* Type 2 */
00317         case 6: output_token("seac"); break;            /* Type 1 ONLY */
00318         case 7: output_token("sbw"); break;             /* Type 1 ONLY */
00319         case 8: output_token("store"); break;           /* Type 2 */
00320         case 9: output_token("abs"); break;             /* Type 2 */
00321         case 10: output_token("add"); break;            /* Type 2 */
00322         case 11: output_token("sub"); break;            /* Type 2 */
00323         case 12: output_token("div"); break;
00324         case 13: output_token("load"); break;           /* Type 2 */
00325         case 14: output_token("neg"); break;            /* Type 2 */
00326         case 15: output_token("eq"); break;             /* Type 2 */
00327         case 16: output_token("callothersubr"); break;  /* Type 1 ONLY */
00328         case 17: output_token("pop"); break;            /* Type 1 ONLY */
00329         case 18: output_token("drop"); break;           /* Type 2 */
00330         case 20: output_token("put"); break;            /* Type 2 */
00331         case 21: output_token("get"); break;            /* Type 2 */
00332         case 22: output_token("ifelse"); break;         /* Type 2 */
00333         case 23: output_token("random"); break;         /* Type 2 */
00334         case 24: output_token("mul"); break;            /* Type 2 */
00335         case 26: output_token("sqrt"); break;           /* Type 2 */
00336         case 27: output_token("dup"); break;            /* Type 2 */
00337         case 28: output_token("exch"); break;           /* Type 2 */
00338         case 29: output_token("index"); break;          /* Type 2 */
00339         case 30: output_token("roll"); break;           /* Type 2 */
00340         case 33: output_token("setcurrentpoint"); break;/* Type 1 ONLY */
00341         case 34: output_token("hflex"); break;          /* Type 2 */
00342         case 35: output_token("flex"); break;           /* Type 2 */
00343         case 36: output_token("hflex1"); break;         /* Type 2 */
00344         case 37: output_token("flex1"); break;          /* Type 2 */
00345         default:
00346           sprintf(buf, "escape_%d", b);
00347           unknown++;
00348           output_token(buf);
00349           break;
00350         }
00351         break;
00352       default:
00353        sprintf(buf, "UNKNOWN_%d", b);
00354        unknown++;
00355        output_token(buf);
00356        break;
00357       }
00358       output_token("\n");
00359     }
00360   }
00361   if (i > len) {
00362     output("\terror\n");
00363 //    error("disassembly error: charstring too short");
00364     pserrno = PSERR_CHARSTRINGTOOSHORT;
00365   }
00366   
00367   return pserrno;
00368 }
00369 
00370 
00371 /* Disassembly font_reader functions */
00372 
00373 static int in_eexec = 0;
00374 static unsigned char *save = 0;
00375 static int save_len = 0;
00376 static int save_cap = 0;
00377 
00378 static void
00379 append_save(unsigned char *line, int len)
00380 {
00381   if (save_len + len >= save_cap) {
00382     unsigned char *new_save;
00383     if (!save_cap) save_cap = 1024;
00384     while (save_len + len >= save_cap) save_cap *= 2;
00385     new_save = (unsigned char *)malloc(save_cap);
00386 #if 0    
00387     if (!new_save)
00388       fatal_error("out of memory");
00389 #endif
00390     memcpy(new_save, save, save_len);
00391     free(save);
00392     save = new_save;
00393   }
00394   memcpy(save + save_len, line, len);
00395   save_len += len;
00396 }
00397 
00398 /* returns 1 if next \n should be deleted */
00399 
00400 static int
00401 eexec_line(unsigned char *line, int line_len)
00402 {
00403   int cs_start_len = strlen(cs_start);
00404   int pos;
00405   int first_space;
00406   int digits;
00407   int cut_newline = 0;
00408   
00409   /* append this data to the end of `save' if necessary */
00410   if (save_len) {
00411     append_save(line, line_len);
00412     line = save;
00413     line_len = save_len;
00414   }
00415   
00416   if (!line_len)
00417     return 0;
00418   
00419   /* Look for charstring start */
00420   
00421   /* skip first word */
00422   for (pos = 0; pos < line_len && isspace(line[pos]); pos++) ;
00423   while (pos < line_len && !isspace(line[pos])) pos++;
00424   if (pos >= line_len) goto not_charstring;
00425   
00426   /* skip spaces */
00427   first_space = pos;
00428   while (pos < line_len && isspace(line[pos])) pos++;
00429   if (pos >= line_len || !isdigit(line[pos])) goto not_charstring;
00430 
00431   /* skip number */
00432   digits = pos;
00433   while (pos < line_len && isdigit(line[pos])) pos++;
00434   
00435   /* check for subr (another number) */
00436   if (pos < line_len - 1 && isspace(line[pos]) && isdigit(line[pos+1])) {
00437     first_space = pos;
00438     digits = pos + 1;
00439     for (pos = digits; pos < line_len && isdigit(line[pos]); pos++) ;
00440   }
00441   
00442   /* check for charstring start */
00443   if (pos + 2 + cs_start_len < line_len
00444       && pos > digits
00445       && line[pos] == ' '
00446       && strncmp(line + pos + 1, cs_start, cs_start_len) == 0
00447       && line[pos + 1 + cs_start_len] == ' ') {
00448     /* check if charstring is long enough */
00449     int cs_len = atoi(line + digits);
00450     if (pos + 2 + cs_start_len + cs_len < line_len) {
00451       /* long enough! */
00452       if (line[line_len - 1] == '\r') {
00453         line[line_len - 1] = '\n';
00454         cut_newline = 1;
00455       }
00456       psPrintf(out, "%.*s {\n", first_space, line);
00457       decrypt_charstring(line + pos + 2 + cs_start_len, cs_len);
00458       pos += 2 + cs_start_len + cs_len;
00459       psPrintf(out, "\t}%.*s", line_len - pos, line + pos);
00460       save_len = 0;
00461       return cut_newline;
00462     } else {
00463       /* not long enough! */
00464       if (line != save)
00465         append_save(line, line_len);
00466       return 0;
00467     }
00468   }
00469   
00470   /* otherwise, just output the line */
00471  not_charstring:
00472   if (line[line_len - 1] == '\r') {
00473     line[line_len - 1] = '\n';
00474     cut_newline = 1;
00475   }
00476   set_lenIV(line);
00477   set_cs_start(line);
00478   psPrintf(out, "%.*s", line_len, line);
00479   save_len = 0;
00480   
00481   /* look for `currentfile closefile' to see if we should stop decrypting */
00482   if (strstr(line, "currentfile closefile") != 0)
00483     in_eexec = -1;
00484   
00485   return cut_newline;
00486 }
00487 
00488 static int
00489 all_zeroes(char *string)
00490 {
00491   if (*string != '0') return 0;
00492   while (*string == '0')
00493     string++;
00494   return *string == '\0' || *string == '\n';
00495 }
00496 
00497 static void
00498 disasm_output_ascii(PSStream* fio, char *line)
00499 {
00500   int was_in_eexec = in_eexec;
00501   in_eexec = 0;
00502   
00503   /* if we just came from the "ASCII part" of an eexec section, we need to
00504      process the saved lines */
00505   if (was_in_eexec < 0) {
00506     int i = 0;
00507     int save_char = 0;          /* note: save[] is unsigned char * */
00508     
00509     while (i < save_len) {
00510       /* grab a line */
00511       int start = i;
00512       while (i < save_len && save[i] != '\r' && save[i] != '\n')
00513         i++;
00514       if (i < save_len) {
00515         if (i < save_len - 1 && save[i] == '\r' && save[i+1] == '\n')
00516           save_char = -1;
00517         else
00518           save_char = save[i+1];
00519         save[i] = '\n';
00520         save[i+1] = 0;
00521       } else
00522         save[i] = 0;
00523 
00524       /* output it */
00525       disasm_output_ascii(out, save + start);
00526 
00527       /* repair damage */
00528       if (i < save_len) {
00529         if (save_char >= 0) {
00530           save[i+1] = save_char;
00531           i++;
00532         } else
00533           i += 2;
00534       }
00535     }
00536     save_len = 0;
00537   }
00538   
00539   if (!all_zeroes(line))
00540     output(line);
00541 }
00542 
00543 /* collect until '\n' or end of binary section */
00544 
00545 static void
00546 disasm_output_binary(PSStream *fio, unsigned char *data, int len)
00547 {
00548   static int ignore_newline;
00549   static uint16 er;
00550   
00551   byte plain;
00552   int i;
00553   
00554   /* if we're in the ASCII portion of a binary section, just save this data */
00555   if (in_eexec < 0) {
00556     append_save(data, len);
00557     return;
00558   }
00559   
00560   /* eexec initialization */
00561   if (in_eexec == 0) {
00562     er = er_default;
00563     ignore_newline = 0;
00564     in_eexec = 0;
00565   }
00566   if (in_eexec < 4) {
00567     for (i = 0; i < len && in_eexec < 4; i++, in_eexec++) {
00568       byte cipher = data[i];
00569       plain = (byte)(cipher ^ (er >> 8));
00570       er = (uint16)((cipher + er) * c1 + c2);
00571       data[i] = plain;
00572     }
00573     data += i;
00574     len -= i;
00575   }
00576   
00577   /* now make lines: collect until '\n' or '\r' and pass them off to
00578      eexec_line. */
00579   i = 0;
00580   while (in_eexec > 0) {
00581     int start = i;
00582     
00583     for (; i < len; i++) {
00584       byte cipher = data[i];
00585       plain = (byte)(cipher ^ (er >> 8));
00586       er = (uint16)((cipher + er) * c1 + c2);
00587       data[i] = plain;
00588       if (plain == '\r' || plain == '\n') break;
00589     }
00590     
00591     if (ignore_newline && start < i && data[start] == '\n') {
00592       ignore_newline = 0;
00593       continue;
00594     }
00595     
00596     if (i >= len) {
00597       if (start < len) append_save(data + start, i - start);
00598       break;
00599     }
00600     
00601     i++;
00602     ignore_newline = eexec_line(data + start, i - start);
00603   }
00604   
00605   /* if in_eexec < 0, we have some plaintext lines sitting around in a binary
00606      section of the PFB. save them for later */
00607   if (in_eexec < 0 && i < len)
00608     append_save(data + i, len - i);
00609 }
00610 
00611 static void
00612 disasm_output_end(PSStream* fio)
00613 {
00614   /* take care of leftover saved data */
00615   disasm_output_ascii(fio, "");
00616 }
00617 
00618 struct font_writer
00619   fw =
00620   {
00621     disasm_output_ascii,
00622     disasm_output_binary,
00623     disasm_output_end
00624   };
00625 
00626 static void
00627 InitStatics(PSStream *nout)
00628 {
00629   out = nout;
00630   
00631   lenIV = 4;
00632   unknown = 0;
00633   c1 = 52845;
00634   c2 = 22719;
00635   cr_default = 4330;
00636   er_default = 55665;
00637   in_eexec = 0;
00638   save = NULL;
00639   save_len = 0;
00640   save_cap = 0;
00641 }
00642   
00653 int
00654 psPFXDisassemble(PSStream* in, PSStream* out)
00655 {
00656   int
00657     c;
00658 
00659   pserrno = PSERR_NONE;
00660   
00661   InitStatics(out);
00662       
00663   /* peek at first byte to see if it is the PFB marker 0x80 */
00664   c = psGetC(in);
00665   psUngetC(c, in);
00666   
00667   /* do the file */
00668   if (c == PFB_MARKER)
00669     process_pfb(in, &fw, out);
00670   else if (c == '%')
00671     process_pfa(in, &fw, out);
00672   else
00673     pserrno = PSERR_UNKNOWNFILETYPE;
00674     
00675   return !pserrno;
00676 }
00677 
00678 #if 0 /* removed for libps */
00679 /*****
00680  * Command line
00681  **/
00682 
00683 #define OUTPUT_OPT      301
00684 #define VERSION_OPT     302
00685 #define HELP_OPT        303
00686 
00687 static Clp_Option options[] = {
00688   { "help", 0, HELP_OPT, 0, 0 },
00689   { "output", 'o', OUTPUT_OPT, Clp_ArgString, 0 },
00690   { "version", 0, VERSION_OPT, 0, 0 },
00691 };
00692 static char *program_name;
00693 
00694 void
00695 fatal_error(const char *message, ...)
00696 {
00697   va_list val;
00698   va_start(val, message);
00699   fprintf(stderr, "%s: ", program_name);
00700   vfprintf(stderr, message, val);
00701   fputc('\n', stderr);
00702   exit(1);
00703 }
00704 
00705 void
00706 error(const char *message, ...)
00707 {
00708   va_list val;
00709   va_start(val, message);
00710   fprintf(stderr, "%s: ", program_name);
00711   vfprintf(stderr, message, val);
00712   fputc('\n', stderr);
00713   error_count++;
00714 }
00715 
00716 void
00717 short_usage(void)
00718 {
00719   fprintf(stderr, "Usage: %s [INPUT [OUTPUT]]\n\
00720 Try `%s --help' for more information.\n",
00721           program_name, program_name);
00722 }
00723 
00724 void
00725 usage(void)
00726 {
00727   printf("\
00728 `T1disasm' translates a PostScript Type 1 font in PFB or PFA format into a\n\
00729 human-readable, human-editable form. The result is written to the standard\n\
00730 output unless an OUTPUT file is given.\n\
00731 \n\
00732 Usage: %s [OPTION]... [INPUT [OUTPUT]]\n\
00733 \n\
00734 Options:\n\
00735   -o, --output=FILE             Write output to FILE.\n\
00736   -h, --help                    Print this message and exit.\n\
00737       --version                 Print version number and warranty and exit.\n\
00738 \n\
00739 Report bugs to <eddietwo@lcs.mit.edu>.\n", program_name);
00740 }
00741 
00742 
00743 int
00744 main(int argc, char **argv)
00745 {
00746   struct font_reader fr;
00747   int c;
00748   FILE *ifp = 0;
00749   const char *ifp_filename = "<stdin>";
00750   
00751   Clp_Parser *clp =
00752     Clp_NewParser(argc, argv, sizeof(options) / sizeof(options[0]), options);
00753   program_name = (char *)Clp_ProgramName(clp);
00754   
00755   /* interpret command line arguments using CLP */
00756   while (1) {
00757     int opt = Clp_Next(clp);
00758     switch (opt) {
00759       
00760      output_file:
00761      case OUTPUT_OPT:
00762       if (ofp)
00763         fatal_error("output file already specified");
00764       if (strcmp(clp->arg, "-") == 0)
00765         ofp = stdout;
00766       else {
00767         ofp = fopen(clp->arg, "w");
00768         if (!ofp) fatal_error("%s: %s", clp->arg, strerror(errno));
00769       }
00770       break;
00771       
00772      case HELP_OPT:
00773       usage();
00774       exit(0);
00775       break;
00776       
00777      case VERSION_OPT:
00778       printf("t1disasm (LCDF t1utils) %s\n", VERSION);
00779       printf("Copyright (C) 1992-2000 I. Lee Hetherington, Eddie Kohler et al.\n\
00780 This is free software; see the source for copying conditions.\n\
00781 There is NO warranty, not even for merchantability or fitness for a\n\
00782 particular purpose.\n");
00783       exit(0);
00784       break;
00785       
00786      case Clp_NotOption:
00787       if (ifp && ofp)
00788         fatal_error("too many arguments");
00789       else if (ifp)
00790         goto output_file;
00791       if (strcmp(clp->arg, "-") == 0)
00792         ifp = stdin;
00793       else {
00794         ifp_filename = clp->arg;
00795         ifp = fopen(clp->arg, "rb");
00796         if (!ifp) fatal_error("%s: %s", clp->arg, strerror(errno));
00797       }
00798       break;
00799       
00800      case Clp_Done:
00801       goto done;
00802       
00803      case Clp_BadOption:
00804       short_usage();
00805       exit(1);
00806       break;
00807       
00808     }
00809   }
00810   
00811  done:
00812   if (!ifp) ifp = stdin;
00813   if (!ofp) ofp = stdout;
00814   
00815 #if defined(_MSDOS) || defined(_WIN32)
00816   /* As we might be processing a PFB (binary) input file, we must set its file
00817      mode to binary. */
00818   _setmode(_fileno(ifp), _O_BINARY);
00819 #endif
00820   
00821   /* prepare font reader */
00822   fr.output_ascii = disasm_output_ascii;
00823   fr.output_binary = disasm_output_binary;
00824   fr.output_end = disasm_output_end;
00825   
00826   /* peek at first byte to see if it is the PFB marker 0x80 */
00827   c = getc(ifp);
00828   ungetc(c, ifp);
00829   
00830   /* do the file */
00831   if (c == PFB_MARKER)
00832     process_pfb(ifp, ifp_filename, &fr);
00833   else if (c == '%')
00834     process_pfa(ifp, ifp_filename, &fr);
00835   else
00836     fatal_error("%s does not start with font marker (`%%' or 0x80)", ifp_filename);
00837   
00838   fclose(ifp);
00839   fclose(ofp);
00840   
00841   if (unknown)
00842     error((unknown > 1
00843            ? "encountered %d unknown charstring commands"
00844            : "encountered %d unknown charstring command"),
00845           unknown);
00846   
00847   return (error_count ? 1 : 0);
00848 }
00849 #endif

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