/* * ANSI C code that converts a .pfb file to a PostScript file. * * For a discussion of this code, see the * September 2002 version of the Acumen Journal * http://www.acumentraining.com/ajournal.asp. * * Written by John Deubert, Acumen Training * * * History * * Sept 5, 2002 Fixed bug that would make the program fail if the pfb file * did not end with an explicite end-of-file code. (Added an * feof check.) Thanks to Tom Brodhead for stumbling onto this * problem. * * Mar 28, 2003 Fixed another bug (again, thanks to Tom Brodhead). Minor problem * with shifting signed char's in the Binary to ASCII Hex converter. * (Can't understand how this passed even my minimal testing.) */ #include #include #include /* ************************ * Constants and typedefs */ #define kFontFileName "COB_____.PFB" // Source pfb file #define kDestFileName "CourierBold.ps" // Destination PS file #define kBigEndian true // Set to false if necessary enum ErrCode { // Error codes returned by procedures kErrNoErr, kErrFileOpenFailed, kErrMemory }; enum { // Header codes indicating how to handle kTypeASCII = 1, // each section in the .pfb file. kTypeBinary, kTypeEOF }; enum { false, true }; // The usual typedef int boolean; typedef struct { char firstByte; char segmentType; long length; } SegmentHeader; /* ************************ * Procedure Declarations */ int main(void); boolean GetSegmentHeader(FILE *src, SegmentHeader *hdr); enum ErrCode SendSegment(FILE *src, FILE *end, SegmentHeader *hdr); void ReverseBytes(long *val); char * ConvertToASCII(char *src, long count); /* ************************ * Procedure Definitions */ int main(void) { FILE *srcFile; FILE *destFile; SegmentHeader hdr; boolean notDone = true; enum ErrCode err; // Open the source and destination files srcFile = fopen(kFontFileName, "rb"); if (!srcFile) return kErrFileOpenFailed; destFile = fopen(kDestFileName, "wb"); if (!destFile) { fclose(srcFile); return kErrFileOpenFailed; } // Loop through all of the segments err = kErrNoErr; do { notDone = GetSegmentHeader(srcFile, &hdr); if (notDone) err = SendSegment(srcFile, destFile, &hdr); } while (notDone && !err); fclose(srcFile); fclose(destFile); return err; } // Get the header of the next segment boolean GetSegmentHeader(FILE *src, SegmentHeader *hdr) { fread(&(hdr->firstByte), 1, 1, src); fread(&(hdr->segmentType), 1, 1, src); fread(&(hdr->length), 1, 4, src); // The length is always in the .pfb file low-byte-first if (kBigEndian) ReverseBytes(&(hdr->length)); // Return 'true' if the segment type indicates EOF return ((hdr->segmentType != kTypeEOF) && !feof(src)); } // This reverses the bytes in a long int. // (I've never found a very elegant way to do this.) void ReverseBytes(long *val) { char temp; char *b; b = (char *)val; temp = b[3]; b[3] = b[0]; b[0] = temp; temp = b[2]; b[2] = b[1]; b[1] = temp; } // Send the data associated with the current segment. enum ErrCode SendSegment(FILE *src, FILE *dest, SegmentHeader *hdr) { char *srcData; // Allocate an appropriately-sized buffer srcData = (char *)malloc(hdr->length); if (!srcData) return kErrMemory; // Get the segment data, converting to ASCII if needed. fread(srcData, 1, hdr->length, src); if (hdr->segmentType == kTypeBinary) { srcData = ConvertToASCII(srcData, hdr->length); hdr->length *= 2; } if (!srcData) return kErrMemory; // Send the data on its way. fwrite(srcData, 1, hdr->length, dest); free(srcData); return kErrNoErr; } // Converts binary to ASCII in-place. // (Well, sort of. It reallocates the buffer, returning // a pointer to the new, double-size buffer.) // Changed 3/28/03: asc & bin became unsigned char * char * ConvertToASCII(char *src, long count) { unsigned char *asc, *bin; long i; static char *numerals = "0123456789ABCDEF"; src = (char *)realloc(src, 2 * count); if (!src) return src; bin = (unsigned char *)src + count - 1; asc = (unsigned char *)src + (2 * count - 1); for (i = count; i > 0; i--) { *asc-- = numerals[*bin & 0x0f]; *asc-- = numerals[*bin >> 4]; bin--; } return src; }