📄 t1asm.c
字号:
/* 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. **** author: I. Lee Hetherington (ilh@lcs.mit.edu)*/#ifndef lintstatic char sccsid[] = "@(#) t1asm.c 1.2 10:09:46 5/22/92";static char copyright[] = "@(#) Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.";#endif/* Note: this is ANSI C. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#ifdef MSDOS#define WB "wb"#else#define WB "w"#endif#define BANNER "This is t1asm 1.2.\n"#define LINESIZE 256#define MAXBLOCKLEN ((1<<17)-6)#define MINBLOCKLEN ((1<<8)-6)#define MARKER 128#define ASCII 1#define BINARY 2#define DONE 3typedef unsigned char byte;static FILE *ifp;static 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 + 1];/* 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 int blocklen = MAXBLOCKLEN;static int blockpos = -1;static int blocktyp = ASCII;/* decryption stuff */static unsigned short er, cr;static unsigned short 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 }, { "escape", 12, -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 decryption functions because eexec and charstring decryption must proceed in parallel. */static byte eencrypt(byte plain){ byte cipher; cipher = (plain ^ (er >> 8)); er = (cipher + er) * c1 + c2; return cipher;}static byte cencrypt(byte plain){ byte cipher; cipher = (plain ^ (cr >> 8)); cr = (cipher + cr) * c1 + c2; return cipher;}/* This function flushes a buffered PFB block. */static void output_block(){ int i; /* output four-byte block length */ fputc(blockpos & 0xff, ofp); fputc((blockpos >> 8) & 0xff, ofp); fputc((blockpos >> 16) & 0xff, ofp); fputc((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 and writes ASCII trailer. 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 < 7; i++) { for (j = 0; j < 64; j++) eexec_byte('0'); eexec_byte('\n'); } eexec_string("cleartomark\n"); 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 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(v) int v;{ byte b = ((unsigned int)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 %s ", charstring_bp - charstring_buf, 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", cp->name); 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);}int main(int argc, char **argv){ char *p, *q, *r; int c; extern char *optarg; extern int optind; extern int getopt(int argc, char **argv, char *optstring); ifp = stdin; ofp = stdout; fprintf(stderr, "%s", 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], WB); if (!ofp) { fprintf(stderr, "error: cannot open %s for writing\n", argv[2]); exit(1); } } /* 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)) { 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 (start_charstring) { if (!cs_start[0]) { fprintf(stderr, "error: couldn't find charstring start command\n"); exit(1); } parse_charstring(); } } eexec_end(); fclose(ifp); fclose(ofp); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -