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