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