make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / common / boot / grub2 / font / manager.c
blob80d8d07b5dadd762a88b4f4b3708bd4a68f339f3
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2003,2005,2006,2007 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/file.h>
20 #include <grub/misc.h>
21 #include <grub/dl.h>
22 #include <grub/normal.h>
23 #include <grub/types.h>
24 #include <grub/mm.h>
25 #include <grub/font.h>
27 struct entry
29 grub_uint32_t code;
30 grub_uint32_t offset;
33 struct font
35 struct font *next;
36 grub_file_t file;
37 grub_uint32_t num;
38 struct entry table[0];
41 static struct font *font_list;
43 /* Fill unknown glyph's with rounded question mark. */
44 static grub_uint8_t unknown_glyph[16] =
45 { /* 76543210 */
46 0x7C, /* ooooo */
47 0x82, /* o o */
48 0xBA, /* o ooo o */
49 0xAA, /* o o o o */
50 0xAA, /* o o o o */
51 0x8A, /* o o o */
52 0x9A, /* o oo o */
53 0x92, /* o o o */
54 0x92, /* o o o */
55 0x92, /* o o o */
56 0x92, /* o o o */
57 0x82, /* o o */
58 0x92, /* o o o */
59 0x82, /* o o */
60 0x7C, /* ooooo */
61 0x00 /* */
64 static int
65 add_font (const char *filename)
67 grub_file_t file = 0;
68 char magic[4];
69 grub_uint32_t num, i;
70 struct font *font = 0;
72 file = grub_file_open (filename);
73 if (! file)
74 goto fail;
76 if (grub_file_read (file, magic, 4) != 4)
77 goto fail;
79 if (grub_memcmp (magic, GRUB_FONT_MAGIC, 4) != 0)
81 grub_error (GRUB_ERR_BAD_FONT, "invalid font magic");
82 goto fail;
85 if (grub_file_read (file, (char *) &num, 4) != 4)
86 goto fail;
88 num = grub_le_to_cpu32 (num);
89 font = (struct font *) grub_malloc (sizeof (struct font)
90 + sizeof (struct entry) * num);
91 if (! font)
92 goto fail;
94 font->file = file;
95 font->num = num;
97 for (i = 0; i < num; i++)
99 grub_uint32_t code, offset;
101 if (grub_file_read (file, (char *) &code, 4) != 4)
102 goto fail;
104 if (grub_file_read (file, (char *) &offset, 4) != 4)
105 goto fail;
107 font->table[i].code = grub_le_to_cpu32 (code);
108 font->table[i].offset = grub_le_to_cpu32 (offset);
111 font->next = font_list;
112 font_list = font;
114 return 1;
116 fail:
117 if (font)
118 grub_free (font);
120 if (file)
121 grub_file_close (file);
123 return 0;
126 static void
127 remove_font (struct font *font)
129 struct font **p, *q;
131 for (p = &font_list, q = *p; q; p = &(q->next), q = q->next)
132 if (q == font)
134 *p = q->next;
136 grub_file_close (font->file);
137 grub_free (font);
139 break;
143 /* Return the offset of the glyph corresponding to the codepoint CODE
144 in the font FONT. If no found, return zero. */
145 static grub_uint32_t
146 find_glyph (const struct font *font, grub_uint32_t code)
148 grub_uint32_t start = 0;
149 grub_uint32_t end = font->num - 1;
150 const struct entry *table = font->table;
152 /* This shouldn't happen. */
153 if (font->num == 0)
154 return 0;
156 /* Do a binary search. */
157 while (start <= end)
159 grub_uint32_t i = (start + end) / 2;
161 if (table[i].code < code)
162 start = i + 1;
163 else if (table[i].code > code)
164 end = i - 1;
165 else
166 return table[i].offset;
169 return 0;
172 /* Set the glyph to something stupid. */
173 static void
174 fill_with_default_glyph (grub_font_glyph_t glyph)
176 unsigned i;
178 /* Use pre-defined pattern to fill unknown glyphs. */
179 for (i = 0; i < 16; i++)
180 glyph->bitmap[i] = unknown_glyph[i];
182 glyph->char_width = 1;
183 glyph->width = glyph->char_width * 8;
184 glyph->height = 16;
185 glyph->baseline = (16 * 3) / 4;
188 /* Get a glyph corresponding to the codepoint CODE. Always fill glyph
189 information with something, even if no glyph is found. */
191 grub_font_get_glyph (grub_uint32_t code,
192 grub_font_glyph_t glyph)
194 struct font *font;
195 grub_uint8_t bitmap[32];
197 /* FIXME: It is necessary to cache glyphs! */
199 restart:
200 for (font = font_list; font; font = font->next)
202 grub_uint32_t offset;
204 offset = find_glyph (font, code);
205 if (offset)
207 grub_uint32_t w;
208 int len;
210 /* Make sure we can find glyphs for error messages. Push active
211 error message to error stack and reset error message. */
212 grub_error_push ();
214 grub_file_seek (font->file, offset);
215 if ((len = grub_file_read (font->file, (char *) &w, sizeof (w)))
216 != sizeof (w))
218 remove_font (font);
219 goto restart;
222 w = grub_le_to_cpu32 (w);
223 if (w != 1 && w != 2)
225 /* grub_error (GRUB_ERR_BAD_FONT, "invalid width"); */
226 remove_font (font);
227 goto restart;
230 if (grub_file_read (font->file, (char *) bitmap, w * 16)
231 != (grub_ssize_t) w * 16)
233 remove_font (font);
234 goto restart;
237 /* Fill glyph with information. */
238 grub_memcpy (glyph->bitmap, bitmap, w * 16);
240 glyph->char_width = w;
241 glyph->width = glyph->char_width * 8;
242 glyph->height = 16;
243 glyph->baseline = (16 * 3) / 4;
245 /* Restore old error message. */
246 grub_error_pop ();
248 return 1;
252 /* Uggh... No font was found. */
253 fill_with_default_glyph (glyph);
254 return 0;
257 static grub_err_t
258 font_command (struct grub_arg_list *state __attribute__ ((unused)),
259 int argc __attribute__ ((unused)),
260 char **args __attribute__ ((unused)))
262 if (argc == 0)
263 return grub_error (GRUB_ERR_BAD_ARGUMENT, "no font specified");
265 while (argc--)
266 if (! add_font (*args++))
267 return 1;
269 return 0;
272 GRUB_MOD_INIT(font_manager)
274 grub_register_command ("font", font_command, GRUB_COMMAND_FLAG_BOTH,
275 "font FILE...",
276 "Specify one or more font files to display.", 0);
279 GRUB_MOD_FINI(font_manager)
281 grub_unregister_command ("font");