This is unadobe.c in view mode; [Download] [Up]
/* ** U N A D O B E ** ** Extract font PostScript code from a Macintosh font file resource fork ** (a procedure somewhat akin to extracting water out of rocks), basically ** the same function as the oldie unAdobe program on the Macintosh. ** In addition to this it does the job of the unfont (or pfbtopfa) ** program, that is, reads PC pfb format packed font files. ** ** Information used in this program was acquired from: ** - Inside Macintosh I p.128: Format of a Resource File ** - Adobe TechNote #5040: Supporting Downloadable PostScript Language Fonts ** ** BUGS: this code is specifically written for Motorola-endian machines (like ** Macintosh resource files also are); there is no provision for reading ** MacBinary-encoded Macintosh files (solution: get rid of 128 first bytes, ** for example with "dd", then feed file on stdin). ** ** A million thanks to Rob Elliott <relliott@b11.b11.ingr.com> for pointing ** me in the correct direction on where to find the unpacking information and ** Mark Adler <madler@cco.caltech.edu> for telling me about the NeXT method ** of making the Macintosh file system resource fork available as .#rsrc# ** ** Written by Otto J. Makela <otto@jyu.fi> ** Distributed under the GNU Public Licence -- see file COPYING for details */ #include <stdio.h> #include <stdlib.h> #include <string.h> int verbose=0; main(int argc, char *argv[]) { int loop,i,files=0,type=0; FILE *fi,*fo; /* Loop thru all files given on command line */ loop: for(loop=1; loop<argc; loop++) { /* Possible argument */ if(*argv[loop]=='-') if(argv[loop][1]) { while(i=*++argv[loop]) switch(i) { case 'm': type=1; break; case 'p': type=2; break; case 'v': verbose++; break; default: goto usage; } continue; } else { /* Bare dashes mean stdin/out */ fi=stdin; fo=stdout; } else if(!(fi=fopen(argv[loop],"rb"))) { fprintf(stderr,"%s: can't open file \"%s\" for input\n", *argv,argv[loop]); exit(1); } else { char *p,filename[BUFSIZ]; strcpy(filename,argv[loop]); /* On a NeXT you see Macintosh resource forks as .#rsrc# files */ if(p=strstr(filename,".#rsrc#")) { *p='\0'; if(!type) type=1; } else if(p=strstr(filename,".pfb")) { p[3]='a'; if(!type) type=2; } else strcat(filename,".ps"); if(!(fo=fopen(filename,"wt"))) { fprintf(stderr,"%s: can't open file \"%s\" for output\n", *argv,filename); exit(1); } } if(type==1) { if(verbose) fprintf(stderr,"Macintosh resource file %s:\n",argv[loop]); if(macfont(fi,fo)) { fprintf(stderr,"%s: EOF or data format errors reading file \"%s\"\n", *argv,argv[loop]); exit(1); } } else if(type==2) { if(verbose) fprintf(stderr,"PC pfb file %s:\n",argv[loop]); if(pcfont(fi,fo)) { fprintf(stderr,"%s: EOF or data format errors reading file \"%s\"\n", *argv,argv[loop]); exit(1); } } else { fprintf(stderr,"%s: could not determine file \"%s\" type\n", *argv,argv[loop]); usage: fprintf(stderr,"usage: %s [-mpv] fontfile...\n" "where the font file type is guessed from file extension or:\n" "-m\tSet Macintosh resource file format for next file\n" "-p\tSet PC pfb file format for next file\n" "-v\tIncrease verboseness (repeat for more)\n",*argv); exit(1); } if(fi!=stdin) fclose(fi); if(fo!=stdout) fclose(fo); type=0; files++; } /* If no arguments given, read stdin and output to stdout */ if(!files) { argv[1]="-"; argc=2; goto loop; } exit(0); } /* ** Read a Macintosh resource fork file */ macfont(FILE *fi,FILE *fo) { int i; /* The following data represents a Macintosh resource fork structure */ struct { unsigned long int data_offset; unsigned long int map_offset; unsigned long int data_length; unsigned long int map_length; } resourceheader; struct { unsigned char dummy0[16]; unsigned long int dummy1; unsigned short int dummy2; unsigned short int resourcefile_attribute; unsigned short int typelist_offset; unsigned short int namelist_offset; } resourcemap; unsigned short type_count; struct { char resource_type[4]; unsigned short int reference_count; unsigned short int referencelist_offset; } typelist; struct { unsigned short int resource_id; unsigned short int referencelist_offset; union { unsigned char resource_attribute; unsigned long data_offset; } reference; unsigned long int dummy3; } referencelist; /* First read main resource file header */ if(fread(&resourceheader,1,sizeof(resourceheader),fi)!= sizeof(resourceheader)) return(1); if(verbose) fprintf(stderr, "resource data\toffset = %lu\n" "\t\tlength = %lu\n" "resource map\toffset = %lu\n" "\t\tlength = %lu\n", resourceheader.data_offset,resourceheader.data_length, resourceheader.map_offset,resourceheader.map_length); fseek(fi,resourceheader.map_offset,0); if(fread(&resourcemap,1,sizeof(resourcemap),fi)!=sizeof(resourcemap)) return(1); if(verbose) fprintf(stderr, "resourcefile attribute = %04x\n" "type list offset = %lu (absolute %lu)\n" "name list offset = %lu (absolute %lu)\n", resourcemap.resourcefile_attribute, resourcemap.typelist_offset, resourceheader.map_offset+resourcemap.typelist_offset, resourcemap.namelist_offset, resourceheader.map_offset+resourcemap.namelist_offset); fseek(fi,resourceheader.map_offset+resourcemap.typelist_offset,0); if(fread(&type_count,1,sizeof(type_count),fi)!=sizeof(type_count)) return(1); /* Search for a POST resource containing the PostScript code */ for(i=0; i<=type_count; i++) { if(fread(&typelist,1,sizeof(typelist),fi)!=sizeof(typelist)) return(1); if(verbose) fprintf(stderr,"resource_type=\"%.4s\"\n",typelist.resource_type); if(!strncmp(typelist.resource_type,"POST",4)) break; } /* No POST resource was found */ if(i>type_count) return(1); if(verbose) fprintf(stderr, "%.4s resources = %u\n" "%.4s reference list offset = %lu (absolute %lu)\n", typelist.resource_type,typelist.reference_count+1, typelist.resource_type,typelist.referencelist_offset, resourceheader.map_offset+resourcemap.typelist_offset+ typelist.referencelist_offset); /* Loop thru the resources in numerical order */ for(i=0; i<=typelist.reference_count; i++) { fseek(fi,resourceheader.map_offset+resourcemap.typelist_offset+ typelist.referencelist_offset+i*sizeof(referencelist),0); if(fread(&referencelist,1,sizeof(referencelist),fi)!= sizeof(referencelist)) return(1); if(verbose) fprintf(stderr, "resource_id = %u, attribute %02x\n", referencelist.resource_id, referencelist.reference.resource_attribute); referencelist.reference.resource_attribute=0; if(verbose) fprintf(stderr, "data offset = %lu (absolute %lu)\n", referencelist.reference.data_offset, resourceheader.data_offset+ referencelist.reference.data_offset); if(read_resource(fi,resourceheader.data_offset+ referencelist.reference.data_offset,fo)) return(1); } return(0); } /* ** Read resource data from given offset of file, decode Adobe coding */ read_resource(FILE *fi,unsigned long offset,FILE *fo) { unsigned long size; int c; fseek(fi,offset,0); if(fread(&size,1,sizeof(size),fi)!=sizeof(size)) return(1); if(!size) return(0); if(verbose) fprintf(stderr,"\tlength = %lu\n",size); c=fgetc(fi); /* This bit is a wart. I really don't know why it's needed! */ /* Unfortunately, the results will be incorrect without it */ fgetc(fi); size--; switch(c) { /* Comment resource, just ignore */ case 0: break; /* ASCII text, copy directly to output */ case 1: while(--size) if((c=fgetc(fi))==-1) return(1); else if(c=='\r') fputc('\n',fo); else fputc(c,fo); break; /* Binary data, convert to hexadecimal */ case 2: for(c=1; --size; c++) fprintf(fo,(c%32)?"%02X":"%02X\n",fgetc(fi)); fputc('\n',fo); break; /* End of file marker -- we actually should send ^D at this point? */ case 3: break; /* Font program is in data fork -- what the hell do we do to this? */ /* (we'll assume calling script has handled this bit) */ case 4: fprintf(stderr,"Font program is in data fork\n"); /* Flow thru: Hit EOF -- a error */ case -1: default: return(1); /* End-of-font marker resource */ case 5: break; } return(0); } /* ** Read a PC pfb format file */ pcfont(FILE *fi,FILE *fo) { int c; unsigned long size; while((c=fgetc(fi))==128) { c=fgetc(fi); size=fgetc(fi); size+=fgetc(fi)<<(8); size+=fgetc(fi)<<(8+8); size+=fgetc(fi)<<(8+8+8); if(verbose) fprintf(stderr,"segment type = %u, length = %lu\n",c,size); switch(c) { /* ASCII text, copy directly to output */ case 1: while(size--) if((c=fgetc(fi))==-1) return(1); else if(c=='\r') fputc('\n',fo); else fputc(c,fo); break; /* Binary data, convert to hexadecimal */ case 2: for(c=1; size--; c++) fprintf(fo,(c%32)?"%02X":"%02X\n",fgetc(fi)); fputc('\n',fo); break; /* End of file marker or real EOF */ case 3: return(0); /* Hit EOF or anything else -- a error */ default: return(1); } } if(verbose && c!=-1) fprintf(stderr,"read illegal byte = 0x%02x\n",c); return(c!=-1); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.