X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=pdf2swf%2Fttf2pt1%2Ft1asm.c;fp=pdf2swf%2Fttf2pt1%2Ft1asm.c;h=d9c3061cc8fd9caf8e00ef49577dff9011094dae;hb=92c5f229fdf4d1a1d1efd8205dae033e70d07a1a;hp=0000000000000000000000000000000000000000;hpb=774da0eb175e36c6b8a563f3a7af82e6640b19c9;p=swftools.git diff --git a/pdf2swf/ttf2pt1/t1asm.c b/pdf2swf/ttf2pt1/t1asm.c new file mode 100644 index 0000000..d9c3061 --- /dev/null +++ b/pdf2swf/ttf2pt1/t1asm.c @@ -0,0 +1,604 @@ +/* t1asm + * + * This program `assembles' Adobe Type-1 font programs in pseudo-PostScript + * form into either PFB or PFA format. The human readable/editable input is + * charstring- and eexec-encrypted as specified in the `Adobe Type 1 Font + * Format' version 1.1 (the `black book'). There is a companion program, + * t1disasm, which `disassembles' PFB and PFA files into a pseudo-PostScript + * file. + * + * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved. + * + * Permission is hereby granted to use, modify, and distribute this program + * for any purpose provided this copyright notice and the one below remain + * intact. + * + * I. Lee Hetherington (ilh@lcs.mit.edu) + * + * Revision 1.2 92/05/22 11:54:45 ilh + * Fixed bug where integers larger than 32000 could not be encoded in + * charstrings. Now integer range is correct for four-byte + * twos-complement integers: -(1<<31) <= i <= (1<<31)-1. Bug detected by + * Piet Tutelaers (rcpt@urc.tue.nl). + * + * Revision 1.1 92/05/22 11:48:46 ilh + * initial version + * + * Ported to Microsoft C/C++ Compiler and MS-DOS operating system by + * Kai-Uwe Herbing (herbing@netmbx.netmbx.de) on June 12, 1992. Code + * specific to the MS-DOS version is encapsulated with #ifdef _MSDOS + * ... #endif, where _MSDOS is an identifier, which is automatically + * defined, if you compile with the Microsoft C/C++ Compiler. + * + */ + +#ifndef lint +static char copyright[] = + "@(#) Copyright (c) 1992 by I. Lee Hetherington, all rights reserved."; +#ifdef _MSDOS +static char portnotice[] = + "@(#) Ported to MS-DOS by Kai-Uwe Herbing (herbing@netmbx.netmbx.de)."; +#endif +#endif + +/* Note: this is ANSI C. */ + +#ifdef _MSDOS + #include + #include + #include +#endif +#include +#include +#include +#include +#include + +#ifdef WINDOWS +# ifdef STANDALONE +# define WINDOWS_FUNCTIONS +# include "windows.h" +# endif +#endif + +/* int32 must be at least 32-bit and uint16 must be at least 16-bit */ +#if INT_MAX >= 0x7FFFFFFFUL +typedef int int32; +#else +typedef long int32; +#endif +#if USHRT_MAX >= 0xFFFFUL +typedef unsigned short uint16; +#else +typedef unsigned int uint16; +#endif + +#define LINESIZE 256 + +#define MAXBLOCKLEN ((1L<<17)-6) +#define MINBLOCKLEN ((1L<<8)-6) + +#define MARKER 128 +#define ASCII 1 +#define BINARY 2 +#define DONE 3 + +typedef unsigned char byte; + +/* must be visible from outside */ +FILE *ifp; +FILE *ofp; + +/* flags */ +static int pfb = 0; +static int active = 0; +static int start_charstring = 0; +static int in_eexec = 0; + +static char line[LINESIZE]; + +/* lenIV and charstring start command */ +static int lenIV = 4; +static char cs_start[10]; + +/* for charstring buffering */ +static byte charstring_buf[65535]; +static byte *charstring_bp; + +/* for PFB block buffering */ +static byte blockbuf[MAXBLOCKLEN]; +static int32 blocklen = MAXBLOCKLEN; +static int32 blockpos = -1; +static int blocktyp = ASCII; + +/* decryption stuff */ +static uint16 er, cr; +static uint16 c1 = 52845, c2 = 22719; + +/* table of charstring commands */ +static struct command { + char *name; + int one, two; +} command_table[] = { + { "callothersubr", 12, 16 }, + { "callsubr", 10, -1 }, + { "closepath", 9, -1 }, + { "div", 12, 12 }, + { "dotsection", 12, 0 }, + { "endchar", 14, -1 }, + { "hlineto", 6, -1 }, + { "hmoveto", 22, -1 }, + { "hsbw", 13, -1 }, + { "hstem", 1, -1 }, + { "hstem3", 12, 2 }, + { "hvcurveto", 31, -1 }, + { "pop", 12, 17 }, + { "return", 11, -1 }, + { "rlineto", 5, -1 }, + { "rmoveto", 21, -1 }, + { "rrcurveto", 8, -1 }, + { "sbw", 12, 7 }, + { "seac", 12, 6 }, + { "setcurrentpoint", 12, 33 }, + { "vhcurveto", 30, -1 }, + { "vlineto", 7, -1 }, + { "vmoveto", 4, -1 }, + { "vstem", 3, -1 }, + { "vstem3", 12, 1 }, +}; /* alphabetical */ + +/* Two separate encryption functions because eexec and charstring encryption + must proceed in parallel. */ + +static byte eencrypt(byte plain) +{ + byte cipher; + + cipher = (byte) (plain ^ (er >> 8)); + er = (uint16) ((cipher + er) * c1 + c2); + return cipher; +} + +static byte cencrypt(byte plain) +{ + byte cipher; + + cipher = (byte) (plain ^ (cr >> 8)); + cr = (uint16) ((cipher + cr) * c1 + c2); + return cipher; +} + +/* This function flushes a buffered PFB block. */ + +static void output_block() +{ + int32 i; + + /* output four-byte block length */ + fputc((int) (blockpos & 0xff), ofp); + fputc((int) ((blockpos >> 8) & 0xff), ofp); + fputc((int) ((blockpos >> 16) & 0xff), ofp); + fputc((int) ((blockpos >> 24) & 0xff), ofp); + + /* output block data */ + for (i = 0; i < blockpos; i++) + fputc(blockbuf[i], ofp); + + /* mark block buffer empty and uninitialized */ + blockpos = -1; +} + +/* This function outputs a single byte. If output is in PFB format then output + is buffered through blockbuf[]. If output is in PFA format, then output + will be hexadecimal if in_eexec is set, ASCII otherwise. */ + +static void output_byte(byte b) +{ + static char *hexchar = "0123456789ABCDEF"; + static int hexcol = 0; + + if (pfb) { + /* PFB */ + if (blockpos < 0) { + fputc(MARKER, ofp); + fputc(blocktyp, ofp); + blockpos = 0; + } + blockbuf[blockpos++] = b; + if (blockpos == blocklen) + output_block(); + } else { + /* PFA */ + if (in_eexec) { + /* trim hexadecimal lines to 64 columns */ + if (hexcol >= 64) { + fputc('\n', ofp); + hexcol = 0; + } + fputc(hexchar[(b >> 4) & 0xf], ofp); + fputc(hexchar[b & 0xf], ofp); + hexcol += 2; + } else { + fputc(b, ofp); + } + } +} + +/* This function outputs a byte through possible eexec encryption. */ + +static void eexec_byte(byte b) +{ + if (in_eexec) + output_byte(eencrypt(b)); + else + output_byte(b); +} + +/* This function outputs a null-terminated string through possible eexec + encryption. */ + +static void eexec_string(char *string) +{ + while (*string) + eexec_byte((byte) *string++); +} + +/* This function gets ready for the eexec-encrypted data. If output is in + PFB format then flush current ASCII block and get ready for binary block. + We start encryption with four random (zero) bytes. */ + +static void eexec_start() +{ + eexec_string(line); + if (pfb) { + output_block(); + blocktyp = BINARY; + } + + in_eexec = 1; + er = 55665; + eexec_byte(0); + eexec_byte(0); + eexec_byte(0); + eexec_byte(0); +} + +/* This function wraps-up the eexec-encrypted data. + If output is in PFB format then this entails flushing binary block and + starting an ASCII block. */ + +static void eexec_end() +{ + int i, j; + + if (pfb) { + output_block(); + blocktyp = ASCII; + } else { + fputc('\n', ofp); + } + in_eexec = 0; + for (i = 0; i < 8; i++) { + for (j = 0; j < 64; j++) + eexec_byte('0'); + eexec_byte('\n'); + } +#if 0 + eexec_string("cleartomark\n"); +#endif +} + +/* This function writes ASCII trailer. + If output is in PFB format then this entails flushing binary block and + starting an ASCII block. */ + +static void file_end() +{ + if (pfb) { + output_block(); + fputc(MARKER, ofp); + fputc(DONE, ofp); + } +} +/* This function returns an input line of characters. A line is terminated by + length (including terminating null) greater than LINESIZE, a newline \n, or + when active (looking for charstrings) by '{'. When terminated by a newline + the newline is put into line[]. When terminated by '{', the '{' is not put + into line[], and the flag start_charstring is set to 1. */ + +static void t1asm_getline() +{ + int c; + char *p = line; + int comment = 0; + + start_charstring = 0; + while (p < line + LINESIZE) { + c = fgetc(ifp); + if (c == EOF) + break; + if (c == '%') + comment = 1; + if (active && !comment && c == '{') { + start_charstring = 1; + break; + } + *p++ = (char) c; + if (c == '\n') + break; + } + *p = '\0'; +} + +/* This function is used by the binary search, bsearch(), for command names in + the command table. */ + +static int command_compare(const void *key, const void *item) +{ + return strcmp((char *) key, ((struct command *) item)->name); +} + +/* This function returns 1 if the string is an integer and 0 otherwise. */ + +static int is_integer(char *string) +{ + if (isdigit(string[0]) || string[0] == '-' || string[0] == '+') { + while (*++string && isdigit(*string)) + ; /* deliberately empty */ + if (!*string) + return 1; + } + return 0; +} + +/* This function initializes charstring encryption. Note that this is called + at the beginning of every charstring. */ + +static void charstring_start() +{ + int i; + + charstring_bp = charstring_buf; + cr = 4330; + for (i = 0; i < lenIV; i++) + *charstring_bp++ = cencrypt((byte) 0); +} + +/* This function encrypts and buffers a single byte of charstring data. */ + +static void charstring_byte(int v) +{ + byte b = (byte) (v & 0xff); + + if (charstring_bp - charstring_buf > sizeof(charstring_buf)) { + fprintf(stderr, "error: charstring_buf full (%d bytes)\n", + sizeof(charstring_buf)); + exit(1); + } + *charstring_bp++ = cencrypt(b); +} + +/* This function outputs buffered, encrypted charstring data through possible + eexec encryption. */ + +static void charstring_end() +{ + byte *bp; + + sprintf(line, "%d ", charstring_bp - charstring_buf); + eexec_string(line); + sprintf(line, "%s ", cs_start); + eexec_string(line); + for (bp = charstring_buf; bp < charstring_bp; bp++) + eexec_byte(*bp); +} + +/* This function generates the charstring representation of an integer. */ + +static void charstring_int(int num) +{ + int x; + + if (num >= -107 && num <= 107) { + charstring_byte(num + 139); + } else if (num >= 108 && num <= 1131) { + x = num - 108; + charstring_byte(x / 256 + 247); + charstring_byte(x % 256); + } else if (num >= -1131 && num <= -108) { + x = abs(num) - 108; + charstring_byte(x / 256 + 251); + charstring_byte(x % 256); + } else if (num >= (-2147483647-1) && num <= 2147483647) { + charstring_byte(255); + charstring_byte(num >> 24); + charstring_byte(num >> 16); + charstring_byte(num >> 8); + charstring_byte(num); + } else { + fprintf(stderr, + "error: cannot format the integer %d, too large\n", num); + exit(1); + } +} + +/* This function parses an entire charstring into integers and commands, + outputting bytes through the charstring buffer. */ + +static void parse_charstring() +{ + struct command *cp; + + charstring_start(); + while (fscanf(ifp, "%s", line) == 1) { + if (line[0] == '%') { + /* eat comment to end of line */ + while (fgetc(ifp) != '\n' && !feof(ifp)) + ; /* deliberately empty */ + continue; + } + if (line[0] == '}') + break; + if (is_integer(line)) { + charstring_int(atoi(line)); + } else { + cp = (struct command *) + bsearch((void *) line, (void *) command_table, + sizeof(command_table) / sizeof(struct command), + sizeof(struct command), + command_compare); + if (cp) { + charstring_byte(cp->one); + if (cp->two >= 0) + charstring_byte(cp->two); + } else { + fprintf(stderr, "error: cannot use `%s' in charstring\n",line); + exit(1); + } + } + } + charstring_end(); +} + +static void usage() +{ + fprintf(stderr, + "usage: t1asm [-b] [-l block-length] [input [output]]\n"); + fprintf(stderr, + "\n-b means output in PFB format, otherwise PFA format.\n"); + fprintf(stderr, + "The block length applies to the length of blocks in the\n"); + fprintf(stderr, + "PFB output file; the default is to use the largest possible.\n"); + exit(1); +} + +static void print_banner() +{ + static char rcs_revision[] = ""; /* removed RCS */ + static char revision[20]; + + if (sscanf(rcs_revision, "$Revision: %19s", revision) != 1) + revision[0] = '\0'; + fprintf(stderr, "This is t1asm %s.\n", revision); +} + +#ifdef STANDALONE +int main(int argc, char **argv) +{ + char *p, *q, *r; + int c; + + extern char *optarg; + extern int optind; + + ifp = stdin; + ofp = stdout; + + print_banner(); + + /* interpret command line arguments using getopt */ + while ((c = getopt(argc, argv, "bl:")) != -1) + switch (c) { + case 'b': + pfb = 1; + break; + case 'l': + blocklen = atoi(optarg); + if (blocklen < MINBLOCKLEN) { + blocklen = MINBLOCKLEN; + fprintf(stderr, + "warning: using minimum block length of %d\n", + blocklen); + } else if (blocklen > MAXBLOCKLEN) { + blocklen = MAXBLOCKLEN; + fprintf(stderr, + "warning: using maximum block length of %d\n", + blocklen); + } + break; + default: + usage(); + break; + } + if (argc - optind > 2) + usage(); + + /* possibly open input & output files */ + if (argc - optind >= 1) { + ifp = fopen(argv[optind], "r"); + if (!ifp) { + fprintf(stderr, "error: cannot open %s for reading\n", argv[1]); + exit(1); + } + } + if (argc - optind >= 2) { + ofp = fopen(argv[optind + 1], "w"); + if (!ofp) { + fprintf(stderr, "error: cannot open %s for writing\n", argv[2]); + exit(1); + } + } + +#else +int runt1asm(int pfbflag) +{ + char *p, *q, *r; + + pfb = pfbflag; +#endif + + #ifdef _MSDOS + /* If we are processing a PFB (binary) output */ + /* file, we must set its file mode to binary. */ + if (pfb) + _setmode(_fileno(ofp), _O_BINARY); + #endif + + /* Finally, we loop until no more input. Some special things to look for + are the `currentfile eexec' line, the beginning of the `/Subrs' + definition, the definition of `/lenIV', and the definition of the + charstring start command which has `...string currentfile...' in it. */ + + while (!feof(ifp) && !ferror(ifp)) { + t1asm_getline(); + if (strcmp(line, "currentfile eexec\n") == 0) { + eexec_start(); + continue; + } else if (strstr(line, "/Subrs") && isspace(line[6])) { + active = 1; + } else if ((p = strstr(line, "/lenIV"))) { + sscanf(p, "%*s %d", &lenIV); + } else if ((p = strstr(line, "string currentfile"))) { + /* locate the name of the charstring start command */ + *p = '\0'; /* damage line[] */ + q = strrchr(line, '/'); + if (q) { + r = cs_start; + ++q; + while (!isspace(*q) && *q != '{') + *r++ = *q++; + *r = '\0'; + } + *p = 's'; /* repair line[] */ + } + /* output line data */ + eexec_string(line); + if ((p = strstr(line, "currentfile closefile"))) { + eexec_end(); + } + if (start_charstring) { + if (!cs_start[0]) { + fprintf(stderr, "error: couldn't find charstring start command\n"); + exit(1); + } + parse_charstring(); + } + } + file_end(); + + fclose(ifp); + fclose(ofp); + + return 0; +}