Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1471 lines
38 KiB

/******************************Module*Header*******************************\
* Module Name: sbit.cxx
*
* (Brief description)
*
* Created: 14-Nov-1993 09:39:47
* Author: Bodin Dresevic [BodinD]
*
* Copyright (c) 1990 Microsoft Corporation
*
* utility for generating bdat and bloc tables out of the set of
* individual .DBF files, where each .DBF (Distribution Bitmap Format)
* file contains a set of bitmaps at one point size, i.e. one "strike",
* in the commonly accepted jargon.
*
*
*
*
*
\**************************************************************************/
#define DEBUGTABLES
extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "windows.h"
};
#include "table.h" // no function declarations only structures
#include "FSERROR.H"
//#include "FSCDEFS.H" // inlcudes fsconfig.h
#include "FONTMATH.H"
#include "SFNT.H" // includes sfnt_en.h
#include "FNT.H"
#include "INTERP.H"
#include "FNTERR.H"
#include "SFNTACCS.H"
#include "FSGLUE.H"
#include "SCENTRY.H"
#include "SBIT.H"
#include "FSCALER.H"
#include "SCGLOBAL.H"
#include "sbit.hxx"
BOOL bCreateWriteToAndCloseFile
(
PBYTE pj, // buffer with the information to be written to the file
ULONG cj, // size of the buffer above
PSZ pszFileName // name of the file to be created
);
#ifdef DEBUGTABLES
BOOL bView(ULONG cjBLOC, ULONG cjBDAT);
#endif // DEBUGTABLES
BOOL bCompute_bitmapSizeTable(
int iSizeTable,
bitmapSizeTable *p,
char *psz,
uint32 *pcjBDAT,
BYTE *pjBLOC,
BYTE *pjBDAT,
BYTE *pj
);
VOID vConvertToBigEndian(BYTE *pjBLOC, BYTE *pjBDAT);
typedef struct _GLYPHMET
{
LONG gi;
LONG cjGlyph; // how much room it takes in the tt file
smallGlyphMetrics sgm;
} GLYPHMET;
BOOL bDoAGlyph(
FILEVIEW *pfvw,
LONG gi,
LONG dp,
GLYPHMET *pgm, // various useful glyph information
BYTE *pjBuf // copy glyph to this buffer
);
#define CCH_FILENAME 40
CHAR achBDT[CCH_FILENAME];
CHAR achBLC[CCH_FILENAME];
static char szMe[] = "SBIT"; /* program name */
int main (int argc, char** argv)
{
int iFile, cSizes = argc - 2;
bitmapSizeTable abmpsz[C_SIZES]; // one for every input file
uint32 cjBLOC, cjBDAT, cjBDATdbg;
uint32 cchTTF;
PSTR pszTTF;
if (cSizes == 0)
{
fprintf(stderr, "%s: Usage is \"%s file1.dbf file2.dbf ... file.ttf\".\n", szMe,szMe);
return EXIT_FAILURE;
}
if (cSizes > C_SIZES)
{
fprintf(stderr, "%s: must have less than %ld input files. \n", szMe,C_SIZES);
return EXIT_FAILURE;
}
// map lucon.ttf to make sure that glyph indicies in the dbf fonts are
// computed correctly:
pszTTF = argv[argc - 1];
cchTTF = strlen(pszTTF) + 1;
// 6 = strlen(".ttf") + 1 + 1
// (for term. '\0') (for at least one more glyph before .ttf)
if
(
(cchTTF < 6) ||
(cchTTF > CCH_FILENAME) ||
_strcmpi(&pszTTF[cchTTF - 5],".ttf")
)
{
fprintf(stderr, ".ttf file name too long or not a .ttf file\n");
return EXIT_FAILURE;
}
// prepare buffers with output file names:
strcpy(achBLC, pszTTF); strcpy(&achBLC[cchTTF - 4], "blc");
strcpy(achBDT, pszTTF); strcpy(&achBDT[cchTTF - 4], "bdt");
MAPFILEOBJ mfoTTF(pszTTF);
if (!mfoTTF.bValid())
return EXIT_FAILURE;
BYTE *pjTTF = mfoTTF.fvw.pjView;
BYTE *pjMap = pjMapTable(&mfoTTF.fvw);
if (!pjMap)
return EXIT_FAILURE;
// init only
cjBDATdbg = cjBDAT = sizeof(bdatHeader);
for (iFile = 1; iFile <= cSizes; iFile++)
{
if
(
!bCompute_bitmapSizeTable(
(iFile - 1),
&abmpsz[iFile - 1],
argv[iFile],
&cjBDAT,
NULL,
NULL,
pjMap
)
)
{
fprintf(stderr,
"%s: bitmapSizeTable computation error for \"%s\".\n",
szMe,
argv[iFile]
);
return EXIT_FAILURE;
}
}
// compute the size of bloc and bdat tables
cjBLOC = sizeof(blocHeader) + cSizes * sizeof(bitmapSizeTable);
for (iFile = 0; iFile < cSizes; iFile++)
{
abmpsz[iFile].indexSubTableArrayOffset = cjBLOC;
cjBLOC += abmpsz[iFile].indexTablesSize;
}
// done with BLOC, BDAT sizes, allocate memory for those two tables
MALLOCOBJ memoBLOC((size_t)cjBLOC);
MALLOCOBJ memoBDAT((size_t)cjBDAT);
if (!memoBLOC.bValid() || !memoBDAT.bValid())
return EXIT_FAILURE;
// do the headers:
((blocHeader *)memoBLOC.pv())->version = 0x20000;
((blocHeader *)memoBLOC.pv())->numSizes = cSizes;
((bdatHeader *)memoBDAT.pv())->version = 0x20000;
// do the tables:
for (iFile = 1; iFile <= cSizes; iFile++)
{
if
(
!bCompute_bitmapSizeTable(
(iFile - 1),
&abmpsz[iFile - 1],
argv[iFile],
&cjBDATdbg, // dbg one for control
(BYTE *)memoBLOC.pv(),
(BYTE *)memoBDAT.pv(),
NULL // no ttf, already done checking
)
)
{
fprintf(stderr,
"%s: bitmapSizeTable computation error for \"%s\".\n",
szMe,
argv[iFile]
);
return EXIT_FAILURE;
}
}
ASSERT(cjBDATdbg == cjBDAT, "problem in cjBDAT computation\n");
// all data has to be converted to Big Endian format
vConvertToBigEndian((BYTE *)memoBLOC.pv(),(BYTE *)memoBDAT.pv());
// create .blc and .bdt files and write to them. When done close these files
// and exit.
if
(
!bCreateWriteToAndCloseFile ((BYTE *)memoBLOC.pv(),cjBLOC,achBLC) ||
!bCreateWriteToAndCloseFile ((BYTE *)memoBDAT.pv(),cjBDAT,achBDT)
)
{
fprintf(stderr, "failed to create bdat or bloc files\n");
return EXIT_FAILURE;
}
// this routine is here for debugging purposes only.
// It looks through bloc and bdat files and makes sure that
// the data is in place where you would expect it.
#ifdef DEBUGTABLES
bView(cjBLOC, cjBDAT);
#endif //
return EXIT_SUCCESS;
}
/******************************Public*Routine******************************\
*
* BYTE *pjNextLine(BYTE *pjLine)
*
* get to the beginning of the next line. The line pointed to by pjLine
* finishes with /r/n
*
*
* History:
* 16-Nov-1993 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BYTE *pjNextLine(BYTE *pjLine, BYTE *pjEOF)
{
BYTE *pjBegin = pjLine;
if (pjLine >= pjEOF)
{
fprintf(stderr,"pjLine >= pjEOF\n");
return NULL;
}
while ((pjLine < pjEOF) && (*pjLine++ != '\r'))
;
// skip '\n' following \r
pjLine++;
if ((pjLine - pjBegin) >= C_BIG)
{
fprintf(stderr,"too long line\n");
return NULL;
}
return pjLine;
}
/******************************Public*Routine******************************\
*
* pjNextWord
*
* History:
* 16-Nov-1993 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
// word defined as a sequence of nonspace glyphs
#define ISSPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\r') || ((c) == '\n') || ((c) == '.'))
BYTE *pjNextWord(BYTE *pjWord, BYTE *pjEnd, BYTE * psz)
{
// zero init in case no nonwhitespace on this line
*psz = '\0';
// skip the possible space at the beginning of the line
while ((pjWord < pjEnd) && ISSPACE(*pjWord)) // skip space
pjWord++;
// we are at the beginning at the nonwhite space now, copy it out
while ((pjWord < pjEnd) && !ISSPACE(*pjWord))
*psz++ = *pjWord++;
// zero terminate the string in the buffer
*psz = '\0';
// go to the beginning of the next word
while ((pjWord < pjEnd) && ISSPACE(*pjWord)) // skip space
pjWord++;
return pjWord;
}
/******************************Public*Routine******************************\
*
* BYTE *pjGetNextNumber(BYTE *pjWord, BYTE *pjEnd, BYTE * psz, LONG *pl)
*
*
* History:
* 17-Nov-1993 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BYTE *pjGetNextNumber(BYTE *pjWord, BYTE *pjEnd, BYTE * psz, LONG *pl)
{
BYTE *pj = pjNextWord(pjWord,pjEnd,psz);
if (pl)
*pl = atol((char *)psz);
return pj;
}
/******************************Public*Routine******************************\
*
* bCompute_bitmapSizeTable
*
* Effects:
*
* Warnings:
*
* History:
* 15-Nov-1993 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BOOL bCompute_bitmapSizeTable(
int iSizeTable,
bitmapSizeTable *pbmpsz,
char * pszFileName,
uint32 *pcjBDAT,
BYTE *pjBLOC,
BYTE *pjBDAT,
BYTE *pjCMAP // optionaly can be NULL
)
{
BYTE *pjLine, *pjNext, *pjEOF;
BYTE ajWord[C_BIG]; // buffer for words
BYTE *pjWord;
LONG ppemX, ppemY, xRes, yRes;
RECT rc;
LONG cChars;
LONG lWidth, cx,cy;
ULONG i;
uint16 indexFormat,cjOffset;
MAPFILEOBJ mfo(pszFileName);
if (!mfo.bValid())
return FALSE;
pjEOF = mfo.fvw.pjView + mfo.fvw.cjView;
if (!pjBLOC)
{
pbmpsz->indexSubTableArrayOffset = 0; /* ptr to array of ranges */
pbmpsz->colorRef= 0; /* reserved, set to 0 */
memset(&pbmpsz->vert,0,sizeof(sbitLineMetrics));
pbmpsz->grayScaleLevels = 1; /* 1 = Black; >1 = Gray */
pbmpsz->flags = flgHorizontal; /* hori or vert metrics */
}
else
{
// this is second pass of this function, we are actually writing this to
// the buffer
((bitmapSizeTable *)(pjBLOC + sizeof(blocHeader)))[iSizeTable] = *pbmpsz;
}
// parse the header info
for (pjLine = mfo.fvw.pjView; pjLine < pjEOF; pjLine = pjNext)
{
if (!(pjNext = pjNextLine(pjLine, pjEOF))) return FALSE;
// get the keyword at the beginning of the line
pjWord = pjNextWord(pjLine,pjNext, ajWord);
if (!strcmp((char *)ajWord,"STARTFONT"))
{
// get the next word and convert it to the hex number
pjWord = pjNextWord(pjWord,pjNext, ajWord);
}
else if (!strcmp((char *)ajWord,"COMMENT"))
{
continue; // ignore this line
}
else if (!strcmp((char *)ajWord,"FONT"))
{
continue; // ignore this line
}
else if (!strcmp((char *)ajWord,"SIZE"))
{
if (!pjBLOC)
{
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &ppemY);
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &xRes);
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &yRes);
ppemX = ppemY;
if (yRes != 72)
ppemY = MulDiv((int)ppemY,(int)72,(int)yRes);
pbmpsz->ppemY = (uint8)ppemY;
if (xRes != 72)
ppemX = MulDiv((int)ppemX,(int)72,(int)xRes);
pbmpsz->ppemX = (uint8)ppemX;
#ifdef DEBUGOUTPUT
fprintf(stdout,
"ppemY = %ld, xRes = %ld, yRes = %ld \n",
pbmpsz->ppemY,
xRes,
yRes);
#endif // DEBUGOUTPUT
}
}
else if (!strcmp((char *)ajWord,"FONTBOUNDINGBOX"))
{
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &cx);
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &cy);
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &rc.left);
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &rc.bottom);
rc.right = rc.left + cx;
rc.top = rc.bottom + cy;
#ifdef DEBUGOUTPUT
fprintf(stdout,
"rcBound: l = %ld, t = %ld, r = %ld, b = %ld \n",
rc.left, rc.top, rc.right, rc.bottom
);
#endif // DEBUGOUTPUT
}
else if (!strcmp((char *)ajWord,"STARTPROPERTIES"))
{
// go to the end of the section
for (pjLine = pjNext; pjLine < pjEOF; pjLine = pjNext)
{
if (!(pjNext = pjNextLine(pjLine, pjEOF))) return FALSE;
pjWord = pjNextWord(pjLine,pjNext, ajWord);
if (!strcmp((char *)ajWord,"ENDPROPERTIES"))
break;
}
}
else if (!strcmp((char *)ajWord,"CHARS"))
{
// Get the number of chars and get out of the loop
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &cChars);
#ifdef DEBUGOUTPUT
fprintf(stdout,"cChars = %ld\n", cChars);
#endif // DEBUGOUTPUT
// get out of this loop and get into the loop over chars
pjLine = pjNext;
break;
}
else
{
continue;
}
} // header loop
// now that we have cChars and font bounding box we can estimate
// the size of the BDAT table and use it to determine the index format
// for the bloc table. We assume imageFormat = 1 in either case
// which means every glyph has a different glyph metrics
{
ULONG cjAllGlyphs = (ULONG)cChars *
(ULONG)(sizeof(smallGlyphMetrics) + cy * ((cx + 7) >> 3));
if (cjAllGlyphs <= (0xffff - sizeof(bdatHeader)))
{
indexFormat = 3; // 16 bit offsets
cjOffset = sizeof(uint16);
}
else
{
indexFormat = 1; // 32 bit offsets
cjOffset = sizeof(uint32);
}
fprintf(stdout, "indexFormat = %d\n", indexFormat);
}
// pjLine now points to the first STARTCHAR
MALLOCOBJ memo((size_t)(cChars * sizeof(GINDEX)));
if (!memo.bValid())
return FALSE;
GINDEX *pgix = (GINDEX *)memo.pv();
ULONG cRuns = cComputeGlyphRanges(&mfo.fvw, pgix, cChars,pjCMAP);
if (!cRuns)
return FALSE;
MALLOCOBJ memoIndexSet((size_t)(SZ_INDEXSET(cRuns,cChars)));
if (!memoIndexSet.bValid())
return FALSE;
// now compute the index set
INDEXSET *piset = (INDEXSET *)memoIndexSet.pv();
cComputeIndexSet (pgix,cChars,cRuns, piset);
// if we are writing to the BLOC and BDAT buffers it is now time to
// initialize indexSubTableArray
indexSubTableArray *pista = NULL;
if (pjBLOC)
{
pista = (indexSubTableArray *)(pjBLOC + pbmpsz->indexSubTableArrayOffset);
// dpAdditionalOffset is computed relative to the top of the FIRST
// indexSubTableArray, not relative to the top of pjBLOC table.
// That is the offset from the beginning of the pjBLOC table is computed
// as pbmpsz->indexSubTableArrayOffset + dpAdditionalOffset
uint32 dpAdditionalOffset = piset->cRuns * sizeof(indexSubTableArray);
for (i = 0; i < piset->cRuns; i++)
{
pista[i].firstGlyphIndex = piset->agirun[i].giLow;
pista[i].lastGlyphIndex = piset->agirun[i].giLow +
piset->agirun[i].cGlyphs - 1;
pista[i].additionalOffsetToIndexSubtable = dpAdditionalOffset;
// need one more offset than there are glyphs, the size of the last
// glyph is equal to (offsetArray[cGlyphs] - offsetArray[cGlyphs - 1])
dpAdditionalOffset += (
offsetof(indexSubTable1,offsetArray) +
(piset->agirun[i].cGlyphs + 1) * cjOffset // need an extra offset
);
}
}
else // pjBLOC == 0
{
// initialize some variables;
pbmpsz->numberOfIndexSubTables = piset->cRuns; /* array size */
// bytes array+subtables
pbmpsz->indexTablesSize = piset->cRuns * sizeof(indexSubTableArray);
}
BYTE *pjBuf = NULL; // initialization is essential
// now go through the loop with glyphs:
// pjLine points to the first STARTCHAR line
lWidth = 0;
for (i = 0; i < piset->cRuns; i++)
{
// need one more offset than there are glyphs, the size of the last
// glyph is equal to (offsetArray[cGlyphs] - offsetArray[cGlyphs - 1])
uint32 cjSubTableSize;
if (indexFormat == 1)
{
cjSubTableSize = offsetof(indexSubTable1,offsetArray) +
(piset->agirun[i].cGlyphs + 1) * cjOffset;
}
else
{
ASSERT(indexFormat == 3, "indexFormat is screwed \n");
cjSubTableSize = offsetof(indexSubTable3,offsetArray) +
(piset->agirun[i].cGlyphs + 1) * cjOffset;
// cjSubTableSize has to be DWORD aligned according to APPLE's spec
// for the next indexSubTable to start at the DWORD boundary:
cjSubTableSize = ((cjSubTableSize + 3) & ~3);
}
indexSubTable1 * pist1 = NULL;
indexSubTable3 * pist3 = NULL;
if (!pjBLOC)
{
pbmpsz->indexTablesSize += cjSubTableSize;
}
else
{
pist1 = (indexSubTable1 *)(
pjBLOC +
pbmpsz->indexSubTableArrayOffset +
pista[i].additionalOffsetToIndexSubtable );
pist3 = (indexSubTable3 *)pist1;
pist1->header.indexFormat = indexFormat;
pist1->header.imageFormat = 1;
pist1->header.imageDataOffset = *pcjBDAT;
}
for (USHORT iGlyph = 0; iGlyph < piset->agirun[i].cGlyphs; iGlyph++)
{
GLYPHMET gm;
if (pjBLOC)
{
if (indexFormat == 1)
{
pist1->offsetArray[iGlyph] =
(*pcjBDAT - pist1->header.imageDataOffset);
pjBuf = pjBDAT + pist1->header.imageDataOffset + pist1->offsetArray[iGlyph];
}
else
{
ASSERT(indexFormat == 3, "indexFormat is screwed \n");
pist3->offsetArray[iGlyph] =
(uint16)(*pcjBDAT - pist3->header.imageDataOffset);
pjBuf = pjBDAT + pist3->header.imageDataOffset + pist3->offsetArray[iGlyph];
}
}
if
(
!bDoAGlyph(
&mfo.fvw,
iGlyph + piset->agirun[i].giLow,
piset->agirun[i].pdp[iGlyph],
&gm,
pjBuf
)
)
{
return FALSE;
}
// do a comparison on the width
if ((LONG)gm.sgm.advance > lWidth)
lWidth = gm.sgm.advance;
// add size
*pcjBDAT += gm.cjGlyph;
}
// Now need to fill an extra offset at the end of offsetArray
if (pjBLOC)
{
if (indexFormat == 1)
{
pist1->offsetArray[piset->agirun[i].cGlyphs] =
*pcjBDAT - pist1->header.imageDataOffset;
}
else
{
ASSERT(indexFormat == 3, "indexFormat is screwed \n");
pist3->offsetArray[piset->agirun[i].cGlyphs] =
(uint16)(*pcjBDAT - pist3->header.imageDataOffset);
}
}
} // end of the loop through glyphs
if (!pjBLOC)
{
pbmpsz->numberOfIndexSubTables = piset->cRuns;
pbmpsz->startGlyphIndex = (uint16)piset->agirun[0].giLow;
pbmpsz->endGlyphIndex = piset->agirun[piset->cRuns - 1].giLow +
piset->agirun[piset->cRuns - 1].cGlyphs - 1;
// strike wide metrics
pbmpsz->hori.ascender = (int8)rc.top;
pbmpsz->hori.descender = (int8)(-rc.bottom);
pbmpsz->hori.widthMax = (uint8)lWidth;
pbmpsz->hori.caretSlopeNumerator = 1;
pbmpsz->hori.caretSlopeDenominator = 0;
pbmpsz->hori.caretOffset = 0;
pbmpsz->hori.minOriginSB = (int8)rc.left;
pbmpsz->hori.minAdvanceSB = (int8)(rc.right - lWidth);
pbmpsz->hori.maxBeforeBL = (int8)rc.top;
pbmpsz->hori.minAfterBL = (int8)rc.bottom;
pbmpsz->hori.pad1 = 0;
pbmpsz->hori.pad2 = 0;
}
return TRUE;
}
BYTE jNibble(BYTE j)
{
switch(j)
{
case '0':
return 0;
case '1':
return 1;
case '2':
return 2;
case '3':
return 3;
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
case 'a':
case 'A':
return 10;
case 'b':
case 'B':
return 11;
case 'c':
case 'C':
return 12;
case 'd':
case 'D':
return 13;
case 'e':
case 'E':
return 14;
case 'f':
case 'F':
return 15;
default :
ASSERT(0, "bogus bitmap\n");
return 0;
}
}
VOID vDoARow(BYTE *pjRow, LONG cjRow, BYTE * ajWord)
{
ASSERT((2*cjRow) == (LONG)strlen((char *)ajWord), "cjRow problem \n");
BYTE *pjRowEnd = pjRow + cjRow;
for ( ; pjRow < pjRowEnd; pjRow++)
{
(*pjRow) = jNibble(*ajWord) << 4;
ajWord++;
(*pjRow) |= jNibble(*ajWord);
ajWord++;
}
}
PSZ gpsz[16] = {
" ",
" X",
" X ",
" XX",
" X ",
" X X",
" XX ",
" XXX",
"X ",
"X X",
"X X ",
"X XX",
"XX ",
"XX X",
"XXX ",
"XXXX"
};
VOID vFakeARow(BYTE *ajWord)
{
#ifdef DEBUGOUTPUT
for ( ; *ajWord != '\0'; ajWord++)
{
fprintf(stdout, "%s", gpsz[jNibble(*ajWord)]);
}
fprintf(stdout, "\n");
#endif // DEBUGOUTPUT
}
BOOL bDoAGlyph(
FILEVIEW *pfvw,
LONG gi,
LONG dp,
GLYPHMET *pgm, // various useful glyph information
BYTE *pjBuf // copy glyph to this buffer
)
{
BYTE *pjLine, *pjNext, *pjEOF, *pjWord;
BYTE ajWord[C_BIG]; // buffer for words
RECT rcChar;
LONG cx,cy, iRow;
POINTL ptlDevD, ptlScD;
LONG giDbg;
pgm->gi = gi;
pjLine = pfvw->pjView + dp;
pjEOF = pfvw->pjView + pfvw->cjView;
if (!(pjNext = pjNextLine(pjLine, pjEOF))) return FALSE;
// get the keyword at the beginning of the line
pjWord = pjNextWord(pjLine,pjNext, ajWord);
if (!strcmp((char *)ajWord,"STARTCHAR"))
{
// get the next word and convert it to the hex number
ULONG lUnicode;
pjWord = pjNextWord(pjWord,pjNext, ajWord);
#ifdef DEBUGOUTPUT
fprintf(stdout, "STARTCHAR %s\n", ajWord);
#endif // DEBUGOUTPUT
// get unicode code point for this glyph
pjWord = pjGetHexNumber(pjWord,pjNext, ajWord, &lUnicode);
// get glyph index, store the offset
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &giDbg);
if (giDbg != gi)
{
fprintf(stderr,
"gi problem: lUnicode = 0x%lx, gi = %ld, giDbg = %ld\n",
lUnicode, gi, giDbg);
}
}
else
{
fprintf(stderr, "STARTCHAR problem: %s\n", ajWord);
return FALSE;
}
pjLine = pjNext; // reset pjLine to point to ENCODING
// ENCODING, we ignore this value, it has no importance to us
if (!(pjNext = pjNextLine(pjLine, pjEOF))) return FALSE;
// get the keyword at the beginning of the line
pjWord = pjNextWord(pjLine,pjNext, ajWord);
if (!strcmp((char *)ajWord,"ENCODING"))
{
// get the next word and convert it to the hex number
#ifdef DEBUGOUTPUT
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &gi);
fprintf(stdout, "ENCODING %ld\n", gi);
#endif // DEBUGOUTPUT
}
else
{
fprintf(stderr, "ENCODING problem\n");
return FALSE;
}
pjLine = pjNext; // reset pjLine to point to SWIDTH
// SWIDTH
if (!(pjNext = pjNextLine(pjLine, pjEOF))) return FALSE;
// get the keyword at the beginning of the line
pjWord = pjNextWord(pjLine,pjNext, ajWord);
if (!strcmp((char *)ajWord,"SWIDTH"))
{
// get swidth
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &ptlScD.x);
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &ptlScD.y);
#ifdef DEBUGOUTPUT
fprintf(stdout, "SWIDTH = %ld, %ld\n",ptlScD.x,ptlScD.y);
#endif // DEBUGOUTPUT
}
else
{
fprintf(stderr, "SWIDTH problem\n");
return FALSE;
}
pjLine = pjNext; // reset pjLine to point to DWIDTH
// DWIDTH
if (!(pjNext = pjNextLine(pjLine, pjEOF))) return FALSE;
// get the keyword at the beginning of the line
pjWord = pjNextWord(pjLine,pjNext, ajWord);
if (!strcmp((char *)ajWord,"DWIDTH"))
{
// get dwidth
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &ptlDevD.x);
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &ptlDevD.y);
#ifdef DEBUGOUTPUT
fprintf(stdout, "DWIDTH = %ld, %ld\n",ptlDevD.x,ptlDevD.y);
#endif // DEBUGOUTPUT
pgm->sgm.advance = (uint8)ptlDevD.x;
ASSERT(ptlDevD.y == 0, "DWIDTH.y != 0\n");
}
else
{
fprintf(stderr, "DWIDTH problem\n");
return FALSE;
}
pjLine = pjNext; // reset pjLine to point to BBOX
// BBX
if (!(pjNext = pjNextLine(pjLine, pjEOF))) return FALSE;
// get the keyword at the beginning of the line
pjWord = pjNextWord(pjLine,pjNext, ajWord);
if (!strcmp((char *)ajWord,"BBX"))
{
// get BBX
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &cx);
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &cy);
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &rcChar.left);
pjWord = pjGetNextNumber(pjWord,pjNext, ajWord, &rcChar.bottom);
rcChar.right = rcChar.left + cx;
rcChar.top = rcChar.bottom + cy;
#ifdef DEBUGOUTPUT
fprintf(stdout,
"BBX: l = %ld, t = %ld, r = %ld, b = %ld \n",
rcChar.left, rcChar.top, rcChar.right, rcChar.bottom
);
#endif // DEBUGOUTPUT
pgm->sgm.width = (uint8)cx;
pgm->sgm.height = (uint8)cy;
pgm->sgm.bearingX = (int8)rcChar.left;
pgm->sgm.bearingY = (int8)rcChar.top;
// use cx and cy to compute how much room will this bitmap take in the
// bdat table, we are assuming imageFormat1
pgm->cjGlyph = sizeof(smallGlyphMetrics) + cy * ((cx + 7) >> 3);
}
else
{
fprintf(stderr, "BBX problem\n");
return FALSE;
}
pjLine = pjNext; // reset pjLine to point to BITMAP
// BITMAP
if (!(pjNext = pjNextLine(pjLine, pjEOF))) return FALSE;
// get the keyword at the beginning of the line
pjWord = pjNextWord(pjLine,pjNext, ajWord);
if (!strcmp((char *)ajWord,"BITMAP"))
{
#ifdef DEBUGOUTPUT
fprintf(stdout, "BITMAP\n");
#endif // DEBUGOUTPUT
}
else
{
fprintf(stderr, "BITMAP problem\n");
return FALSE;
}
pjLine = pjNext; // reset pjLine to point to the first row of the bitmap
// process the rows of the bitmap, one at the time
// if the glyph has to be written out let us do it
if (pjBuf)
{
*((smallGlyphMetrics *)pjBuf) = pgm->sgm;
pjBuf += sizeof(smallGlyphMetrics);
}
LONG cjRow = (cx + 7) >> 3;
BYTE *pjRow = pjBuf;
for (iRow = 0; iRow < cy; iRow++, pjRow += cjRow)
{
if (!(pjNext = pjNextLine(pjLine, pjEOF))) return FALSE;
// get the keyword at the beginning of the line
pjWord = pjNextWord(pjLine,pjNext, ajWord);
if (!pjBuf)
{
vFakeARow(ajWord);
}
else
{
vDoARow(pjRow,cjRow,ajWord);
}
pjLine = pjNext; // reset pjLine to point to the next row
}
// ENDCHAR
if (!(pjNext = pjNextLine(pjLine, pjEOF))) return FALSE;
// get the keyword at the beginning of the line
pjWord = pjNextWord(pjLine,pjNext, ajWord);
if (!strcmp((char *)ajWord,"ENDCHAR"))
{
#ifdef DEBUGOUTPUT
fprintf(stdout, "ENDCHAR\n");
#endif // DEBUGOUTPUT
}
else
{
fprintf(stderr, "ENDCHAR problem\n");
return FALSE;
}
return TRUE;
}
/******************************Public*Routine******************************\
*
*
*
* Effects:
*
* Warnings:
*
* History:
* 19-Nov-1993 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BOOL bCreateWriteToAndCloseFile
(
PBYTE pj, // buffer with the information to be written to the file
ULONG cj, // size of the buffer above
PSZ pszFileName // name of the file to be created
)
{
HANDLE hf;
ULONG cjWritten;
BOOL bRet;
hf = CreateFile(pszFileName, // file name of the new converted file
GENERIC_WRITE,
FILE_SHARE_READ,
0,
CREATE_ALWAYS, //
FILE_ATTRIBUTE_NORMAL,
0);
if (hf == (HANDLE)-1)
{
fprintf(stderr,"CreateFile failed\n");
bRet = FALSE;
goto exit;
}
// set file ptr to the beginning of the file
if (SetFilePointer(hf, 0, NULL, FILE_BEGIN) == -1)
{
fprintf(stderr,"SetFilePointer failed\n");
bRet = FALSE;
goto closefile;
}
if (
!WriteFile(hf, (PVOID)pj, cj, &cjWritten, NULL) ||
(cjWritten != cj)
)
{
fprintf(stderr,"WriteFile failed");
bRet = FALSE;
goto closefile;
}
bRet = TRUE;
closefile:
if (!CloseHandle(hf))
{
fprintf(stderr,"CloseHandle failed");
bRet = FALSE;
}
exit:
return(bRet);
}
VOID vSwap_bdatHeader(bdatHeader *p)
{
p->version = (Fixed) SWAPL(p->version);
}
VOID vSwap_blocHeader(blocHeader *p)
{
p->version = (Fixed) SWAPL(p->version);
p->numSizes = (uint32)SWAPL(p->numSizes);
}
VOID vSwap_bitmapSizeTable(bitmapSizeTable *p)
{
p->indexSubTableArrayOffset = (uint32)SWAPL(p->indexSubTableArrayOffset);
p->indexTablesSize = (uint32)SWAPL(p->indexTablesSize);
p->numberOfIndexSubTables = (uint32)SWAPL(p->numberOfIndexSubTables);
p->colorRef = (uint32)SWAPL(p->colorRef);
p->startGlyphIndex = (uint16)SWAPW(p->startGlyphIndex);
p->endGlyphIndex = (uint16)SWAPW(p->endGlyphIndex);
}
VOID vSwap_indexSubTableArray(indexSubTableArray *p)
{
p->firstGlyphIndex = (uint16)SWAPW(p->firstGlyphIndex);
p->lastGlyphIndex = (uint16)SWAPW(p->lastGlyphIndex);
p->additionalOffsetToIndexSubtable = (uint32)SWAPL(p->additionalOffsetToIndexSubtable);
}
VOID vSwap_indexSubHeader(indexSubHeader *p)
{
p->indexFormat = (uint16)SWAPW(p->indexFormat);
p->imageFormat = (uint16)SWAPW(p->imageFormat);
p->imageDataOffset = (uint32)SWAPL(p->imageDataOffset);
}
#ifdef DEBUGTABLES
VOID vDoAGlyph(BYTE *pjGlyph, ULONG ulGlyphIndex)
{
smallGlyphMetrics *psgm = (smallGlyphMetrics *)pjGlyph;
ULONG cx,cy, iRow, cjRow;
cx = psgm->width;
cy = psgm->height;
cjRow = (cx + 7) >> 3;
fprintf(stdout, "\nStarting Glyph, gi = %ld, cx = %ld, cy = %ld\n",
ulGlyphIndex, cx, cy);
// point pjGlyph into bits:
pjGlyph += sizeof(smallGlyphMetrics);
for (iRow = 0; iRow < cy; iRow++, pjGlyph += cjRow)
{
BYTE *pjRow = pjGlyph;
BYTE *pjRowEnd = pjGlyph + cjRow;
for ( ; pjRow < pjRowEnd; pjRow++)
{
fprintf(stdout, "%s", gpsz[(*pjRow) >> 4]);
fprintf(stdout, "%s", gpsz[(*pjRow) & 0x0f]);
}
fprintf(stdout, "\n");
}
fprintf(stdout, "Ending Glyph\n");
}
/******************************Public*Routine******************************\
* bView
*
* this routine is here for debugging purposes only.
* It looks through bloc and bdat files and makes sure that
* the data is in place where you would expect it.
*
* History:
* 20-Nov-1993 -by- Bodin Dresevic [BodinD]
* Wrote it.
\**************************************************************************/
BOOL bView(ULONG cjBLOC, ULONG cjBDAT)
{
MAPFILEOBJ mfoBLOC(achBLC);
MAPFILEOBJ mfoBDAT(achBDT);
if (!mfoBLOC.bValid() || !mfoBDAT.bValid())
return FALSE;
ASSERT(mfoBLOC.fvw.cjView == cjBLOC, "bView, cjBLOC\n");
ASSERT(mfoBDAT.fvw.cjView == cjBDAT, "bView, cjBDAT\n");
BYTE *pjBLOC = mfoBLOC.fvw.pjView;
BYTE *pjBDAT = mfoBDAT.fvw.pjView;
ULONG cSizes = (ULONG)SWAPL(((blocHeader *)pjBLOC)->numSizes);
bitmapSizeTable * pbmpsz = (bitmapSizeTable *)
(pjBLOC + sizeof(blocHeader));
// loop through the sizes:
for (ULONG iSize = 0; iSize < cSizes; iSize++)
{
bitmapSizeTable bmpsz = pbmpsz[iSize];
vSwap_bitmapSizeTable(&bmpsz);
fprintf(stdout, "\n\nSize = %ld\n\n",
(ULONG)bmpsz.ppemY
);
ULONG cGlyphs = 0; // total nubmer of glyphs supported at this size;
indexSubTableArray *pista, *pistaEnd;
pista = (indexSubTableArray *)(pjBLOC + bmpsz.indexSubTableArrayOffset);
pistaEnd = pista + bmpsz.numberOfIndexSubTables;
ASSERT(pista->firstGlyphIndex == pbmpsz[iSize].startGlyphIndex,
"pista->firstGlyphIndex \n");
ASSERT(pistaEnd[-1].lastGlyphIndex == pbmpsz[iSize].endGlyphIndex,
"pista->firstGlyphIndex \n");
for ( ; pista < pistaEnd; pista++)
{
indexSubTableArray ista = *pista;
vSwap_indexSubTableArray(&ista);
ULONG cGlyphsInRun = (ULONG)(ista.lastGlyphIndex
- ista.firstGlyphIndex + 1);
cGlyphs += cGlyphsInRun;
indexSubTable1 * pist1 = (indexSubTable1 *) (
pjBLOC +
bmpsz.indexSubTableArrayOffset +
ista.additionalOffsetToIndexSubtable);
indexSubTable3 * pist3 = (indexSubTable3 *) pist1;
fprintf(stdout, "\nStarting glyph run: giStart = %d\n", ista.firstGlyphIndex);
for (ULONG iGlyph = 0; iGlyph < cGlyphsInRun; iGlyph++)
{
BYTE *pjGlyph;
if (pist1->header.indexFormat == 0x0100)
{
pjGlyph = pjBDAT +
SWAPL(pist1->header.imageDataOffset) +
SWAPL(pist1->offsetArray[iGlyph]) ;
}
else
{
ASSERT(pist1->header.indexFormat == 0x0300, "indexFormat screwed 2\n");
pjGlyph = pjBDAT +
SWAPL(pist3->header.imageDataOffset) +
SWAPW(pist3->offsetArray[iGlyph]) ;
}
vDoAGlyph(pjGlyph, (ULONG)(ista.firstGlyphIndex + iGlyph));
}
fprintf(stdout, "\nEnding glyph run: giEnd = %d\n", ista.lastGlyphIndex);
}
fprintf(stdout, "\nThere are %ld glyphs supported at size %ld.\n",
cGlyphs,
(ULONG)bmpsz.ppemY);
}
return TRUE;
}
#endif // DEBUGTABLES
VOID vConvertToBigEndian(BYTE *pjBLOC, BYTE *pjBDAT)
{
uint16 indexFormat;
// this is the only DWORD or WORD information in the BDAT table:
vSwap_bdatHeader((bdatHeader *)pjBDAT);
// now do BLOC table:
ULONG cSizes = ((blocHeader *)pjBLOC)->numSizes;
vSwap_blocHeader((blocHeader *)pjBLOC);
bitmapSizeTable * pbmpsz = (bitmapSizeTable *)
(pjBLOC + sizeof(blocHeader));
// loop through the sizes:
for (ULONG iSize = 0; iSize < cSizes; iSize++)
{
bitmapSizeTable bmpsz = pbmpsz[iSize];
vSwap_bitmapSizeTable(&pbmpsz[iSize]);
indexSubTableArray *pista, *pistaEnd;
pista = (indexSubTableArray *)(pjBLOC + bmpsz.indexSubTableArrayOffset);
pistaEnd = pista + bmpsz.numberOfIndexSubTables;
for ( ; pista < pistaEnd; pista++)
{
indexSubTableArray ista = *pista;
vSwap_indexSubTableArray(pista);
ULONG cGlyphsInRun = (ULONG)(ista.lastGlyphIndex
- ista.firstGlyphIndex + 1);
indexSubTable1 * pist1 = (indexSubTable1 *)(
pjBLOC +
bmpsz.indexSubTableArrayOffset +
ista.additionalOffsetToIndexSubtable);
indexSubTable3 *pist3 = (indexSubTable3 *)pist1;
indexFormat = pist1->header.indexFormat;
vSwap_indexSubHeader(&pist1->header);
// do not forget to swap the last index in the array, the one that
// does not point to any glyph data but is only used instead
// for the computation of the size of the last glyph.
ULONG iGlyph;
if (indexFormat == 1) // 32 bit indicies
{
for (iGlyph = 0; iGlyph < (cGlyphsInRun + 1); iGlyph++)
{
pist1->offsetArray[iGlyph]
= (uint32)SWAPL(pist1->offsetArray[iGlyph]);
}
}
else // 16 indicies
{
ASSERT(indexFormat == 3, "indexFormat is screwed up\n");
for (iGlyph = 0; iGlyph < (cGlyphsInRun + 1); iGlyph++)
{
pist3->offsetArray[iGlyph]
= (uint16)SWAPW(pist3->offsetArray[iGlyph]);
}
}
}
}
}
BYTE *pjGetHexNumber(BYTE *pjWord, BYTE *pjEnd, BYTE * psz, ULONG *pul)
{
BYTE *pj = pjNextWord(pjWord,pjEnd,psz);
if (pul)
{
*pul = 0;
// skip the zeros at the beginning:
for ( ; *psz && (*psz == '0'); psz++)
;
for ( ; *psz != '\0'; psz++)
{
*pul = (*pul << 4) + jNibble(*psz);
}
}
return pj;
}