/* unpost ** ** This program converts Macintosh type-1 fonts stored in MacBinary (I or II) ** format or raw resource fork to PFA and PFB formats. ** ** 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) */ /* Note: this is ANSI C. */ #ifndef lint static char sccsid[] = "@(#) unpost.c 1.1 10:58:18 5/21/92"; static char copyright[] = "@(#) Copyright (c) 1992 by I. Lee Hetherington, all rights reserved."; #endif #define BANNER "This is unpost 1.1.\n" #include #include /* Some functions to read one, two, three, and four byte integers in 68000 byte order (most significant byte first). */ static int read_one(FILE *fi) { return fgetc(fi); } static int read_two(FILE *fi) { int val; val = read_one(fi); val = (val << 8) + read_one(fi); return val; } static long read_three(FILE *fi) { long val; val = read_one(fi); val = (val << 8) + read_one(fi); val = (val << 8) + read_one(fi); return val; } static long read_four(FILE *fi) { long val; val = read_one(fi); val = (val << 8) + read_one(fi); val = (val << 8) + read_one(fi); val = (val << 8) + read_one(fi); return val; } /* Function to write four byte length to PFB file: least significant byte first. */ static void write_pfb_length(FILE *fo, long len) { fputc(len & 0xff, fo); len >>= 8; fputc(len & 0xff, fo); len >>= 8; fputc(len & 0xff, fo); len >>= 8; fputc(len & 0xff, fo); } static void reposition(FILE *fi, long absolute) { if (fseek(fi, absolute, 0) == -1) { fprintf(stderr, "error: fseek failed to position %d.\n", absolute); fprintf(stderr, " Is this file seekable?\n"); exit(1); } } static int hex_column = 0; /* current column of hex */ /* ASCII output */ static void output_hex_byte(FILE *fo, int b) { static char *hex = "0123456789ABCDEF"; if (hex_column > 62) { /* 64 column output */ fputc('\n', fo); hex_column = 0; } fputc(hex[b >> 4], fo); fputc(hex[b & 0xf], fo); hex_column += 2; } /* Function to extract a particular POST resource. Offset points to the four byte length which is followed by the data. The first byte of the POST data specifies resource type: 1 for ASCII, 2 for binary, and 5 for end. The second byte is always zero. */ static void extract_data(FILE *fi, FILE *fo, long offset, int binary) { enum PS_type { PS_ascii = 1, PS_binary = 2, PS_end = 5 }; static enum PS_type last_type = PS_ascii; long len, save_offset = ftell(fi); int c; reposition(fi, offset); len = read_four(fi) - 2; /* subtract type field */ switch ((enum PS_type)read_one(fi)) { case PS_ascii: (void) read_one(fi); if (binary) { fputc(128, fo); fputc(1, fo); write_pfb_length(fo, len); while (len--) { if ((c = read_one(fi)) == '\r') /* change \r to \n */ c = '\n'; fputc(c, fo); } } else { if (last_type == PS_binary) fputc('\n', fo); while (len--) { if ((c = read_one(fi)) == '\r') /* change \r to \n */ c = '\n'; fputc(c, fo); } } last_type = 1; break; case PS_binary: (void) read_one(fi); if (binary) { fputc(128, fo); fputc(2, fo); write_pfb_length(fo, len); while (len--) fputc(read_one(fi), fo); } else { if (last_type != 2) hex_column = 0; while (len--) output_hex_byte(fo, read_one(fi)); last_type = 2; } break; case PS_end: (void) read_one(fi); if (binary) { fputc(128, fo); fputc(3, fo); } break; } reposition(fi, save_offset); } static void usage(void) { fprintf(stderr, "usage: unpost [-b] [-r] in-file [out-file]\n"); exit(1); } int main(int argc, char **argv) { FILE *fi, *fo; long data_fork_size; long res_offset, res_data_offset, res_map_offset, type_list_offset; long post_type; int num_types, num_of_type, num_extracted = 0, binary = 0, raw = 0; int c; extern int optind; extern int getopt(int, char **, char*); fprintf(stderr, "%s", BANNER); /* parse command line */ while ((c = getopt(argc, argv, "br?")) != -1) switch(c) { case 'b': ++binary; break; case 'r': ++raw; break; default: usage(); } /* open files */ if (argc - optind == 1) { fi = fopen(argv[optind++], "r"); if (!fi) { fprintf(stderr, "error: couldn't open `%s' for reading\n", argv[--optind]); exit(1); } fo = stdout; } else if (argc - optind == 2) { fi = fopen(argv[optind++], "r"); if (!fi) { fprintf(stderr, "error: couldn't open `%s' for reading\n", argv[--optind]); exit(1); } fo = fopen(argv[optind++], "w"); if (!fo) { fprintf(stderr, "error: couldn't open `%s' for writing\n", argv[--optind]); exit(1); } } else { usage(); } if (raw) { /* raw resource file */ res_offset = 0; } else { /* MacBinary (I or II) file */ /* SHOULD CHECK INTEGRITY OF MACBINARY HEADER HERE TO VERIFY THAT WE REALLY HAVE A MACBINARY FILE. MACBINARY-II-STANDARD.TXT DESCRIBES AN APPROPRIATE VERIFICATION PROCEDURE. */ /* read data and resource fork sizes in MacBinary header */ reposition(fi, 83); data_fork_size = read_four(fi); (void) read_four(fi); /* round data_fork_size up to multiple of 128 */ if (data_fork_size % 128) data_fork_size += 128 - data_fork_size % 128; res_offset = 128 + data_fork_size; } /* read offsets from resource fork header */ reposition(fi, res_offset); res_data_offset = res_offset + read_four(fi); res_map_offset = res_offset + read_four(fi); /* read type list offset from resource map header */ reposition(fi, res_map_offset + 24); type_list_offset = res_map_offset + read_two(fi); /* read type list */ reposition(fi, type_list_offset); num_types = read_two(fi) + 1; /* find POST type */ post_type = ('P' << 24) + ('O' << 16) + ('S' << 8) + 'T'; while (num_types--) { if (read_four(fi) == post_type) { num_of_type = 1 + read_two(fi); reposition(fi, type_list_offset + read_two(fi)); while (num_of_type--) { (void) read_two(fi); /* ID */ (void) read_two(fi); (void) read_one(fi); extract_data(fi, fo, res_data_offset + read_three(fi), binary); ++num_extracted; (void) read_four(fi); } break; } else { (void) read_two(fi); (void) read_two(fi); } } fclose(fi); if (fo != stdout) { fclose(fo); fprintf(stderr, "Extracted %d POST resource%s.\n", num_extracted, (num_extracted == 1) ? "" : "s"); } return 0; } /* * for Emacs... * Local Variables: * mode: C * comment-column: 50 * fill-column: 79 * c-indent-level: 2 * c-continued-statement-offset: 2 * c-brace-offset: -2 * c-argdecl-indent: 2 * c-label-offset: -2 * End: */