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