]>
Commit | Line | Data |
---|---|---|
18d9c7cd | 1 | /* |
4b13b216 | 2 | * GRUB -- GRand Unified Bootloader |
502c87e8 | 3 | * Copyright (C) 2003,2005 Free Software Foundation, Inc. |
18d9c7cd | 4 | * |
5 | * This program 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 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program 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. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | */ | |
19 | ||
4b13b216 | 20 | #include <grub/file.h> |
21 | #include <grub/misc.h> | |
22 | #include <grub/dl.h> | |
23 | #include <grub/normal.h> | |
24 | #include <grub/types.h> | |
25 | #include <grub/mm.h> | |
26 | #include <grub/font.h> | |
18d9c7cd | 27 | |
28 | struct entry | |
29 | { | |
4b13b216 | 30 | grub_uint32_t code; |
31 | grub_uint32_t offset; | |
18d9c7cd | 32 | }; |
33 | ||
34 | struct font | |
35 | { | |
36 | struct font *next; | |
4b13b216 | 37 | grub_file_t file; |
38 | grub_uint32_t num; | |
18d9c7cd | 39 | struct entry table[0]; |
40 | }; | |
41 | ||
42 | static struct font *font_list; | |
43 | ||
44 | static int | |
45 | add_font (const char *filename) | |
46 | { | |
4b13b216 | 47 | grub_file_t file = 0; |
18d9c7cd | 48 | char magic[4]; |
4b13b216 | 49 | grub_uint32_t num, i; |
18d9c7cd | 50 | struct font *font = 0; |
51 | ||
4b13b216 | 52 | file = grub_file_open (filename); |
18d9c7cd | 53 | if (! file) |
54 | goto fail; | |
55 | ||
4b13b216 | 56 | if (grub_file_read (file, magic, 4) != 4) |
18d9c7cd | 57 | goto fail; |
58 | ||
4b13b216 | 59 | if (grub_memcmp (magic, GRUB_FONT_MAGIC, 4) != 0) |
18d9c7cd | 60 | { |
4b13b216 | 61 | grub_error (GRUB_ERR_BAD_FONT, "invalid font magic"); |
18d9c7cd | 62 | goto fail; |
63 | } | |
64 | ||
4b13b216 | 65 | if (grub_file_read (file, (char *) &num, 4) != 4) |
18d9c7cd | 66 | goto fail; |
67 | ||
4b13b216 | 68 | num = grub_le_to_cpu32 (num); |
69 | font = (struct font *) grub_malloc (sizeof (struct font) | |
18d9c7cd | 70 | + sizeof (struct entry) * num); |
71 | if (! font) | |
72 | goto fail; | |
73 | ||
74 | font->file = file; | |
75 | font->num = num; | |
76 | ||
77 | for (i = 0; i < num; i++) | |
78 | { | |
4b13b216 | 79 | grub_uint32_t code, offset; |
18d9c7cd | 80 | |
4b13b216 | 81 | if (grub_file_read (file, (char *) &code, 4) != 4) |
18d9c7cd | 82 | goto fail; |
83 | ||
4b13b216 | 84 | if (grub_file_read (file, (char *) &offset, 4) != 4) |
18d9c7cd | 85 | goto fail; |
86 | ||
4b13b216 | 87 | font->table[i].code = grub_le_to_cpu32 (code); |
88 | font->table[i].offset = grub_le_to_cpu32 (offset); | |
18d9c7cd | 89 | } |
90 | ||
91 | font->next = font_list; | |
92 | font_list = font; | |
93 | ||
94 | return 1; | |
95 | ||
96 | fail: | |
97 | if (font) | |
4b13b216 | 98 | grub_free (font); |
18d9c7cd | 99 | |
100 | if (file) | |
4b13b216 | 101 | grub_file_close (file); |
18d9c7cd | 102 | |
103 | return 0; | |
104 | } | |
105 | ||
106 | static void | |
107 | remove_font (struct font *font) | |
108 | { | |
109 | struct font **p, *q; | |
110 | ||
111 | for (p = &font_list, q = *p; q; p = &(q->next), q = q->next) | |
112 | if (q == font) | |
113 | { | |
114 | *p = q->next; | |
115 | ||
4b13b216 | 116 | grub_file_close (font->file); |
117 | grub_free (font); | |
18d9c7cd | 118 | |
119 | break; | |
120 | } | |
121 | } | |
122 | ||
123 | /* Return the offset of the glyph corresponding to the codepoint CODE | |
124 | in the font FONT. If no found, return zero. */ | |
4b13b216 | 125 | static grub_uint32_t |
126 | find_glyph (const struct font *font, grub_uint32_t code) | |
18d9c7cd | 127 | { |
4b13b216 | 128 | grub_uint32_t start = 0; |
129 | grub_uint32_t end = font->num - 1; | |
18d9c7cd | 130 | struct entry *table = font->table; |
131 | ||
132 | /* This shouldn't happen. */ | |
133 | if (font->num == 0) | |
134 | return 0; | |
135 | ||
136 | /* Do a binary search. */ | |
137 | while (start <= end) | |
138 | { | |
4b13b216 | 139 | grub_uint32_t i = (start + end) / 2; |
18d9c7cd | 140 | |
141 | if (table[i].code < code) | |
142 | start = i + 1; | |
143 | else if (table[i].code > code) | |
144 | end = i - 1; | |
145 | else | |
146 | return table[i].offset; | |
147 | } | |
148 | ||
149 | return 0; | |
150 | } | |
151 | ||
152 | /* Set the glyph to something stupid. */ | |
153 | static void | |
154 | fill_with_default_glyph (unsigned char bitmap[32], unsigned *width) | |
155 | { | |
156 | if (bitmap) | |
157 | { | |
158 | unsigned i; | |
159 | ||
160 | for (i = 0; i < 16; i++) | |
161 | bitmap[i] = (i & 1) ? 0x55 : 0xaa; | |
162 | } | |
163 | ||
164 | *width = 1; | |
165 | } | |
166 | ||
167 | /* Get a glyph corresponding to the codepoint CODE. Always fill BITMAP | |
168 | and WIDTH with something, even if no glyph is found. */ | |
169 | int | |
4b13b216 | 170 | grub_font_get_glyph (grub_uint32_t code, |
18d9c7cd | 171 | unsigned char bitmap[32], unsigned *width) |
172 | { | |
173 | struct font *font; | |
174 | ||
175 | /* FIXME: It is necessary to cache glyphs! */ | |
176 | ||
177 | restart: | |
178 | for (font = font_list; font; font = font->next) | |
179 | { | |
4b13b216 | 180 | grub_uint32_t offset; |
18d9c7cd | 181 | |
182 | offset = find_glyph (font, code); | |
183 | if (offset) | |
184 | { | |
4b13b216 | 185 | grub_uint32_t w; |
18d9c7cd | 186 | |
4b13b216 | 187 | grub_file_seek (font->file, offset); |
188 | if (grub_file_read (font->file, (char *) &w, 4) != 4) | |
18d9c7cd | 189 | { |
190 | remove_font (font); | |
191 | goto restart; | |
192 | } | |
193 | ||
4b13b216 | 194 | w = grub_le_to_cpu32 (w); |
18d9c7cd | 195 | if (w != 1 && w != 2) |
196 | { | |
4b13b216 | 197 | /* grub_error (GRUB_ERR_BAD_FONT, "invalid width"); */ |
18d9c7cd | 198 | remove_font (font); |
199 | goto restart; | |
200 | } | |
201 | ||
202 | if (bitmap | |
4b13b216 | 203 | && (grub_file_read (font->file, bitmap, w * 16) |
204 | != (grub_ssize_t) w * 16)) | |
18d9c7cd | 205 | { |
206 | remove_font (font); | |
207 | goto restart; | |
208 | } | |
209 | ||
210 | *width = w; | |
211 | return 1; | |
212 | } | |
213 | } | |
214 | ||
215 | /* Uggh... No font was found. */ | |
216 | fill_with_default_glyph (bitmap, width); | |
217 | return 0; | |
218 | } | |
219 | ||
4b13b216 | 220 | static grub_err_t |
221 | font_command (struct grub_arg_list *state __attribute__ ((unused)), | |
db1771cf | 222 | int argc __attribute__ ((unused)), |
223 | char **args __attribute__ ((unused))) | |
18d9c7cd | 224 | { |
225 | if (argc == 0) | |
4b13b216 | 226 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "no font specified"); |
18d9c7cd | 227 | |
228 | while (argc--) | |
db1771cf | 229 | if (! add_font (*args++)) |
18d9c7cd | 230 | return 1; |
231 | ||
232 | return 0; | |
233 | } | |
234 | ||
6d099807 | 235 | GRUB_MOD_INIT(fontmanager) |
18d9c7cd | 236 | { |
db1771cf | 237 | (void) mod; /* Stop warning. */ |
4b13b216 | 238 | grub_register_command ("font", font_command, GRUB_COMMAND_FLAG_BOTH, |
502c87e8 | 239 | "font FILE...", |
240 | "Specify one or more font files to display.", 0); | |
18d9c7cd | 241 | } |
242 | ||
6d099807 | 243 | GRUB_MOD_FINI(fontmanager) |
18d9c7cd | 244 | { |
4b13b216 | 245 | grub_unregister_command ("font"); |
18d9c7cd | 246 | } |