bdfread.c revision 96317916
1/************************************************************************
2Copyright 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
3
4                        All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of Digital not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22************************************************************************/
23
24/*
25
26Copyright 1994, 1998  The Open Group
27
28Permission to use, copy, modify, distribute, and sell this software and its
29documentation for any purpose is hereby granted without fee, provided that
30the above copyright notice appear in all copies and that both that
31copyright notice and this permission notice appear in supporting
32documentation.
33
34The above copyright notice and this permission notice shall be included
35in all copies or substantial portions of the Software.
36
37THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
38OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
39MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
40IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
41OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
42ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
43OTHER DEALINGS IN THE SOFTWARE.
44
45Except as contained in this notice, the name of The Open Group shall
46not be used in advertising or otherwise to promote the sale, use or
47other dealings in this Software without prior written authorization
48from The Open Group.
49
50*/
51
52#ifdef HAVE_CONFIG_H
53#include <config.h>
54#endif
55
56#include <ctype.h>
57#include <X11/fonts/fntfilst.h>
58#include <X11/fonts/fontutil.h>
59/* use bitmap structure */
60#include <X11/fonts/bitmap.h>
61#include <X11/fonts/bdfint.h>
62
63#if HAVE_STDINT_H
64#include <stdint.h>
65#elif !defined(INT32_MAX)
66#define INT32_MAX 0x7fffffff
67#endif
68
69#define INDICES 256
70#define MAXENCODING 0xFFFF
71#define BDFLINELEN  1024
72
73static Bool bdfPadToTerminal(FontPtr pFont);
74extern int  bdfFileLineNum;
75
76/***====================================================================***/
77
78static Bool
79bdfReadBitmap(CharInfoPtr pCI, FontFilePtr file, int bit, int byte,
80	      int glyph, int scan, CARD32 *sizes)
81{
82    int         widthBits,
83                widthBytes,
84                widthHexChars;
85    int         height,
86                row;
87    int         i,
88                inLineLen,
89                nextByte;
90    unsigned char *pInBits,
91               *picture,
92               *line = NULL;
93    unsigned char        lineBuf[BDFLINELEN];
94
95    widthBits = GLYPHWIDTHPIXELS(pCI);
96    height = GLYPHHEIGHTPIXELS(pCI);
97
98    widthBytes = BYTES_PER_ROW(widthBits, glyph);
99    if (widthBytes * height > 0) {
100	picture = malloc(widthBytes * height);
101	if (!picture) {
102          bdfError("Couldn't allocate picture (%d*%d)\n", widthBytes, height);
103	    goto BAILOUT;
104      }
105    } else
106	picture = NULL;
107    pCI->bits = (char *) picture;
108
109    if (sizes) {
110	for (i = 0; i < GLYPHPADOPTIONS; i++)
111	    sizes[i] += BYTES_PER_ROW(widthBits, (1 << i)) * height;
112    }
113    nextByte = 0;
114    widthHexChars = BYTES_PER_ROW(widthBits, 1);
115
116/* 5/31/89 (ef) -- hack, hack, hack.  what *am* I supposed to do with */
117/*		0 width characters? */
118
119    for (row = 0; row < height; row++) {
120	line = bdfGetLine(file, lineBuf, BDFLINELEN);
121	if (!line)
122	    break;
123
124	if (widthBits == 0) {
125	    if ((!line) || (bdfIsPrefix(line, "ENDCHAR")))
126		break;
127	    else
128		continue;
129	}
130	pInBits = line;
131	inLineLen = strlen((char *) pInBits);
132
133	if (inLineLen & 1) {
134	    bdfError("odd number of characters in hex encoding\n");
135	    line[inLineLen++] = '0';
136	    line[inLineLen] = '\0';
137	}
138	inLineLen >>= 1;
139	i = inLineLen;
140	if (i > widthHexChars)
141	    i = widthHexChars;
142	for (; i > 0; i--, pInBits += 2)
143	    picture[nextByte++] = bdfHexByte(pInBits);
144
145	/* pad if line is too short */
146	if (inLineLen < widthHexChars) {
147	    for (i = widthHexChars - inLineLen; i > 0; i--)
148		picture[nextByte++] = 0;
149	} else {
150	    unsigned char mask;
151
152	    mask = 0xff << (8 - (widthBits & 0x7));
153	    if (mask && picture[nextByte - 1] & ~mask) {
154		picture[nextByte - 1] &= mask;
155	    }
156	}
157
158	if (widthBytes > widthHexChars) {
159	    i = widthBytes - widthHexChars;
160	    while (i-- > 0)
161		picture[nextByte++] = 0;
162	}
163    }
164
165    if ((line && (!bdfIsPrefix(line, "ENDCHAR"))) || (height == 0))
166	line = bdfGetLine(file, lineBuf, BDFLINELEN);
167
168    if ((!line) || (!bdfIsPrefix(line, "ENDCHAR"))) {
169	bdfError("missing 'ENDCHAR'\n");
170	goto BAILOUT;
171    }
172    if (nextByte != height * widthBytes) {
173	bdfError("bytes != rows * bytes_per_row (%d != %d * %d)\n",
174		 nextByte, height, widthBytes);
175	goto BAILOUT;
176    }
177    if (picture != NULL) {
178	if (bit == LSBFirst)
179	    BitOrderInvert(picture, nextByte);
180	if (bit != byte) {
181	    if (scan == 2)
182		TwoByteSwap(picture, nextByte);
183	    else if (scan == 4)
184		FourByteSwap(picture, nextByte);
185	}
186    }
187    return (TRUE);
188BAILOUT:
189    if (picture)
190	free(picture);
191    pCI->bits = NULL;
192    return (FALSE);
193}
194
195/***====================================================================***/
196
197static Bool
198bdfSkipBitmap(FontFilePtr file, int height)
199{
200    unsigned char *line;
201    int         i = 0;
202    unsigned char        lineBuf[BDFLINELEN];
203
204    do {
205	line = bdfGetLine(file, lineBuf, BDFLINELEN);
206	i++;
207    } while (line && !bdfIsPrefix(line, "ENDCHAR") && i <= height);
208
209    if (i > 1 && line && !bdfIsPrefix(line, "ENDCHAR")) {
210	bdfError("Error in bitmap, missing 'ENDCHAR'\n");
211	return (FALSE);
212    }
213    return (TRUE);
214}
215
216/***====================================================================***/
217
218static void
219bdfFreeFontBits(FontPtr pFont)
220{
221    BitmapFontPtr  bitmapFont;
222    BitmapExtraPtr bitmapExtra;
223    int         i, nencoding;
224
225    bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
226    bitmapExtra = (BitmapExtraPtr) bitmapFont->bitmapExtra;
227    free(bitmapFont->ink_metrics);
228    if(bitmapFont->encoding) {
229        nencoding = (pFont->info.lastCol - pFont->info.firstCol + 1) *
230	    (pFont->info.lastRow - pFont->info.firstRow + 1);
231        for(i=0; i<NUM_SEGMENTS(nencoding); i++)
232            free(bitmapFont->encoding[i]);
233    }
234    free(bitmapFont->encoding);
235    for (i = 0; i < bitmapFont->num_chars; i++)
236	free(bitmapFont->metrics[i].bits);
237    free(bitmapFont->metrics);
238    if (bitmapExtra)
239    {
240	free (bitmapExtra->glyphNames);
241	free (bitmapExtra->sWidths);
242	free (bitmapExtra);
243    }
244    free(pFont->info.props);
245    free(bitmapFont);
246}
247
248
249static Bool
250bdfReadCharacters(FontFilePtr file, FontPtr pFont, bdfFileState *pState,
251		  int bit, int byte, int glyph, int scan)
252{
253    unsigned char *line;
254    register CharInfoPtr ci;
255    int         i,
256                ndx,
257                nchars,
258                nignored;
259    unsigned int char_row, char_col;
260    int         numEncodedGlyphs = 0;
261    CharInfoPtr *bdfEncoding[256];
262    BitmapFontPtr  bitmapFont;
263    BitmapExtraPtr bitmapExtra;
264    CARD32     *bitmapsSizes;
265    unsigned char        lineBuf[BDFLINELEN];
266    int         nencoding;
267
268    bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
269    bitmapExtra = (BitmapExtraPtr) bitmapFont->bitmapExtra;
270
271    if (bitmapExtra) {
272	bitmapsSizes = bitmapExtra->bitmapsSizes;
273	for (i = 0; i < GLYPHPADOPTIONS; i++)
274	    bitmapsSizes[i] = 0;
275    } else
276	bitmapsSizes = NULL;
277
278    bzero(bdfEncoding, sizeof(bdfEncoding));
279    bitmapFont->metrics = NULL;
280    ndx = 0;
281
282    line = bdfGetLine(file, lineBuf, BDFLINELEN);
283
284    if ((!line) || (sscanf((char *) line, "CHARS %d", &nchars) != 1)) {
285	bdfError("bad 'CHARS' in bdf file\n");
286	return (FALSE);
287    }
288    if (nchars < 1) {
289	bdfError("invalid number of CHARS in BDF file\n");
290	return (FALSE);
291    }
292    if (nchars > INT32_MAX / sizeof(CharInfoRec)) {
293	bdfError("Couldn't allocate pCI (%d*%d)\n", nchars,
294		 (int) sizeof(CharInfoRec));
295	goto BAILOUT;
296    }
297    ci = calloc(nchars, sizeof(CharInfoRec));
298    if (!ci) {
299	bdfError("Couldn't allocate pCI (%d*%d)\n", nchars,
300		 (int) sizeof(CharInfoRec));
301	goto BAILOUT;
302    }
303    bitmapFont->metrics = ci;
304
305    if (bitmapExtra) {
306	bitmapExtra->glyphNames = malloc(nchars * sizeof(Atom));
307	if (!bitmapExtra->glyphNames) {
308	    bdfError("Couldn't allocate glyphNames (%d*%d)\n",
309		     nchars, (int) sizeof(Atom));
310	    goto BAILOUT;
311	}
312    }
313    if (bitmapExtra) {
314	bitmapExtra->sWidths = malloc(nchars * sizeof(int));
315	if (!bitmapExtra->sWidths) {
316	    bdfError("Couldn't allocate sWidth (%d *%d)\n",
317		     nchars, (int) sizeof(int));
318	    return FALSE;
319	}
320    }
321    line = bdfGetLine(file, lineBuf, BDFLINELEN);
322    pFont->info.firstRow = 256;
323    pFont->info.lastRow = 0;
324    pFont->info.firstCol = 256;
325    pFont->info.lastCol = 0;
326    nignored = 0;
327    for (ndx = 0; (ndx < nchars) && (line) && (bdfIsPrefix(line, "STARTCHAR"));) {
328	int         t;
329	int         wx;		/* x component of width */
330	int         wy;		/* y component of width */
331	int         bw;		/* bounding-box width */
332	int         bh;		/* bounding-box height */
333	int         bl;		/* bounding-box left */
334	int         bb;		/* bounding-box bottom */
335	int         enc,
336	            enc2;	/* encoding */
337	unsigned char *p;	/* temp pointer into line */
338	char        charName[100];
339	int         ignore;
340
341	if (sscanf((char *) line, "STARTCHAR %99s", charName) != 1) {
342	    bdfError("bad character name in BDF file\n");
343	    goto BAILOUT;	/* bottom of function, free and return error */
344	}
345	if (bitmapExtra)
346	    bitmapExtra->glyphNames[ndx] = bdfForceMakeAtom(charName, NULL);
347
348	line = bdfGetLine(file, lineBuf, BDFLINELEN);
349	if (!line || (t = sscanf((char *) line, "ENCODING %d %d", &enc, &enc2)) < 1) {
350	    bdfError("bad 'ENCODING' in BDF file\n");
351	    goto BAILOUT;
352	}
353	if (enc < -1 || (t == 2 && enc2 < -1)) {
354	    bdfError("bad ENCODING value");
355	    goto BAILOUT;
356	}
357	if (t == 2 && enc == -1)
358	    enc = enc2;
359	ignore = 0;
360	if (enc == -1) {
361	    if (!bitmapExtra) {
362		nignored++;
363		ignore = 1;
364	    }
365	} else if (enc > MAXENCODING) {
366	    bdfError("char '%s' has encoding too large (%d)\n",
367		     charName, enc);
368	} else {
369	    char_row = (enc >> 8) & 0xFF;
370	    char_col = enc & 0xFF;
371	    if (char_row < pFont->info.firstRow)
372		pFont->info.firstRow = char_row;
373	    if (char_row > pFont->info.lastRow)
374		pFont->info.lastRow = char_row;
375	    if (char_col < pFont->info.firstCol)
376		pFont->info.firstCol = char_col;
377	    if (char_col > pFont->info.lastCol)
378		pFont->info.lastCol = char_col;
379	    if (bdfEncoding[char_row] == (CharInfoPtr *) NULL) {
380		bdfEncoding[char_row] = malloc(256 * sizeof(CharInfoPtr));
381		if (!bdfEncoding[char_row]) {
382		    bdfError("Couldn't allocate row %d of encoding (%d*%d)\n",
383			     char_row, INDICES, (int) sizeof(CharInfoPtr));
384		    goto BAILOUT;
385		}
386		for (i = 0; i < 256; i++)
387		    bdfEncoding[char_row][i] = (CharInfoPtr) NULL;
388	    }
389	    if (bdfEncoding[char_row] != NULL) {
390		bdfEncoding[char_row][char_col] = ci;
391		numEncodedGlyphs++;
392	    }
393	}
394
395	line = bdfGetLine(file, lineBuf, BDFLINELEN);
396	if ((!line) || (sscanf((char *) line, "SWIDTH %d %d", &wx, &wy) != 2)) {
397	    bdfError("bad 'SWIDTH'\n");
398	    goto BAILOUT;
399	}
400	if (wy != 0) {
401	    bdfError("SWIDTH y value must be zero\n");
402	    goto BAILOUT;
403	}
404	if (bitmapExtra)
405	    bitmapExtra->sWidths[ndx] = wx;
406
407/* 5/31/89 (ef) -- we should be able to ditch the character and recover */
408/*		from all of these.					*/
409
410	line = bdfGetLine(file, lineBuf, BDFLINELEN);
411	if ((!line) || (sscanf((char *) line, "DWIDTH %d %d", &wx, &wy) != 2)) {
412	    bdfError("bad 'DWIDTH'\n");
413	    goto BAILOUT;
414	}
415	if (wy != 0) {
416	    bdfError("DWIDTH y value must be zero\n");
417	    goto BAILOUT;
418	}
419	line = bdfGetLine(file, lineBuf, BDFLINELEN);
420	if ((!line) || (sscanf((char *) line, "BBX %d %d %d %d", &bw, &bh, &bl, &bb) != 4)) {
421	    bdfError("bad 'BBX'\n");
422	    goto BAILOUT;
423	}
424	if ((bh < 0) || (bw < 0)) {
425	    bdfError("character '%s' has a negative sized bitmap, %dx%d\n",
426		     charName, bw, bh);
427	    goto BAILOUT;
428	}
429	line = bdfGetLine(file, lineBuf, BDFLINELEN);
430	if ((line) && (bdfIsPrefix(line, "ATTRIBUTES"))) {
431	    for (p = line + strlen("ATTRIBUTES ");
432		    (*p == ' ') || (*p == '\t');
433		    p++)
434		 /* empty for loop */ ;
435	    ci->metrics.attributes = (bdfHexByte(p) << 8) + bdfHexByte(p + 2);
436	    line = bdfGetLine(file, lineBuf, BDFLINELEN);
437	} else
438	    ci->metrics.attributes = 0;
439
440	if (!line || !bdfIsPrefix(line, "BITMAP")) {
441	    bdfError("missing 'BITMAP'\n");
442	    goto BAILOUT;
443	}
444	/* collect data for generated properties */
445	if ((strlen(charName) == 1)) {
446	    if ((charName[0] >= '0') && (charName[0] <= '9')) {
447		pState->digitWidths += wx;
448		pState->digitCount++;
449	    } else if (charName[0] == 'x') {
450		pState->exHeight = (bh + bb) <= 0 ? bh : bh + bb;
451	    }
452	}
453	if (!ignore) {
454	    ci->metrics.leftSideBearing = bl;
455	    ci->metrics.rightSideBearing = bl + bw;
456	    ci->metrics.ascent = bh + bb;
457	    ci->metrics.descent = -bb;
458	    ci->metrics.characterWidth = wx;
459	    ci->bits = NULL;
460	    bdfReadBitmap(ci, file, bit, byte, glyph, scan, bitmapsSizes);
461	    ci++;
462	    ndx++;
463	} else
464	    bdfSkipBitmap(file, bh);
465
466	line = bdfGetLine(file, lineBuf, BDFLINELEN);	/* get STARTCHAR or
467							 * ENDFONT */
468    }
469
470    if (ndx + nignored != nchars) {
471	bdfError("%d too few characters\n", nchars - (ndx + nignored));
472	goto BAILOUT;
473    }
474    nchars = ndx;
475    bitmapFont->num_chars = nchars;
476    if ((line) && (bdfIsPrefix(line, "STARTCHAR"))) {
477	bdfError("more characters than specified\n");
478	goto BAILOUT;
479    }
480    if ((!line) || (!bdfIsPrefix(line, "ENDFONT"))) {
481	bdfError("missing 'ENDFONT'\n");
482	goto BAILOUT;
483    }
484    if (numEncodedGlyphs == 0)
485	bdfWarning("No characters with valid encodings\n");
486
487    nencoding = (pFont->info.lastRow - pFont->info.firstRow + 1) *
488	(pFont->info.lastCol - pFont->info.firstCol + 1);
489    bitmapFont->encoding = calloc(NUM_SEGMENTS(nencoding),sizeof(CharInfoPtr*));
490    if (!bitmapFont->encoding) {
491	bdfError("Couldn't allocate ppCI (%d,%d)\n",
492                 NUM_SEGMENTS(nencoding),
493                 (int) sizeof(CharInfoPtr*));
494	goto BAILOUT;
495    }
496    pFont->info.allExist = TRUE;
497    i = 0;
498    for (char_row = pFont->info.firstRow;
499	    char_row <= pFont->info.lastRow;
500	    char_row++) {
501	if (bdfEncoding[char_row] == (CharInfoPtr *) NULL) {
502	    pFont->info.allExist = FALSE;
503            i += pFont->info.lastCol - pFont->info.firstCol + 1;
504	} else {
505	    for (char_col = pFont->info.firstCol;
506		    char_col <= pFont->info.lastCol;
507		    char_col++) {
508		if (!bdfEncoding[char_row][char_col])
509		    pFont->info.allExist = FALSE;
510                else {
511                    if (!bitmapFont->encoding[SEGMENT_MAJOR(i)]) {
512                        bitmapFont->encoding[SEGMENT_MAJOR(i)]=
513                            calloc(BITMAP_FONT_SEGMENT_SIZE,
514                                   sizeof(CharInfoPtr));
515                        if (!bitmapFont->encoding[SEGMENT_MAJOR(i)])
516                            goto BAILOUT;
517                    }
518                    ACCESSENCODINGL(bitmapFont->encoding,i) =
519                        bdfEncoding[char_row][char_col];
520                }
521                i++;
522            }
523	}
524    }
525    for (i = 0; i < 256; i++)
526	if (bdfEncoding[i])
527	    free(bdfEncoding[i]);
528    return (TRUE);
529BAILOUT:
530    for (i = 0; i < 256; i++)
531	if (bdfEncoding[i])
532	    free(bdfEncoding[i]);
533    /* bdfFreeFontBits will clean up the rest */
534    return (FALSE);
535}
536
537/***====================================================================***/
538
539static Bool
540bdfReadHeader(FontFilePtr file, bdfFileState *pState)
541{
542    unsigned char *line;
543    char        namebuf[BDFLINELEN];
544    unsigned char        lineBuf[BDFLINELEN];
545
546    line = bdfGetLine(file, lineBuf, BDFLINELEN);
547    if (!line || sscanf((char *) line, "STARTFONT %s", namebuf) != 1 ||
548	    !bdfStrEqual(namebuf, "2.1")) {
549	bdfError("bad 'STARTFONT'\n");
550	return (FALSE);
551    }
552    line = bdfGetLine(file, lineBuf, BDFLINELEN);
553    if (!line || sscanf((char *) line, "FONT %[^\n]", pState->fontName) != 1) {
554	bdfError("bad 'FONT'\n");
555	return (FALSE);
556    }
557    line = bdfGetLine(file, lineBuf, BDFLINELEN);
558    if (!line || !bdfIsPrefix(line, "SIZE")) {
559	bdfError("missing 'SIZE'\n");
560	return (FALSE);
561    }
562    if (sscanf((char *) line, "SIZE %f%d%d", &pState->pointSize,
563	       &pState->resolution_x, &pState->resolution_y) != 3) {
564	bdfError("bad 'SIZE'\n");
565	return (FALSE);
566    }
567    if (pState->pointSize < 1 ||
568	pState->resolution_x < 1 || pState->resolution_y < 1) {
569	bdfError("SIZE values must be > 0\n");
570	return (FALSE);
571    }
572    line = bdfGetLine(file, lineBuf, BDFLINELEN);
573    if (!line || !bdfIsPrefix(line, "FONTBOUNDINGBOX")) {
574	bdfError("missing 'FONTBOUNDINGBOX'\n");
575	return (FALSE);
576    }
577    return (TRUE);
578}
579
580/***====================================================================***/
581
582static Bool
583bdfReadProperties(FontFilePtr file, FontPtr pFont, bdfFileState *pState)
584{
585    int         nProps, props_left,
586                nextProp;
587    char       *stringProps;
588    FontPropPtr props;
589    char        namebuf[BDFLINELEN],
590                secondbuf[BDFLINELEN],
591                thirdbuf[BDFLINELEN];
592    unsigned char *line;
593    unsigned char        lineBuf[BDFLINELEN];
594    BitmapFontPtr  bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
595
596    line = bdfGetLine(file, lineBuf, BDFLINELEN);
597    if (!line || !bdfIsPrefix(line, "STARTPROPERTIES")) {
598	bdfError("missing 'STARTPROPERTIES'\n");
599	return (FALSE);
600    }
601    if (sscanf((char *) line, "STARTPROPERTIES %d", &nProps) != 1) {
602	bdfError("bad 'STARTPROPERTIES'\n");
603	return (FALSE);
604    }
605    pFont->info.isStringProp = NULL;
606    pFont->info.props = NULL;
607    pFont->info.nprops = 0;
608
609    stringProps = malloc((nProps + BDF_GENPROPS) * sizeof(char));
610    pFont->info.isStringProp = stringProps;
611    if (stringProps == NULL) {
612	bdfError("Couldn't allocate stringProps (%d*%d)\n",
613		 (nProps + BDF_GENPROPS), (int) sizeof(Bool));
614	goto BAILOUT;
615    }
616    pFont->info.props = props = calloc(nProps + BDF_GENPROPS,
617				       sizeof(FontPropRec));
618    if (props == NULL) {
619	bdfError("Couldn't allocate props (%d*%d)\n", nProps + BDF_GENPROPS,
620						   (int) sizeof(FontPropRec));
621	goto BAILOUT;
622    }
623
624    nextProp = 0;
625    props_left = nProps;
626    while (props_left-- > 0) {
627	line = bdfGetLine(file, lineBuf, BDFLINELEN);
628	if (line == NULL || bdfIsPrefix(line, "ENDPROPERTIES")) {
629	    bdfError("\"STARTPROPERTIES %d\" followed by only %d properties\n",
630		     nProps, nProps - props_left - 1);
631	    goto BAILOUT;
632	}
633	while (*line && isspace(*line))
634	    line++;
635
636	switch (sscanf((char *) line, "%s%s%s", namebuf, secondbuf, thirdbuf)) {
637	default:
638	    bdfError("missing '%s' parameter value\n", namebuf);
639	    goto BAILOUT;
640
641	case 2:
642	    /*
643	     * Possibilites include: valid quoted string with no white space
644	     * valid integer value invalid value
645	     */
646	    if (secondbuf[0] == '"') {
647		stringProps[nextProp] = TRUE;
648		props[nextProp].value =
649		    bdfGetPropertyValue((char *)line + strlen(namebuf) + 1);
650		if (!props[nextProp].value)
651		    goto BAILOUT;
652		break;
653	    } else if (bdfIsInteger(secondbuf)) {
654		stringProps[nextProp] = FALSE;
655		props[nextProp].value = atoi(secondbuf);
656		break;
657	    } else {
658		bdfError("invalid '%s' parameter value\n", namebuf);
659		goto BAILOUT;
660	    }
661
662	case 3:
663	    /*
664	     * Possibilites include: valid quoted string with some white space
665	     * invalid value (reject even if second string is integer)
666	     */
667	    if (secondbuf[0] == '"') {
668		stringProps[nextProp] = TRUE;
669		props[nextProp].value =
670		    bdfGetPropertyValue((char *)line + strlen(namebuf) + 1);
671		if (!props[nextProp].value)
672		    goto BAILOUT;
673		break;
674	    } else {
675		bdfError("invalid '%s' parameter value\n", namebuf);
676		goto BAILOUT;
677	    }
678	}
679	props[nextProp].name = bdfForceMakeAtom(namebuf, NULL);
680	if (props[nextProp].name == None) {
681	    bdfError("Empty property name.\n");
682	    goto BAILOUT;
683	}
684	if (!bdfSpecialProperty(pFont, &props[nextProp],
685				stringProps[nextProp], pState))
686	    nextProp++;
687    }
688
689    line = bdfGetLine(file, lineBuf, BDFLINELEN);
690    if (!line || !bdfIsPrefix(line, "ENDPROPERTIES")) {
691	bdfError("missing 'ENDPROPERTIES'\n");
692	goto BAILOUT;
693    }
694    if (!pState->haveFontAscent || !pState->haveFontDescent) {
695	bdfError("missing 'FONT_ASCENT' or 'FONT_DESCENT' properties\n");
696	goto BAILOUT;
697    }
698    if (bitmapFont->bitmapExtra) {
699	bitmapFont->bitmapExtra->info.fontAscent = pFont->info.fontAscent;
700	bitmapFont->bitmapExtra->info.fontDescent = pFont->info.fontDescent;
701    }
702    if (!pState->pointSizeProp) {
703	props[nextProp].name = bdfForceMakeAtom("POINT_SIZE", NULL);
704	props[nextProp].value = (INT32) (pState->pointSize * 10.0);
705	stringProps[nextProp] = FALSE;
706	pState->pointSizeProp = &props[nextProp];
707	nextProp++;
708    }
709    if (!pState->fontProp) {
710	props[nextProp].name = bdfForceMakeAtom("FONT", NULL);
711	props[nextProp].value = (INT32) bdfForceMakeAtom(pState->fontName, NULL);
712	stringProps[nextProp] = TRUE;
713	pState->fontProp = &props[nextProp];
714	nextProp++;
715    }
716    if (!pState->weightProp) {
717	props[nextProp].name = bdfForceMakeAtom("WEIGHT", NULL);
718	props[nextProp].value = -1;	/* computed later */
719	stringProps[nextProp] = FALSE;
720	pState->weightProp = &props[nextProp];
721	nextProp++;
722    }
723    if (!pState->resolutionProp &&
724	pState->resolution_x == pState->resolution_y) {
725	props[nextProp].name = bdfForceMakeAtom("RESOLUTION", NULL);
726	props[nextProp].value = (INT32) ((pState->resolution_x * 100.0) / 72.27);
727	stringProps[nextProp] = FALSE;
728	pState->resolutionProp = &props[nextProp];
729	nextProp++;
730    }
731    if (!pState->resolutionXProp) {
732	props[nextProp].name = bdfForceMakeAtom("RESOLUTION_X", NULL);
733	props[nextProp].value = (INT32) pState->resolution_x;
734	stringProps[nextProp] = FALSE;
735	pState->resolutionProp = &props[nextProp];
736	nextProp++;
737    }
738    if (!pState->resolutionYProp) {
739	props[nextProp].name = bdfForceMakeAtom("RESOLUTION_Y", NULL);
740	props[nextProp].value = (INT32) pState->resolution_y;
741	stringProps[nextProp] = FALSE;
742	pState->resolutionProp = &props[nextProp];
743	nextProp++;
744    }
745    if (!pState->xHeightProp) {
746	props[nextProp].name = bdfForceMakeAtom("X_HEIGHT", NULL);
747	props[nextProp].value = -1;	/* computed later */
748	stringProps[nextProp] = FALSE;
749	pState->xHeightProp = &props[nextProp];
750	nextProp++;
751    }
752    if (!pState->quadWidthProp) {
753	props[nextProp].name = bdfForceMakeAtom("QUAD_WIDTH", NULL);
754	props[nextProp].value = -1;	/* computed later */
755	stringProps[nextProp] = FALSE;
756	pState->quadWidthProp = &props[nextProp];
757	nextProp++;
758    }
759    pFont->info.nprops = nextProp;
760    return (TRUE);
761BAILOUT:
762    if (pFont->info.isStringProp) {
763	free(pFont->info.isStringProp);
764	pFont->info.isStringProp = NULL;
765    }
766    if (pFont->info.props) {
767	free(pFont->info.props);
768	pFont->info.props = NULL;
769    }
770    while (line && bdfIsPrefix(line, "ENDPROPERTIES"))
771	line = bdfGetLine(file, lineBuf, BDFLINELEN);
772    return (FALSE);
773}
774
775/***====================================================================***/
776
777static void
778bdfUnloadFont(FontPtr pFont)
779{
780    bdfFreeFontBits (pFont);
781    DestroyFontRec(pFont);
782}
783
784int
785bdfReadFont(FontPtr pFont, FontFilePtr file,
786	    int bit, int byte, int glyph, int scan)
787{
788    bdfFileState state;
789    xCharInfo  *min,
790               *max;
791    BitmapFontPtr  bitmapFont;
792
793    pFont->fontPrivate = 0;
794
795    bzero(&state, sizeof(bdfFileState));
796    bdfFileLineNum = 0;
797
798    if (!bdfReadHeader(file, &state))
799	goto BAILOUT;
800
801    bitmapFont = calloc(1, sizeof(BitmapFontRec));
802    if (!bitmapFont) {
803	bdfError("Couldn't allocate bitmapFontRec (%d)\n",
804		 (int) sizeof(BitmapFontRec));
805	goto BAILOUT;
806    }
807
808    pFont->fontPrivate = (pointer) bitmapFont;
809    bitmapFont->metrics = 0;
810    bitmapFont->ink_metrics = 0;
811    bitmapFont->bitmaps = 0;
812    bitmapFont->encoding = 0;
813    bitmapFont->pDefault = NULL;
814
815    bitmapFont->bitmapExtra = calloc(1, sizeof(BitmapExtraRec));
816    if (!bitmapFont->bitmapExtra) {
817	bdfError("Couldn't allocate bitmapExtra (%d)\n",
818		 (int) sizeof(BitmapExtraRec));
819        goto BAILOUT;
820    }
821
822    bitmapFont->bitmapExtra->glyphNames = 0;
823    bitmapFont->bitmapExtra->sWidths = 0;
824
825    if (!bdfReadProperties(file, pFont, &state))
826	goto BAILOUT;
827
828    if (!bdfReadCharacters(file, pFont, &state, bit, byte, glyph, scan))
829	goto BAILOUT;
830
831    if (state.haveDefaultCh) {
832	unsigned int r, c, cols;
833
834	r = pFont->info.defaultCh >> 8;
835	c = pFont->info.defaultCh & 0xFF;
836	if (pFont->info.firstRow <= r && r <= pFont->info.lastRow &&
837		pFont->info.firstCol <= c && c <= pFont->info.lastCol) {
838	    cols = pFont->info.lastCol - pFont->info.firstCol + 1;
839	    r = r - pFont->info.firstRow;
840	    c = c - pFont->info.firstCol;
841	    bitmapFont->pDefault = ACCESSENCODING(bitmapFont->encoding,
842                                                 r * cols + c);
843	}
844    }
845    pFont->bit = bit;
846    pFont->byte = byte;
847    pFont->glyph = glyph;
848    pFont->scan = scan;
849    pFont->info.anamorphic = FALSE;
850    pFont->info.cachable = TRUE;
851    bitmapComputeFontBounds(pFont);
852    if (FontCouldBeTerminal(&pFont->info)) {
853	bdfPadToTerminal(pFont);
854	bitmapComputeFontBounds(pFont);
855    }
856    FontComputeInfoAccelerators(&pFont->info);
857    if (bitmapFont->bitmapExtra)
858	FontComputeInfoAccelerators(&bitmapFont->bitmapExtra->info);
859    if (pFont->info.constantMetrics) {
860      if (!bitmapAddInkMetrics(pFont)) {
861        bdfError("Failed to add bitmap ink metrics\n");
862        goto BAILOUT;
863      }
864    }
865    if (bitmapFont->bitmapExtra)
866	bitmapFont->bitmapExtra->info.inkMetrics = pFont->info.inkMetrics;
867
868    bitmapComputeFontInkBounds(pFont);
869/*    ComputeFontAccelerators (pFont); */
870
871    /* generate properties */
872    min = &pFont->info.ink_minbounds;
873    max = &pFont->info.ink_maxbounds;
874    if (state.xHeightProp && (state.xHeightProp->value == -1))
875	state.xHeightProp->value = state.exHeight ?
876	    state.exHeight : min->ascent;
877
878    if (state.quadWidthProp && (state.quadWidthProp->value == -1))
879	state.quadWidthProp->value = state.digitCount ?
880	    (INT32) (state.digitWidths / state.digitCount) :
881	    (min->characterWidth + max->characterWidth) / 2;
882
883    if (state.weightProp && (state.weightProp->value == -1))
884	state.weightProp->value = bitmapComputeWeight(pFont);
885
886    pFont->get_glyphs = bitmapGetGlyphs;
887    pFont->get_metrics = bitmapGetMetrics;
888    pFont->unload_font = bdfUnloadFont;
889    pFont->unload_glyphs = NULL;
890    return Successful;
891BAILOUT:
892    if (pFont->fontPrivate)
893	bdfFreeFontBits (pFont);
894    return AllocError;
895}
896
897int
898bdfReadFontInfo(FontInfoPtr pFontInfo, FontFilePtr file)
899{
900    FontRec     font;
901    int         ret;
902
903    bzero(&font, sizeof (FontRec));
904
905    ret = bdfReadFont(&font, file, MSBFirst, LSBFirst, 1, 1);
906    if (ret == Successful) {
907	*pFontInfo = font.info;
908	font.info.props = 0;
909	font.info.isStringProp = 0;
910	font.info.nprops = 0;
911	bdfFreeFontBits (&font);
912    }
913    return ret;
914}
915
916static Bool
917bdfPadToTerminal(FontPtr pFont)
918{
919    BitmapFontPtr  bitmapFont;
920    BitmapExtraPtr bitmapExtra;
921    int         i;
922    int         new_size;
923    CharInfoRec new;
924    int         w,
925                h;
926
927    bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
928
929    bzero(&new, sizeof(CharInfoRec));
930    new.metrics.ascent = pFont->info.fontAscent;
931    new.metrics.descent = pFont->info.fontDescent;
932    new.metrics.leftSideBearing = 0;
933    new.metrics.rightSideBearing = pFont->info.minbounds.characterWidth;
934    new.metrics.characterWidth = new.metrics.rightSideBearing;
935    new_size = BYTES_FOR_GLYPH(&new, pFont->glyph);
936
937    for (i = 0; i < bitmapFont->num_chars; i++) {
938	new.bits = malloc(new_size);
939	if (!new.bits) {
940          bdfError("Couldn't allocate bits (%d)\n", new_size);
941	    return FALSE;
942	}
943	FontCharReshape(pFont, &bitmapFont->metrics[i], &new);
944        new.metrics.attributes = bitmapFont->metrics[i].metrics.attributes;
945	free(bitmapFont->metrics[i].bits);
946	bitmapFont->metrics[i] = new;
947    }
948    bitmapExtra = bitmapFont->bitmapExtra;
949    if (bitmapExtra) {
950	w = GLYPHWIDTHPIXELS(&new);
951	h = GLYPHHEIGHTPIXELS(&new);
952	for (i = 0; i < GLYPHPADOPTIONS; i++)
953	    bitmapExtra->bitmapsSizes[i] = bitmapFont->num_chars *
954		(BYTES_PER_ROW(w, 1 << i) * h);
955    }
956    return TRUE;
957}
958