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.