source: pmb4.2/trunk/fuentes/pmb/classes/font/ttf2ufm/ttf2ufm-src/t1asm.c

Last change on this file was 815, checked in by jrpelegrina, 4 years ago

Initial release of pmb 4.2

  • Property svn:executable set to *
File size: 14.5 KB
Line 
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
36static char copyright[] =
37  "@(#) Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.";
38#ifdef _MSDOS
39static char portnotice[] =
40  "@(#) Ported to MS-DOS by Kai-Uwe Herbing (herbing@netmbx.netmbx.de).";
41#endif
42#endif
43
44/* Note: this is ANSI C. */
45
46#ifdef _MSDOS
47  #include <fcntl.h>
48  #include <getopt.h>
49  #include <io.h>
50#endif
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <ctype.h>
55#include <limits.h>
56
57#ifdef WINDOWS
58#       ifdef STANDALONE
59#               define WINDOWS_FUNCTIONS
60#               include "windows.h"
61#       endif
62#endif
63
64/* int32 must be at least 32-bit and uint16 must be at least 16-bit */
65#if INT_MAX >= 0x7FFFFFFFUL
66typedef int int32;
67#else
68typedef long int32;
69#endif
70#if USHRT_MAX >= 0xFFFFUL
71typedef unsigned short uint16;
72#else
73typedef 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
86typedef unsigned char byte;
87
88/* must be visible from outside */
89FILE *ifp;
90FILE *ofp;
91
92/* flags */
93static int pfb = 0;
94static int active = 0;
95static int start_charstring = 0;
96static int in_eexec = 0;
97
98static char line[LINESIZE];
99
100/* lenIV and charstring start command */
101static int lenIV = 4;
102static char cs_start[10];
103
104/* for charstring buffering */
105static byte charstring_buf[65535];
106static byte *charstring_bp;
107
108/* for PFB block buffering */
109static byte blockbuf[MAXBLOCKLEN];
110static int32 blocklen = MAXBLOCKLEN;
111static int32 blockpos = -1;
112static int blocktyp = ASCII;
113
114/* decryption stuff */
115static uint16 er, cr;
116static uint16 c1 = 52845, c2 = 22719;
117
118/* table of charstring commands */
119static 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
153static 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
162static 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
173static 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
195static 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
229static 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
240static 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
250static 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
270static 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
295static 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
309static 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
336static 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
343static 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
357static 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
369static 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
384static 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
398static 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
428static 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
463static 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
476static 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
487int 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
544int 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}
Note: See TracBrowser for help on using the repository browser.