[alt.sources] [postscript] Re: PostScript downloadable font formats

shiva@well.sf.ca.us (Kenneth Porter) (10/01/90)

Archive-name: pfb2pfa/28-Sep-90
Original-posting-by: shiva@well.sf.ca.us (Kenneth Porter)
Original-subject: Re: PostScript downloadable font formats
Reposted-by: emv@math.lsa.umich.edu (Edward Vielmetti)

[Reposted from comp.lang.postscript.
Comments on this service to emv@math.lsa.umich.edu (Edward Vielmetti).]



Sorry Woody, my PC fonts arrived in binary form, and I had to
use Adobe's downloader to decrypt them.  I used my Sun 386i DOS
window to capture the ASCII output to a file.  Once I had more
time, I wrote a program to decrypt the Adobe binary format.
 
/* Decompress .pfb file into .pfa file */
 
/*
 
Copyright 1990 Kenneth Porter (shiva@well.sf.ca.us)
This is freely re-distributable, NOT public domain.
 
Adobe PostScript font files are distributed in a compressed binary
format to be decompressed and downloaded to the printer by Adobe's
download utilities.  Since we want to download the fonts ourselves, this
utility is necessary to convert the binary file into an ASCII file
readable by the printer.
 
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
/* pfb record types */
 
#define PFBTXT 0x180    /* followed by long byte count */
#define PFBBIN 0x280    /* followed by long byte count */
#define PFBEOF 0x380
 
char *ExitServerString =
"%!PS-Adobe-2.0 ExitServer\n"
"%%BeginExitServer: 0\n"
"serverdict begin 0 exitserver\n"
"%%EndExitServer\n";
 
int Mac2IBM(FILE *mac, FILE *ibm, unsigned long count);
int Bin2Txt(FILE *bin, FILE *txt, unsigned long count);
FILE *srcopen(char *name);
FILE *dstopen(char *name);
FILE *fileopen(char *name, char *mode, char *humanmode);
unsigned long fgetl(FILE *f);
void ExitServer(char *tempfile,char *dstfile);
void CheckFontName(char *linebuf);
 
void main(int argc, char *argv[])
{
    FILE *pfb, *pfa;
    unsigned long count;
    int eof = 0;
    unsigned rtype; /* pfb record type */
    char temp[L_tmpnam];
 
    banner();
    if (argc < 3 || argc > 4) {
        fprintf(stderr,"syntax: %s <PFB file> <PFA file>
[persistent]\n",argv[0]);
        exit(1);
    }
    pfb = srcopen(argv[1]);
    pfa = dstopen(tmpnam(temp));
    while (!eof) {
        rtype = getw(pfb);
	if (feof(pfb)) {
	    fprintf(stderr,"Unexpected end of file\n");
	    break;
	}
        switch (rtype) {
            case PFBEOF:
                eof = 1;
                break;
            case PFBTXT:
                count = fgetl(pfb);
                printf("Text count = %ld\n",count);
                if (feof(pfb)) {
                    fprintf(stderr,"Unexpected end of file\n");
                    eof = 1;
                    break;
                }
                if (Mac2IBM(pfb,pfa,count)) {
                    fprintf(stderr,"Unexpected end of file\n");
                    eof = 1;
                    break;
                }
                break;
            case PFBBIN:
                count = fgetl(pfb);
                printf("Bin  count = %ld\n",count);
                if (feof(pfb)) {
                    fprintf(stderr,"Unexpected end of file\n");
                    eof = 1;
                    break;
                }
                if (Bin2Txt(pfb,pfa,count)) {
                    fprintf(stderr,"Unexpected end of file\n");
                    eof = 1;
                    break;
                }
                break;
            default:
                fprintf(stderr,"Record type %X not recognized\n",rtype);
                eof = 1;
                break;
        }
    }
    fclose(pfa);
    fclose(pfb);
    if (argc == 4) ExitServer(temp,argv[2]);
    else rename(temp,argv[2]);
    exit(0);
}
 
#define CR 13   /* Mac ends line with carriage return, IBM with CRLF */
 
int Mac2IBM(FILE *mac, FILE *ibm, unsigned long count)
{
    int c;
    char *lp;
    static char linebuf[128];
 
    linebuf[0] = 0;
    lp = linebuf;
    while (count--) {
        c = fgetc(mac);
        if (feof(mac)) return(EOF);
        if (c == CR) {
            fputc('\n',ibm);
            *lp = 0;
            CheckFontName(linebuf);
            linebuf[0] = 0;
            lp = linebuf;
        }
        else {
            fputc(c,ibm);
            *lp++ = c;
        }
    }
    *lp = 0;
    CheckFontName(linebuf);
    return(0);
}
 
int Bin2Txt(FILE *bin, FILE *txt, unsigned long count)
{
    int c;
    unsigned long i;
 
    for (i=0; i<count; i++) {
        c = fgetc(bin);
        if (feof(bin)) return(EOF);
        fprintf(txt,"%02X",c);
        if ((i & 0x1F) == 0x1F) fputc('\n',txt);
    }
    if ((i & 0x1F) != 0x1F) fputc('\n',txt);
    return(0);
}
 
FILE *srcopen(char *name)
{
    return(fileopen(name,"rb","read"));
}
 
FILE *dstopen(char *name)
{
    return(fileopen(name,"wt","write"));
}
 
FILE *fileopen(char *name, char *mode, char *humanmode)
{
    FILE *file;
 
    file = fopen(name,mode);
    if (!file) {
        fprintf(stderr,"Failed to open %s for %s: %s\n",
            name,humanmode,strerror(errno));
        exit(1);
    }
    return(file);
}
 
unsigned long fgetl(FILE *f)
{
    unsigned long low, high;
 
    low = (unsigned) getw(f);
    high = (unsigned) getw(f);
    return(low+(high<<16));
}
 
char FontTest1[] =
"% Test for existence of font, abort if present.\n"
"% This won't work on a printer with a hard disk!\n"
"/str 32 string def\n";
 
char FontName[128];
 
char FontTest2[] =
" dup FontDirectory exch known\n"
"{ str cvs print ( is already loaded!\\n) print flush quit }\n"
"{ (loading font ) print str cvs print (\\n) print flush }\n"
"ifelse\n";
 
void ExitServer(char *tempfile,char *dstfile)
{
    FILE *tmp, *pfa;
    static char linebuf[128];
 
    pfa = dstopen(dstfile);
    fputs(ExitServerString,pfa);
    if (FontName[0]) {
        fputs(FontTest1,pfa);
        fputs(FontName,pfa);
        fputs(FontTest2,pfa);
    }
    tmp = srcopen(tempfile);
    fgets(linebuf,sizeof linebuf,tmp);
    while (!feof(tmp)) {
        fputs(linebuf,pfa);
        fgets(linebuf,sizeof linebuf,tmp);
    }
    fclose(tmp);
    unlink(tempfile);
    fclose(pfa);
}
 
char FontNameKey[] = "/FontName";
#define FNKL (sizeof FontNameKey - 1)   /* strlen(FontNameKey) */
 
void CheckFontName(char *linebuf)
{
    char *lp, *dp;
 
    if (!strncmp(FontNameKey,linebuf,FNKL)) {
        lp = &linebuf[FNKL];
        while (*lp == ' ') lp++;
        dp = FontName;
        while (*lp != ' ' && *lp != 0) *dp++ = *lp++;
        *dp = 0;
    }
}
 
void banner(void)
{
    printf("ABF Decompressor\n");
    printf("(c)1990 Kenneth Porter, all rights reserved\n");
}

P.S. I think the usage line got truncated in upload; the end should
read "...,argv[0]);".