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