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