Fix buffer overflow when adding a radio preset.
[kugel-rb.git] / firmware / font.c
blob1635441b7a1975d28e1320f3e3e68804b4e289a2
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (c) 2002 by Greg Haerr <greg@censoft.com>
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 * Rockbox startup font initialization
21 * This file specifies which fonts get compiled-in and
22 * loaded at startup, as well as their mapping into
23 * the FONT_SYSFIXED, FONT_UI and FONT_MP3 ids.
25 #include "config.h"
27 #if defined(HAVE_LCD_BITMAP) || defined(SIMULATOR)
29 #include <stdio.h>
30 #include <string.h>
31 #include "lcd.h"
32 #include "font.h"
33 #include "file.h"
34 #include "debug.h"
35 #include "panic.h"
36 #include "rbunicode.h"
37 /* Font cache includes */
38 #include "font_cache.h"
39 #include "lru.h"
41 #ifndef O_BINARY
42 #define O_BINARY 0
43 #endif
45 /* compiled-in font */
46 extern struct font sysfont;
48 /* structure filled in by font_load */
49 static struct font font_ui;
51 /* system font table, in order of FONT_xxx definition */
52 static struct font* const sysfonts[MAXFONTS] = { &sysfont, &font_ui };
54 /* static buffer allocation structures */
55 static unsigned char mbuf[MAX_FONT_SIZE];
56 static unsigned char *freeptr = mbuf;
57 static unsigned char *fileptr;
58 static unsigned char *eofptr;
60 /* Font cache structures */
61 static struct font_cache font_cache_ui;
62 static int fnt_file = -1; /* >=0 if font is cached */
63 unsigned long file_width_offset; /* offset to file width data */
64 unsigned long file_offset_offset; /* offset to file offset data */
65 static void cache_create(int maxwidth, int height);
66 static int long_offset = 0;
67 static int glyph_file;
68 /* End Font cache structures */
70 void font_init(void)
72 memset(&font_ui, 0, sizeof(struct font));
75 /* Check if we have x bytes left in the file buffer */
76 #define HAVEBYTES(x) (fileptr + (x) <= eofptr)
78 /* Helper functions to read big-endian unaligned short or long from
79 the file buffer. Bounds-checking must be done in the calling
80 function.
83 static short readshort(void)
85 unsigned short s;
87 s = *fileptr++ & 0xff;
88 s |= (*fileptr++ << 8);
89 return s;
92 static long readlong(void)
94 unsigned long l;
96 l = *fileptr++ & 0xff;
97 l |= *fileptr++ << 8;
98 l |= ((unsigned long)(*fileptr++)) << 16;
99 l |= ((unsigned long)(*fileptr++)) << 24;
100 return l;
103 /* read count bytes*/
104 static void readstr(char *buf, int count)
106 while (count--)
107 *buf++ = *fileptr++;
110 void font_reset(void)
112 memset(&font_ui, 0, sizeof(struct font));
115 static struct font* font_load_header(struct font *pf)
117 char version[4+1];
119 /* Check we have enough data */
120 if (!HAVEBYTES(28))
121 return NULL;
123 /* read magic and version #*/
124 memset(version, 0, sizeof(version));
125 readstr(version, 4);
127 if (strcmp(version, VERSION) != 0)
128 return NULL;
130 /* font info*/
131 pf->maxwidth = readshort();
132 pf->height = readshort();
133 pf->ascent = readshort();
134 fileptr += 2; /* Skip padding */
135 pf->firstchar = readlong();
136 pf->defaultchar = readlong();
137 pf->size = readlong();
139 /* get variable font data sizes*/
140 /* # words of bitmap_t*/
141 pf->bits_size = readlong();
143 return pf;
145 /* Load memory font */
146 struct font* font_load_in_memory(struct font* pf)
148 long i, noffset, nwidth;
150 if (!HAVEBYTES(4))
151 return NULL;
153 /* # longs of offset*/
154 noffset = readlong();
156 /* # bytes of width*/
157 nwidth = readlong();
159 /* variable font data*/
160 pf->bits = (unsigned char *)fileptr;
161 fileptr += pf->bits_size*sizeof(unsigned char);
163 if ( pf->bits_size < 0xFFDB )
165 /* pad to 16-bit boundary */
166 fileptr = (unsigned char *)(((long)fileptr + 1) & ~1);
168 else
170 /* pad to 32-bit boundary*/
171 fileptr = (unsigned char *)(((long)fileptr + 3) & ~3);
174 if (noffset)
176 if ( pf->bits_size < 0xFFDB )
178 long_offset = 0;
179 pf->offset = (unsigned short *)fileptr;
181 /* Check we have sufficient buffer */
182 if (!HAVEBYTES(noffset * sizeof(short)))
183 return NULL;
185 for (i=0; i<noffset; ++i)
187 ((unsigned short*)(pf->offset))[i] = (unsigned short)readshort();
190 else
192 long_offset = 1;
193 pf->offset = (unsigned short *)fileptr;
195 /* Check we have sufficient buffer */
196 if (!HAVEBYTES(noffset * sizeof(long)))
197 return NULL;
199 for (i=0; i<noffset; ++i)
201 ((unsigned long*)(pf->offset))[i] = (unsigned long)readlong();
205 else
206 pf->offset = NULL;
208 if (nwidth) {
209 pf->width = (unsigned char *)fileptr;
210 fileptr += nwidth*sizeof(unsigned char);
212 else
213 pf->width = NULL;
215 if (fileptr > eofptr)
216 return NULL;
218 return pf; /* success!*/
221 /* Load cached font */
222 struct font* font_load_cached(struct font* pf)
224 unsigned long noffset, nwidth;
225 unsigned char* oldfileptr = fileptr;
227 if (!HAVEBYTES(2 * sizeof(long)))
228 return NULL;
230 /* # longs of offset*/
231 noffset = readlong();
233 /* # bytes of width*/
234 nwidth = readlong();
236 /* We are now at the bitmap data, this is fixed at 36.. */
237 pf->bits = NULL;
239 /* Calculate offset to offset data */
240 fileptr += pf->bits_size * sizeof(unsigned char);
242 if ( pf->bits_size < 0xFFDB )
244 long_offset = 0;
245 /* pad to 16-bit boundary */
246 fileptr = (unsigned char *)(((long)fileptr + 1) & ~1);
248 else
250 long_offset = 1;
251 /* pad to 32-bit boundary*/
252 fileptr = (unsigned char *)(((long)fileptr + 3) & ~3);
255 if (noffset)
256 file_offset_offset = (unsigned long)(fileptr - freeptr);
257 else
258 file_offset_offset = 0;
260 /* Calculate offset to widths data */
261 if ( pf->bits_size < 0xFFDB )
262 fileptr += noffset * sizeof(unsigned short);
263 else
264 fileptr += noffset * sizeof(unsigned long);
266 if (nwidth)
267 file_width_offset = (unsigned long)(fileptr - freeptr);
268 else
269 file_width_offset = 0;
271 fileptr = oldfileptr;
273 /* Create the cache */
274 cache_create(pf->maxwidth, pf->height);
276 return pf;
279 /* read and load font into incore font structure*/
280 struct font* font_load(const char *path)
282 int size;
283 struct font* pf = &font_ui;
285 /* save loaded glyphs */
286 glyph_cache_save();
288 /* Close font file handle */
289 if (fnt_file >= 0)
290 close(fnt_file);
292 /* open and read entire font file*/
293 fnt_file = open(path, O_RDONLY|O_BINARY);
295 if (fnt_file < 0) {
296 DEBUGF("Can't open font: %s\n", path);
297 return NULL;
300 /* Check file size */
301 size = filesize(fnt_file);
303 font_reset();
305 /* currently, font loading replaces earlier font allocation*/
306 freeptr = (unsigned char *)(((int)mbuf + 3) & ~3);
307 fileptr = freeptr;
310 if (size > MAX_FONT_SIZE)
312 read(fnt_file, fileptr, FONT_HEADER_SIZE);
313 eofptr = fileptr + FONT_HEADER_SIZE;
315 if (!font_load_header(pf))
317 DEBUGF("Failed font header load");
318 return NULL;
321 if (!font_load_cached(pf))
323 DEBUGF("Failed font cache load");
324 return NULL;
327 glyph_cache_load();
329 else
331 read(fnt_file, fileptr, MAX_FONT_SIZE);
332 eofptr = fileptr + size;
333 close(fnt_file);
334 fnt_file = -1;
336 if (!font_load_header(pf))
338 DEBUGF("Failed font header load");
339 return NULL;
342 if (!font_load_in_memory(pf))
344 DEBUGF("Failed mem load");
345 return NULL;
349 /* no need for multiple font loads currently*/
350 /*freeptr += filesize;*/
351 /*freeptr = (unsigned char *)(freeptr + 3) & ~3;*/ /* pad freeptr*/
353 return pf; /* success!*/
357 * Return a pointer to an incore font structure.
358 * If the requested font isn't loaded/compiled-in,
359 * decrement the font number and try again.
361 struct font* font_get(int font)
363 struct font* pf;
365 if (font >= MAXFONTS)
366 font = 0;
368 while (1) {
369 pf = sysfonts[font];
370 if (pf && pf->height)
371 return pf;
372 if (--font < 0)
373 panicf("No font!");
377 * Returns the stringsize of a given string.
379 int font_getstringsize(const unsigned char *str, int *w, int *h, int fontnumber)
381 struct font* pf = font_get(fontnumber);
382 unsigned short ch;
383 int width = 0;
385 for (str = utf8decode(str, &ch); ch != 0 ; str = utf8decode(str, &ch))
388 /* get proportional width and glyph bits*/
389 width += font_get_width(pf,ch);
391 if ( w )
392 *w = width;
393 if ( h )
394 *h = pf->height;
395 return width;
399 * Reads an entry into cache entry
401 static void
402 load_cache_entry(struct font_cache_entry* p, void* callback_data)
404 struct font* pf = callback_data;
405 unsigned short char_code = p->_char_code;
406 unsigned char tmp[2];
408 if (file_width_offset)
410 int width_offset = file_width_offset + char_code;
411 lseek(fnt_file, width_offset, SEEK_SET);
412 read(fnt_file, &(p->width), 1);
414 else
416 p->width = pf->maxwidth;
419 long bitmap_offset = 0;
421 if (file_offset_offset)
423 long offset = file_offset_offset + char_code * (long_offset ? sizeof(long) : sizeof(short));
424 lseek(fnt_file, offset, SEEK_SET);
425 read (fnt_file, tmp, 2);
426 bitmap_offset = tmp[0] | (tmp[1] << 8);
427 if (long_offset) {
428 read (fnt_file, tmp, 2);
429 bitmap_offset |= (tmp[0] << 16) | (tmp[1] << 24);
432 else
434 bitmap_offset = ((pf->height + 7) / 8) * p->width * char_code;
437 long file_offset = FONT_HEADER_SIZE + bitmap_offset;
438 lseek(fnt_file, file_offset, SEEK_SET);
440 int src_bytes = p->width * ((pf->height + 7) / 8);
441 read(fnt_file, p->bitmap, src_bytes);
445 * Converts cbuf into a font cache
447 static void cache_create(int maxwidth, int height)
449 /* maximum size of rotated bitmap */
450 int bitmap_size = maxwidth * ((height + 7) / 8);
452 /* Initialise cache */
453 font_cache_create(&font_cache_ui, mbuf, MAX_FONT_SIZE, bitmap_size);
457 * Returns width of character
459 int font_get_width(struct font* pf, unsigned short char_code)
461 /* check input range*/
462 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
463 char_code = pf->defaultchar;
464 char_code -= pf->firstchar;
466 return (fnt_file >= 0 && pf != &sysfont)?
467 font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->width:
468 pf->width? pf->width[char_code]: pf->maxwidth;
471 const unsigned char* font_get_bits(struct font* pf, unsigned short char_code)
473 const unsigned char* bits;
475 /* check input range*/
476 if (char_code < pf->firstchar || char_code >= pf->firstchar+pf->size)
477 char_code = pf->defaultchar;
478 char_code -= pf->firstchar;
480 if (fnt_file >= 0 && pf != &sysfont)
482 bits =
483 (unsigned char*)font_cache_get(&font_cache_ui,char_code,load_cache_entry,pf)->bitmap;
485 else
487 bits = pf->bits + (pf->offset?
488 pf->offset[char_code]:
489 (((pf->height + 7) / 8) * pf->maxwidth * char_code));
492 return bits;
495 void glyph_file_write(void* data)
497 struct font_cache_entry* p = data;
498 struct font* pf = &font_ui;
499 unsigned short ch;
500 unsigned char tmp[2];
502 ch = p->_char_code + pf->firstchar;
504 if (ch != 0xffff && glyph_file >= 0) {
505 tmp[0] = ch >> 8;
506 tmp[1] = ch & 0xff;
507 if (write(glyph_file, tmp, 2) != 2) {
508 close(glyph_file);
509 glyph_file = -1;
512 return;
515 /* save the char codes of the loaded glyphs to a file */
516 void glyph_cache_save(void)
519 if (fnt_file >= 0) {
521 glyph_file = creat(GLYPH_CACHE_FILE);
523 if (glyph_file < 0) return;
525 lru_traverse(&font_cache_ui._lru, glyph_file_write);
527 if (glyph_file >= 0)
528 close(glyph_file);
530 return;
533 void glyph_cache_load(void)
535 if (fnt_file >= 0) {
537 int fd;
538 unsigned char tmp[2];
539 unsigned short ch;
540 struct font* pf = &font_ui;
542 fd = open(GLYPH_CACHE_FILE, O_RDONLY|O_BINARY);
544 if (fd >= 0) {
546 while (read(fd, tmp, 2) == 2) {
547 ch = (tmp[0] << 8) | tmp[1];
548 font_get_bits(pf, ch);
551 close(fd);
552 } else {
553 /* load latin1 chars into cache */
554 ch = 256;
555 while (ch-- > 32)
556 font_get_bits(pf, ch);
559 return;
562 #endif /* HAVE_LCD_BITMAP */
564 /* -----------------------------------------------------------------
565 * vim: et sw=4 ts=8 sts=4 tw=78