/* t1binary ** ** This program takes an Adobe Type-1 font program in ASCII (PFA) format and ** converts it to binary (PFB) format. ** ** 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 lint static char sccsid[] = "@(#) t1binary.c 1.1 10:58:16 5/21/92"; static char copyright[] = "@(#) Copyright (c) 1992 by I. Lee Hetherington, all rights reserved."; #endif /* Note: this is ANSI C. */ #include #include #include #include #ifdef MSDOS #define WB "wb" #else #define WB "w" #endif #define BANNER "This is t1binary 1.1.\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 3 typedef unsigned char byte; static FILE *ifp = stdin; static FILE *ofp = stdout; static char line[LINESIZE]; /* for PFB block buffering */ static byte blockbuf[MAXBLOCKLEN]; static int blocklen = MAXBLOCKLEN; static int blockpos = -1; static int blocktyp = ASCII; /* 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) { if (blockpos < 0) { fputc(MARKER, ofp); fputc(blocktyp, ofp); blockpos = 0; } blockbuf[blockpos++] = b; if (blockpos == blocklen) output_block(); } /* This function outputs a null-terminated string through the PFB buffering. */ static void output_string(char *string) { while (*string) output_byte((byte) *string++); } /* This function returns the value (0-15) of a single hex digit. It returns 0 for an invalid hex digit. */ static int hexval(char c) { if (c >= 'A' && c <= 'F') return c - 'A' + 10; else if (c >= 'a' && c <= 'f') return c - 'a' + 10; else if (c >= '0' && c <= '9') return c - '0'; else return 0; } /* This function outputs the binary data associated with a string of hexadecimal digits. There must be an even number of digits. */ static void output_hex_string(char *string) { while (string[0] && string[0] != '\n') { if (!string[1]) { fprintf(stderr, "error: only one hex digit\n"); exit(1); } output_byte((byte)((hexval(string[0]) << 4) + hexval(string[1]))); string += 2; } } /* This function returns 1 if the string contains all '0's. */ static int all_zeroes(char *string) { while (*string == '0') string++; return *string == '\0' || *string == '\n'; } static void usage() { fprintf(stderr, "usage: t1binary [-l block-length] [input [output]]\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) { int c; extern char *optarg; extern int optind; extern int getopt(int argc, char **argv, char *optstring); fprintf(stderr, "%s", BANNER); /* interpret command line arguments using getopt */ while ((c = getopt(argc, argv, "l:")) != -1) switch (c) { 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[optind]); exit(1); } } if (argc - optind >= 2) { ofp = fopen(argv[optind + 1], WB); if (!ofp) { fprintf(stderr, "error: cannot open %s for writing\n", argv[optind + 1]); exit(1); } } /* peek at first byte to see if it is the PFB marker 0x80 */ c = fgetc(ifp); if (c == MARKER) { fprintf(stderr, "error: input may already be binary (starts with 0x80)\n"); exit(1); } ungetc(c, ifp); /* Finally, we loop until no more input. We need to look for `currentfile eexec' to start eexec section (hex to binary conversion) and line of all zeros to switch back to ASCII. */ while (fgets(line, LINESIZE, ifp), !feof(ifp) && !ferror(ifp)) { if (blocktyp == ASCII && strcmp(line, "currentfile eexec\n") == 0) { output_string(line); output_block(); blocktyp = BINARY; } else if (blocktyp == BINARY && all_zeroes(line)) { output_block(); blocktyp = ASCII; output_string(line); } else if (blocktyp == ASCII) { output_string(line); } else { output_hex_string(line); } } output_block(); fputc(MARKER, ofp); fputc(DONE, ofp); fclose(ifp); fclose(ofp); return 0; }