#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <X11/fonts/fntfilst.h>
#include <X11/fonts/bitmap.h>
#include <X11/fonts/pcf.h>
#ifndef MAX
#define MAX(a,b) (((a)>(b)) ? a : b)
#endif
#include <stdarg.h>
#include <stdint.h>
void
pcfError(const char* message, ...)
{
va_list args;
va_start(args, message);
fprintf(stderr, "PCF Error: ");
vfprintf(stderr, message, args);
va_end(args);
}
static void pcfUnloadFont ( FontPtr pFont );
static int position;
#define IS_EOF(file) ((file)->eof == BUFFILEEOF)
#define FONT_FILE_GETC_ERR(f) (tmp = FontFileGetc(f), BAIL_ON_EOF)
static int
pcfGetLSB32(FontFilePtr file)
{
int c;
c = FontFileGetc(file);
c |= FontFileGetc(file) << 8;
c |= FontFileGetc(file) << 16;
c |= FontFileGetc(file) << 24;
position += 4;
return c;
}
static int
pcfGetINT32(FontFilePtr file, CARD32 format)
{
int c;
if (PCF_BYTE_ORDER(format) == MSBFirst) {
c = FontFileGetc(file) << 24;
c |= FontFileGetc(file) << 16;
c |= FontFileGetc(file) << 8;
c |= FontFileGetc(file);
} else {
c = FontFileGetc(file);
c |= FontFileGetc(file) << 8;
c |= FontFileGetc(file) << 16;
c |= FontFileGetc(file) << 24;
}
position += 4;
return c;
}
static int
pcfGetINT16(FontFilePtr file, CARD32 format)
{
int c;
if (PCF_BYTE_ORDER(format) == MSBFirst) {
c = FontFileGetc(file) << 8;
c |= FontFileGetc(file);
} else {
c = FontFileGetc(file);
c |= FontFileGetc(file) << 8;
}
position += 2;
return c;
}
#define pcfGetINT8(file, format) (position++, FontFileGetc(file))
static PCFTablePtr
pcfReadTOC(FontFilePtr file, int *countp)
{
CARD32 version;
PCFTablePtr tables;
int count;
int i;
position = 0;
version = pcfGetLSB32(file);
if (version != PCF_FILE_VERSION)
return (PCFTablePtr) NULL;
count = pcfGetLSB32(file);
if (IS_EOF(file)) return (PCFTablePtr) NULL;
if (count < 0 || count > INT32_MAX / sizeof(PCFTableRec)) {
pcfError("pcfReadTOC(): invalid file format\n");
return NULL;
}
tables = malloc(count * sizeof(PCFTableRec));
if (!tables) {
pcfError("pcfReadTOC(): Couldn't allocate tables (%d*%d)\n", count, sizeof(PCFTableRec));
return (PCFTablePtr) NULL;
}
for (i = 0; i < count; i++) {
tables[i].type = pcfGetLSB32(file);
tables[i].format = pcfGetLSB32(file);
tables[i].size = pcfGetLSB32(file);
tables[i].offset = pcfGetLSB32(file);
if (IS_EOF(file)) goto Bail;
}
*countp = count;
return tables;
Bail:
free(tables);
return (PCFTablePtr) NULL;
}
static Bool
pcfGetMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
{
metric->leftSideBearing = pcfGetINT16(file, format);
metric->rightSideBearing = pcfGetINT16(file, format);
metric->characterWidth = pcfGetINT16(file, format);
metric->ascent = pcfGetINT16(file, format);
metric->descent = pcfGetINT16(file, format);
metric->attributes = pcfGetINT16(file, format);
if (IS_EOF(file)) return FALSE;
return TRUE;
}
static Bool
pcfGetCompressedMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
{
metric->leftSideBearing = pcfGetINT8(file, format) - 0x80;
metric->rightSideBearing = pcfGetINT8(file, format) - 0x80;
metric->characterWidth = pcfGetINT8(file, format) - 0x80;
metric->ascent = pcfGetINT8(file, format) - 0x80;
metric->descent = pcfGetINT8(file, format) - 0x80;
metric->attributes = 0;
if (IS_EOF(file)) return FALSE;
return TRUE;
}
static Bool
pcfSeekToType(FontFilePtr file, PCFTablePtr tables, int ntables,
CARD32 type, CARD32 *formatp, CARD32 *sizep)
{
int i;
for (i = 0; i < ntables; i++)
if (tables[i].type == type) {
if (position > tables[i].offset)
return FALSE;
if (!FontFileSkip(file, tables[i].offset - position))
return FALSE;
position = tables[i].offset;
*sizep = tables[i].size;
*formatp = tables[i].format;
return TRUE;
}
return FALSE;
}
static Bool
pcfHasType (PCFTablePtr tables, int ntables, CARD32 type)
{
int i;
for (i = 0; i < ntables; i++)
if (tables[i].type == type)
return TRUE;
return FALSE;
}
static Bool
pcfGetProperties(FontInfoPtr pFontInfo, FontFilePtr file,
PCFTablePtr tables, int ntables)
{
FontPropPtr props = 0;
int nprops;
char *isStringProp = 0;
CARD32 format;
int i;
CARD32 size;
int string_size;
char *strings;
if (!pcfSeekToType(file, tables, ntables, PCF_PROPERTIES, &format, &size))
goto Bail;
format = pcfGetLSB32(file);
if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
goto Bail;
nprops = pcfGetINT32(file, format);
if (nprops <= 0 || nprops > INT32_MAX / sizeof(FontPropRec)) {
pcfError("pcfGetProperties(): invalid nprops value (%d)\n", nprops);
goto Bail;
}
if (IS_EOF(file)) goto Bail;
props = malloc(nprops * sizeof(FontPropRec));
if (!props) {
pcfError("pcfGetProperties(): Couldn't allocate props (%d*%d)\n", nprops, sizeof(FontPropRec));
goto Bail;
}
isStringProp = malloc(nprops * sizeof(char));
if (!isStringProp) {
pcfError("pcfGetProperties(): Couldn't allocate isStringProp (%d*%d)\n", nprops, sizeof(char));
goto Bail;
}
for (i = 0; i < nprops; i++) {
props[i].name = pcfGetINT32(file, format);
isStringProp[i] = pcfGetINT8(file, format);
props[i].value = pcfGetINT32(file, format);
if (props[i].name < 0
|| (isStringProp[i] != 0 && isStringProp[i] != 1)
|| (isStringProp[i] && props[i].value < 0)) {
pcfError("pcfGetProperties(): invalid file format %d %d %d\n",
props[i].name, isStringProp[i], props[i].value);
goto Bail;
}
if (IS_EOF(file)) goto Bail;
}
if (nprops & 3)
{
i = 4 - (nprops & 3);
(void)FontFileSkip(file, i);
position += i;
}
if (IS_EOF(file)) goto Bail;
string_size = pcfGetINT32(file, format);
if (string_size < 0) goto Bail;
if (IS_EOF(file)) goto Bail;
strings = malloc(string_size);
if (!strings) {
pcfError("pcfGetProperties(): Couldn't allocate strings (%d)\n", string_size);
goto Bail;
}
FontFileRead(file, strings, string_size);
if (IS_EOF(file)) goto Bail;
position += string_size;
for (i = 0; i < nprops; i++) {
props[i].name = MakeAtom(strings + props[i].name,
strlen(strings + props[i].name), TRUE);
if (isStringProp[i]) {
props[i].value = MakeAtom(strings + props[i].value,
strlen(strings + props[i].value), TRUE);
}
}
free(strings);
pFontInfo->isStringProp = isStringProp;
pFontInfo->props = props;
pFontInfo->nprops = nprops;
return TRUE;
Bail:
free(isStringProp);
free(props);
return FALSE;
}
static Bool
pcfGetAccel(FontInfoPtr pFontInfo, FontFilePtr file,
PCFTablePtr tables, int ntables, CARD32 type)
{
CARD32 format;
CARD32 size;
if (!pcfSeekToType(file, tables, ntables, type, &format, &size) ||
IS_EOF(file))
goto Bail;
format = pcfGetLSB32(file);
if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
!PCF_FORMAT_MATCH(format, PCF_ACCEL_W_INKBOUNDS))
{
goto Bail;
}
pFontInfo->noOverlap = pcfGetINT8(file, format);
pFontInfo->constantMetrics = pcfGetINT8(file, format);
pFontInfo->terminalFont = pcfGetINT8(file, format);
pFontInfo->constantWidth = pcfGetINT8(file, format);
pFontInfo->inkInside = pcfGetINT8(file, format);
pFontInfo->inkMetrics = pcfGetINT8(file, format);
pFontInfo->drawDirection = pcfGetINT8(file, format);
pFontInfo->anamorphic = FALSE;
pFontInfo->cachable = TRUE;
pcfGetINT8(file, format);
pFontInfo->fontAscent = pcfGetINT32(file, format);
pFontInfo->fontDescent = pcfGetINT32(file, format);
pFontInfo->maxOverlap = pcfGetINT32(file, format);
if (IS_EOF(file)) goto Bail;
if (!pcfGetMetric(file, format, &pFontInfo->minbounds))
goto Bail;
if (!pcfGetMetric(file, format, &pFontInfo->maxbounds))
goto Bail;
if (PCF_FORMAT_MATCH(format, PCF_ACCEL_W_INKBOUNDS)) {
if (!pcfGetMetric(file, format, &pFontInfo->ink_minbounds))
goto Bail;
if (!pcfGetMetric(file, format, &pFontInfo->ink_maxbounds))
goto Bail;
} else {
pFontInfo->ink_minbounds = pFontInfo->minbounds;
pFontInfo->ink_maxbounds = pFontInfo->maxbounds;
}
return TRUE;
Bail:
return FALSE;
}
int
pcfReadFont(FontPtr pFont, FontFilePtr file,
int bit, int byte, int glyph, int scan)
{
CARD32 format;
CARD32 size;
BitmapFontPtr bitmapFont = 0;
int i;
PCFTablePtr tables = 0;
int ntables;
int nmetrics;
int nbitmaps;
int sizebitmaps;
int nink_metrics;
CharInfoPtr metrics = 0;
xCharInfo *ink_metrics = 0;
char *bitmaps = 0;
CharInfoPtr **encoding = 0;
int nencoding = 0;
int encodingOffset;
CARD32 bitmapSizes[GLYPHPADOPTIONS];
CARD32 *offsets = 0;
Bool hasBDFAccelerators;
pFont->info.nprops = 0;
pFont->info.props = 0;
if (!(tables = pcfReadTOC(file, &ntables)))
goto Bail;
if (!pcfGetProperties(&pFont->info, file, tables, ntables))
goto Bail;
hasBDFAccelerators = pcfHasType (tables, ntables, PCF_BDF_ACCELERATORS);
if (!hasBDFAccelerators)
if (!pcfGetAccel (&pFont->info, file, tables, ntables, PCF_ACCELERATORS))
goto Bail;
if (!pcfSeekToType(file, tables, ntables, PCF_METRICS, &format, &size)) {
goto Bail;
}
format = pcfGetLSB32(file);
if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
!PCF_FORMAT_MATCH(format, PCF_COMPRESSED_METRICS)) {
goto Bail;
}
if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
nmetrics = pcfGetINT32(file, format);
else
nmetrics = pcfGetINT16(file, format);
if (IS_EOF(file)) goto Bail;
if (nmetrics < 0 || nmetrics > INT32_MAX / sizeof(CharInfoRec)) {
pcfError("pcfReadFont(): invalid file format\n");
goto Bail;
}
metrics = malloc(nmetrics * sizeof(CharInfoRec));
if (!metrics) {
pcfError("pcfReadFont(): Couldn't allocate metrics (%d*%d)\n", nmetrics, sizeof(CharInfoRec));
goto Bail;
}
for (i = 0; i < nmetrics; i++)
if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT)) {
if (!pcfGetMetric(file, format, &(metrics + i)->metrics))
goto Bail;
} else {
if (!pcfGetCompressedMetric(file, format, &(metrics + i)->metrics))
goto Bail;
}
if (!pcfSeekToType(file, tables, ntables, PCF_BITMAPS, &format, &size))
goto Bail;
format = pcfGetLSB32(file);
if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
goto Bail;
nbitmaps = pcfGetINT32(file, format);
if (nbitmaps != nmetrics || IS_EOF(file))
goto Bail;
offsets = malloc(nbitmaps * sizeof(CARD32));
if (!offsets) {
pcfError("pcfReadFont(): Couldn't allocate offsets (%d*%d)\n", nbitmaps, sizeof(CARD32));
goto Bail;
}
for (i = 0; i < nbitmaps; i++) {
offsets[i] = pcfGetINT32(file, format);
if (IS_EOF(file)) goto Bail;
}
for (i = 0; i < GLYPHPADOPTIONS; i++) {
bitmapSizes[i] = pcfGetINT32(file, format);
if (IS_EOF(file)) goto Bail;
if (bitmapSizes[i] < 0) goto Bail;
}
sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX(format)];
bitmaps = malloc(sizebitmaps ? sizebitmaps : 1);
if (!bitmaps) {
pcfError("pcfReadFont(): Couldn't allocate bitmaps (%d)\n", sizebitmaps ? sizebitmaps : 1);
goto Bail;
}
FontFileRead(file, bitmaps, sizebitmaps);
if (IS_EOF(file)) goto Bail;
position += sizebitmaps;
if (PCF_BIT_ORDER(format) != bit)
BitOrderInvert((unsigned char *)bitmaps, sizebitmaps);
if ((PCF_BYTE_ORDER(format) == PCF_BIT_ORDER(format)) != (bit == byte)) {
switch (bit == byte ? PCF_SCAN_UNIT(format) : scan) {
case 1:
break;
case 2:
TwoByteSwap((unsigned char *)bitmaps, sizebitmaps);
break;
case 4:
FourByteSwap((unsigned char *)bitmaps, sizebitmaps);
break;
}
}
if (PCF_GLYPH_PAD(format) != glyph) {
char *padbitmaps;
int sizepadbitmaps;
int old,
new;
xCharInfo *metric;
sizepadbitmaps = bitmapSizes[PCF_SIZE_TO_INDEX(glyph)];
padbitmaps = malloc(sizepadbitmaps);
if (!padbitmaps) {
pcfError("pcfReadFont(): Couldn't allocate padbitmaps (%d)\n", sizepadbitmaps);
goto Bail;
}
new = 0;
for (i = 0; i < nbitmaps; i++) {
old = offsets[i];
metric = &metrics[i].metrics;
offsets[i] = new;
new += RepadBitmap(bitmaps + old, padbitmaps + new,
PCF_GLYPH_PAD(format), glyph,
metric->rightSideBearing - metric->leftSideBearing,
metric->ascent + metric->descent);
}
free(bitmaps);
bitmaps = padbitmaps;
}
for (i = 0; i < nbitmaps; i++)
metrics[i].bits = bitmaps + offsets[i];
free(offsets);
offsets = NULL;
ink_metrics = NULL;
if (pcfSeekToType(file, tables, ntables, PCF_INK_METRICS, &format, &size)) {
format = pcfGetLSB32(file);
if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
!PCF_FORMAT_MATCH(format, PCF_COMPRESSED_METRICS)) {
goto Bail;
}
if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
nink_metrics = pcfGetINT32(file, format);
else
nink_metrics = pcfGetINT16(file, format);
if (IS_EOF(file)) goto Bail;
if (nink_metrics != nmetrics)
goto Bail;
ink_metrics = malloc(nink_metrics * sizeof(xCharInfo));
if (!ink_metrics) {
pcfError("pcfReadFont(): Couldn't allocate ink_metrics (%d*%d)\n", nink_metrics, sizeof(xCharInfo));
goto Bail;
}
for (i = 0; i < nink_metrics; i++)
if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT)) {
if (!pcfGetMetric(file, format, ink_metrics + i))
goto Bail;
} else {
if (!pcfGetCompressedMetric(file, format, ink_metrics + i))
goto Bail;
}
}
if (!pcfSeekToType(file, tables, ntables, PCF_BDF_ENCODINGS, &format, &size))
goto Bail;
format = pcfGetLSB32(file);
if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
goto Bail;
pFont->info.firstCol = pcfGetINT16(file, format);
pFont->info.lastCol = pcfGetINT16(file, format);
pFont->info.firstRow = pcfGetINT16(file, format);
pFont->info.lastRow = pcfGetINT16(file, format);
pFont->info.defaultCh = pcfGetINT16(file, format);
if (IS_EOF(file)) goto Bail;
if (pFont->info.firstCol > pFont->info.lastCol ||
pFont->info.firstRow > pFont->info.lastRow ||
pFont->info.lastCol-pFont->info.firstCol > 255) goto Bail;
nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
(pFont->info.lastRow - pFont->info.firstRow + 1);
encoding = calloc(NUM_SEGMENTS(nencoding), sizeof(CharInfoPtr*));
if (!encoding) {
pcfError("pcfReadFont(): Couldn't allocate encoding (%d*%d)\n", nencoding, sizeof(CharInfoPtr));
goto Bail;
}
pFont->info.allExist = TRUE;
for (i = 0; i < nencoding; i++) {
encodingOffset = pcfGetINT16(file, format);
if (IS_EOF(file)) goto Bail;
if (encodingOffset == 0xFFFF) {
pFont->info.allExist = FALSE;
} else {
if(!encoding[SEGMENT_MAJOR(i)]) {
encoding[SEGMENT_MAJOR(i)]=
calloc(BITMAP_FONT_SEGMENT_SIZE, sizeof(CharInfoPtr));
if(!encoding[SEGMENT_MAJOR(i)])
goto Bail;
}
ACCESSENCODINGL(encoding, i) = metrics + encodingOffset;
}
}
if (hasBDFAccelerators)
if (!pcfGetAccel (&pFont->info, file, tables, ntables, PCF_BDF_ACCELERATORS))
goto Bail;
bitmapFont = malloc(sizeof *bitmapFont);
if (!bitmapFont) {
pcfError("pcfReadFont(): Couldn't allocate bitmapFont (%d)\n", sizeof *bitmapFont);
goto Bail;
}
bitmapFont->version_num = PCF_FILE_VERSION;
bitmapFont->num_chars = nmetrics;
bitmapFont->num_tables = ntables;
bitmapFont->metrics = metrics;
bitmapFont->ink_metrics = ink_metrics;
bitmapFont->bitmaps = bitmaps;
bitmapFont->encoding = encoding;
bitmapFont->pDefault = (CharInfoPtr) 0;
if (pFont->info.defaultCh != (unsigned short) NO_SUCH_CHAR) {
unsigned int r,
c,
cols;
r = pFont->info.defaultCh >> 8;
c = pFont->info.defaultCh & 0xFF;
if (pFont->info.firstRow <= r && r <= pFont->info.lastRow &&
pFont->info.firstCol <= c && c <= pFont->info.lastCol) {
cols = pFont->info.lastCol - pFont->info.firstCol + 1;
r = r - pFont->info.firstRow;
c = c - pFont->info.firstCol;
bitmapFont->pDefault = ACCESSENCODING(encoding, r * cols + c);
}
}
bitmapFont->bitmapExtra = (BitmapExtraPtr) 0;
pFont->fontPrivate = (pointer) bitmapFont;
pFont->get_glyphs = bitmapGetGlyphs;
pFont->get_metrics = bitmapGetMetrics;
pFont->unload_font = pcfUnloadFont;
pFont->unload_glyphs = NULL;
pFont->bit = bit;
pFont->byte = byte;
pFont->glyph = glyph;
pFont->scan = scan;
free(tables);
return Successful;
Bail:
free(ink_metrics);
if(encoding) {
for(i=0; i<NUM_SEGMENTS(nencoding); i++)
free(encoding[i]);
}
free(encoding);
free(bitmaps);
free(metrics);
free(pFont->info.props);
pFont->info.nprops = 0;
pFont->info.props = 0;
free (pFont->info.isStringProp);
free(bitmapFont);
free(tables);
free(offsets);
return AllocError;
}
int
pcfReadFontInfo(FontInfoPtr pFontInfo, FontFilePtr file)
{
PCFTablePtr tables;
int ntables;
CARD32 format;
CARD32 size;
int nencoding;
Bool hasBDFAccelerators;
pFontInfo->isStringProp = NULL;
pFontInfo->props = NULL;
pFontInfo->nprops = 0;
if (!(tables = pcfReadTOC(file, &ntables)))
goto Bail;
if (!pcfGetProperties(pFontInfo, file, tables, ntables))
goto Bail;
hasBDFAccelerators = pcfHasType (tables, ntables, PCF_BDF_ACCELERATORS);
if (!hasBDFAccelerators)
if (!pcfGetAccel (pFontInfo, file, tables, ntables, PCF_ACCELERATORS))
goto Bail;
if (!pcfSeekToType(file, tables, ntables, PCF_BDF_ENCODINGS, &format, &size))
goto Bail;
format = pcfGetLSB32(file);
if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
goto Bail;
pFontInfo->firstCol = pcfGetINT16(file, format);
pFontInfo->lastCol = pcfGetINT16(file, format);
pFontInfo->firstRow = pcfGetINT16(file, format);
pFontInfo->lastRow = pcfGetINT16(file, format);
pFontInfo->defaultCh = pcfGetINT16(file, format);
if (IS_EOF(file)) goto Bail;
if (pFontInfo->firstCol > pFontInfo->lastCol ||
pFontInfo->firstRow > pFontInfo->lastRow ||
pFontInfo->lastCol-pFontInfo->firstCol > 255) goto Bail;
nencoding = (pFontInfo->lastCol - pFontInfo->firstCol + 1) *
(pFontInfo->lastRow - pFontInfo->firstRow + 1);
pFontInfo->allExist = TRUE;
while (nencoding--) {
if (pcfGetINT16(file, format) == 0xFFFF)
pFontInfo->allExist = FALSE;
if (IS_EOF(file)) goto Bail;
}
if (IS_EOF(file)) goto Bail;
if (hasBDFAccelerators)
if (!pcfGetAccel (pFontInfo, file, tables, ntables, PCF_BDF_ACCELERATORS))
goto Bail;
free(tables);
return Successful;
Bail:
pFontInfo->nprops = 0;
free (pFontInfo->props);
free (pFontInfo->isStringProp);
free(tables);
return AllocError;
}
static void
pcfUnloadFont(FontPtr pFont)
{
BitmapFontPtr bitmapFont;
int i,nencoding;
bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
free(bitmapFont->ink_metrics);
if(bitmapFont->encoding) {
nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
(pFont->info.lastRow - pFont->info.firstRow + 1);
for(i=0; i<NUM_SEGMENTS(nencoding); i++)
free(bitmapFont->encoding[i]);
}
free(bitmapFont->encoding);
free(bitmapFont->bitmaps);
free(bitmapFont->metrics);
free(pFont->info.isStringProp);
free(pFont->info.props);
free(bitmapFont);
DestroyFontRec(pFont);
}