snfread.c revision 41c30155
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/bitmap.h>
59#include "snfstr.h"
60
61#include <stdarg.h>
62
63static void _X_ATTRIBUTE_PRINTF(1, 2)
64snfError(const char* message, ...)
65{
66    va_list args;
67
68    va_start(args, message);
69
70    fprintf(stderr, "SNF Error: ");
71    vfprintf(stderr, message, args);
72    va_end(args);
73}
74
75static void snfUnloadFont(FontPtr pFont);
76
77static int
78snfReadCharInfo(FontFilePtr file, CharInfoPtr charInfo, char *base)
79{
80    snfCharInfoRec snfCharInfo;
81
82#define Width(m)    ((m).rightSideBearing - (m).leftSideBearing)
83#define Height(m)   ((m).ascent + (m).descent)
84
85    if (FontFileRead(file, (char *) &snfCharInfo, sizeof snfCharInfo) !=
86	    sizeof(snfCharInfo)) {
87	return BadFontName;
88    }
89    charInfo->metrics = snfCharInfo.metrics;
90    if (snfCharInfo.exists)
91	charInfo->bits = base + snfCharInfo.byteOffset;
92    else
93	charInfo->bits = 0;
94    return Successful;
95}
96
97static int
98snfReadxCharInfo(FontFilePtr file, xCharInfo *charInfo)
99{
100    snfCharInfoRec snfCharInfo;
101
102    if (FontFileRead(file, (char *) &snfCharInfo, sizeof snfCharInfo) !=
103	    sizeof(snfCharInfo)) {
104	return BadFontName;
105    }
106    *charInfo = snfCharInfo.metrics;
107    return Successful;
108}
109
110static void
111snfCopyInfo(snfFontInfoPtr snfInfo, FontInfoPtr pFontInfo)
112{
113    pFontInfo->firstCol = snfInfo->firstCol;
114    pFontInfo->lastCol = snfInfo->lastCol;
115    pFontInfo->firstRow = snfInfo->firstRow;
116    pFontInfo->lastRow = snfInfo->lastRow;
117    pFontInfo->defaultCh = snfInfo->chDefault;
118    pFontInfo->noOverlap = snfInfo->noOverlap;
119    pFontInfo->terminalFont = snfInfo->terminalFont;
120    pFontInfo->constantMetrics = snfInfo->constantMetrics;
121    pFontInfo->constantWidth = snfInfo->constantWidth;
122    pFontInfo->inkInside = snfInfo->inkInside;
123    pFontInfo->inkMetrics = snfInfo->inkMetrics;
124    pFontInfo->allExist = snfInfo->allExist;
125    pFontInfo->drawDirection = snfInfo->drawDirection;
126    pFontInfo->anamorphic = FALSE;
127    pFontInfo->cachable = TRUE;
128    pFontInfo->maxOverlap = 0;
129    pFontInfo->minbounds = snfInfo->minbounds.metrics;
130    pFontInfo->maxbounds = snfInfo->maxbounds.metrics;
131    pFontInfo->fontAscent = snfInfo->fontAscent;
132    pFontInfo->fontDescent = snfInfo->fontDescent;
133    pFontInfo->nprops = snfInfo->nProps;
134}
135
136static int
137snfReadProps(snfFontInfoPtr snfInfo, FontInfoPtr pFontInfo, FontFilePtr file)
138{
139    char       *strings;
140    FontPropPtr pfp;
141    snfFontPropPtr psnfp;
142    char       *propspace;
143    int         bytestoalloc;
144    int         i;
145
146    bytestoalloc = snfInfo->nProps * sizeof(snfFontPropRec) +
147	BYTESOFSTRINGINFO(snfInfo);
148    propspace = malloc(bytestoalloc);
149    if (!propspace) {
150      snfError("snfReadProps(): Couldn't allocate propspace (%d)\n", bytestoalloc);
151	return AllocError;
152    }
153
154    if (FontFileRead(file, propspace, bytestoalloc) != bytestoalloc) {
155	free(propspace);
156	return BadFontName;
157    }
158    psnfp = (snfFontPropPtr) propspace;
159
160    strings = propspace + BYTESOFPROPINFO(snfInfo);
161
162    for (i = 0, pfp = pFontInfo->props; i < snfInfo->nProps; i++, pfp++, psnfp++) {
163	pfp->name = MakeAtom(&strings[psnfp->name],
164			     (unsigned) strlen(&strings[psnfp->name]), 1);
165	pFontInfo->isStringProp[i] = psnfp->indirect;
166	if (psnfp->indirect)
167	    pfp->value = (INT32) MakeAtom(&strings[psnfp->value],
168			       (unsigned) strlen(&strings[psnfp->value]), 1);
169	else
170	    pfp->value = psnfp->value;
171    }
172
173    free(propspace);
174    return Successful;
175}
176
177static int
178snfReadHeader(snfFontInfoPtr snfInfo, FontFilePtr file)
179{
180    if (FontFileRead(file, (char *) snfInfo, sizeof *snfInfo) != sizeof *snfInfo)
181	return BadFontName;
182
183    if (snfInfo->version1 != FONT_FILE_VERSION ||
184	    snfInfo->version2 != FONT_FILE_VERSION)
185	return BadFontName;
186    return Successful;
187}
188
189static int  snf_set;
190static int  snf_bit, snf_byte, snf_glyph, snf_scan;
191
192void
193SnfSetFormat (int bit, int byte, int glyph, int scan)
194{
195    snf_bit = bit;
196    snf_byte = byte;
197    snf_glyph = glyph;
198    snf_scan = scan;
199    snf_set = 1;
200}
201
202static void
203SnfGetFormat (int *bit, int *byte, int *glyph, int *scan)
204{
205    if (!snf_set)
206	FontDefaultFormat (&snf_bit, &snf_byte, &snf_glyph, &snf_scan);
207    *bit = snf_bit;
208    *byte = snf_byte;
209    *glyph = snf_glyph;
210    *scan = snf_scan;
211}
212
213int
214snfReadFont(FontPtr pFont, FontFilePtr file,
215	    int bit, int byte, int glyph, int scan)
216{
217    snfFontInfoRec fi;
218    unsigned    bytestoalloc;
219    int         i, j;
220    char       *fontspace;
221    BitmapFontPtr  bitmapFont;
222    int         num_chars;
223    int         bitmapsSize;
224    int         ret;
225    int         metrics_off;
226    int         encoding_off;
227    int         props_off;
228    int         isStringProp_off;
229    int         ink_off;
230    char	*bitmaps;
231    int		def_bit, def_byte, def_glyph, def_scan;
232
233    ret = snfReadHeader(&fi, file);
234    if (ret != Successful)
235	return ret;
236
237    SnfGetFormat (&def_bit, &def_byte, &def_glyph, &def_scan);
238
239    /*
240     * we'll allocate one chunk of memory and split it among the various parts
241     * of the font:
242     *
243     * BitmapFontRec CharInfoRec's Glyphs Encoding DIX Properties Ink CharInfoRec's
244     *
245     * If the glyphpad is not the same as the font file, then the glyphs
246     * are allocated separately, to be later realloc'ed when we know
247     * how big to make them.
248     */
249
250    bitmapsSize = BYTESOFGLYPHINFO(&fi);
251    num_chars = n2dChars(&fi);
252    bytestoalloc = sizeof(BitmapFontRec);	/* bitmapFont */
253    metrics_off = bytestoalloc;
254    bytestoalloc += num_chars * sizeof(CharInfoRec);	/* metrics */
255    encoding_off = bytestoalloc;
256    bytestoalloc += NUM_SEGMENTS(num_chars) * sizeof(CharInfoPtr**);
257                                                /* encoding */
258    props_off = bytestoalloc;
259    bytestoalloc += fi.nProps * sizeof(FontPropRec);	/* props */
260    isStringProp_off = bytestoalloc;
261    bytestoalloc += fi.nProps * sizeof(char);	/* isStringProp */
262    bytestoalloc = (bytestoalloc + 3) & ~3;
263    ink_off = bytestoalloc;
264    if (fi.inkMetrics)
265	bytestoalloc += num_chars * sizeof(xCharInfo);	/* ink_metrics */
266
267    fontspace = malloc(bytestoalloc);
268    if (!fontspace) {
269      snfError("snfReadFont(): Couldn't allocate fontspace (%d)\n", bytestoalloc);
270	return AllocError;
271    }
272    bitmaps = malloc (bitmapsSize);
273    if (!bitmaps)
274    {
275      snfError("snfReadFont(): Couldn't allocate bitmaps (%d)\n", bitmapsSize);
276	free (fontspace);
277	return AllocError;
278    }
279    /*
280     * now fix up pointers
281     */
282
283    bitmapFont = (BitmapFontPtr) fontspace;
284    bitmapFont->num_chars = num_chars;
285    bitmapFont->metrics = (CharInfoPtr) (fontspace + metrics_off);
286    bitmapFont->encoding = (CharInfoPtr **) (fontspace + encoding_off);
287    bitmapFont->bitmaps = bitmaps;
288    bitmapFont->pDefault = NULL;
289    bitmapFont->bitmapExtra = NULL;
290    pFont->info.props = (FontPropPtr) (fontspace + props_off);
291    pFont->info.isStringProp = (char *) (fontspace + isStringProp_off);
292    if (fi.inkMetrics)
293	bitmapFont->ink_metrics = (xCharInfo *) (fontspace + ink_off);
294    else
295	bitmapFont->ink_metrics = 0;
296
297    /*
298     * read the CharInfo
299     */
300
301    ret = Successful;
302    memset(bitmapFont->encoding, 0,
303           NUM_SEGMENTS(num_chars)*sizeof(CharInfoPtr*));
304    for (i = 0; ret == Successful && i < num_chars; i++) {
305	ret = snfReadCharInfo(file, &bitmapFont->metrics[i], bitmaps);
306	if (bitmapFont->metrics[i].bits) {
307            if (!bitmapFont->encoding[SEGMENT_MAJOR(i)]) {
308                bitmapFont->encoding[SEGMENT_MAJOR(i)]=
309                    calloc(BITMAP_FONT_SEGMENT_SIZE, sizeof(CharInfoPtr));
310                if (!bitmapFont->encoding[SEGMENT_MAJOR(i)]) {
311                    ret = AllocError;
312                    break;
313                }
314            }
315            ACCESSENCODINGL(bitmapFont->encoding,i) = &bitmapFont->metrics[i];
316        }
317    }
318
319    if (ret != Successful) {
320	free(bitmaps);
321        if(bitmapFont->encoding) {
322            for(j=0; j<SEGMENT_MAJOR(i); j++)
323                free(bitmapFont->encoding[i]);
324        }
325	free(fontspace);
326	return ret;
327    }
328    /*
329     * read the glyphs
330     */
331
332    if (FontFileRead(file, bitmaps, bitmapsSize) != bitmapsSize) {
333	free(bitmaps);
334	free(fontspace);
335	return BadFontName;
336    }
337
338    if (def_bit != bit)
339	BitOrderInvert((unsigned char *)bitmaps, bitmapsSize);
340    if ((def_byte == def_bit) != (bit == byte)) {
341	switch (bit == byte ? def_scan : scan) {
342	case 1:
343	    break;
344	case 2:
345	    TwoByteSwap((unsigned char *)bitmaps, bitmapsSize);
346	    break;
347	case 4:
348	    FourByteSwap((unsigned char *)bitmaps, bitmapsSize);
349	    break;
350	}
351    }
352    if (def_glyph != glyph) {
353	char	    *padbitmaps;
354	int         sizepadbitmaps;
355	int	    sizechar;
356	CharInfoPtr metric;
357
358	sizepadbitmaps = 0;
359	metric = bitmapFont->metrics;
360	for (i = 0; i < num_chars; i++)
361	{
362	    if (metric->bits)
363		sizepadbitmaps += BYTES_FOR_GLYPH(metric,glyph);
364	    metric++;
365	}
366	padbitmaps = malloc(sizepadbitmaps);
367	if (!padbitmaps) {
368	    snfError("snfReadFont(): Couldn't allocate padbitmaps (%d)\n", sizepadbitmaps);
369	    free (bitmaps);
370	    free (fontspace);
371	    return AllocError;
372	}
373	metric = bitmapFont->metrics;
374	bitmapFont->bitmaps = padbitmaps;
375	for (i = 0; i < num_chars; i++) {
376	    sizechar = RepadBitmap(metric->bits, padbitmaps,
377			       def_glyph, glyph,
378			       metric->metrics.rightSideBearing -
379			       metric->metrics.leftSideBearing,
380			       metric->metrics.ascent + metric->metrics.descent);
381	    metric->bits = padbitmaps;
382	    padbitmaps += sizechar;
383	    metric++;
384	}
385	free(bitmaps);
386    }
387
388    /* now read and atom'ize properties */
389
390    ret = snfReadProps(&fi, &pFont->info, file);
391    if (ret != Successful) {
392	free(fontspace);
393	return ret;
394    }
395    snfCopyInfo(&fi, &pFont->info);
396
397    /* finally, read the ink metrics if the exist */
398
399    if (fi.inkMetrics) {
400	ret = Successful;
401	ret = snfReadxCharInfo(file, &pFont->info.ink_minbounds);
402	ret = snfReadxCharInfo(file, &pFont->info.ink_maxbounds);
403	for (i = 0; ret == Successful && i < num_chars; i++)
404	    ret = snfReadxCharInfo(file, &bitmapFont->ink_metrics[i]);
405	if (ret != Successful) {
406	    free(fontspace);
407	    return ret;
408	}
409    } else {
410	pFont->info.ink_minbounds = pFont->info.minbounds;
411	pFont->info.ink_maxbounds = pFont->info.maxbounds;
412    }
413
414    if (pFont->info.defaultCh != (unsigned short) NO_SUCH_CHAR) {
415	unsigned int r,
416	            c,
417	            cols;
418
419	r = pFont->info.defaultCh >> 8;
420	c = pFont->info.defaultCh & 0xFF;
421	if (pFont->info.firstRow <= r && r <= pFont->info.lastRow &&
422		pFont->info.firstCol <= c && c <= pFont->info.lastCol) {
423	    cols = pFont->info.lastCol - pFont->info.firstCol + 1;
424	    r = r - pFont->info.firstRow;
425	    c = c - pFont->info.firstCol;
426	    bitmapFont->pDefault = &bitmapFont->metrics[r * cols + c];
427	}
428    }
429    bitmapFont->bitmapExtra = (BitmapExtraPtr) 0;
430    pFont->fontPrivate = (pointer) bitmapFont;
431    pFont->get_glyphs = bitmapGetGlyphs;
432    pFont->get_metrics = bitmapGetMetrics;
433    pFont->unload_font = snfUnloadFont;
434    pFont->unload_glyphs = NULL;
435    pFont->bit = bit;
436    pFont->byte = byte;
437    pFont->glyph = glyph;
438    pFont->scan = scan;
439    return Successful;
440}
441
442int
443snfReadFontInfo(FontInfoPtr pFontInfo, FontFilePtr file)
444{
445    int         ret;
446    snfFontInfoRec fi;
447    int         bytestoskip;
448    int         num_chars;
449
450    ret = snfReadHeader(&fi, file);
451    if (ret != Successful)
452	return ret;
453    snfCopyInfo(&fi, pFontInfo);
454
455    pFontInfo->props = malloc(fi.nProps * sizeof(FontPropRec));
456    if (!pFontInfo->props) {
457	snfError("snfReadFontInfo(): Couldn't allocate props (%d*%d)\n",
458		 fi.nProps, (int) sizeof(FontPropRec));
459	return AllocError;
460    }
461    pFontInfo->isStringProp = malloc(fi.nProps * sizeof(char));
462    if (!pFontInfo->isStringProp) {
463	snfError("snfReadFontInfo(): Couldn't allocate isStringProp (%d*%d)\n",
464		 fi.nProps, (int) sizeof(char));
465	free(pFontInfo->props);
466	return AllocError;
467    }
468    num_chars = n2dChars(&fi);
469    bytestoskip = num_chars * sizeof(snfCharInfoRec);	/* charinfos */
470    bytestoskip += BYTESOFGLYPHINFO(&fi);
471    (void)FontFileSkip(file, bytestoskip);
472
473    ret = snfReadProps(&fi, pFontInfo, file);
474    if (ret != Successful) {
475	free(pFontInfo->props);
476	free(pFontInfo->isStringProp);
477	return ret;
478    }
479    if (fi.inkMetrics) {
480	ret = snfReadxCharInfo(file, &pFontInfo->ink_minbounds);
481	if (ret != Successful) {
482	    free(pFontInfo->props);
483	    free(pFontInfo->isStringProp);
484	    return ret;
485	}
486	ret = snfReadxCharInfo(file, &pFontInfo->ink_maxbounds);
487	if (ret != Successful) {
488	    free(pFontInfo->props);
489	    free(pFontInfo->isStringProp);
490	    return ret;
491	}
492    } else {
493	pFontInfo->ink_minbounds = pFontInfo->minbounds;
494	pFontInfo->ink_maxbounds = pFontInfo->maxbounds;
495    }
496    return Successful;
497
498}
499
500static void
501snfUnloadFont(FontPtr pFont)
502{
503    BitmapFontPtr   bitmapFont;
504
505    bitmapFont = (BitmapFontPtr) pFont->fontPrivate;
506    free (bitmapFont->bitmaps);
507    free (bitmapFont);
508    DestroyFontRec (pFont);
509}
510
511