make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / common / boot / grub2 / video / readers / tga.c
blob7b944b09ff49ecaf7c68c34a1d4c23d46d6a7e10
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 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/bitmap.h>
20 #include <grub/types.h>
21 #include <grub/normal.h>
22 #include <grub/dl.h>
23 #include <grub/mm.h>
24 #include <grub/misc.h>
25 #include <grub/arg.h>
26 #include <grub/file.h>
28 /* Uncomment following define to enable TGA debug. */
29 //#define TGA_DEBUG
31 #if defined(TGA_DEBUG)
32 #define dump_int_field(x) grub_printf( #x " = %d (0x%04x)\n", x, x);
33 #endif
35 enum
37 GRUB_TGA_IMAGE_TYPE_NONE = 0,
38 GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_INDEXCOLOR = 1,
39 GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR = 2,
40 GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_BLACK_AND_WHITE = 3,
41 GRUB_TGA_IMAGE_TYPE_RLE_INDEXCOLOR = 9,
42 GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR = 10,
43 GRUB_TGA_IMAGE_TYPE_RLE_BLACK_AND_WHITE = 11,
46 enum
48 GRUB_TGA_COLOR_MAP_TYPE_NONE = 0,
49 GRUB_TGA_COLOR_MAP_TYPE_INCLUDED = 1
52 enum
54 GRUB_TGA_IMAGE_ORIGIN_RIGHT = 0x10,
55 GRUB_TGA_IMAGE_ORIGIN_TOP = 0x20
58 struct grub_tga_header
60 grub_uint8_t id_length;
61 grub_uint8_t color_map_type;
62 grub_uint8_t image_type;
64 /* Color Map Specification. */
65 grub_uint16_t color_map_first_index;
66 grub_uint16_t color_map_length;
67 grub_uint8_t color_map_bpp;
69 /* Image Specification. */
70 grub_uint16_t image_x_origin;
71 grub_uint16_t image_y_origin;
72 grub_uint16_t image_width;
73 grub_uint16_t image_height;
74 grub_uint8_t image_bpp;
75 grub_uint8_t image_descriptor;
76 } __attribute__ ((packed));
78 static grub_err_t
79 tga_load_truecolor_rle_R8G8B8 (struct grub_video_bitmap *bitmap,
80 struct grub_tga_header *header,
81 grub_file_t file)
83 unsigned int x;
84 unsigned int y;
85 grub_uint8_t type;
86 grub_uint8_t *ptr;
87 grub_uint8_t tmp[4]; /* Size should be max_bpp / 8. */
88 grub_uint8_t bytes_per_pixel;
90 bytes_per_pixel = header->image_bpp / 8;
92 for (y = 0; y < header->image_height; y++)
94 ptr = bitmap->data;
95 if ((header->image_descriptor & GRUB_TGA_IMAGE_ORIGIN_TOP) != 0)
96 ptr += y * bitmap->mode_info.pitch;
97 else
98 ptr += (header->image_height - 1 - y) * bitmap->mode_info.pitch;
100 for (x = 0; x < header->image_width;)
102 if (grub_file_read (file, (char *)&type, sizeof (type)) != sizeof(type))
103 return grub_errno;
105 if (type & 0x80)
107 /* RLE-encoded packet. */
108 type &= 0x7f;
109 type++;
111 if (grub_file_read (file, (char *)&tmp[0], bytes_per_pixel)
112 != bytes_per_pixel)
113 return grub_errno;
115 while (type)
117 if (x < header->image_width)
119 ptr[0] = tmp[2];
120 ptr[1] = tmp[1];
121 ptr[2] = tmp[0];
122 ptr += 3;
125 type--;
126 x++;
129 else
131 /* RAW-encoded packet. */
132 type++;
134 while (type)
136 if (grub_file_read (file, (char *)&tmp[0], bytes_per_pixel)
137 != bytes_per_pixel)
138 return grub_errno;
140 if (x < header->image_width)
142 ptr[0] = tmp[2];
143 ptr[1] = tmp[1];
144 ptr[2] = tmp[0];
145 ptr += 3;
148 type--;
149 x++;
154 return GRUB_ERR_NONE;
157 static grub_err_t
158 tga_load_truecolor_rle_R8G8B8A8 (struct grub_video_bitmap *bitmap,
159 struct grub_tga_header *header,
160 grub_file_t file)
162 unsigned int x;
163 unsigned int y;
164 grub_uint8_t type;
165 grub_uint8_t *ptr;
166 grub_uint8_t tmp[4]; /* Size should be max_bpp / 8. */
167 grub_uint8_t bytes_per_pixel;
169 bytes_per_pixel = header->image_bpp / 8;
171 for (y = 0; y < header->image_height; y++)
173 ptr = bitmap->data;
174 if ((header->image_descriptor & GRUB_TGA_IMAGE_ORIGIN_TOP) != 0)
175 ptr += y * bitmap->mode_info.pitch;
176 else
177 ptr += (header->image_height - 1 - y) * bitmap->mode_info.pitch;
179 for (x = 0; x < header->image_width;)
181 if (grub_file_read (file, (char *)&type, sizeof (type)) != sizeof(type))
182 return grub_errno;
184 if (type & 0x80)
186 /* RLE-encoded packet. */
187 type &= 0x7f;
188 type++;
190 if (grub_file_read (file, (char *)&tmp[0], bytes_per_pixel)
191 != bytes_per_pixel)
192 return grub_errno;
194 while (type)
196 if (x < header->image_width)
198 ptr[0] = tmp[2];
199 ptr[1] = tmp[1];
200 ptr[2] = tmp[0];
201 ptr[3] = tmp[3];
202 ptr += 4;
205 type--;
206 x++;
209 else
211 /* RAW-encoded packet. */
212 type++;
214 while (type)
216 if (grub_file_read (file, (char *)&tmp[0], bytes_per_pixel)
217 != bytes_per_pixel)
218 return grub_errno;
220 if (x < header->image_width)
222 ptr[0] = tmp[2];
223 ptr[1] = tmp[1];
224 ptr[2] = tmp[0];
225 ptr[3] = tmp[3];
226 ptr += 4;
229 type--;
230 x++;
235 return GRUB_ERR_NONE;
238 static grub_err_t
239 tga_load_truecolor_R8G8B8 (struct grub_video_bitmap *bitmap,
240 struct grub_tga_header *header,
241 grub_file_t file)
243 unsigned int x;
244 unsigned int y;
245 grub_uint8_t *ptr;
246 grub_uint8_t tmp[4]; /* Size should be max_bpp / 8. */
247 grub_uint8_t bytes_per_pixel;
249 bytes_per_pixel = header->image_bpp / 8;
251 for (y = 0; y < header->image_height; y++)
253 ptr = bitmap->data;
254 if ((header->image_descriptor & GRUB_TGA_IMAGE_ORIGIN_TOP) != 0)
255 ptr += y * bitmap->mode_info.pitch;
256 else
257 ptr += (header->image_height - 1 - y) * bitmap->mode_info.pitch;
259 for (x = 0; x < header->image_width; x++)
261 if (grub_file_read (file, (char *)&tmp[0], bytes_per_pixel)
262 != bytes_per_pixel)
263 return grub_errno;
265 ptr[0] = tmp[2];
266 ptr[1] = tmp[1];
267 ptr[2] = tmp[0];
269 ptr += 3;
272 return GRUB_ERR_NONE;
275 static grub_err_t
276 tga_load_truecolor_R8G8B8A8 (struct grub_video_bitmap *bitmap,
277 struct grub_tga_header *header,
278 grub_file_t file)
280 unsigned int x;
281 unsigned int y;
282 grub_uint8_t *ptr;
283 grub_uint8_t tmp[4]; /* Size should be max_bpp / 8. */
284 grub_uint8_t bytes_per_pixel;
286 bytes_per_pixel = header->image_bpp / 8;
288 for (y = 0; y < header->image_height; y++)
290 ptr = bitmap->data;
291 if ((header->image_descriptor & GRUB_TGA_IMAGE_ORIGIN_TOP) != 0)
292 ptr += y * bitmap->mode_info.pitch;
293 else
294 ptr += (header->image_height - 1 - y) * bitmap->mode_info.pitch;
296 for (x = 0; x < header->image_width; x++)
298 if (grub_file_read (file, (char *)&tmp[0], bytes_per_pixel)
299 != bytes_per_pixel)
300 return grub_errno;
302 ptr[0] = tmp[2];
303 ptr[1] = tmp[1];
304 ptr[2] = tmp[0];
305 ptr[3] = tmp[3];
307 ptr += 4;
310 return GRUB_ERR_NONE;
313 static grub_err_t
314 grub_video_reader_tga (struct grub_video_bitmap **bitmap,
315 const char *filename)
317 grub_file_t file;
318 grub_ssize_t pos;
319 struct grub_tga_header header;
320 int has_alpha;
322 file = grub_file_open (filename);
323 if (! file)
324 return grub_errno;
326 /* TGA Specification states that we SHOULD start by reading
327 ID from end of file, but we really don't care about that as we are
328 not going to support developer area & extensions at this point. */
330 /* Read TGA header from beginning of file. */
331 if (grub_file_read (file, (char*)&header, sizeof (header))
332 != sizeof (header))
334 grub_file_close (file);
335 return grub_errno;
338 /* Skip ID field. */
339 pos = grub_file_tell (file);
340 pos += header.id_length;
341 grub_file_seek (file, pos);
342 if (grub_errno != GRUB_ERR_NONE)
344 grub_file_close (file);
345 return grub_errno;
348 #if defined(TGA_DEBUG)
349 grub_printf("tga: header\n");
350 dump_int_field(header.id_length);
351 dump_int_field(header.color_map_type);
352 dump_int_field(header.image_type);
353 dump_int_field(header.color_map_first_index);
354 dump_int_field(header.color_map_length);
355 dump_int_field(header.color_map_bpp);
356 dump_int_field(header.image_x_origin);
357 dump_int_field(header.image_y_origin);
358 dump_int_field(header.image_width);
359 dump_int_field(header.image_height);
360 dump_int_field(header.image_bpp);
361 dump_int_field(header.image_descriptor);
362 #endif
364 /* Check that bitmap encoding is supported. */
365 switch (header.image_type)
367 case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR:
368 case GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR:
369 break;
371 default:
372 grub_file_close (file);
373 return grub_error (GRUB_ERR_BAD_FILE_TYPE,
374 "Unsupported bitmap format (unknown encoding).");
377 /* Check that bitmap depth is supported. */
378 switch (header.image_bpp)
380 case 24:
381 has_alpha = 0;
382 break;
384 case 32:
385 has_alpha = 1;
386 break;
388 default:
389 grub_file_close (file);
390 return grub_error (GRUB_ERR_BAD_FILE_TYPE,
391 "Unsupported bitmap format (bpp=%d).",
392 header.image_bpp);
395 /* Allocate bitmap. If there is alpha information store it too. */
396 if (has_alpha)
398 grub_video_bitmap_create (bitmap, header.image_width,
399 header.image_height,
400 GRUB_VIDEO_BLIT_FORMAT_R8G8B8A8);
401 if (grub_errno != GRUB_ERR_NONE)
403 grub_file_close (file);
404 return grub_errno;
407 /* Load bitmap data. */
408 switch (header.image_type)
410 case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR:
411 tga_load_truecolor_R8G8B8A8 (*bitmap, &header, file);
412 break;
414 case GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR:
415 tga_load_truecolor_rle_R8G8B8A8 (*bitmap, &header, file);
416 break;
419 else
421 grub_video_bitmap_create (bitmap, header.image_width,
422 header.image_height,
423 GRUB_VIDEO_BLIT_FORMAT_R8G8B8);
424 if (grub_errno != GRUB_ERR_NONE)
426 grub_file_close (file);
427 return grub_errno;
430 /* Load bitmap data. */
431 switch (header.image_type)
433 case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR:
434 tga_load_truecolor_R8G8B8 (*bitmap, &header, file);
435 break;
437 case GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR:
438 tga_load_truecolor_rle_R8G8B8 (*bitmap, &header, file);
439 break;
443 /* If there was a loading problem, destroy bitmap. */
444 if (grub_errno != GRUB_ERR_NONE)
446 grub_video_bitmap_destroy (*bitmap);
447 *bitmap = 0;
450 grub_file_close (file);
451 return grub_errno;
454 #if defined(TGA_DEBUG)
455 static grub_err_t
456 grub_cmd_tgatest (struct grub_arg_list *state __attribute__ ((unused)),
457 int argc, char **args)
459 struct grub_video_bitmap *bitmap = 0;
461 if (argc != 1)
462 return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
464 grub_video_reader_tga (&bitmap, args[0]);
465 if (grub_errno != GRUB_ERR_NONE)
466 return grub_errno;
468 grub_video_bitmap_destroy (bitmap);
470 return GRUB_ERR_NONE;
472 #endif
474 static struct grub_video_bitmap_reader tga_reader = {
475 .extension = ".tga",
476 .reader = grub_video_reader_tga,
477 .next = 0
480 GRUB_MOD_INIT(video_reader_tga)
482 grub_video_bitmap_reader_register (&tga_reader);
483 #if defined(TGA_DEBUG)
484 grub_register_command ("tgatest", grub_cmd_tgatest, GRUB_COMMAND_FLAG_BOTH,
485 "tgatest FILE", "Tests loading of TGA bitmap.", 0);
486 #endif
489 GRUB_MOD_FINI(video_reader_tga)
491 #if defined(TGA_DEBUG)
492 grub_unregister_command ("tgatest");
493 #endif
494 grub_video_bitmap_reader_unregister (&tga_reader);