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