1/*
2
3Copyright 1990, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29/*
30 * Author:  Keith Packard, MIT X Consortium
31 */
32
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36#include "libxfontint.h"
37#include "src/util/replace.h"
38
39#include <X11/fonts/fntfilst.h>
40#include <X11/fonts/bitmap.h>
41#include <X11/fonts/pcf.h>
42
43#ifndef MAX
44#define   MAX(a,b)    (((a)>(b)) ? a : b)
45#endif
46
47#include <stdarg.h>
48#include <stdint.h>
49#include <string.h>
50
51void
52pcfError(const char* message, ...)
53{
54    va_list args;
55
56    va_start(args, message);
57
58    fprintf(stderr, "PCF Error: ");
59    vfprintf(stderr, message, args);
60    va_end(args);
61}
62
63/* Read PCF font files */
64
65static void pcfUnloadFont ( FontPtr pFont );
66static int  position;
67
68
69#define IS_EOF(file) ((file)->eof == BUFFILEEOF)
70
71#define FONT_FILE_GETC_ERR(f)  (tmp = FontFileGetc(f), BAIL_ON_EOF)
72
73static int
74pcfGetLSB32(FontFilePtr file)
75{
76    int         c;
77
78    c = FontFileGetc(file);
79    c |= FontFileGetc(file) << 8;
80    c |= FontFileGetc(file) << 16;
81    c |= FontFileGetc(file) << 24;
82    position += 4;
83    return c;
84}
85
86static int
87pcfGetINT32(FontFilePtr file, CARD32 format)
88{
89    int         c;
90
91    if (PCF_BYTE_ORDER(format) == MSBFirst) {
92	c = FontFileGetc(file) << 24;
93	c |= FontFileGetc(file) << 16;
94	c |= FontFileGetc(file) << 8;
95	c |= FontFileGetc(file);
96    } else {
97	c = FontFileGetc(file);
98	c |= FontFileGetc(file) << 8;
99	c |= FontFileGetc(file) << 16;
100	c |= FontFileGetc(file) << 24;
101    }
102    position += 4;
103    return c;
104}
105
106static int
107pcfGetINT16(FontFilePtr file, CARD32 format)
108{
109    int         c;
110
111    if (PCF_BYTE_ORDER(format) == MSBFirst) {
112	c = FontFileGetc(file) << 8;
113	c |= FontFileGetc(file);
114    } else {
115	c = FontFileGetc(file);
116	c |= FontFileGetc(file) << 8;
117    }
118    position += 2;
119    return c;
120}
121
122#define pcfGetINT8(file, format) (position++, FontFileGetc(file))
123
124static      PCFTablePtr
125pcfReadTOC(FontFilePtr file, int *countp)
126{
127    CARD32      version;
128    PCFTablePtr tables;
129    int         count;
130    int         i;
131
132    position = 0;
133    version = pcfGetLSB32(file);
134    if (version != PCF_FILE_VERSION)
135	return (PCFTablePtr) NULL;
136    count = pcfGetLSB32(file);
137    if (IS_EOF(file)) return (PCFTablePtr) NULL;
138    if (count < 0 || count > INT32_MAX / sizeof(PCFTableRec)) {
139	pcfError("pcfReadTOC(): invalid file format\n");
140	return NULL;
141    }
142    tables = mallocarray(count, sizeof(PCFTableRec));
143    if (!tables) {
144	pcfError("pcfReadTOC(): Couldn't allocate tables (%d*%d)\n",
145		 count, (int) sizeof(PCFTableRec));
146	return (PCFTablePtr) NULL;
147    }
148    for (i = 0; i < count; i++) {
149	tables[i].type = pcfGetLSB32(file);
150	tables[i].format = pcfGetLSB32(file);
151	tables[i].size = pcfGetLSB32(file);
152	tables[i].offset = pcfGetLSB32(file);
153	if (IS_EOF(file)) goto Bail;
154    }
155
156    *countp = count;
157    return tables;
158
159 Bail:
160    free(tables);
161    return (PCFTablePtr) NULL;
162}
163
164/*
165 * PCF supports two formats for metrics, both the regular
166 * jumbo size, and 'lite' metrics, which are useful
167 * for most fonts which have even vaguely reasonable
168 * metrics
169 */
170
171static Bool
172pcfGetMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
173{
174    metric->leftSideBearing = pcfGetINT16(file, format);
175    metric->rightSideBearing = pcfGetINT16(file, format);
176    metric->characterWidth = pcfGetINT16(file, format);
177    metric->ascent = pcfGetINT16(file, format);
178    metric->descent = pcfGetINT16(file, format);
179    metric->attributes = pcfGetINT16(file, format);
180    if (IS_EOF(file)) return FALSE;
181
182    return TRUE;
183}
184
185static Bool
186pcfGetCompressedMetric(FontFilePtr file, CARD32 format, xCharInfo *metric)
187{
188    metric->leftSideBearing = pcfGetINT8(file, format) - 0x80;
189    metric->rightSideBearing = pcfGetINT8(file, format) - 0x80;
190    metric->characterWidth = pcfGetINT8(file, format) - 0x80;
191    metric->ascent = pcfGetINT8(file, format) - 0x80;
192    metric->descent = pcfGetINT8(file, format) - 0x80;
193    metric->attributes = 0;
194    if (IS_EOF(file)) return FALSE;
195
196    return TRUE;
197}
198
199/*
200 * Position the file to the beginning of the specified table
201 * in the font file
202 */
203static Bool
204pcfSeekToType(FontFilePtr file, PCFTablePtr tables, int ntables,
205	      CARD32 type, CARD32 *formatp, CARD32 *sizep)
206{
207    int         i;
208
209    for (i = 0; i < ntables; i++)
210	if (tables[i].type == type) {
211	    if (position > tables[i].offset)
212		return FALSE;
213	    if (!FontFileSkip(file, tables[i].offset - position))
214		return FALSE;
215	    position = tables[i].offset;
216	    *sizep = tables[i].size;
217	    *formatp = tables[i].format;
218	    return TRUE;
219	}
220    return FALSE;
221}
222
223static Bool
224pcfHasType (PCFTablePtr tables, int ntables, CARD32 type)
225{
226    int         i;
227
228    for (i = 0; i < ntables; i++)
229	if (tables[i].type == type)
230	    return TRUE;
231    return FALSE;
232}
233
234/*
235 * pcfGetProperties
236 *
237 * Reads the font properties from the font file, filling in the FontInfo rec
238 * supplied.  Used by by both ReadFont and ReadFontInfo routines.
239 */
240
241static Bool
242pcfGetProperties(FontInfoPtr pFontInfo, FontFilePtr file,
243		 PCFTablePtr tables, int ntables)
244{
245    FontPropPtr props = 0;
246    int         nprops;
247    char       *isStringProp = 0;
248    CARD32      format;
249    int         i;
250    CARD32      size;
251    int         string_size;
252    char       *strings;
253
254    /* font properties */
255
256    if (!pcfSeekToType(file, tables, ntables, PCF_PROPERTIES, &format, &size))
257	goto Bail;
258    format = pcfGetLSB32(file);
259    if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
260	goto Bail;
261    nprops = pcfGetINT32(file, format);
262    if (nprops <= 0 || nprops > INT32_MAX / sizeof(FontPropRec)) {
263	pcfError("pcfGetProperties(): invalid nprops value (%d)\n", nprops);
264	goto Bail;
265    }
266    if (IS_EOF(file)) goto Bail;
267    props = mallocarray(nprops, sizeof(FontPropRec));
268    if (!props) {
269	pcfError("pcfGetProperties(): Couldn't allocate props (%d*%d)\n",
270	       nprops, (int) sizeof(FontPropRec));
271	goto Bail;
272    }
273    isStringProp = mallocarray(nprops, sizeof(char));
274    if (!isStringProp) {
275	pcfError("pcfGetProperties(): Couldn't allocate isStringProp (%d*%d)\n",
276	       nprops, (int) sizeof(char));
277	goto Bail;
278    }
279    for (i = 0; i < nprops; i++) {
280	props[i].name = pcfGetINT32(file, format);
281	isStringProp[i] = pcfGetINT8(file, format);
282	props[i].value = pcfGetINT32(file, format);
283	if (props[i].name < 0
284	    || (isStringProp[i] != 0 && isStringProp[i] != 1)
285	    || (isStringProp[i] && props[i].value < 0)) {
286	    pcfError("pcfGetProperties(): invalid file format %ld %d %ld\n",
287		     props[i].name, isStringProp[i], props[i].value);
288	    goto Bail;
289	}
290	if (IS_EOF(file)) goto Bail;
291    }
292    /* pad the property array */
293    /*
294     * clever here - nprops is the same as the number of odd-units read, as
295     * only isStringProp are odd length
296     */
297    if (nprops & 3)
298    {
299	i = 4 - (nprops & 3);
300	(void)FontFileSkip(file, i);
301	position += i;
302    }
303    if (IS_EOF(file)) goto Bail;
304    string_size = pcfGetINT32(file, format);
305    if (string_size < 0) goto Bail;
306    if (IS_EOF(file)) goto Bail;
307    strings = malloc(string_size);
308    if (!strings) {
309      pcfError("pcfGetProperties(): Couldn't allocate strings (%d)\n", string_size);
310	goto Bail;
311    }
312    FontFileRead(file, strings, string_size);
313    if (IS_EOF(file)) goto Bail;
314    position += string_size;
315    for (i = 0; i < nprops; i++) {
316	if (props[i].name >= string_size) {
317	    pcfError("pcfGetProperties(): String starts out of bounds (%ld/%d)\n", props[i].name, string_size);
318	    goto Bail;
319	}
320	props[i].name = MakeAtom(strings + props[i].name,
321				 strnlen(strings + props[i].name, string_size - props[i].name), TRUE);
322	if (isStringProp[i]) {
323	    if (props[i].value >= string_size) {
324		pcfError("pcfGetProperties(): String starts out of bounds (%ld/%d)\n", props[i].value, string_size);
325		goto Bail;
326	    }
327	    props[i].value = MakeAtom(strings + props[i].value,
328				      strnlen(strings + props[i].value, string_size - props[i].value), TRUE);
329	}
330    }
331    free(strings);
332    pFontInfo->isStringProp = isStringProp;
333    pFontInfo->props = props;
334    pFontInfo->nprops = nprops;
335    return TRUE;
336Bail:
337    free(isStringProp);
338    free(props);
339    return FALSE;
340}
341
342
343/*
344 * pcfReadAccel
345 *
346 * Fill in the accelerator information from the font file; used
347 * to read both BDF_ACCELERATORS and old style ACCELERATORS
348 */
349
350static Bool
351pcfGetAccel(FontInfoPtr pFontInfo, FontFilePtr file,
352	    PCFTablePtr tables, int ntables, CARD32 type)
353{
354    CARD32      format;
355    CARD32	size;
356
357    if (!pcfSeekToType(file, tables, ntables, type, &format, &size) ||
358	IS_EOF(file))
359	goto Bail;
360    format = pcfGetLSB32(file);
361    if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
362	!PCF_FORMAT_MATCH(format, PCF_ACCEL_W_INKBOUNDS))
363    {
364	goto Bail;
365    }
366    pFontInfo->noOverlap = pcfGetINT8(file, format);
367    pFontInfo->constantMetrics = pcfGetINT8(file, format);
368    pFontInfo->terminalFont = pcfGetINT8(file, format);
369    pFontInfo->constantWidth = pcfGetINT8(file, format);
370    pFontInfo->inkInside = pcfGetINT8(file, format);
371    pFontInfo->inkMetrics = pcfGetINT8(file, format);
372    pFontInfo->drawDirection = pcfGetINT8(file, format);
373    pFontInfo->anamorphic = FALSE;
374    pFontInfo->cachable = TRUE;
375     /* natural alignment */ pcfGetINT8(file, format);
376    pFontInfo->fontAscent = pcfGetINT32(file, format);
377    pFontInfo->fontDescent = pcfGetINT32(file, format);
378    pFontInfo->maxOverlap = pcfGetINT32(file, format);
379    if (IS_EOF(file)) goto Bail;
380    if (!pcfGetMetric(file, format, &pFontInfo->minbounds))
381	goto Bail;
382    if (!pcfGetMetric(file, format, &pFontInfo->maxbounds))
383	goto Bail;
384    if (PCF_FORMAT_MATCH(format, PCF_ACCEL_W_INKBOUNDS)) {
385	if (!pcfGetMetric(file, format, &pFontInfo->ink_minbounds))
386	    goto Bail;
387	if (!pcfGetMetric(file, format, &pFontInfo->ink_maxbounds))
388	    goto Bail;
389    } else {
390	pFontInfo->ink_minbounds = pFontInfo->minbounds;
391	pFontInfo->ink_maxbounds = pFontInfo->maxbounds;
392    }
393    return TRUE;
394Bail:
395    return FALSE;
396}
397
398int
399pcfReadFont(FontPtr pFont, FontFilePtr file,
400	    int bit, int byte, int glyph, int scan)
401{
402    CARD32      format;
403    CARD32      size;
404    BitmapFontPtr  bitmapFont = 0;
405    int         i;
406    PCFTablePtr tables = 0;
407    int         ntables;
408    int         nmetrics;
409    int         nbitmaps;
410    int         sizebitmaps;
411    int         nink_metrics;
412    CharInfoPtr metrics = 0;
413    xCharInfo  *ink_metrics = 0;
414    char       *bitmaps = 0;
415    CharInfoPtr **encoding = 0;
416    int         nencoding = 0;
417    int         encodingOffset;
418    CARD32      bitmapSizes[GLYPHPADOPTIONS];
419    CARD32     *offsets = 0;
420    Bool	hasBDFAccelerators;
421
422    pFont->info.nprops = 0;
423    pFont->info.props = 0;
424    pFont->info.isStringProp=0;
425
426    if (!(tables = pcfReadTOC(file, &ntables)))
427	goto Bail;
428
429    /* properties */
430
431    if (!pcfGetProperties(&pFont->info, file, tables, ntables))
432	goto Bail;
433
434    /* Use the old accelerators if no BDF accelerators are in the file */
435
436    hasBDFAccelerators = pcfHasType (tables, ntables, PCF_BDF_ACCELERATORS);
437    if (!hasBDFAccelerators)
438	if (!pcfGetAccel (&pFont->info, file, tables, ntables, PCF_ACCELERATORS))
439	    goto Bail;
440
441    /* metrics */
442
443    if (!pcfSeekToType(file, tables, ntables, PCF_METRICS, &format, &size)) {
444	goto Bail;
445    }
446    format = pcfGetLSB32(file);
447    if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
448	    !PCF_FORMAT_MATCH(format, PCF_COMPRESSED_METRICS)) {
449	goto Bail;
450    }
451    if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
452	nmetrics = pcfGetINT32(file, format);
453    else
454	nmetrics = pcfGetINT16(file, format);
455    if (IS_EOF(file)) goto Bail;
456    if (nmetrics < 0 || nmetrics > INT32_MAX / sizeof(CharInfoRec)) {
457	pcfError("pcfReadFont(): invalid file format\n");
458	goto Bail;
459    }
460    metrics = mallocarray(nmetrics, sizeof(CharInfoRec));
461    if (!metrics) {
462	pcfError("pcfReadFont(): Couldn't allocate metrics (%d*%d)\n",
463		 nmetrics, (int) sizeof(CharInfoRec));
464	goto Bail;
465    }
466    for (i = 0; i < nmetrics; i++)
467	if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT)) {
468	    if (!pcfGetMetric(file, format, &(metrics + i)->metrics))
469		goto Bail;
470	} else {
471	    if (!pcfGetCompressedMetric(file, format, &(metrics + i)->metrics))
472		goto Bail;
473	}
474
475    /* bitmaps */
476
477    if (!pcfSeekToType(file, tables, ntables, PCF_BITMAPS, &format, &size))
478	goto Bail;
479    format = pcfGetLSB32(file);
480    if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
481	goto Bail;
482
483    nbitmaps = pcfGetINT32(file, format);
484    if (nbitmaps != nmetrics || IS_EOF(file))
485	goto Bail;
486    /* nmetrics is already ok, so nbitmap also is */
487    offsets = mallocarray(nbitmaps, sizeof(CARD32));
488    if (!offsets) {
489	pcfError("pcfReadFont(): Couldn't allocate offsets (%d*%d)\n",
490		 nbitmaps, (int) sizeof(CARD32));
491	goto Bail;
492    }
493    for (i = 0; i < nbitmaps; i++) {
494	offsets[i] = pcfGetINT32(file, format);
495	if (IS_EOF(file)) goto Bail;
496    }
497
498    for (i = 0; i < GLYPHPADOPTIONS; i++) {
499	bitmapSizes[i] = pcfGetINT32(file, format);
500	if (IS_EOF(file)) goto Bail;
501    }
502
503    sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX(format)];
504    /* guard against completely empty font */
505    bitmaps = malloc(sizebitmaps ? sizebitmaps : 1);
506    if (!bitmaps) {
507      pcfError("pcfReadFont(): Couldn't allocate bitmaps (%d)\n", sizebitmaps ? sizebitmaps : 1);
508	goto Bail;
509    }
510    FontFileRead(file, bitmaps, sizebitmaps);
511    if (IS_EOF(file)) goto Bail;
512    position += sizebitmaps;
513
514    if (PCF_BIT_ORDER(format) != bit)
515	BitOrderInvert((unsigned char *)bitmaps, sizebitmaps);
516    if ((PCF_BYTE_ORDER(format) == PCF_BIT_ORDER(format)) != (bit == byte)) {
517	switch (bit == byte ? PCF_SCAN_UNIT(format) : scan) {
518	case 1:
519	    break;
520	case 2:
521	    TwoByteSwap((unsigned char *)bitmaps, sizebitmaps);
522	    break;
523	case 4:
524	    FourByteSwap((unsigned char *)bitmaps, sizebitmaps);
525	    break;
526	}
527    }
528    if (PCF_GLYPH_PAD(format) != glyph) {
529	char       *padbitmaps;
530	int         sizepadbitmaps;
531	int         old,
532	            new;
533	xCharInfo  *metric;
534
535	sizepadbitmaps = bitmapSizes[PCF_SIZE_TO_INDEX(glyph)];
536	padbitmaps = malloc(sizepadbitmaps);
537	if (!padbitmaps) {
538          pcfError("pcfReadFont(): Couldn't allocate padbitmaps (%d)\n", sizepadbitmaps);
539	    goto Bail;
540	}
541	new = 0;
542	for (i = 0; i < nbitmaps; i++) {
543	    old = offsets[i];
544	    metric = &metrics[i].metrics;
545	    offsets[i] = new;
546	    new += RepadBitmap(bitmaps + old, padbitmaps + new,
547			       PCF_GLYPH_PAD(format), glyph,
548			  metric->rightSideBearing - metric->leftSideBearing,
549			       metric->ascent + metric->descent);
550	}
551	free(bitmaps);
552	bitmaps = padbitmaps;
553    }
554    for (i = 0; i < nbitmaps; i++)
555	metrics[i].bits = bitmaps + offsets[i];
556
557    free(offsets);
558    offsets = NULL;
559
560    /* ink metrics ? */
561
562    ink_metrics = NULL;
563    if (pcfSeekToType(file, tables, ntables, PCF_INK_METRICS, &format, &size)) {
564	format = pcfGetLSB32(file);
565	if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT) &&
566		!PCF_FORMAT_MATCH(format, PCF_COMPRESSED_METRICS)) {
567	    goto Bail;
568	}
569	if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
570	    nink_metrics = pcfGetINT32(file, format);
571	else
572	    nink_metrics = pcfGetINT16(file, format);
573	if (IS_EOF(file)) goto Bail;
574	if (nink_metrics != nmetrics)
575	    goto Bail;
576	/* nmetrics already checked */
577	ink_metrics = mallocarray(nink_metrics, sizeof(xCharInfo));
578	if (!ink_metrics) {
579            pcfError("pcfReadFont(): Couldn't allocate ink_metrics (%d*%d)\n",
580		     nink_metrics, (int) sizeof(xCharInfo));
581	    goto Bail;
582	}
583	for (i = 0; i < nink_metrics; i++)
584	    if (PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT)) {
585		if (!pcfGetMetric(file, format, ink_metrics + i))
586		    goto Bail;
587	    } else {
588		if (!pcfGetCompressedMetric(file, format, ink_metrics + i))
589		    goto Bail;
590	    }
591    }
592
593    /* encoding */
594
595    if (!pcfSeekToType(file, tables, ntables, PCF_BDF_ENCODINGS, &format, &size))
596	goto Bail;
597    format = pcfGetLSB32(file);
598    if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
599	goto Bail;
600
601    pFont->info.firstCol = pcfGetINT16(file, format);
602    pFont->info.lastCol = pcfGetINT16(file, format);
603    pFont->info.firstRow = pcfGetINT16(file, format);
604    pFont->info.lastRow = pcfGetINT16(file, format);
605    pFont->info.defaultCh = pcfGetINT16(file, format);
606    if (IS_EOF(file)) goto Bail;
607    if (pFont->info.firstCol > pFont->info.lastCol ||
608       pFont->info.firstRow > pFont->info.lastRow ||
609       pFont->info.lastCol-pFont->info.firstCol > 255) goto Bail;
610
611    nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
612	(pFont->info.lastRow - pFont->info.firstRow + 1);
613
614    encoding = calloc(NUM_SEGMENTS(nencoding), sizeof(CharInfoPtr*));
615    if (!encoding) {
616	pcfError("pcfReadFont(): Couldn't allocate encoding (%d*%d)\n",
617		 nencoding, (int) sizeof(CharInfoPtr));
618	goto Bail;
619    }
620
621    pFont->info.allExist = TRUE;
622    for (i = 0; i < nencoding; i++) {
623	encodingOffset = pcfGetINT16(file, format);
624	if (IS_EOF(file)) goto Bail;
625	if (encodingOffset == 0xFFFF) {
626	    pFont->info.allExist = FALSE;
627	} else {
628            if(!encoding[SEGMENT_MAJOR(i)]) {
629                encoding[SEGMENT_MAJOR(i)]=
630                    calloc(BITMAP_FONT_SEGMENT_SIZE, sizeof(CharInfoPtr));
631                if(!encoding[SEGMENT_MAJOR(i)])
632                    goto Bail;
633            }
634	    ACCESSENCODINGL(encoding, i) = metrics + encodingOffset;
635        }
636    }
637
638    /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
639
640    if (hasBDFAccelerators)
641	if (!pcfGetAccel (&pFont->info, file, tables, ntables, PCF_BDF_ACCELERATORS))
642	    goto Bail;
643
644    bitmapFont = malloc(sizeof *bitmapFont);
645    if (!bitmapFont) {
646	pcfError("pcfReadFont(): Couldn't allocate bitmapFont (%d)\n",
647		 (int) sizeof *bitmapFont);
648	goto Bail;
649    }
650
651    bitmapFont->version_num = PCF_FILE_VERSION;
652    bitmapFont->num_chars = nmetrics;
653    bitmapFont->num_tables = ntables;
654    bitmapFont->metrics = metrics;
655    bitmapFont->ink_metrics = ink_metrics;
656    bitmapFont->bitmaps = bitmaps;
657    bitmapFont->encoding = encoding;
658    bitmapFont->pDefault = (CharInfoPtr) 0;
659    if (pFont->info.defaultCh != (unsigned short) NO_SUCH_CHAR) {
660	unsigned int r,
661	            c,
662	            cols;
663
664	r = pFont->info.defaultCh >> 8;
665	c = pFont->info.defaultCh & 0xFF;
666	if (pFont->info.firstRow <= r && r <= pFont->info.lastRow &&
667		pFont->info.firstCol <= c && c <= pFont->info.lastCol) {
668	    cols = pFont->info.lastCol - pFont->info.firstCol + 1;
669	    r = r - pFont->info.firstRow;
670	    c = c - pFont->info.firstCol;
671	    bitmapFont->pDefault = ACCESSENCODING(encoding, r * cols + c);
672	}
673    }
674    bitmapFont->bitmapExtra = (BitmapExtraPtr) 0;
675    pFont->fontPrivate = (pointer) bitmapFont;
676    pFont->get_glyphs = bitmapGetGlyphs;
677    pFont->get_metrics = bitmapGetMetrics;
678    pFont->unload_font = pcfUnloadFont;
679    pFont->unload_glyphs = NULL;
680    pFont->bit = bit;
681    pFont->byte = byte;
682    pFont->glyph = glyph;
683    pFont->scan = scan;
684    free(tables);
685    return Successful;
686Bail:
687    free(ink_metrics);
688    if(encoding) {
689        for(i=0; i<NUM_SEGMENTS(nencoding); i++)
690            free(encoding[i]);
691    }
692    free(encoding);
693    free(bitmaps);
694    free(metrics);
695    free(pFont->info.props);
696    pFont->info.nprops = 0;
697    pFont->info.props = 0;
698    free (pFont->info.isStringProp);
699    free(bitmapFont);
700    free(tables);
701    free(offsets);
702    return AllocError;
703}
704
705int
706pcfReadFontInfo(FontInfoPtr pFontInfo, FontFilePtr file)
707{
708    PCFTablePtr tables;
709    int         ntables;
710    CARD32      format;
711    CARD32      size;
712    int         nencoding;
713    Bool	hasBDFAccelerators;
714
715    pFontInfo->isStringProp = NULL;
716    pFontInfo->props = NULL;
717    pFontInfo->nprops = 0;
718
719    if (!(tables = pcfReadTOC(file, &ntables)))
720	goto Bail;
721
722    /* properties */
723
724    if (!pcfGetProperties(pFontInfo, file, tables, ntables))
725	goto Bail;
726
727    /* Use the old accelerators if no BDF accelerators are in the file */
728
729    hasBDFAccelerators = pcfHasType (tables, ntables, PCF_BDF_ACCELERATORS);
730    if (!hasBDFAccelerators)
731	if (!pcfGetAccel (pFontInfo, file, tables, ntables, PCF_ACCELERATORS))
732	    goto Bail;
733
734    /* encoding */
735
736    if (!pcfSeekToType(file, tables, ntables, PCF_BDF_ENCODINGS, &format, &size))
737	goto Bail;
738    format = pcfGetLSB32(file);
739    if (!PCF_FORMAT_MATCH(format, PCF_DEFAULT_FORMAT))
740	goto Bail;
741
742    pFontInfo->firstCol = pcfGetINT16(file, format);
743    pFontInfo->lastCol = pcfGetINT16(file, format);
744    pFontInfo->firstRow = pcfGetINT16(file, format);
745    pFontInfo->lastRow = pcfGetINT16(file, format);
746    pFontInfo->defaultCh = pcfGetINT16(file, format);
747    if (IS_EOF(file)) goto Bail;
748    if (pFontInfo->firstCol > pFontInfo->lastCol ||
749       pFontInfo->firstRow > pFontInfo->lastRow ||
750       pFontInfo->lastCol-pFontInfo->firstCol > 255) goto Bail;
751
752    nencoding = (pFontInfo->lastCol - pFontInfo->firstCol + 1) *
753	(pFontInfo->lastRow - pFontInfo->firstRow + 1);
754
755    pFontInfo->allExist = TRUE;
756    while (nencoding--) {
757	if (pcfGetINT16(file, format) == 0xFFFF)
758	    pFontInfo->allExist = FALSE;
759	if (IS_EOF(file)) goto Bail;
760    }
761    if (IS_EOF(file)) goto Bail;
762
763    /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
764
765    if (hasBDFAccelerators)
766	if (!pcfGetAccel (pFontInfo, file, tables, ntables, PCF_BDF_ACCELERATORS))
767	    goto Bail;
768
769    free(tables);
770    return Successful;
771Bail:
772    pFontInfo->nprops = 0;
773    free (pFontInfo->props);
774    free (pFontInfo->isStringProp);
775    free(tables);
776    return AllocError;
777}
778
779static void
780pcfUnloadFont(FontPtr pFont)
781{
782    BitmapFontPtr  bitmapFont;
783    int i,nencoding;
784
785    bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
786    free(bitmapFont->ink_metrics);
787    if(bitmapFont->encoding) {
788        nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
789	    (pFont->info.lastRow - pFont->info.firstRow + 1);
790        for(i=0; i<NUM_SEGMENTS(nencoding); i++)
791            free(bitmapFont->encoding[i]);
792    }
793    free(bitmapFont->encoding);
794    free(bitmapFont->bitmaps);
795    free(bitmapFont->metrics);
796    free(pFont->info.isStringProp);
797    free(pFont->info.props);
798    free(bitmapFont);
799    DestroyFontRec(pFont);
800}
801