2301 lines
69 KiB
C
2301 lines
69 KiB
C
|
//---------------------------------------------------------------------------
|
||
|
// 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 == NULL ) {
|
||
|
; // PostError(str(MSG_PFM_BAD_MALLOC));
|
||
|
parseError = TRUE;
|
||
|
return;
|
||
|
}
|
||
|
STRCPY(p, glyph);
|
||
|
array[index] = p;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|