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