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