Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2298 lines
69 KiB

//---------------------------------------------------------------------------
// makepfm.c
//---------------------------------------------------------------------------
// Create PFM file for Rev-3 fonts
//---------------------------------------------------------------------------
//
// Copyright 1990, 1991 -- Adobe Systems, Inc.
// PostScript is a trademark of Adobe Systems, Inc.
//
// NOTICE: All information contained herein or attendant hereto is, and
// remains, the property of Adobe Systems, Inc. Many of the intellectual
// and technical concepts contained herein are proprietary to Adobe Systems,
// Inc. and may be covered by U.S. and Foreign Patents or Patents Pending or
// are protected as trade secrets. Any dissemination of this information or
// reproduction of this material are strictly forbidden unless prior written
// permission is obtained from Adobe Systems, Inc.
//
//---------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include "windows.h"
#pragma pack(1)
#include "makepfm.h"
#pragma pack(4)
#include "fvscodes.h" // FVS_xxxxxx (font validation status) codes and macros.
#ifdef WIN30
#define LPCSTR LPSTR
#endif
#define WINATM 1
#if !WINATM
LPSZ stringtable[] = {
"MAKEPFM utility version %s released on %s.\n",
"Copyright (C) 1989-91, Adobe Systems Inc. All Rights Reserved.\n\n",
"Usage: makepfm [options] AFMfile\n",
" -h n - set device to PCL (n=1 for 1 byte typeface, 2 for 2 byte).\n",
" -p n - integral point size - only for PCL.\n",
" -c str - PCL symbol set (9U for WinAnsi for example) - only for PCL.\n",
" -d - set orientation to landscape - only for PCL.\n",
" -e str - encoding file.\n",
" -o str - output file.\n",
" -i str - fontinfo file.\n",
" -l str - optional log file - defaults to \"user.log\".\n",
" -f str - take input parameters from file instead of command line.\n",
" -w - display warning messages.\n",
" -s n - force dfCharSet to n.\n",
"Unrecognized command-line option: '%s'\n",
"Unable to open: %s\n",
"Too many track kerning data. Ignoring after %d.\n",
"Unexpected end of file - expected: %s\n",
"Expected: %s - current line: %s\n",
"Parsing character metrics - current line: %s\n",
"Parsing %s.\n",
"Missing \"MSFamily\" value\n",
"Can't create: %s\n",
"Disk is full...\n",
"Memory allocation\n",
"encoding file",
"Creating font metrics ( %s )",
"Finished.\n",
NULL
};
#endif
AFM afm = { 0 };
static ETM etm;
static PFM pfm;
static PFMEXT pfmext;
static DRIVERINFO d;
typedef LPSZ GlyphName;
/* CHAR rgbBuffer[2048]; The file buffer */
CHAR rgbBuffer[8704] = ""; /* increased to handle an additional 512 bytes of width info */
static INT cbBuffer; /* The number of bytes in the buffer */
static LPSZ pbBuffer; /* Ptr to current location in buffer */
static CHAR rgbLine[160]; /* The current line of text being processed */
static LPSZ szLine; /* Ptr to the current location in the line */
static BOOL fEOF = FALSE;
static BOOL fUnGetLine = FALSE;
/*----------------------------------------------------------------------------*/
static LPSZ notdef = "";
#define IBULLET 0x095 /* 87-1-15 sec (was 1) */
#define ISPACE 0x20
#define IWINSPACE 0xA0
static BOOL parseError;
static float sf; /* scale factor for converting to display widths */
/* flags type of PFM to build POSTSCRIPT vs PCL */
INT devType = POSTSCRIPT;
PCLINFO pclinfo = { PORTRAIT, WINANSI_SET, epsymGENERIC8, 0, 0, 2, 0, NULL };
static SHORT fiCapHeight;
static GlyphName *glyphArray;
extern GlyphName *SetupGlyphArray(LPSZ) ;
INT charset = -1;
static BOOL forceVariablePitch = TRUE;
/* names, pointers, and handles for output, log and data files */
CHAR encfile[FNAMEMAX] = "";
CHAR outfile[FNAMEMAX] = "";
CHAR infofile[FNAMEMAX] = "";
static INT fhIn;
#define TK_STARTKERNDATA 2
#define TK_STARTKERNPAIRS 3
#define TK_KPX 4
#define TK_ENDKERNPAIRS 5
#define TK_ENDKERNDATA 6
#define TK_FONTNAME 7
#define TK_WEIGHT 8
#define TK_ITALICANGLE 9
#define TK_ISFIXEDPITCH 10
#define TK_UNDERLINEPOSITION 11
#define TK_UNDERLINETHICKNESS 12
#define TK_FONTBBOX 13
#define TK_CAPHEIGHT 14
#define TK_XHEIGHT 15
#define TK_DESCENDER 16
#define TK_ASCENDER 17
#define TK_STARTCHARMETRICS 18
#define TK_ENDCHARMETRICS 19
#define TK_ENDFONTMETRICS 20
#define TK_STARTFONTMETRICS 21
#define TK_STARTTRACKKERN 22
#define TK_TRACKKERN 23
#define TK_ENDTRACKKERN 24
static KEY afmKeys[] = {
"FontBBox", TK_FONTBBOX,
"StartFontMetrics", TK_STARTFONTMETRICS,
"FontName", TK_FONTNAME,
"Weight", TK_WEIGHT,
"ItalicAngle", TK_ITALICANGLE,
"IsFixedPitch", TK_ISFIXEDPITCH,
"UnderlinePosition", TK_UNDERLINEPOSITION,
"UnderlineThickness", TK_UNDERLINETHICKNESS,
"CapHeight", TK_CAPHEIGHT,
"XHeight", TK_XHEIGHT,
"Descender", TK_DESCENDER,
"Ascender", TK_ASCENDER,
"StartCharMetrics", TK_STARTCHARMETRICS,
"EndCharMetrics", TK_ENDCHARMETRICS,
"StartKernData", TK_STARTKERNDATA,
"StartKernPairs", TK_STARTKERNPAIRS,
"KPX", TK_KPX,
"EndKernPairs", TK_ENDKERNPAIRS,
"EndKernData", TK_ENDKERNDATA,
"EndFontMetrics", TK_ENDFONTMETRICS,
"StartTrackKern", TK_STARTTRACKKERN,
"TrackKern", TK_TRACKKERN,
"EndTrackKern", TK_ENDTRACKKERN,
NULL, 0
};
#define CVTTOSCR(i) (INT)(((float)(i) * sf) + 0.5)
#define DRIVERINFO_VERSION (1)
/*----------------------------------------------------------------------------*/
VOID KxSort(KX *, KX *);
INT GetCharCode(LPSZ, GlyphName *);
VOID ParseKernPairs(INT);
VOID ParseTrackKern(INT);
VOID ParseKernData(INT);
VOID ParseFontName(VOID);
VOID ParseMSFields(VOID);
VOID ParseCharMetrics(BOOL);
VOID ParseCharBox(BBOX *);
LPSZ ParseCharName(VOID);
INT ParseCharWidth(VOID);
INT ParseCharCode(VOID);
VOID ParseBoundingBox(BOOL);
VOID ParsePitchType(VOID);
VOID InitAfm(VOID);
short _MakePfm(VOID);
BOOL ReadFontInfo(INT);
VOID GetCharMetrics(INT, CM *);
VOID SetCharMetrics(INT, CM *);
VOID GetSmallCM(INT, CM *);
VOID SetFractionMetrics(INT, INT, INT, INT);
VOID FixCharWidths(VOID);
VOID SetAfm(VOID);
VOID SetAvgWidth(VOID);
VOID SetMaxWidth(VOID);
/*----------------------------------------------------------------------------*/
VOID ResetBuffer(VOID);
VOID PutByte(SHORT);
VOID PutRgb(LPSZ, INT);
VOID PutWord(SHORT);
VOID PutLong(long);
VOID SetDf(INT);
VOID PutString(LPSZ);
VOID PutDeviceName(LPSZ);
VOID PutFaceName(VOID);
BOOL MakeDf(BOOL, SHORT, LPSZ);
VOID PutPairKernTable(SHORT);
VOID PutTrackKernTable(SHORT);
VOID PutExtentOrWidthTable(INT);
BOOL WritePfm(LPSZ);
/*----------------------------------------------------------------------------*/
VOID SetDriverInfo(VOID);
VOID PutDriverInfo(INT);
LPSZ GetEscapeSequence(VOID);
/*----------------------------------------------------------------------------*/
VOID AfmToEtm(BOOL);
VOID PutEtm(BOOL);
/*----------------------------------------------------------------------------*/
VOID StartParse(VOID);
BOOL szIsEqual(LPSZ, LPSZ);
VOID szMove(LPSZ, LPSZ, INT);
BOOL GetBuffer(INT);
VOID UnGetLine(VOID);
BOOL GetLine(INT);
BOOL _GetLine(INT);
VOID EatWhite(VOID);
VOID GetWord(LPSZ, INT);
BOOL GetString(LPSZ, INT);
BOOL GetNumber(SHORT *);
BOOL GetFloat(float *, SHORT *);
INT MapToken(LPSZ, KEY *);
INT GetToken(INT, KEY *);
/*----------------------------------------------------------------------------*/
GlyphName *AllocateGlyphArray(INT);
VOID PutGlyphName(GlyphName *, INT, LPSZ);
/*----------------------------------------------------------------------------*/
#if DEBUG_MODE
VOID DumpAfm(VOID);
VOID DumpKernPairs(VOID);
VOID DumpKernTracks(VOID);
VOID DumpCharMetrics(VOID);
VOID DumpPfmHeader(VOID);
VOID DumpCharWidths(VOID);
VOID DumpPfmExtension(VOID);
VOID DumpDriverInfo(VOID);
VOID DumpEtm(VOID);
#endif
/*----------------------------------------------------------------------------*/
extern INT OpenParseFile(LPSZ); /* main.c */
extern INT OpenTargetFile(LPSZ);
// extern VOID cdecl PostWarning(LPCSTR, ...);
// extern VOID cdecl PostError(LPCSTR, ...);
extern LPVOID AllocateMem(UINT);
extern VOID FreeAllMem(VOID);
extern VOID WriteDots(VOID);
extern GlyphName *SetupGlyphArray(LPSZ);
#if !WINATM
extern GlyphName *NewGlyphArray(INT);
extern LPSZ ReadLine(FILE *, LPSZ, INT);
extern LPSZ FirstTokenOnLine(FILE *, LPSZ, INT);
extern LPSZ Token(INT);
extern VOID ParseError(VOID);
#endif
/*----------------------------------------------------------------------------*/
/***************************************************************
* Name: KxSort()
* Action: Sort the pair kerning data using the quicksort algorithm.
******************************************************************/
VOID KxSort(pkx1, pkx2)
KX *pkx1;
KX *pkx2;
{
static WORD iPivot;
INT iKernAmount;
KX *pkx1T;
KX *pkx2T;
if (pkx1>=pkx2) return;
iPivot = pkx1->iKey;;
iKernAmount = pkx1->iKernAmount;
pkx1T = pkx1;
pkx2T = pkx2;
while (pkx1T < pkx2T)
{
while (pkx1T < pkx2T)
{
if (pkx2T->iKey < iPivot)
{
pkx1T->iKey = pkx2T->iKey;
pkx1T->iKernAmount = pkx2T->iKernAmount;
++pkx1T;
break;
}
else
--pkx2T;
}
while (pkx1T < pkx2T)
{
if (pkx1T->iKey > iPivot)
{
pkx2T->iKey = pkx1T->iKey;
pkx2T->iKernAmount = pkx1T->iKernAmount;
--pkx2T;
break;
}
else
++pkx1T;
}
}
pkx2T->iKey = iPivot;
pkx2T->iKernAmount = (SHORT)iKernAmount;
++pkx2T;
if ((pkx1T - pkx1) < (pkx2 - pkx2T))
{
KxSort(pkx1, pkx1T);
KxSort(pkx2T, pkx2);
}
else
{
KxSort(pkx2T, pkx2);
KxSort(pkx1, pkx1T);
}
}
/******************************************************************
* Name: GetCharCode(glyphname, glypharray)
* Action: Lookup glyphname in glypharray & return index.
********************************************************************/
INT GetCharCode(glyphname, glypharray)
LPSZ glyphname;
GlyphName *glypharray;
{
register INT i;
if ( STRCMP(glyphname, "") != 0 )
for(i=0; glypharray[i]!=NULL; i++)
if ( STRCMP(glypharray[i], glyphname) == 0 ) return(i);
/* printf("GetCharCode: Undefined character = %s\n", glyphname); */
return(-1);
}
/******************************************************************
* Name: ParseKernPairs()
* Action: Parse the pairwise kerning data.
********************************************************************/
VOID ParseKernPairs(pcl)
INT pcl;
{
UINT iCh1, iCh2;
KP *pkp;
INT iToken;
WORD cPairs, i;
SHORT iKernAmount;
CHAR szWord[80];
GetNumber(&cPairs);
if( cPairs == 0 )
return;
pkp = &afm.kp;
pkp->cPairs = 0;
pkp->rgPairs = (PKX) AllocateMem( (UINT) (sizeof(KX) * cPairs) );
if( pkp->rgPairs == NULL ) {
; // PostError(str(MSG_PFM_BAD_MALLOC));
parseError = TRUE;
return;
}
for (i = 0; i < cPairs; ++i) {
if( !GetLine(fhIn) ) break;
if( GetToken(fhIn, afmKeys) != TK_KPX ) {
UnGetLine();
break;
}
GetWord(szWord, sizeof(szWord));
iCh1 = (UINT)GetCharCode(szWord, glyphArray);
GetWord(szWord, sizeof(szWord));
iCh2 = (UINT)GetCharCode(szWord, glyphArray);
GetNumber(&iKernAmount);
/* no kern pairs for unencoded characters or miniscule kern amounts */
if( (iCh1 == -1 || iCh2 == -1) || (pcl && CVTTOSCR(iKernAmount) == 0) )
continue;
pkp->rgPairs[pkp->cPairs].iKey = iCh2 << 8 | iCh1;
pkp->rgPairs[pkp->cPairs++].iKernAmount =
(pcl) ? CVTTOSCR(iKernAmount) : iKernAmount;
}
GetLine(fhIn);
iToken = GetToken(fhIn, afmKeys);
if( iToken == TK_EOF )
; // PostWarning(str(MSG_PFM_BAD_EOF), "EndKernPairs");
else if( iToken != TK_ENDKERNPAIRS ) {
; // PostError(str(MSG_PFM_BAD_TOKEN), "EndKernPairs", rgbLine);
parseError = TRUE;
}
KxSort(&afm.kp.rgPairs[0], &afm.kp.rgPairs[afm.kp.cPairs - 1]);
}
/******************************************************************
* Name: ParseTrackKern()
* Action: Parse the track kerning data.
********************************************************************/
VOID ParseTrackKern(pcl)
INT pcl;
{
float one;
INT i;
KT *pkt;
INT iToken;
one = (float) 1;
pkt = &afm.kt;
GetNumber(&pkt->cTracks);
if( pkt->cTracks > MAXTRACKS) ; // PostWarning(str(MSG_PFM_BAD_TRACK), MAXTRACKS);
for (i = 0; i < pkt->cTracks; ++i) {
if( !GetLine(fhIn) ) {
; // PostError(str(MSG_PFM_BAD_EOF), "EndTrackKern");
parseError = TRUE;
return;
}
if( GetToken(fhIn, afmKeys) != TK_TRACKKERN ) {
; // PostError(str(MSG_PFM_BAD_TOKEN), "EndTrackKern", rgbLine);
parseError = TRUE;
return;
}
if( i < MAXTRACKS) {
GetNumber(&pkt->rgTracks[i].iDegree);
GetFloat(&one, &pkt->rgTracks[i].iPtMin);
(pcl) ? GetFloat(&sf, &pkt->rgTracks[i].iKernMin) :
GetFloat(&one, &pkt->rgTracks[i].iKernMin);
GetFloat(&one, &pkt->rgTracks[i].iPtMax);
(pcl) ? GetFloat(&sf, &pkt->rgTracks[i].iKernMax) :
GetFloat(&one, &pkt->rgTracks[i].iKernMax);
}
}
GetLine(fhIn);
iToken = GetToken(fhIn, afmKeys);
if( iToken == TK_EOF ) {
; // PostError(str(MSG_PFM_BAD_EOF), "EndTrackKern");
parseError = TRUE;
}
else if( iToken != TK_ENDTRACKKERN ) {
; // PostError(str(MSG_PFM_BAD_TOKEN), "EndTrackKern", rgbLine);
parseError = TRUE;
}
}
/********************************************************
* Name: ParseKernData()
* Action: Start processing the kerning data.
*************************************************************/
VOID ParseKernData(pcl)
INT pcl;
{
INT iToken;
do {
if ( !GetLine(fhIn) ) {
; // PostError(str(MSG_PFM_BAD_EOF), "EndKernData");
parseError = TRUE;
}
iToken = GetToken(fhIn, afmKeys);
if( iToken == TK_STARTKERNPAIRS ) ParseKernPairs(pcl);
else if( iToken == TK_STARTTRACKKERN ) ParseTrackKern(pcl);
} while( iToken != TK_ENDKERNDATA);
}
/***********************************************************
* Name: ParseFontName()
* Action: Move the font name from the input buffer into the afm
* structure.
**************************************************************/
VOID ParseFontName()
{
EatWhite();
szMove(afm.szFont, szLine, sizeof(afm.szFont));
}
/**************************************************************
* Name: ParseCharMetrics()
* Action: Parse the character metrics entry in the input file
* and set the width and bounding box in the afm structure.
*****************************************************************/
VOID ParseCharMetrics(pcl)
BOOL pcl;
{
SHORT cChars;
INT i, iChar, iWidth;
BBOX rcChar;
if (afm.iFamily == FF_DECORATIVE)
glyphArray = AllocateGlyphArray(255);
else
glyphArray = SetupGlyphArray(encfile);
if( glyphArray == NULL ) {
parseError = TRUE;
return;
}
GetNumber(&cChars);
for (i = 0; i < cChars; ++i) {
if( !GetLine(fhIn) ) {
; // PostError(str(MSG_PFM_BAD_EOF), "EndCharMetrics");
parseError = TRUE;
return;
}
iChar = ParseCharCode();
iWidth = ParseCharWidth();
if( afm.iFamily == FF_DECORATIVE ) {
if( iChar < 0 || iChar > 255 ) continue;
PutGlyphName(glyphArray, iChar, ParseCharName());
} else {
iChar = GetCharCode(ParseCharName(), glyphArray);
if( iChar == -1 ) continue;
}
ParseCharBox(&rcChar);
if( parseError == TRUE ) return;
afm.rgcm[iChar].iWidth = (pcl) ? CVTTOSCR(iWidth) : iWidth;
afm.rgcm[iChar].rc.top = (pcl) ? CVTTOSCR(rcChar.top) : rcChar.top;
afm.rgcm[iChar].rc.left = (pcl) ? CVTTOSCR(rcChar.left) : rcChar.left;
afm.rgcm[iChar].rc.right = (pcl) ? CVTTOSCR(rcChar.right) : rcChar.right;
afm.rgcm[iChar].rc.bottom = (pcl) ? CVTTOSCR(rcChar.bottom) : rcChar.bottom;
}
GetLine(fhIn);
if (GetToken(fhIn, afmKeys)!=TK_ENDCHARMETRICS) {
; // PostError(str(MSG_PFM_BAD_TOKEN), "EndCharMetrics", rgbLine);
parseError = TRUE;
}
}
/***************************************************************
* Name: ParseCharBox()
* Action: Parse the character's bounding box and return its
* dimensions in the destination rectangle.
*****************************************************************/
VOID ParseCharBox(prc)
BBOX *prc; /* Pointer to the destination rectangle */
{
CHAR szWord[16];
GetWord(szWord, sizeof(szWord));
if( szIsEqual("B", szWord) ) {
GetNumber(&prc->left);
GetNumber(&prc->bottom);
GetNumber(&prc->right);
GetNumber(&prc->top);
}
else {
; // PostError(str(MSG_PFM_BAD_CHARMETRICS), rgbLine);
parseError = TRUE;
return;
}
EatWhite();
if (*szLine++ != ';') {
; // PostError(str(MSG_PFM_BAD_CHARMETRICS), rgbLine);
parseError = TRUE;
}
}
/*********************************************************
* Name: ParseCharName()
* Action: Parse a character's name
************************************************************/
LPSZ ParseCharName()
{
static CHAR szWord[40];
EatWhite();
GetWord(szWord, sizeof(szWord));
if (szIsEqual("N", szWord))
GetWord(szWord, sizeof(szWord));
else {
; // PostError(str(MSG_PFM_BAD_CHARMETRICS), rgbLine);
parseError = TRUE;
return(szWord);
}
EatWhite();
if (*szLine++ != ';') {
; // PostError(str(MSG_PFM_BAD_CHARMETRICS), rgbLine);
parseError = TRUE;
}
return(szWord);
}
/***********************************************************
* Name: ParseCharWidth()
* Action: Parse a character's width and return its numeric
* value.
*************************************************************/
INT ParseCharWidth()
{
SHORT iWidth;
CHAR szWord[16];
GetWord(szWord, sizeof(szWord));
if (szIsEqual("WX", szWord)) {
GetNumber(&iWidth);
if (iWidth==0) ; // PostWarning(str(MSG_PFM_BAD_CHARMETRICS), rgbLine);
EatWhite();
if (*szLine++ != ';') {
; // PostError(str(MSG_PFM_BAD_CHARMETRICS), rgbLine);
parseError = TRUE;
}
}
else {
; // PostError(str(MSG_PFM_BAD_CHARMETRICS), rgbLine);
parseError = TRUE;
}
return(iWidth);
}
/*****************************************************************
* Name: ParseCharCode()
* Action: Parse the ascii form of a character's code point and
* return its numeric value.
******************************************************************/
INT ParseCharCode()
{
SHORT iChar;
CHAR szWord[16];
iChar = 0;
GetWord(szWord, sizeof(szWord));
if (szIsEqual("C", szWord)) {
GetNumber(&iChar);
if (iChar==0) {
; // PostError(str(MSG_PFM_BAD_CHARMETRICS), rgbLine);
parseError = TRUE;
return(0);
}
EatWhite();
if (*szLine++ != ';') {
; // PostError(str(MSG_PFM_BAD_CHARMETRICS), rgbLine);
parseError = TRUE;
}
}
return(iChar);
}
/****************************************************************
* Name: ParseBounding Box()
* Action: Parse a character's bounding box and return its size in
* the afm structure.
*******************************************************************/
VOID ParseBoundingBox(pcl)
BOOL pcl;
{
SHORT i;
/* 8-26-91 yh Note that values in rcBBox are not scaled for PCL either */
GetNumber(&i);
// afm.rcBBox.left = (pcl) ? CVTTOSCR(i) : i;
afm.rcBBox.left = i;
GetNumber(&i);
// afm.rcBBox.bottom = (pcl) ? CVTTOSCR(i) : i;
afm.rcBBox.bottom = i;
GetNumber(&i);
// afm.rcBBox.right = (pcl) ? CVTTOSCR(i) : i;
afm.rcBBox.right = i;
GetNumber(&i);
// afm.rcBBox.top = (pcl) ? CVTTOSCR(i) : i;
afm.rcBBox.top = i;
}
/************************************************************
* Name: ParsePitchType()
*
* Action: Parse the pitch type and set the variable pitch
* flag in the afm structure.
* Always set the pitch to be variable pitch for
* our fonts in Windows
*
**********************************************************/
VOID ParsePitchType()
{
CHAR szWord[16];
EatWhite();
GetWord(szWord, sizeof(szWord));
if( !STRCMP(_strlwr(szWord), "true" ) ) {
afm.fWasVariablePitch = FALSE;
afm.fVariablePitch = forceVariablePitch;
}
// afm.fVariablePitch = TRUE;
}
/***********************************************************
* Name: InitAfm()
* Action: Initialize the afm structure.
************************************************************/
VOID InitAfm()
{
register int i;
afm.iFirstChar = 0x20;
afm.iLastChar = 0x0ff;
afm.iAvgWidth = 0;
afm.iMaxWidth = 0;
afm.iItalicAngle = 0;
afm.iFamily = 0;
afm.ulOffset = 0;
afm.ulThick = 0;
afm.iAscent = 0;
afm.iDescent = 0;
afm.fVariablePitch = TRUE;
afm.fWasVariablePitch = TRUE;
afm.szFont[0] = 0;
afm.szFace[0] = 0;
afm.iWeight = 400;
afm.kp.cPairs = 0;
afm.kt.cTracks = 0;
afm.rcBBox.left = 0;
afm.rcBBox.bottom = 0;
afm.rcBBox.right = 0;
afm.rcBBox.top = 0;
for(i=0; i<256; i++ ) {
afm.rgcm[i].rc.left = 0;
afm.rgcm[i].rc.bottom = 0;
afm.rgcm[i].rc.right = 0;
afm.rgcm[i].rc.top = 0;
afm.rgcm[i].iWidth = 0;
}
}
/*----------------------------------------------------------------------------
** Returns: 16-bit encoded value indicating error and type of file where
** error occurred. (see fvscodes.h) for definitions.
** The following table lists the "status" portion of the codes
** returned.
**
** FVS_SUCCESS
** FVS_INVALID_FONTFILE
** FVS_FILE_OPEN_ERR
** FVS_FILE_BUILD_ERR
*/
short _MakePfm()
{
INT hfile;
SHORT i;
float ten = (float) 10;
BOOL fPrint = FALSE, fEndOfInput = FALSE, fStartInput = FALSE;
BOOL bRes;
// if ( devType == PCL ) sf = ((float)afm.iPtSize / 1000.0) * (300.0 / 72.0);
InitAfm();
if( (hfile = OpenParseFile(infofile)) == -1 ) {
; // PostError(str(MSG_PFM_BAD_FOPEN), infofile);
return(FVS_MAKE_CODE(FVS_FILE_OPEN_ERR, FVS_FILE_INF));
}
if( !ReadFontInfo(hfile) ) {
CLOSE(hfile);
; // PostError(str(MSG_PFM_BAD_PARSE), infofile);
return(FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_INF));
}
CLOSE(hfile);
if( (fhIn = OpenParseFile(afm.szFile)) == -1 ) {
; // PostError(str(MSG_PFM_BAD_FOPEN), afm.szFile);
return(FVS_MAKE_CODE(FVS_FILE_OPEN_ERR, FVS_FILE_AFM));
}
parseError = FALSE;
while (!fEndOfInput) {
if( !GetLine(fhIn) ) break;
switch( GetToken(fhIn, afmKeys) ) {
case TK_STARTFONTMETRICS:
fStartInput = TRUE;
break;
case TK_STARTKERNDATA:
ParseKernData(devType == PCL);
break;
case TK_FONTNAME:
ParseFontName();
break;
case TK_WEIGHT:
break;
case TK_ITALICANGLE:
GetFloat(&ten, &afm.iItalicAngle);
break;
case TK_ISFIXEDPITCH:
ParsePitchType();
break;
case TK_UNDERLINEPOSITION:
GetNumber(&i);
afm.ulOffset = (devType==POSTSCRIPT) ? abs(i) : CVTTOSCR(abs(i));
break;
case TK_UNDERLINETHICKNESS:
GetNumber(&i);
afm.ulThick = (devType == POSTSCRIPT) ? i : CVTTOSCR(i);
break;
case TK_FONTBBOX:
ParseBoundingBox(devType == PCL);
break;
case TK_CAPHEIGHT:
GetNumber(&i);
if( fiCapHeight == 0 ) fiCapHeight = i;
break;
case TK_XHEIGHT:
break;
case TK_DESCENDER:
GetNumber(&i);
afm.iDescent = (devType == POSTSCRIPT) ? i : CVTTOSCR(i);
break;
case TK_ASCENDER:
GetNumber(&i);
if (i < 667) i = 667;
afm.iAscent = (devType == POSTSCRIPT) ? i : CVTTOSCR(i);
break;
case TK_STARTCHARMETRICS:
if (afm.iFamily == 0) {
; // PostError(str(MSG_PFM_MISSING_MSFAMILY));
CLOSE(fhIn);
return(FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_AFM));
}
ParseCharMetrics(devType == PCL);
break;
case TK_ENDFONTMETRICS:
fEndOfInput = TRUE;
break;
}
if( parseError ) {
CLOSE(fhIn);
return(FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_AFM));
}
}
CLOSE(fhIn);
if( !fStartInput ) {
; // PostError(str(MSG_PFM_BAD_EOF), "StartFontMetrics");
return(FVS_MAKE_CODE(FVS_INVALID_FONTFILE, FVS_FILE_AFM));
}
FixCharWidths();
SetAfm();
#if DEBUG_MODE
DumpAfm();
DumpKernPairs();
DumpKernTracks();
DumpCharMetrics();
#endif
bRes = MakeDf(FALSE, (SHORT)devType, outfile);
FreeAllMem();
return(bRes ? FVS_MAKE_CODE(FVS_SUCCESS, FVS_FILE_UNK) :
FVS_MAKE_CODE(FVS_FILE_BUILD_ERR, FVS_FILE_PFM));
}
/*----------------------------------------------------------------------------*/
BOOL ReadFontInfo(hfile)
INT hfile;
{
INT iToken;
CHAR szTemp[6];
BOOL found[LAST_FI_TOKEN+1];
static KEY infKeys[] = {
"MSMenuName", TK_MSMENUNAME,
"VPStyle", TK_VPSTYLE,
"Pi", TK_PI,
"Serif", TK_SERIF,
"PCLStyle", TK_PCLSTYLE,
"PCLStrokeWeight", TK_PCLSTROKEWEIGHT,
"PCLTypefaceID", TK_PCLTYPEFACEID,
"CapHeight", TK_INF_CAPHEIGHT,
NULL, 0
};
fiCapHeight = 0;
for(iToken=0; iToken<=LAST_FI_TOKEN; iToken++) found[iToken] = FALSE;
while( GetLine(hfile) ) {
iToken = GetToken(hfile,infKeys);
found[iToken] = TRUE;
switch(iToken) {
case TK_MSMENUNAME:
if( !GetString(afm.szFace, sizeof(afm.szFace)) ) return(FALSE);
break;
case TK_VPSTYLE:
if( !GetString(szTemp, sizeof(szTemp)) ) return(FALSE);
switch( toupper(szTemp[0]) ) {
case 'N':
case 'I': afm.iWeight = FW_NORMAL; break;
case 'B':
case 'T': afm.iWeight = FW_BOLD; break;
default: return(FALSE); break;
}
break;
case TK_PI:
GetWord(szTemp, sizeof(szTemp));
if( !STRCMP(_strupr(szTemp), "TRUE") )
afm.iFamily = FF_DECORATIVE;
else if( STRCMP(szTemp, "FALSE") ) return(FALSE);
break;
case TK_SERIF:
GetWord(szTemp, sizeof(szTemp));
if( !STRCMP(_strupr(szTemp), "TRUE") ) {
if( afm.iFamily != FF_DECORATIVE ) afm.iFamily = FF_ROMAN;
}
else if( !STRCMP(szTemp, "FALSE") ) {
if( afm.iFamily != FF_DECORATIVE ) afm.iFamily = FF_SWISS;
}
else return(FALSE);
break;
case TK_INF_CAPHEIGHT:
GetNumber(&fiCapHeight);
break;
case TK_PCLSTYLE:
GetNumber(&pclinfo.style);
break;
case TK_PCLSTROKEWEIGHT:
GetNumber(&pclinfo.strokeWeight);
break;
case TK_PCLTYPEFACEID:
GetNumber((SHORT *)&pclinfo.typeface);
if( pclinfo.typefaceLen == 1 ) pclinfo.typeface &= 0xFF;
break;
}
}
if( found[TK_MSMENUNAME] == FALSE ||
found[TK_VPSTYLE] == FALSE ||
found[TK_PI] == FALSE ||
found[TK_SERIF] == FALSE ||
found[TK_INF_CAPHEIGHT] == FALSE ) return(FALSE);
if ( devType == PCL )
if( found[TK_PCLSTYLE] == FALSE ||
found[TK_PCLSTROKEWEIGHT] == FALSE ||
found[TK_PCLTYPEFACEID] == FALSE ) return(FALSE);
return(TRUE);
}
#if DEBUG_MODE
/*----------------------------------------------------------------------------*/
VOID DumpAfm()
{
printf("\nAFM HEADER\n");
printf("afm.iFirstChar: %d\n", afm.iFirstChar);
printf("afm.iLastChar: %d\n", afm.iLastChar);
printf("afm.iPtSize: %d\n", afm.iPtSize);
printf("afm.iAvgWidth: %d\n", afm.iAvgWidth);
printf("afm.iMaxWidth: %d\n", afm.iMaxWidth);
printf("afm.iItalicAngle: %d\n", afm.iItalicAngle);
printf("afm.iFamily: %d\n", afm.iFamily);
printf("afm.ulOffset: %d\n", afm.ulOffset);
printf("afm.ulThick: %d\n", afm.ulThick);
printf("afm.iAscent: %d\n", afm.iAscent);
printf("afm.iDescent: %d\n", afm.iDescent);
printf("afm.fVariablePitch: %d\n", afm.fVariablePitch);
printf("afm.szFile: %s\n", afm.szFile);
printf("afm.szFont: %s\n", afm.szFont);
printf("afm.szFace: %s\n", afm.szFace);
printf("afm.iWeight: %d\n", afm.iWeight);
printf("afm.rcBBox - top: %d left: %d right: %d bottom: %d\n",
afm.rcBBox.top, afm.rcBBox.left, afm.rcBBox.right, afm.rcBBox.bottom);
}
/*----------------------------------------------------------------------------*/
VOID DumpKernPairs()
{
INT indx;
printf("\nKERN PAIRS\n");
printf("afm.kp.cPairs: %d\n", afm.kp.cPairs);
for (indx = 0; indx < afm.kp.cPairs; indx++)
printf("afm.kp.rgPairs[%d] - iKey: %u iKernAmount: %d\n", indx,
afm.kp.rgPairs[indx].iKey, afm.kp.rgPairs[indx].iKernAmount);
}
/*----------------------------------------------------------------------------*/
VOID DumpKernTracks()
{
INT indx;
printf("\nKERN TRACKS\n");
printf("afm.kt.cTracks: %d\n", afm.kt.cTracks);
for (indx = 0; indx < afm.kt.cTracks; indx++) {
printf("track: %d iDegree: %d iPtMin: %d iKernMin: %d iPtMax: %d iKernMax: %d\n",
indx,
afm.kt.rgTracks[indx].iDegree,
afm.kt.rgTracks[indx].iPtMin,
afm.kt.rgTracks[indx].iKernMin,
afm.kt.rgTracks[indx].iPtMax,
afm.kt.rgTracks[indx].iKernMax);
}
}
/*----------------------------------------------------------------------------*/
VOID DumpCharMetrics()
{
INT indx;
printf("\nCHARACTER METRICS\n");
for (indx = afm.iFirstChar; indx <= afm.iLastChar; ++indx) {
printf("indx: %d width: %d top: %d left: %d right: %d bottom: %d\n",
indx,
afm.rgcm[indx].iWidth,
afm.rgcm[indx].rc.top,
afm.rgcm[indx].rc.left,
afm.rgcm[indx].rc.right,
afm.rgcm[indx].rc.bottom);
}
}
/*----------------------------------------------------------------------------*/
#endif
/******************************************************
* Name: GetCharMetrics()
* Action: Get the character metrics for a specified character.
**********************************************************/
VOID GetCharMetrics(iChar, pcm)
INT iChar;
CM *pcm;
{
CM *pcmSrc;
pcmSrc = &afm.rgcm[iChar];
pcm->iWidth = pcmSrc->iWidth;
pcm->rc.top = pcmSrc->rc.top;
pcm->rc.left = pcmSrc->rc.left;
pcm->rc.bottom = pcmSrc->rc.bottom;
pcm->rc.right = pcmSrc->rc.right;
}
/*************************************************************
* Name: SetCharMetrics()
* Action: Set the character metrics for a specified character.
***************************************************************/
VOID SetCharMetrics(iChar, pcm)
INT iChar;
CM *pcm;
{
CM *pcmDst;
pcmDst = &afm.rgcm[iChar];
pcmDst->iWidth = pcm->iWidth;
pcmDst->rc.top = pcm->rc.top;
pcmDst->rc.left = pcm->rc.left;
pcmDst->rc.bottom = pcm->rc.bottom;
pcmDst->rc.right = pcm->rc.right;
}
/************************************************************
* Name: GetSmallCM()
* Action: Compute the character metrics for small sized characters
* such as superscripts.
**************************************************************/
VOID GetSmallCM(iCh, pcm)
INT iCh;
CM *pcm;
{
GetCharMetrics(iCh, pcm);
pcm->iWidth = pcm->iWidth / 2;
pcm->rc.bottom = pcm->rc.top + (pcm->rc.top - pcm->rc.bottom)/2;
pcm->rc.right = pcm->rc.left + (pcm->rc.right - pcm->rc.left)/2;
}
/*************************************************************
* Name: SetFractionMetrics()
* Action: Set the character metrics for a fractional character
* which must be simulated.
***************************************************************/
VOID SetFractionMetrics(iChar, iTop, iBottom, pcl)
INT iChar; /* The character code point */
INT iTop; /* The ascii numerator character */
INT iBottom; /* The denominator character */
INT pcl; /* device type */
{
INT cxBottom; /* The width of the denominator */
CM cm;
#define IFRACTIONBAR 167
/* Set denominator width to 60 percent of bottom character */
GetCharMetrics(iBottom, &cm);
cxBottom = (INT)((long)cm.iWidth * (long)((pcl) ? CVTTOSCR(60) : 60)
/ (long)((pcl) ? CVTTOSCR(100) : 100));
/* Set numerator width to 40 percent of top character */
GetCharMetrics(iTop, &cm);
cxBottom = (INT)((long)cm.iWidth * (long)((pcl) ? CVTTOSCR(40) : 40)
/ (long)((pcl) ? CVTTOSCR(100) : 100));
cm.iWidth = iTop + iBottom + (pcl) ? CVTTOSCR(IFRACTIONBAR) : IFRACTIONBAR;
cm.rc.right = cm.rc.left + cm.iWidth;
SetCharMetrics(iChar, &cm);
}
/***********************************************************************
* Name: FixCharWidths()
* Action: Fix up the character widths for those characters which
* must be simulated in the driver.
*************************************************************************/
VOID FixCharWidths()
{
CM cm;
CM cmSubstitute;
INT i;
#if 0
if (afm.iFamily == FF_DECORATIVE) {
GetCharMetrics(ISPACE, &cmSubstitute);
for (i = afm.iFirstChar; i <= afm.iLastChar; ++i) {
GetCharMetrics(i, &cm);
if (cm.iWidth == 0) {
SetCharMetrics(i, &cmSubstitute);
}
}
return;
}
/* this is a text font */
GetCharMetrics(IBULLET, &cmSubstitute);
for (i=0x07f; i<0x091; ++i) SetCharMetrics(i, &cmSubstitute);
for (i=0x098; i<0x0a1; ++i) SetCharMetrics(i, &cmSubstitute);
#else
/* yh 8-27-91 Added some characters for Windows 3.1. */
if (afm.iFamily == FF_DECORATIVE)
GetCharMetrics(ISPACE, &cmSubstitute);
else { /* WINANSI encoding */
GetCharMetrics(ISPACE, &cm); /* 'space' is encoded twice */
SetCharMetrics(IWINSPACE, &cm);
GetCharMetrics(IBULLET, &cmSubstitute);
}
for (i = afm.iFirstChar; i <= afm.iLastChar; ++i) {
GetCharMetrics(i, &cm);
if (cm.iWidth == 0)
SetCharMetrics(i, &cmSubstitute);
}
#endif
}
/***************************************************************
* Name: SetAfm()
* Action: Set the character metrics in the afm to their default values.
********************************************************************/
VOID SetAfm()
{
INT i, cx;
afm.iFirstChar = 0x0020;
afm.iLastChar = 0x00ff;
if( !afm.fVariablePitch ) {
cx = afm.rgcm[afm.iFirstChar].iWidth;
for (i=afm.iFirstChar; i<=afm.iLastChar; ++i)
afm.rgcm[i].iWidth = (SHORT)cx;
}
SetAvgWidth();
SetMaxWidth();
}
/******************************************************************
* Name: SetAvgWidth()
* Action: This routine computes the average character width
* from the character metrics in the afm structure.
********************************************************************/
VOID SetAvgWidth()
{
CM *rgcm;
INT i;
long cx; /* The average character width */
long cb; /* The number of characters */
rgcm = afm.rgcm;
cx = 0L;
cb = (long) (afm.iLastChar - afm.iFirstChar + 1);
for (i=afm.iFirstChar; i<=afm.iLastChar; ++i)
cx += (long) rgcm[i].iWidth;
afm.iAvgWidth = (INT) (cx / cb);
}
/*****************************************************************
* Name: SetMaxWidth()
* Action: This routine computes the maximum character width from
* the character metrics in the afm structure.
*******************************************************************/
VOID SetMaxWidth()
{
CM *rgcm;
INT cx;
INT i;
rgcm = afm.rgcm;
cx = 0;
for (i=afm.iFirstChar; i<=afm.iLastChar; ++i)
if (rgcm[i].iWidth > cx) cx = rgcm[i].iWidth;
afm.iMaxWidth = (SHORT)cx;
}
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/******************************************************************
* Name: ResetBuffer()
* Action: This function resets the output buffer.
********************************************************************/
VOID ResetBuffer()
{
pbBuffer = rgbBuffer;
cbBuffer = 0;
}
/****************************************************************
* Name: PutByte()
* Action: This function writes a byte to the output buffer.
******************************************************************/
VOID PutByte(iByte)
SHORT iByte;
{
*pbBuffer++ = (BYTE) (iByte & 0x0ff);
++cbBuffer;
}
/****************************************************************
* Name: PutRgb()
* Action: This function writes an array of bytes to the output buffer.
******************************************************************/
VOID PutRgb(pb, cb)
LPSZ pb;
INT cb;
{
while (--cb>=0)
PutByte(*pb++);
}
/****************************************************************
* Name: PutWord()
* Action: This function writes a word to the output buffer.
******************************************************************/
VOID PutWord(iWord)
SHORT iWord;
{
*pbBuffer++ = (CHAR) (iWord & 0x0ff);
*pbBuffer++ = (CHAR) ( (iWord >> 8) & 0x0ff );
cbBuffer += 2;
}
/****************************************************************
* Name: PutLong()
* Action: This function writes a long word to the output buffer.
******************************************************************/
VOID PutLong(lWord)
long lWord;
{
PutWord((WORD) (lWord & 0x0ffffL));
lWord >>= 16;
PutWord((WORD) (lWord & 0x0ffffL));
}
/**************************************************************
* Name: SetDf()
* Action: This function sets the values in the device font structure
* from the values in the afm structure.
*****************************************************************/
static CHAR szCopyright[] = "Copyright 1988-1991 Adobe Systems Inc.";
VOID SetDf(pcl)
INT pcl;
{
//WORD minAscent;
WORD pixHeight;
WORD internalLeading;
SHORT leading;
#ifndef FF_MASKFAMILY
#define FF_MASKFAMILY ((BYTE) 0xF0)
#endif
#define MAX(a,b) ((a)>(b)?(a):(b))
pfm.iVersion = 0x0100; /* Version 1.00 */
szMove(pfm.szCopyright, szCopyright, sizeof(pfm.szCopyright));
pfm.iType = (pcl) ? PCL_FONTTYPE : PS_FONTTYPE;
pfm.iCharSet = (charset == -1) ? (BYTE) ANSI_CHARSET : (BYTE) charset;
/* (pcl && (afm.iFamily==FF_DECORATIVE)) ? PCL_PI_CHARSET : ANSI_CHARSET );
Windows WRITE only displays fonts with CharSet=0 in the menu */
pfm.iDefaultChar = (BYTE) (
( (afm.iFamily==FF_DECORATIVE) ? ISPACE : IBULLET ) - afm.iFirstChar );
pfm.iBreakChar = (BYTE) (ISPACE - afm.iFirstChar);
/* for a scalable font (i.e. PostScript) default to 80 column text */
pfm.iPoints = (pcl) ? afm.iPtSize : 10;
/* if we ever support other bitmapped printers we will no longer be able
to assume that the default x and y res are 300. */
pfm.iVertRes = 300;
pfm.iHorizRes = 300;
pfm.iItalic = (BYTE) ((afm.iItalicAngle != 0) ? 1 : 0);
pfm.iWeight = afm.iWeight;
pfm.iPitchAndFamily = (BYTE) afm.iFamily;
pfm.iFirstChar = (BYTE) afm.iFirstChar;
pfm.iLastChar = (BYTE) afm.iLastChar;
pfm.iAvgWidth = afm.iAvgWidth;
pfm.iMaxWidth = afm.iMaxWidth;
pfm.iPixWidth = (afm.fVariablePitch) ? 0 : afm.iAvgWidth;
/* pfm.iPixHeight = afm.rcBBox.top - afm.rcBBox.bottom;
* Changed to reduce round off error. 8-26-91 yh
*/
pixHeight = afm.rcBBox.top - afm.rcBBox.bottom;
pfm.iPixHeight = (pcl) ? CVTTOSCR(pixHeight) : pixHeight;
/* pfm.iInternalLeading =
* (pcl) ? pfm.iPixHeight - ((afm.iPtSize * 300) / 72) : 0;
* Changed to match ATM. 7-31-91 yh
* Changed to reduce round off error. 8-26-91 yh
*/
internalLeading = max(0, pixHeight - EM);
pfm.iInternalLeading = (pcl) ? CVTTOSCR(internalLeading) : internalLeading;
/* pfm.iAscent = afm.rcBBox.top;
* Changed to fix text alignment problem. 10-08-90 yh
*/
/* pfm.iAscent = afm.iAscent;
* Changed to match ATM. 7-31-91 yh
* Changed to reduce round off error. 8-26-91 yh
*/
pfm.iAscent = (pcl) ?
CVTTOSCR(EM + afm.rcBBox.bottom) + CVTTOSCR(internalLeading) :
EM + afm.rcBBox.bottom + internalLeading;
/* Deleted to match ATM. yh 9-13-91
* minAscent = (pcl) ? CVTTOSCR(667) : 667; 2/3 of EM
* if( pfm.iAscent < minAscent ) pfm.iAscent = minAscent;
*/
/* pfm.iExternalLeading = 196; */
/* Changed to 0 to fix a bug in PCL landscape. Was getting huge leading. */
/*
* yh 8-26-91 Changed ExternalLeading for pcl to match ATM .
*/
if (!pcl)
/* PostScript driver ignores this field and comes up with own
* ExternalLeading value.
*
* !!! HACK ALERT !!!
*
* ATM needs to have ExternalLeading=0. PFMs generated with Rev. 2
* MAKEPFM have a bug in default & break character fields. We had
* encoding number instead of offsets. ATM uses following algorithm
* to recognize the Rev. 2 PFMs:
* rev2pfm = pfmRec->fmExternalLeading != 0 &&
* etmRec->etmStrikeOutOffset == 500 &&
* pfmRec->fmDefaultChar >= pfmRec->fmFirstChar;
* So, we need to make sure that either ExternalLeading stays zero or
* StrikeOutOffset is not 500. With current algorithm, StrikeOutOffset
* is very likely to be less than 500.
* etm.iStrikeOutOffset = fiCapHeight / 2 - (afm.ulThick / 2);
*/
pfm.iExternalLeading = 0;
else if (!afm.fWasVariablePitch)
pfm.iExternalLeading = 0;
else /* pcl & Variable pitch */
{
/* Adjust external leading such that we are compatible */
/* with the values returned by the PostScript driver. */
/* Who did this code?? Microsoft? Has to be! */
switch (pfm.iPitchAndFamily & FF_MASKFAMILY)
{
case FF_ROMAN: leading = (pfm.iVertRes + 18) / 36; //2-pnt leading
break;
case FF_SWISS: if (pfm.iPoints <= 12)
leading = (pfm.iVertRes + 18) / 36; //2-pnt leading
else if (pfm.iPoints < 14)
leading = (pfm.iVertRes + 12) / 24; //3-pnt leading
else
leading = (pfm.iVertRes + 9) / 18; //4-pnt leading
break;
default: /* Give 19.6% of the height for leading. */
leading = (short) (
(long) (pfm.iPixHeight-pfm.iInternalLeading)
* 196L / 1000L );
break;
}
pfm.iExternalLeading = MAX(0, (SHORT)(leading - pfm.iInternalLeading));
}
pfm.iWidthBytes = 0;
if (afm.fVariablePitch) pfm.iPitchAndFamily |= 1;
pfm.iUnderline = 0;
pfm.iStrikeOut = 0;
pfm.oBitsPointer = 0L;
pfm.oBitsOffset = 0L;
}
/**********************************************************
* Name: PutString()
* Action: This function writes a null terminated string
* to the output file.
***********************************************************/
VOID PutString(sz)
LPSZ sz;
{
INT bCh;
do {
bCh = *pbBuffer++ = *sz++;
++cbBuffer;
} while( bCh );
}
/***************************************************************
* Name: PutdeviceName()
* Action: This function writes the device name to the output file.
**************************************************************/
VOID PutDeviceName(szDevice)
LPSZ szDevice;
{
pfm.oDevice = cbBuffer;
PutString(szDevice);
}
/***************************************************************
* Name: PutFaceName()
* Action: This function writes the font's face name to the output file.
**************************************************************/
VOID PutFaceName()
{
pfm.oFace = cbBuffer;
PutString(afm.szFace);
}
/**************************************************************
* Name: MakeDf()
* Action: This function writes the device font info structure
* to the output file.
* Method: This function makes two passes over the data. On the first pass
* it collects offset data as it places data in the output buffer. On the
* second pass, it first resets the output buffer and then writes the data
* to the output buffer again with the offsets computed from pass 1.
***************************************************************/
BOOL MakeDf(fPass2, devType, outfile)
BOOL fPass2; /* TRUE if this is the second pass */
SHORT devType; /* 1=POSTSCRIPT 2=PCL */
LPSZ outfile;
{
BOOL result = TRUE;
INT iMarker;
ResetBuffer();
SetDf(devType == PCL);
/* put out the PFM header structure */
PutWord(pfm.iVersion);
PutLong(pfm.iSize);
PutRgb(pfm.szCopyright, 60);
PutWord(pfm.iType);
PutWord(pfm.iPoints);
PutWord(pfm.iVertRes);
PutWord(pfm.iHorizRes);
PutWord(pfm.iAscent);
PutWord(pfm.iInternalLeading);
PutWord(pfm.iExternalLeading);
PutByte(pfm.iItalic);
PutByte(pfm.iUnderline);
PutByte(pfm.iStrikeOut);
PutWord(pfm.iWeight);
PutByte(pfm.iCharSet);
PutWord(pfm.iPixWidth);
PutWord(pfm.iPixHeight);
PutByte(pfm.iPitchAndFamily);
PutWord(pfm.iAvgWidth);
PutWord(pfm.iMaxWidth);
PutByte(pfm.iFirstChar);
PutByte(pfm.iLastChar);
PutByte(pfm.iDefaultChar);
PutByte(pfm.iBreakChar);
PutWord(pfm.iWidthBytes);
PutLong(pfm.oDevice);
PutLong(pfm.oFace);
PutLong(pfm.oBitsPointer);
PutLong(pfm.oBitsOffset);
/* need to determine if proportional etc. */
if (devType == PCL) PutExtentOrWidthTable(1);
/* put out the PFM extension structure */
iMarker = cbBuffer;
PutWord(pfmext.oSizeFields);
PutLong(pfmext.oExtMetricsOffset);
PutLong(pfmext.oExtentTable);
PutLong(pfmext.oOriginTable);
PutLong(pfmext.oPairKernTable);
PutLong(pfmext.oTrackKernTable);
PutLong(pfmext.oDriverInfo);
PutLong(pfmext.iReserved);
pfmext.oSizeFields = cbBuffer - iMarker;
if (devType == POSTSCRIPT) {
/* Put the extended text metrics table */
pfmext.oExtMetricsOffset = cbBuffer;
PutEtm(FALSE);
PutDeviceName("PostScript");
PutFaceName();
PutDriverInfo(FALSE);
/* Put the extent table */
PutExtentOrWidthTable(0);
pfmext.oOriginTable = 0;
pfmext.iReserved = 0;
PutPairKernTable(POSTSCRIPT);
PutTrackKernTable(POSTSCRIPT);
}
if (devType == PCL) {
PutFaceName();
PutDeviceName("PCL/HP LaserJet");
/* Put the extended text metrics table */
pfmext.oExtMetricsOffset = cbBuffer;
PutEtm(TRUE);
PutPairKernTable(PCL);
PutTrackKernTable(PCL);
PutDriverInfo(TRUE);
pfmext.oOriginTable = 0;
pfmext.iReserved = 0;
}
if( !fPass2 ) {
pfm.iSize = (long)cbBuffer;
if( !MakeDf(TRUE, devType, outfile) ) result = FALSE;
}
else {
if( !WritePfm(outfile) ) result = FALSE;
#if DEBUG_MODE
DumpPfmHeader();
DumpCharWidths();
DumpPfmExtension();
#endif
}
return(result);
}
/*******************************************************************
* Name: PutPairKernTable(devType)
* Action: Send the pairwise kerning table to the output file.
*********************************************************************/
VOID PutPairKernTable(devType)
SHORT devType; /* 1=POSTSCRIPT 2=PCL */
{
WORD i;
if( afm.kp.cPairs > 0 ) {
pfmext.oPairKernTable = cbBuffer;
#if DEBUG_MODE
printf("Pair Kern Table - pairs: %d\n", afm.kp.cPairs);
#endif
if( devType == POSTSCRIPT ) PutWord(afm.kp.cPairs);
for (i = 0; i < afm.kp.cPairs; ++i) {
PutWord(afm.kp.rgPairs[i].iKey);
PutWord(afm.kp.rgPairs[i].iKernAmount);
#if DEBUG_MODE
printf("key: %x kern amount: %d\n",
afm.kp.rgPairs[i].iKey, afm.kp.rgPairs[i].iKernAmount);
#endif
}
}
else
pfmext.oPairKernTable = 0;
}
/******************************************************************
* Name: PutTrackKernTable(devType)
* Action: Send the track kerning table to the output file.
********************************************************************/
VOID PutTrackKernTable(devType)
SHORT devType; /* 1=POSTSCRIPT 2=PCL */
{
INT i;
if (afm.kt.cTracks == 0)
{
pfmext.oTrackKernTable = 0;
return;
}
pfmext.oTrackKernTable = cbBuffer;
if (devType == POSTSCRIPT) PutWord(afm.kt.cTracks);
for (i=0; i<afm.kt.cTracks; ++i)
{
PutWord(afm.kt.rgTracks[i].iDegree);
PutWord(afm.kt.rgTracks[i].iPtMin);
PutWord(afm.kt.rgTracks[i].iKernMin);
PutWord(afm.kt.rgTracks[i].iPtMax);
PutWord(afm.kt.rgTracks[i].iKernMax);
}
}
/***************************************************************
* Name: PutExtentTable()
* Action: Send the character extent information to the output file.
*****************************************************************/
VOID PutExtentOrWidthTable(width)
INT width; /* 0=extent 1=width */
{
INT i;
/* is the typeface proportional ?? */
if (pfm.iPitchAndFamily & 1)
{
pfmext.oExtentTable = (width) ? 0 : cbBuffer;
for (i = afm.iFirstChar; i <= afm.iLastChar; i++)
PutWord(afm.rgcm[i].iWidth);
if (width) PutWord(0);
}
else
pfmext.oExtentTable = 0;
}
/***********************************************************
* Name: WritePfm()
* Action: Flush the ouput buffer to the file. Note that this
* function is only called after the entire pfm structure
* has been built in the output buffer.
*************************************************************/
BOOL WritePfm(outfile)
LPSZ outfile;
{
INT fh;
if( (fh = OpenTargetFile(outfile) ) == -1 ) {
; // PostError(str(MSG_PFM_BAD_CREATE), outfile);
return(FALSE);
}
if( cbBuffer > 0 )
if( (WORD)WRITE_BLOCK(fh, rgbBuffer, cbBuffer) != (WORD)cbBuffer ) {
CLOSE(fh);
; // PostError(str(MSG_PFM_DISK_FULL));
return(FALSE);
}
CLOSE(fh);
return(TRUE);
}
#if DEBUG_MODE
/*----------------------------------------------------------------------------*/
VOID DumpPfmHeader()
{
printf("\nDUMP PFM HEADER\n");
printf("pfm.iVersion=%d\n",pfm.iVersion);
printf("pfm.iSize=%ld\n",pfm.iSize);
printf("pfm.szCopyright=%s\n",pfm.szCopyright);
printf("pfm.iType=%d\n",pfm.iType);
printf("pfm.iPoints=%d\n",pfm.iPoints);
printf("pfm.iVertRes=%d\n",pfm.iVertRes);
printf("pfm.iHorizRes=%d\n",pfm.iHorizRes);
printf("pfm.iAscent=%d\n",pfm.iAscent);
printf("pfm.iInternalLeading=%d\n",pfm.iInternalLeading);
printf("pfm.iExternalLeading=%d\n",pfm.iExternalLeading);
printf("pfm.iItalic=%d\n",pfm.iItalic);
printf("pfm.iUnderline=%d\n",pfm.iUnderline);
printf("pfm.iStrikeOut=%d\n",pfm.iStrikeOut);
printf("pfm.iWeight=%d\n",pfm.iWeight);
printf("pfm.iCharSet=%d\n",pfm.iCharSet);
printf("pfm.iPixWidth=%d\n",pfm.iPixWidth);
printf("pfm.iPixHeight=%d\n",pfm.iPixHeight);
printf("pfm.iPitchAndFamily=%d\n",pfm.iPitchAndFamily);
printf("pfm.iAvgWidth=%d\n",pfm.iAvgWidth);
printf("pfm.iMaxWidth=%d\n",pfm.iMaxWidth);
printf("pfm.iFirstChar=%c\n",pfm.iFirstChar);
printf("pfm.iLastChar=%c\n",pfm.iLastChar);
printf("pfm.iDefaultChar=%d\n",pfm.iDefaultChar);
printf("pfm.iBreakChar=%d\n",pfm.iBreakChar);
printf("pfm.iWidthBytes=%d\n",pfm.iWidthBytes);
printf("pfm.oDevice=%x\n",pfm.oDevice);
printf("pfm.oFace=%x\n",pfm.oFace);
printf("pfm.oBitsPointer=%ld\n",pfm.oBitsPointer);
printf("pfm.oBitsOffset=%ld\n",pfm.oBitsOffset);
}
/*----------------------------------------------------------------------------*/
VOID DumpCharWidths()
{
INT indx;
printf("\nCHARACTER WIDTHS\n");
for (indx = afm.iFirstChar; indx <= afm.iLastChar; indx++)
printf("indx: %d width: %d\n", indx, afm.rgcm[indx].iWidth);
}
/*----------------------------------------------------------------------------*/
VOID DumpPfmExtension()
{
printf("\nDUMP PFM EXTENSION\n");
printf("pfmext.oSizeFields=%d\n",pfmext.oSizeFields);
printf("pfmext.oExtMetricsOffset=%x\n",pfmext.oExtMetricsOffset);
printf("pfmext.oExtentTable=%x\n",pfmext.oExtentTable);
printf("pfmext.oOriginTable=%x\n",pfmext.oOriginTable);
printf("pfmext.oPairKernTable=%x\n",pfmext.oPairKernTable);
printf("pfmext.oTrackKernTable=%x\n",pfmext.oTrackKernTable);
printf("pfmext.oDriverInfo=%x\n",pfmext.oDriverInfo);
printf("pfm.iReserved=%x\n",pfm.iReserved);
}
#endif
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/* Main purpose of these structures is to set up a translation table which
allows the driver to translate the font from the character set indicated in
the dfCharset field into the printer-specific character set. */
#define AVGSIZE (30 * 1024)
VOID SetDriverInfo()
{
INT i;
long sumWidth = 0L;
for (i = afm.iFirstChar; i <= afm.iLastChar; i++)
sumWidth = sumWidth + (long)afm.rgcm[i].iWidth;
d.epSize = sizeof(DRIVERINFO);
d.epVersion = DRIVERINFO_VERSION;
d.epMemUsage = (long) ( ((sumWidth+7L) >> 3) * (long)pfm.iPixHeight + 63L );
d.xtbl.symbolSet = pclinfo.symbolsetNum;
d.xtbl.offset = 0L;
d.xtbl.len = 0;
d.xtbl.firstchar = 0;
d.xtbl.lastchar = 0;
pclinfo.epEscapeSequence = GetEscapeSequence();
}
/*----------------------------------------------------------------------------*/
VOID PutDriverInfo(pcl)
INT pcl;
{
pfmext.oDriverInfo = cbBuffer;
if (pcl) {
SetDriverInfo();
PutWord(d.epSize);
PutWord(d.epVersion);
PutLong(d.epMemUsage);
PutLong(d.epEscape);
PutWord((WORD)d.xtbl.symbolSet);
PutLong(d.xtbl.offset);
PutWord(d.xtbl.len);
PutByte(d.xtbl.firstchar);
PutByte(d.xtbl.lastchar);
d.epEscape = cbBuffer;
PutString(pclinfo.epEscapeSequence);
} else
PutString(afm.szFont);
}
/*--------------------------------------------------------------------------*/
LPSZ GetEscapeSequence()
{
static char escapeStr[80];
char fixedPitch[2], pitch[10], height[10], *cp;
int enc;
float size;
size = (float) afm.iPtSize;
if( afm.fWasVariablePitch == TRUE ) {
STRCPY(fixedPitch, "1");
enc = ISPACE;
}
else {
STRCPY(fixedPitch, "");
enc = afm.iFirstChar;
}
sprintf(pitch, "%1.3f", 300.0 / (float)afm.rgcm[enc].iWidth);
if( cp = strchr(pitch, '.') ) cp[3] = '\0';
sprintf(height, "%1.2f", size);
sprintf(escapeStr, "\x01B&l%dO\x01B(%s\x01B(s%sp%sh%sv%ds%db%uT",
pclinfo.orientation, pclinfo.symbolsetStr,
fixedPitch, pitch, height,
pclinfo.style, pclinfo.strokeWeight, pclinfo.typeface);
return(escapeStr);
}
/*----------------------------------------------------------------------------*/
#if DEBUG_MODE
VOID DumpDriverInfo()
{
printf("\nDUMP DRIVERINFO STRUCTURE\n");
printf("d.epSize: %d\n", d.epSize);
printf("d.epVersion: %d\n", d.epVersion);
printf("d.epMemUsage: %ld\n", d.epMemUsage);
printf("d.epEscape: %ld\n", d.epEscape);
printf("d.xtbl.symbolSet: %d\n", d.xtbl.symbolSet);
printf("d.xtbl.offset: %ld\n", d.xtbl.offset);
printf("d.xtbl.len: %d\n", d.xtbl.len);
printf("d.xtbl.firstchar: %d\n", d.xtbl.firstchar);
printf("d.xtbl.lastchar: %d\n", d.xtbl.lastchar);
printf("d.epEscapeSequence: %s\n", d.epEscapeSequence);
}
#endif
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/* Convert from PostScript to extended text metrics */
VOID AfmToEtm(pcl)
BOOL pcl; /* true if this is a PCL type device */
{
etm.iSize = 52;
/* point size in twips */
etm.iPointSize = afm.iPtSize * 20;
etm.iOrientation = (pcl) ? pclinfo.orientation + 1 : 0;
etm.iMasterHeight = (pcl) ? pfm.iPixHeight : 1000;
etm.iMinScale = (pcl) ? etm.iMasterHeight : 3;
etm.iMaxScale = (pcl) ? etm.iMasterHeight : 1000;
etm.iMasterUnits = (pcl) ? etm.iMasterHeight : 1000;
/* in general need to worry a little about what happens if these various
glyphs are not present as in a decorative font. */
etm.iCapHeight = afm.rgcm['H'].rc.top;
etm.iXHeight = afm.rgcm['x'].rc.top;
etm.iLowerCaseAscent = afm.rgcm['d'].rc.top;
etm.iLowerCaseDescent = - afm.rgcm['p'].rc.bottom;
etm.iSlant = (pcl) ? afm.iItalicAngle * 10 : afm.iItalicAngle;
etm.iSuperScript = (pcl) ? 0 : -500;
etm.iSubScript = (pcl) ? 0 : 250;
etm.iSuperScriptSize = (pcl) ? 0 : 500;
etm.iSubScriptSize = (pcl) ? 0 : 500;
etm.iUnderlineOffset = (pcl) ? 0 : afm.ulOffset;
etm.iUnderlineWidth = (pcl) ? 1 : afm.ulThick;
etm.iDoubleUpperUnderlineOffset = (pcl) ? 0 : afm.ulOffset / 2;
etm.iDoubleLowerUnderlineOffset = (pcl) ? 0 : afm.ulOffset;
etm.iDoubleUpperUnderlineWidth = (pcl) ? 1 : afm.ulThick / 2;
etm.iDoubleLowerUnderlineWidth = (pcl) ? 1 : afm.ulThick / 2;
etm.iStrikeOutOffset = (pcl) ? 0 : fiCapHeight / 2 - (afm.ulThick / 2);
etm.iStrikeOutWidth = (pcl) ? 1 : afm.ulThick;
etm.nKernPairs = afm.kp.cPairs;
etm.nKernTracks = afm.kt.cTracks;
}
/*----------------------------------------------------------------------------*/
VOID PutEtm(pcl)
BOOL pcl; /* true if this is a PCL type device */
{
AfmToEtm(pcl);
PutWord(etm.iSize);
PutWord(etm.iPointSize);
PutWord(etm.iOrientation);
PutWord(etm.iMasterHeight);
PutWord(etm.iMinScale);
PutWord(etm.iMaxScale);
PutWord(etm.iMasterUnits);
PutWord(etm.iCapHeight);
PutWord(etm.iXHeight);
PutWord(etm.iLowerCaseAscent);
PutWord(etm.iLowerCaseDescent);
PutWord(etm.iSlant);
PutWord(etm.iSuperScript);
PutWord(etm.iSubScript);
PutWord(etm.iSuperScriptSize);
PutWord(etm.iSubScriptSize);
PutWord(etm.iUnderlineOffset);
PutWord(etm.iUnderlineWidth);
PutWord(etm.iDoubleUpperUnderlineOffset);
PutWord(etm.iDoubleLowerUnderlineOffset);
PutWord(etm.iDoubleUpperUnderlineWidth);
PutWord(etm.iDoubleLowerUnderlineWidth);
PutWord(etm.iStrikeOutOffset);
PutWord(etm.iStrikeOutWidth);
PutWord(etm.nKernPairs);
PutWord(etm.nKernTracks);
#if DEBUG_MODE
DumpEtm();
#endif
}
/*----------------------------------------------------------------------------*/
#if DEBUG_MODE
VOID DumpEtm()
{
printf("\nDUMP ETM STRUCTURE\n");
printf("etm.iSize: %d\n", etm.iSize);
printf("etm.iPointSize: %d\n", etm.iPointSize);
printf("etm.iOrientation: %d\n", etm.iOrientation);
printf("etm.iMasterHeight: %d\n", etm.iMasterHeight);
printf("etm.iMinScale: %d\n", etm.iMinScale);
printf("etm.iMaxScale: %d\n", etm.iMaxScale);
printf("etm.iMasterUnits: %d\n", etm.iMasterUnits);
printf("etm.iCapHeight: %d\n", etm.iCapHeight);
printf("etm.iXHeight: %d\n", etm.iXHeight);
printf("etm.iLowerCaseAscent: %d\n", etm.iLowerCaseAscent);
printf("etm.iLowerCaseDescent: %d\n", etm.iLowerCaseDescent);
printf("etm.iSlant: %d\n", etm.iSlant);
printf("etm.iSuperScript: %d\n", etm.iSuperScript);
printf("etm.iSubScript: %d\n", etm.iSubScript);
printf("etm.iSuperScriptSize: %d\n", etm.iSuperScriptSize);
printf("etm.iSubScriptSize: %d\n", etm.iSubScriptSize);
printf("etm.iUnderlineOffset: %d\n", etm.iUnderlineOffset);
printf("etm.iUnderlineWidth: %d\n", etm.iUnderlineWidth);
printf("etm.iDoubleUpperUnderlineOffset: %d\n",
etm.iDoubleUpperUnderlineOffset);
printf("etm.iDoubleLowerUnderlineOffset: %d\n",
etm.iDoubleLowerUnderlineOffset);
printf("etm.iDoubleUpperUnderlineWidth: %d\n",
etm.iDoubleUpperUnderlineWidth);
printf("etm.iDoubleLowerUnderlineWidth: %d\n",
etm.iDoubleLowerUnderlineWidth);
printf("etm.iStrikeOutOffset: %d\n", etm.iStrikeOutOffset);
printf("etm.iStrikeOutWidth: %d\n", etm.iStrikeOutWidth);
printf("etm.nKernPairs: %d\n", etm.nKernPairs);
printf("etm.nKernTracks: %d\n", etm.nKernTracks);
}
#endif
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
/**************************************************************
* Name: StartParse()
***************************************************************/
VOID StartParse()
{
fEOF = FALSE;
fUnGetLine = FALSE;
cbBuffer = 0;
}
/**************************************************************
* Name: szIsEqual()
* Action: Compare two NULL terminated strings.
* Returns: TRUE if they are equal FALSE if they are different
***************************************************************/
BOOL szIsEqual(sz1, sz2)
LPSZ sz1;
LPSZ sz2;
{
while (*sz1 && *sz2)
if (*sz1++ != *sz2++) return(FALSE);
return(*sz1 == *sz2);
}
/**************************************************************
* Name: szMove()
* Action: Copy a string. This function will copy at most the
* number of bytes in the destination area - 1.
***************************************************************/
VOID szMove(szDst, szSrc, cbDst)
LPSZ szDst; /* Ptr to the destination area */
LPSZ szSrc; /* Ptr to the source area */
INT cbDst; /* The size of the destination area */
{
while (*szDst++ = *szSrc++)
if (--cbDst <= 0) {
*(szDst-1) = 0;
break;
}
}
/*****************************************************************
* Name: GetBuffer()
* Action: Read a new buffer full of text from the input file.
******************************************************************/
BOOL GetBuffer(hfile)
INT hfile;
{
cbBuffer = 0;
if (!fEOF) {
cbBuffer = READ_BLOCK(hfile, rgbBuffer, sizeof(rgbBuffer));
if (cbBuffer<=0) {
cbBuffer = 0;
fEOF = TRUE;
}
}
pbBuffer = rgbBuffer;
return(!fEOF);
}
/*****************************************************************
* Name: UnGetLine()
* Action: This routine pushes the most recent line back into the
* input buffer.
*******************************************************************/
VOID UnGetLine()
{
fUnGetLine = TRUE;
szLine = rgbLine;
}
/******************************************************************
* Name: GetLine()
* Action: This routine gets the next line of text out of the
* input buffer. Handles both binary & text mode.
********************************************************************/
BOOL GetLine(hfile)
INT hfile;
{
CHAR szWord[10];
// WriteDots();
szLine = rgbLine;
do { /* skip comment lines */
if( !_GetLine(hfile) ) return(FALSE);
GetWord(szWord, sizeof(szWord));
} while( szIsEqual("Comment", szWord) );
szLine = rgbLine;
return(TRUE);
}
BOOL _GetLine(hfile)
INT hfile;
{
INT cbLine;
CHAR bCh;
if( fUnGetLine ) {
szLine = rgbLine;
fUnGetLine = FALSE;
return(TRUE);
}
cbLine = 0;
szLine = rgbLine;
*szLine = 0;
if( !fEOF )
{
while( TRUE )
{
if ( cbBuffer <= 0 )
if( !GetBuffer(hfile) ) return(FALSE);
while( --cbBuffer >= 0 )
{
bCh = *pbBuffer++;
if( bCh=='\n' || ++cbLine > (sizeof(rgbLine)-1) )
{
*szLine = 0;
szLine = rgbLine;
EatWhite();
if( *szLine != 0 ) goto DONE;
szLine = rgbLine;
cbLine = 0;
continue;
}
else if( bCh >= ' ' )
{
*szLine++ = bCh;
}
}
}
}
*szLine = 0;
DONE:
szLine = rgbLine;
return(!fEOF);
}
/****************************************************************
* Name: EatWhite()
* Action: This routine moves the input buffer pointer forward to
* the next non-white character.
******************************************************************/
VOID EatWhite()
{
while (*szLine && (*szLine==' ' || *szLine=='\t'))
++szLine;
}
/*******************************************************************
* Name: GetWord()
* Action: This routine gets the next word delimited by white space
* from the input buffer.
*********************************************************************/
VOID GetWord(szWord, cbWord)
LPSZ szWord; /* Ptr to the destination area */
INT cbWord; /* The size of the destination area */
{
CHAR bCh;
EatWhite();
while (--cbWord>0) {
switch(bCh = *szLine++) {
case 0:
case ' ':
case '\t': --szLine;
goto DONE;
case ';': *szWord++ = bCh;
goto DONE;
default: *szWord++ = bCh;
break;
}
}
DONE:
*szWord = 0;
}
/*******************************************************************
* Name: GetString()
* Action: This routine gets the next word delimited by parentheses
* from the input buffer.
*********************************************************************/
BOOL GetString(szWord, cbWord)
LPSZ szWord; /* Ptr to the destination area */
INT cbWord; /* The size of the destination area */
{
CHAR bCh;
BOOL result = TRUE;
EatWhite();
if( *szLine == '(' ) szLine++;
else result = FALSE;
while (--cbWord>0) {
switch(bCh = *szLine++) {
case 0: result = FALSE;
goto DONE;
case ')': --szLine;
goto DONE;
default: *szWord++ = bCh;
break;
}
}
DONE:
*szWord = 0;
return(result);
}
/************************************************************
* Name: GetNumber()
* Action: This routine parses an ASCII decimal number from the
* input file stream and returns its value.
***************************************************************/
BOOL GetNumber(piVal)
SHORT *piVal;
{
INT iVal;
BOOL fNegative;
fNegative = FALSE;
iVal = 0;
EatWhite();
if (*szLine=='-') {
fNegative = TRUE;
++szLine;
}
if (*szLine<'0' || *szLine>'9') {
*piVal = 0;
return(FALSE);
}
while (*szLine>='0' && *szLine<='9')
iVal = iVal * 10 + (*szLine++ - '0');
if (fNegative) iVal = - iVal;
if (*szLine==0 || *szLine==' ' || *szLine=='\t' || *szLine==';') {
*piVal = (SHORT)iVal;
return(TRUE);
}
else {
return(FALSE);
}
}
/******************************************************************
* Name: GetFloat()
* Action: This routine parses an ASCII floating point decimal number
* from the input file stream and returns its value scaled
* by a specified amount.
*********************************************************************/
BOOL GetFloat(pScale, piVal)
float *pScale; /* The amount to scale the value by */
SHORT *piVal;
{
float scale;
long lVal;
long lDivisor;
BOOL fNegative;
scale = *pScale;
EatWhite();
fNegative = FALSE;
lVal = 0L;
if (*szLine=='-') {
fNegative = TRUE;
++szLine;
}
if (*szLine<'0' || *szLine>'9') {
*piVal = 0;
return(FALSE);
}
while (*szLine>='0' && *szLine<='9') lVal = lVal * 10 + (*szLine++ - '0');
lDivisor = 1L;
if (*szLine=='.') {
++szLine;
while (*szLine>='0' && *szLine<='9') {
lVal = lVal * 10 + (*szLine++ - '0');
lDivisor = lDivisor * 10;
}
}
lVal = (lVal * (long) scale) / lDivisor;
if (fNegative) lVal = - lVal;
if (*szLine==0 || *szLine==' ' || *szLine=='\t' || *szLine==';') {
*piVal = (INT) lVal;
return(TRUE);
}
else {
return(FALSE);
}
}
/***************************************************************
* Name: MapToken()
* Action: This routine maps an ascii key word into an integer token.
* Returns: The token value.
******************************************************************/
INT MapToken(szWord, map)
LPSZ szWord; /* Ptr to the ascii keyword string */
KEY *map;
{
KEY *pkey;
pkey = map;
while (pkey->szKey) {
if( szIsEqual(szWord, pkey->szKey) ) return(pkey->iValue);
++pkey;
}
return(TK_UNDEFINED);
}
/*********************************************************************
* Name: GetToken()
* Action: Get the next token from the input stream.
***********************************************************************/
INT GetToken(hfile, map)
INT hfile;
KEY *map;
{
CHAR szWord[80];
if (*szLine==0)
if( !GetLine(hfile) ) return(TK_EOF);
GetWord(szWord, sizeof(szWord));
return(MapToken(szWord, map));
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
GlyphName *AllocateGlyphArray(arraymax)
INT arraymax;
{
GlyphName *p;
INT i;
p = (GlyphName *) AllocateMem( (UINT) (sizeof(LPSZ) * (arraymax+2)) );
if( p == NULL ) {
; // PostError(str(MSG_PFM_BAD_MALLOC));
return(NULL);
}
for(i=0; i<=arraymax; i++)
p[i] = notdef;
p[i] = NULL;
return(p);
}
/*--------------------------------------------------------------------------*/
VOID PutGlyphName(array, index, glyph)
GlyphName *array;
INT index;
LPSZ glyph;
{
LPSZ p;
if ( !STRCMP(glyph, ".notdef") )
array[index] = notdef;
else {
p = (LPSZ) AllocateMem((UINT) (strlen(glyph)+1));
if (p)
{
STRCPY(p, glyph);
array[index] = p;
}
}
}
/*--------------------------------------------------------------------------*/