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