1 /* t1unmac/unpost
2 *
3 * This program converts Macintosh Type 1 fonts stored in MacBinary (I or II),
4 * AppleSingle, AppleDouble, BinHex, or raw resource fork format to PFA and
5 * PFB formats.
6 *
7 * Copyright (c) 1992 by I. Lee Hetherington, all rights reserved.
8 *
9 * Permission is hereby granted to use, modify, and distribute this program
10 * for any purpose provided this copyright notice and the one below remain
11 * intact.
12 *
13 * I. Lee Hetherington (ilh@lcs.mit.edu)
14 *
15 * 1.5 and later versions contain changes by, and are maintained by,
16 * Eddie Kohler <kohler@icir.org>.
17 *
18 * New change log in `NEWS'. Old change log:
19 *
20 * Revision 1.2 92/06/23 10:57:33 ilh
21 * MSDOS porting by Kai-Uwe Herbing (herbing@netmbx.netmbx.de)
22 * incoporated.
23 *
24 * Revision 1.1 92/05/22 12:07:49 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 /* Note: this is ANSI C. */
35
36 #ifdef HAVE_CONFIG_H
37 # include <config.h>
38 #endif
39 #if defined(_MSDOS) || defined(_WIN32)
40 # include <fcntl.h>
41 # include <getopt.h>
42 # include <io.h>
43 #endif
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <limits.h>
47 #include <stdarg.h>
48 #include <string.h>
49 #include <errno.h>
50 #include <ctype.h>
51 #include <lcdf/clp.h>
52 #include "t1lib.h"
53
54 #ifdef __cplusplus
55 extern "C" {
56 #endif
57
58 /* for PFB block buffering */
59 void fatal_error(const char *message, ...);
60 void error(const char *message, ...);
61
62
63 /* Some functions to read one, two, three, and four byte integers in 68000
64 byte order (most significant byte first). */
65
66 static int
read_one(FILE * fi)67 read_one(FILE *fi)
68 {
69 return getc(fi);
70 }
71
72 static int
read_two(FILE * fi)73 read_two(FILE *fi)
74 {
75 int val;
76
77 val = getc(fi);
78 val = (val << 8) | getc(fi);
79
80 return val;
81 }
82
83 static int32_t
read_three(FILE * fi)84 read_three(FILE *fi)
85 {
86 int32_t val;
87
88 val = getc(fi);
89 val = (val << 8) | getc(fi);
90 val = (val << 8) | getc(fi);
91
92 return val;
93 }
94
95 static int32_t
read_four(FILE * fi)96 read_four(FILE *fi)
97 {
98 int32_t val;
99
100 val = getc(fi);
101 val = (val << 8) | getc(fi);
102 val = (val << 8) | getc(fi);
103 val = (val << 8) | getc(fi);
104
105 return val;
106 }
107
108 /* reposition a file with error messages */
109
110 static void
reposition(FILE * fi,int32_t absolute)111 reposition(FILE *fi, int32_t absolute)
112 {
113 if (fseek(fi, absolute, 0) == -1)
114 fatal_error("can't seek to position %d\n\
115 (The Mac file may be corrupted, or you may need the `-r' option.)",
116 absolute);
117 }
118
119 static int blocklen = -1;
120
121 static int hex_column = 0; /* current column of hex ASCII output */
122
123 static void
output_hex_byte(FILE * fo,int b)124 output_hex_byte(FILE *fo, int b)
125 {
126 static const char *hex = "0123456789abcdef";
127
128 if (hex_column >= blocklen) {
129 putc('\n', fo);
130 hex_column = 0;
131 }
132 putc(hex[b >> 4], fo);
133 putc(hex[b & 0xf], fo);
134 hex_column += 2;
135 }
136
137 /* Function to extract a particular POST resource. Offset points to the four
138 byte length which is followed by the data. The first byte of the POST data
139 specifies resource type: 1 for ASCII, 2 for binary, and 5 for end. The
140 second byte is always zero. */
141
142
143 /* Function to write four byte length to PFB file: least significant byte
144 first. */
145
146 static int
extract_data(FILE * fi,FILE * fo,struct pfb_writer * w,int32_t offset,int pfb)147 extract_data(FILE *fi, FILE *fo, struct pfb_writer *w, int32_t offset, int pfb)
148 {
149 enum PS_type { PS_ascii = 1, PS_binary = 2, PS_end = 5 };
150 static int last_type = -1;
151 static int skip_newline = 0;
152 int32_t len;
153 int more = 1;
154 int i, c;
155
156 reposition(fi, offset);
157 len = read_four(fi) - 2; /* subtract type field */
158
159 switch ((enum PS_type)read_one(fi)) {
160
161 case PS_ascii: {
162 (void) read_one(fi);
163 if (last_type != PFB_ASCII && pfb) {
164 pfb_writer_output_block(w);
165 w->blocktyp = PFB_ASCII;
166 }
167 for (i = 0; i < len; i++) {
168 c = read_one(fi);
169 if (c == '\n' && skip_newline) {
170 skip_newline = 0;
171 continue;
172 }
173 if (c == '\r') {
174 c = '\n';
175 skip_newline = 1;
176 } else
177 skip_newline = 0;
178 if (pfb)
179 PFB_OUTPUT_BYTE(w, c);
180 else
181 putc(c, fo);
182 }
183 last_type = PFB_ASCII;
184 break;
185 }
186
187 case PS_binary: {
188 (void) read_one(fi);
189 if (last_type != PFB_BINARY && pfb) {
190 pfb_writer_output_block(w);
191 w->blocktyp = PFB_BINARY;
192 } else if (last_type != PFB_BINARY)
193 hex_column = 0;
194 if (pfb) {
195 while (len--)
196 PFB_OUTPUT_BYTE(w, read_one(fi));
197 } else {
198 while (len--)
199 output_hex_byte(fo, read_one(fi));
200 }
201 last_type = PFB_BINARY;
202 break;
203 }
204
205 case PS_end:
206 more = 0;
207 break;
208
209 }
210
211 return more;
212 }
213
214
215 /*****
216 * Command line
217 **/
218
219 #define OUTPUT_OPT 301
220 #define VERSION_OPT 302
221 #define HELP_OPT 303
222 #define PFB_OPT 304
223 #define PFA_OPT 305
224 #define MACBINARY_OPT 306
225 #define RAW_OPT 307
226 #define LINE_LEN_OPT 308
227 #define APPLEDOUBLE_OPT 309
228 #define BINHEX_OPT 310
229
230 static Clp_Option options[] = {
231 { "applesingle", 0, APPLEDOUBLE_OPT, 0, 0 },
232 { "appledouble", 0, APPLEDOUBLE_OPT, 0, 0 },
233 { "binhex", 0, BINHEX_OPT, 0, 0 },
234 { "block-length", 0, LINE_LEN_OPT, Clp_ArgUnsigned, 0 },
235 { "help", 0, HELP_OPT, 0, 0 },
236 { "line-length", 'l', LINE_LEN_OPT, Clp_ArgUnsigned, 0 },
237 { "macbinary", 0, MACBINARY_OPT, 0, 0 },
238 { "output", 'o', OUTPUT_OPT, Clp_ArgString, 0 },
239 { "pfa", 'a', PFA_OPT, 0, 0 },
240 { "pfb", 'b', PFB_OPT, 0, 0 },
241 { "raw", 'r', RAW_OPT, 0, 0 },
242 { "version", 0, VERSION_OPT, 0, 0 },
243 };
244 static const char *program_name;
245
246 void
fatal_error(const char * message,...)247 fatal_error(const char *message, ...)
248 {
249 va_list val;
250 va_start(val, message);
251 fprintf(stderr, "%s: ", program_name);
252 vfprintf(stderr, message, val);
253 putc('\n', stderr);
254 exit(1);
255 }
256
257 void
error(const char * message,...)258 error(const char *message, ...)
259 {
260 va_list val;
261 va_start(val, message);
262 fprintf(stderr, "%s: ", program_name);
263 vfprintf(stderr, message, val);
264 putc('\n', stderr);
265 }
266
267 void
short_usage(void)268 short_usage(void)
269 {
270 fprintf(stderr, "Usage: %s [OPTION]... INPUT [OUTPUT]\n\
271 Try `%s --help' for more information.\n",
272 program_name, program_name);
273 }
274
275 void
usage(void)276 usage(void)
277 {
278 printf("\
279 `T1unmac' extracts a PostScript Type 1 font from a Macintosh font file. It can\n\
280 read MacBinary, AppleSingle, AppleDouble, or BinHex files, or raw Macintosh\n\
281 resource forks. The result is written to the standard output unless an OUTPUT\n\
282 file is given.\n\
283 \n\
284 Usage: %s [OPTION]... INPUT [OUTPUT]\n\
285 \n\
286 Options:\n\
287 -r, --raw Input is a raw Macintosh resource fork.\n\
288 --macbinary Input is in MacBinary format.\n\
289 --applesingle Input is in AppleSingle format.\n\
290 --appledouble Input is in AppleDouble format.\n\
291 --binhex Input is in BinHex format.\n\
292 -a, --pfa Output font in ASCII (PFA) format.\n\
293 -b, --pfb Output font in binary (PFB) format. This is\n\
294 the default.\n\
295 -l, --block-length NUM Set max block length for PFB output.\n\
296 -l, --line-length NUM Set max encrypted line length for PFA output.\n\
297 -o, --output FILE Write output to FILE.\n\
298 -h, --help Print this message and exit.\n\
299 --version Print version number and warranty and exit.\n\
300 \n\
301 Report bugs to <kohler@icir.org>.\n", program_name);
302 }
303
304
305 static const char *
check_macbinary(FILE * ifp)306 check_macbinary(FILE *ifp)
307 {
308 int i, j;
309 char buf[124];
310
311 /* check "version" bytes at offsets 0 and 74 */
312 reposition(ifp, 0);
313 if (read_one(ifp) != 0)
314 return "bad version byte";
315 reposition(ifp, 74);
316 if (read_one(ifp) != 0)
317 return "bad version byte";
318
319 #if 0
320 /* write out bullshit */
321 {int t;
322 reposition(ifp, 65);
323 t = read_four(ifp);
324 fprintf(stderr, "Type %c%c%c%c\n", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255);
325 t = read_four(ifp);
326 fprintf(stderr, "Creator %c%c%c%c\n", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255);
327 t = read_one(ifp);
328 fprintf(stderr, "Finder flags 1 %02x\n", t);
329 read_one(ifp);
330 t = read_two(ifp);
331 fprintf(stderr, "horizpos %04x\n", t);
332 t = read_two(ifp);
333 fprintf(stderr, "vertpos %04x\n", t);
334 t = read_two(ifp);
335 fprintf(stderr, "folder id %d\n", t);
336 t = read_one(ifp);
337 fprintf(stderr, "protected? %x\n", t);
338 t = read_one(ifp);
339 t = read_four(ifp);
340 fprintf(stderr, "data len %d\n", t);
341 t = read_four(ifp);
342 fprintf(stderr, "rsrc len %d\n", t);
343 t = read_four(ifp);
344 {
345 struct tm *crap;
346 fprintf(stderr, "creation date %x\n", t);
347 t -= 2082844800;
348 fprintf(stderr, " %s\n", ctime(&t));
349 t = read_four(ifp);
350 fprintf(stderr, "modification date %x\n", t);
351 t -= 2082844800;
352 fprintf(stderr, " %s\n", ctime(&t));
353 t = read_two(ifp);
354 }
355 fprintf(stderr, "getinfo len %d\n", t);
356 t = read_one(ifp);
357 fprintf(stderr, "finderflags 2 %02x\n", t);
358 reposition(ifp, 116);
359 t = read_four(ifp);
360 fprintf(stderr, "total len %d\n", t);
361 t = read_two(ifp);
362 fprintf(stderr, "secondary header len %d\n", t);
363 t = read_one(ifp);
364 fprintf(stderr, "version %d\n", t);
365 t = read_one(ifp);
366 fprintf(stderr, "version %d\n", t);
367 }
368 #endif
369
370 /* check file length */
371 reposition(ifp, 1);
372 i = read_one(ifp);
373 if (i > 63)
374 return "bad length";
375 reposition(ifp, 83);
376 i = read_four(ifp);
377 j = read_four(ifp);
378 if (i < 0 || j < 0 || i >= 0x800000 || j >= 0x800000)
379 return "bad length";
380
381 /* check CRC */
382 reposition(ifp, 0);
383 fread(buf, 1, 124, ifp);
384 if (crcbuf(0, 124, buf) != read_two(ifp)) {
385 reposition(ifp, 82);
386 if (read_one(ifp) != 0)
387 return "bad checksum";
388 }
389
390 return 0;
391 }
392
393 #define APPLESINGLE_MAGIC 0x00051600
394 #define APPLEDOUBLE_MAGIC 0x00051607
395
396 const char *
check_appledouble(FILE * ifp)397 check_appledouble(FILE *ifp)
398 {
399 int i;
400 reposition(ifp, 0);
401 i = read_four(ifp);
402 if (i != APPLEDOUBLE_MAGIC && i != APPLESINGLE_MAGIC)
403 return "bad magic number";
404
405 return 0;
406 }
407
408 const char *
translate_binhex(FILE * f,FILE * tmpf)409 translate_binhex(FILE *f, FILE *tmpf)
410 {
411 int i, c = 0, last_char, after_x90, bits, bitpos;
412 unsigned char value_table[256];
413
414 /* prepare value table */
415 {
416 const char *table = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
417 for (i = 0; i < 256; i++)
418 value_table[i] = 255;
419 for (i = 0; *table; i++, table++)
420 value_table[(unsigned char)*table] = i;
421 }
422
423 /* skip to comment */
424 {
425 const char *comment = "(This file must be converted with BinHex";
426 while (!feof(f)) {
427 const char *s;
428 for (s = comment; *s; s++) {
429 c = getc(f);
430 if (c != *s)
431 break;
432 }
433 /* skip to end of line */
434 while (c >= 0 && c != '\n' && c != '\r')
435 c = getc(f);
436 /* stop if read comment */
437 if (!*s)
438 goto found_comment;
439 }
440 /* failed */
441 return "no comment";
442 }
443
444 found_comment:
445 /* skip spaces, look for ':' */
446 for (c = ' '; isspace(c); c = getc(f)) ;
447 if (c != ':')
448 return "no file-start character";
449
450 /* found ':', process until you find another ':' */
451 last_char = -1;
452 after_x90 = bits = 0;
453 bitpos = 10;
454 for (c = getc(f); c >= 0; c = getc(f))
455 if (!isspace(c)) {
456 /* add 6 bits to bits */
457 if (value_table[c] == 255)
458 break;
459 bits |= (value_table[c] << bitpos);
460 bitpos -= 6;
461
462 /* output character(s) */
463 if (bitpos <= 2) {
464 int d = bits >> 8;
465 bits = (bits << 8) & 0xFF00;
466 bitpos += 8;
467 if (after_x90) {
468 /* handle compression */
469 if (d == 0) {
470 last_char = 0x90;
471 putc(0x90, tmpf);
472 } else
473 for (i = 1; i < d; i++)
474 putc(last_char, tmpf);
475 after_x90 = 0;
476 } else if (d == 0x90)
477 after_x90 = 1;
478 else {
479 last_char = d;
480 putc(d, tmpf);
481 }
482 }
483 }
484
485 if (c < 0)
486 return "unexpected EOF";
487 else if (c != ':')
488 return "bad character";
489
490 fflush(tmpf);
491 return 0;
492 }
493
494 int
check_binhex_crc(FILE * f,int offset,int length)495 check_binhex_crc(FILE *f, int offset, int length)
496 {
497 int crc = 0;
498 char buf[2048];
499 reposition(f, offset);
500 while (length > 0) {
501 int n = (length < 2048 ? length : 2048);
502 fread(buf, 1, n, f);
503 crc = crcbuf(crc, n, buf);
504 length -= n;
505 }
506 return crc == 0;
507 }
508
509 const char *
check_binhex(FILE * f)510 check_binhex(FILE *f)
511 {
512 int fname_len, data_len, rsrc_len, off;
513
514 /* check lengths */
515 reposition(f, 0);
516 fname_len = read_one(f);
517 if (fname_len < 1 || fname_len > 63)
518 return "bad length";
519 reposition(f, 1 + fname_len + 11);
520 data_len = read_four(f);
521 rsrc_len = read_four(f);
522 if (data_len < 0 || rsrc_len < 0 || data_len >= 0x800000 || rsrc_len >= 0x800000)
523 return "bad length";
524
525 /* check version */
526 reposition(f, 1 + fname_len);
527 if (read_one(f) != 0)
528 return "bad version";
529
530 /* check CRC */
531 off = 1 + fname_len + 21;
532 if (!check_binhex_crc(f, 0, off))
533 return "bad header CRC";
534 if (!check_binhex_crc(f, off, data_len + 2))
535 return "bad data CRC";
536 if (!check_binhex_crc(f, off + data_len + 2, rsrc_len + 2))
537 return "bad resource fork CRC";
538
539 return 0;
540 }
541
542 #ifdef __cplusplus
543 }
544 #endif
545
546
547 int
main(int argc,char * argv[])548 main(int argc, char *argv[])
549 {
550 FILE *ifp = 0;
551 FILE *ofp = 0;
552 struct pfb_writer w;
553 const char *ifp_name = "<stdin>";
554 int32_t res_offset, res_data_offset, res_map_offset, type_list_offset;
555 int32_t post_type;
556 int num_types, num_extracted = 0, pfb = 1;
557 int raw = 0, appledouble = 0, binhex = 0, macbinary = 0;
558
559 Clp_Parser *clp =
560 Clp_NewParser(argc, (const char * const *)argv, sizeof(options) / sizeof(options[0]), options);
561 program_name = Clp_ProgramName(clp);
562
563 /* interpret command line arguments using CLP */
564 while (1) {
565 int opt = Clp_Next(clp);
566 switch (opt) {
567
568 case RAW_OPT:
569 raw = 1;
570 appledouble = binhex = macbinary = 0;
571 break;
572
573 case MACBINARY_OPT:
574 macbinary = 1;
575 raw = appledouble = binhex = 0;
576 break;
577
578 case APPLEDOUBLE_OPT:
579 appledouble = 1;
580 raw = binhex = macbinary = 0;
581 break;
582
583 case BINHEX_OPT:
584 binhex = 1;
585 raw = appledouble = macbinary = 0;
586 break;
587
588 output_file:
589 case OUTPUT_OPT:
590 if (ofp)
591 fatal_error("output file already specified");
592 if (strcmp(clp->arg, "-") == 0)
593 ofp = stdout;
594 else {
595 ofp = fopen(clp->arg, "w");
596 if (!ofp) fatal_error("%s: %s", clp->arg, strerror(errno));
597 }
598 break;
599
600 case PFB_OPT:
601 pfb = 1;
602 break;
603
604 case PFA_OPT:
605 pfb = 0;
606 break;
607
608 case LINE_LEN_OPT:
609 blocklen = clp->val.i;
610 break;
611
612 case HELP_OPT:
613 usage();
614 exit(0);
615 break;
616
617 case VERSION_OPT:
618 printf("t1unmac (LCDF t1utils) %s\n", VERSION);
619 printf("Copyright (C) 1992-2003 I. Lee Hetherington, Eddie Kohler et al.\n\
620 This is free software; see the source for copying conditions.\n\
621 There is NO warranty, not even for merchantability or fitness for a\n\
622 particular purpose.\n");
623 exit(0);
624 break;
625
626 case Clp_NotOption:
627 if (ifp && ofp)
628 fatal_error("too many arguments");
629 else if (ifp)
630 goto output_file;
631 if (strcmp(clp->arg, "-") == 0)
632 ifp = stdin;
633 else {
634 ifp_name = clp->arg;
635 ifp = fopen(clp->arg, "rb");
636 if (!ifp) fatal_error("%s: %s", clp->arg, strerror(errno));
637 }
638 break;
639
640 case Clp_Done:
641 goto done;
642
643 case Clp_BadOption:
644 short_usage();
645 exit(1);
646 break;
647
648 }
649 }
650
651 done:
652 if (!ifp) ifp = stdin;
653 if (!ofp) ofp = stdout;
654
655 #if defined(_MSDOS) || defined(_WIN32)
656 _setmode(_fileno(ifp), _O_BINARY);
657 /* If we are processing a PFB (binary) output */
658 /* file, we must set its file mode to binary. */
659 if (pfb)
660 _setmode(_fileno(ofp), _O_BINARY);
661 #endif
662
663 if (pfb)
664 init_pfb_writer(&w, blocklen, ofp);
665 else {
666 if (blocklen == -1)
667 blocklen = 64;
668 else if (blocklen < 8) {
669 blocklen = 8;
670 error("warning: line length raised to %d", blocklen);
671 } else if (blocklen > 1024) {
672 blocklen = 1024;
673 error("warning: line length lowered to %d", blocklen);
674 }
675 }
676
677 /* check for non-seekable input */
678 if (fseek(ifp, 0, 0)) {
679 char buf[2048];
680 FILE *tmp = tmpfile();
681 if (!tmp)
682 fatal_error("cannot open temporary file: %s", strerror(errno));
683 while (!feof(ifp)) {
684 int i = fread(buf, 1, 2048, ifp);
685 if (i > 0)
686 fwrite(buf, 1, i, tmp);
687 }
688 if (ferror(ifp))
689 fatal_error("%s: %s", ifp_name, strerror(errno));
690 reposition(tmp, 0);
691 fflush(tmp);
692 if (ifp != stdin)
693 fclose(ifp);
694 ifp = tmp;
695 }
696
697 /* check for empty file */
698 fseek(ifp, 0, 2);
699 if (ftell(ifp) == 0)
700 fatal_error("%s: empty file\n\
701 (Try re-transferring the files using MacBinary format.)",
702 ifp_name);
703
704 reposition(ifp, 0);
705 if (!raw && !appledouble && !binhex && !macbinary) {
706 /* check magic number, try to figure out what it is */
707 int i, magic;
708 magic = read_four(ifp);
709 reposition(ifp, 0);
710
711 if (magic == APPLESINGLE_MAGIC || magic == APPLEDOUBLE_MAGIC)
712 appledouble = 1;
713 else if ((magic & 0xFF000000) == 0)
714 macbinary = 1;
715 else {
716 binhex = 1;
717 for (i = 0; i < 4; i++, magic >>= 8)
718 if (!isprint(magic & 0xFF) && !isspace(magic & 0xFF))
719 /* not an ASCII character, assume not BinHex */
720 binhex = 0;
721 }
722
723 if (!appledouble && !macbinary && !binhex)
724 fatal_error("%s: unknown file type", ifp_name);
725 }
726
727 if (raw) {
728 /* raw resource file */
729 res_offset = 0;
730
731 } else if (macbinary) { /* MacBinary (I or II) file */
732 const char *check;
733 int32_t data_fork_size;
734
735 /* check integrity of file */
736 check = check_macbinary(ifp);
737 if (check)
738 fatal_error("%s: not a MacBinary file (%s)", ifp_name, check);
739
740 /* read data and resource fork sizes in MacBinary header */
741 reposition(ifp, 83);
742 data_fork_size = read_four(ifp);
743 (void) read_four(ifp);
744
745 /* round data_fork_size up to multiple of 128 */
746 if (data_fork_size % 128)
747 data_fork_size += 128 - data_fork_size % 128;
748
749 res_offset = 128 + data_fork_size;
750
751 } else if (appledouble) { /* AppleDouble file */
752 const char *check;
753 const char *applewhat;
754 int i, n;
755
756 /* check integrity */
757 check = check_appledouble(ifp);
758 if (check)
759 fatal_error("%s: not an AppleDouble file (%s)", ifp_name, check);
760 reposition(ifp, 0);
761 if (read_four(ifp) == APPLESINGLE_MAGIC)
762 applewhat = "AppleSingle";
763 else
764 applewhat = "AppleDouble";
765
766 /* find offset to resource and/or data fork */
767 reposition(ifp, 24);
768 n = read_two(ifp);
769 res_offset = -1;
770 for (i = 0; i < n; i++) {
771 int type = read_four(ifp);
772 if (type == 0)
773 fatal_error("%s: bad %s file (bad entry descriptor)", ifp_name, applewhat);
774 if (type == 2) /* resource fork entry */
775 res_offset = read_four(ifp);
776 else
777 (void) read_four(ifp);
778 (void) read_four(ifp);
779 }
780 if (res_offset < 0)
781 fatal_error("%s: bad %s file (no resource fork)", ifp_name, applewhat);
782
783 } else if (binhex) { /* BinHex file */
784 const char *check;
785 FILE *tmpf = tmpfile();
786 if (!tmpf)
787 fatal_error("cannot open temporary file: %s", strerror(errno));
788
789 /* check integrity */
790 check = translate_binhex(ifp, tmpf);
791 if (check)
792 fatal_error("%s: not a BinHex file (%s)", ifp_name, check);
793 check = check_binhex(tmpf);
794 if (check)
795 fatal_error("%s: bad BinHex file (%s)", ifp_name, check);
796
797 /* find resource offset */
798 reposition(tmpf, 0);
799 res_offset = read_one(tmpf);
800 reposition(tmpf, 1 + res_offset + 11);
801 res_offset += 22 + read_four(tmpf) + 2;
802 if (ifp != stdin)
803 fclose(ifp);
804 ifp = tmpf;
805
806 } else {
807 fatal_error("%s: strange format", ifp_name);
808 exit(1);
809 }
810
811 /* read offsets from resource fork header */
812 reposition(ifp, res_offset);
813 res_data_offset = res_offset + read_four(ifp);
814 res_map_offset = res_offset + read_four(ifp);
815
816 /* read type list offset from resource map header */
817 reposition(ifp, res_map_offset + 24);
818 type_list_offset = res_map_offset + read_two(ifp);
819
820 /* read type list */
821 reposition(ifp, type_list_offset);
822 num_types = read_two(ifp) + 1;
823
824 /* find POST type */
825 post_type = (int32_t)('P' & 0xff) << 24;
826 post_type |= (int32_t)('O' & 0xff) << 16;
827 post_type |= (int32_t)('S' & 0xff) << 8;
828 post_type |= (int32_t)('T' & 0xff);
829
830 while (num_types--) {
831 if (read_four(ifp) == post_type) {
832 int nrsrc = 1 + read_two(ifp);
833 int list_offset = type_list_offset + read_two(ifp);
834 int rsrc_pos = 0;
835 int want_id = 501;
836 int second_time = 1;
837 reposition(ifp, list_offset);
838 /* read resources sequentially, starting with ID 501, until we encounter
839 an "end" resource or we can't find the next resource */
840 while (rsrc_pos < nrsrc) {
841 int offset = ftell(ifp);
842 int id = read_two(ifp);
843 if (id == want_id) {
844 (void) read_two(ifp);
845 (void) read_one(ifp);
846 num_extracted++;
847 if (!extract_data(ifp, ofp, &w, res_data_offset + read_three(ifp), pfb))
848 break;
849 second_time = 0;
850 want_id++;
851 }
852 reposition(ifp, offset + 12);
853 rsrc_pos++;
854 if (rsrc_pos >= nrsrc && !second_time) {
855 reposition(ifp, list_offset);
856 rsrc_pos = 0;
857 }
858 }
859 break;
860 } else {
861 (void) read_two(ifp);
862 (void) read_two(ifp);
863 }
864 }
865
866 #if 0
867 system("/bin/rm -f /tmp/x.*");
868 {
869 FILE *f;
870 int i;
871 reposition(ifp, res_offset + 16);
872 if ((f = fopen("/tmp/x.systemarea", "wb"))) {
873 for (i = res_offset + 16; i < res_data_offset; i++) {
874 putc(getc(ifp), f);
875 }
876 fclose(f);
877 }
878 }
879 reposition(ifp, type_list_offset);
880 num_types = read_two(ifp) + 1;
881 while (num_types--) {
882 int t = read_four(ifp);
883 int num_of_type = 1 + read_two(ifp);
884 int32_t save_offset = ftell(ifp) + 2;
885 reposition(ifp, type_list_offset + read_two(ifp));
886 while (num_of_type--) {
887 FILE *f;
888 char buf[2048];
889 int x, i, attrs;
890 x = ftell(ifp);
891 i = read_two(ifp); /* ID */
892 read_two(ifp);
893 attrs = read_one(ifp);
894 sprintf(buf, "/tmp/x.%c%c%c%c.%d", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255, i);
895 fprintf(stderr, "%c%c%c%c.%d %d", (t>>24)&255, (t>>16)&255, (t>>8)&255, t&255, i, attrs);
896 if ((f = fopen(buf, "wb"))) {
897 int l;
898 reposition(ifp, res_data_offset + read_three(ifp));
899 l = read_four(ifp);
900 fprintf(stderr, " %d\n", l);
901 while (l > 0) {
902 int n = (l < 2048 ? l : 2048);
903 fread(buf, 1, n, ifp);
904 fwrite(buf, 1, n, f);
905 l -= n;
906 }
907 fclose(f);
908 }
909 reposition(ifp, x + 12);
910 }
911 reposition(ifp, save_offset);
912 }
913 #endif
914
915 if (pfb)
916 pfb_writer_end(&w);
917 if (num_extracted == 0)
918 error("%s: not a Type 1 font (no POST resources)", ifp_name);
919
920 fclose(ifp);
921 fclose(ofp);
922 return 0;
923 }
924