tga.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2006,2007 Free Software Foundation, Inc.
  4. *
  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.
  9. *
  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.
  14. *
  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/>.
  17. */
  18. #include <grub/bitmap.h>
  19. #include <grub/types.h>
  20. #include <grub/normal.h>
  21. #include <grub/dl.h>
  22. #include <grub/mm.h>
  23. #include <grub/misc.h>
  24. #include <grub/bufio.h>
  25. GRUB_MOD_LICENSE ("GPLv3+");
  26. /* Uncomment following define to enable TGA debug. */
  27. //#define TGA_DEBUG
  28. #define dump_int_field(x) grub_dprintf ("tga", #x " = %d (0x%04x)\n", x, x);
  29. #if defined(TGA_DEBUG)
  30. static grub_command_t cmd;
  31. #endif
  32. enum
  33. {
  34. GRUB_TGA_IMAGE_TYPE_NONE = 0,
  35. GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_INDEXCOLOR = 1,
  36. GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR = 2,
  37. GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_BLACK_AND_WHITE = 3,
  38. GRUB_TGA_IMAGE_TYPE_RLE_INDEXCOLOR = 9,
  39. GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR = 10,
  40. GRUB_TGA_IMAGE_TYPE_RLE_BLACK_AND_WHITE = 11,
  41. };
  42. enum
  43. {
  44. GRUB_TGA_COLOR_MAP_TYPE_NONE = 0,
  45. GRUB_TGA_COLOR_MAP_TYPE_INCLUDED = 1
  46. };
  47. enum
  48. {
  49. GRUB_TGA_IMAGE_ORIGIN_RIGHT = 0x10,
  50. GRUB_TGA_IMAGE_ORIGIN_TOP = 0x20
  51. };
  52. struct grub_tga_header
  53. {
  54. grub_uint8_t id_length;
  55. grub_uint8_t color_map_type;
  56. grub_uint8_t image_type;
  57. /* Color Map Specification. */
  58. grub_uint16_t color_map_first_index;
  59. grub_uint16_t color_map_length;
  60. grub_uint8_t color_map_bpp;
  61. /* Image Specification. */
  62. grub_uint16_t image_x_origin;
  63. grub_uint16_t image_y_origin;
  64. grub_uint16_t image_width;
  65. grub_uint16_t image_height;
  66. grub_uint8_t image_bpp;
  67. grub_uint8_t image_descriptor;
  68. } GRUB_PACKED;
  69. struct tga_data
  70. {
  71. struct grub_tga_header hdr;
  72. int uses_rle;
  73. int pktlen;
  74. int bpp;
  75. int is_rle;
  76. grub_uint8_t pixel[4];
  77. grub_uint8_t palette[256][3];
  78. struct grub_video_bitmap *bitmap;
  79. grub_file_t file;
  80. unsigned image_width;
  81. unsigned image_height;
  82. };
  83. static grub_err_t
  84. fetch_pixel (struct tga_data *data)
  85. {
  86. if (!data->uses_rle)
  87. {
  88. if (grub_file_read (data->file, &data->pixel[0], data->bpp)
  89. != data->bpp)
  90. return grub_errno;
  91. return GRUB_ERR_NONE;
  92. }
  93. if (!data->pktlen)
  94. {
  95. grub_uint8_t type;
  96. if (grub_file_read (data->file, &type, sizeof (type)) != sizeof(type))
  97. return grub_errno;
  98. data->is_rle = !!(type & 0x80);
  99. data->pktlen = (type & 0x7f) + 1;
  100. if (data->is_rle && grub_file_read (data->file, &data->pixel[0], data->bpp)
  101. != data->bpp)
  102. return grub_errno;
  103. }
  104. if (!data->is_rle && grub_file_read (data->file, &data->pixel[0], data->bpp)
  105. != data->bpp)
  106. return grub_errno;
  107. data->pktlen--;
  108. return GRUB_ERR_NONE;
  109. }
  110. static grub_err_t
  111. tga_load_palette (struct tga_data *data)
  112. {
  113. grub_size_t len = grub_le_to_cpu32 (data->hdr.color_map_length) * 3;
  114. if (len > sizeof (data->palette))
  115. len = sizeof (data->palette);
  116. if (grub_file_read (data->file, &data->palette, len)
  117. != (grub_ssize_t) len)
  118. return grub_errno;
  119. #ifndef GRUB_CPU_WORDS_BIGENDIAN
  120. {
  121. grub_size_t i;
  122. for (i = 0; 3 * i < len; i++)
  123. {
  124. grub_uint8_t t;
  125. t = data->palette[i][0];
  126. data->palette[i][0] = data->palette[i][2];
  127. data->palette[i][2] = t;
  128. }
  129. }
  130. #endif
  131. return GRUB_ERR_NONE;
  132. }
  133. static grub_err_t
  134. tga_load_index_color (struct tga_data *data)
  135. {
  136. unsigned int x;
  137. unsigned int y;
  138. grub_uint8_t *ptr;
  139. for (y = 0; y < data->image_height; y++)
  140. {
  141. ptr = data->bitmap->data;
  142. if ((data->hdr.image_descriptor & GRUB_TGA_IMAGE_ORIGIN_TOP) != 0)
  143. ptr += y * data->bitmap->mode_info.pitch;
  144. else
  145. ptr += (data->image_height - 1 - y) * data->bitmap->mode_info.pitch;
  146. for (x = 0; x < data->image_width; x++)
  147. {
  148. grub_err_t err;
  149. err = fetch_pixel (data);
  150. if (err)
  151. return err;
  152. ptr[0] = data->palette[data->pixel[0]][0];
  153. ptr[1] = data->palette[data->pixel[0]][1];
  154. ptr[2] = data->palette[data->pixel[0]][2];
  155. ptr += 3;
  156. }
  157. }
  158. return GRUB_ERR_NONE;
  159. }
  160. static grub_err_t
  161. tga_load_grayscale (struct tga_data *data)
  162. {
  163. unsigned int x;
  164. unsigned int y;
  165. grub_uint8_t *ptr;
  166. for (y = 0; y < data->image_height; y++)
  167. {
  168. ptr = data->bitmap->data;
  169. if ((data->hdr.image_descriptor & GRUB_TGA_IMAGE_ORIGIN_TOP) != 0)
  170. ptr += y * data->bitmap->mode_info.pitch;
  171. else
  172. ptr += (data->image_height - 1 - y) * data->bitmap->mode_info.pitch;
  173. for (x = 0; x < data->image_width; x++)
  174. {
  175. grub_err_t err;
  176. err = fetch_pixel (data);
  177. if (err)
  178. return err;
  179. ptr[0] = data->pixel[0];
  180. ptr[1] = data->pixel[0];
  181. ptr[2] = data->pixel[0];
  182. ptr += 3;
  183. }
  184. }
  185. return GRUB_ERR_NONE;
  186. }
  187. static grub_err_t
  188. tga_load_truecolor_R8G8B8 (struct tga_data *data)
  189. {
  190. unsigned int x;
  191. unsigned int y;
  192. grub_uint8_t *ptr;
  193. for (y = 0; y < data->image_height; y++)
  194. {
  195. ptr = data->bitmap->data;
  196. if ((data->hdr.image_descriptor & GRUB_TGA_IMAGE_ORIGIN_TOP) != 0)
  197. ptr += y * data->bitmap->mode_info.pitch;
  198. else
  199. ptr += (data->image_height - 1 - y) * data->bitmap->mode_info.pitch;
  200. for (x = 0; x < data->image_width; x++)
  201. {
  202. grub_err_t err;
  203. err = fetch_pixel (data);
  204. if (err)
  205. return err;
  206. #ifdef GRUB_CPU_WORDS_BIGENDIAN
  207. ptr[0] = data->pixel[0];
  208. ptr[1] = data->pixel[1];
  209. ptr[2] = data->pixel[2];
  210. #else
  211. ptr[0] = data->pixel[2];
  212. ptr[1] = data->pixel[1];
  213. ptr[2] = data->pixel[0];
  214. #endif
  215. ptr += 3;
  216. }
  217. }
  218. return GRUB_ERR_NONE;
  219. }
  220. static grub_err_t
  221. tga_load_truecolor_R8G8B8A8 (struct tga_data *data)
  222. {
  223. unsigned int x;
  224. unsigned int y;
  225. grub_uint8_t *ptr;
  226. for (y = 0; y < data->image_height; y++)
  227. {
  228. ptr = data->bitmap->data;
  229. if ((data->hdr.image_descriptor & GRUB_TGA_IMAGE_ORIGIN_TOP) != 0)
  230. ptr += y * data->bitmap->mode_info.pitch;
  231. else
  232. ptr += (data->image_height - 1 - y) * data->bitmap->mode_info.pitch;
  233. for (x = 0; x < data->image_width; x++)
  234. {
  235. grub_err_t err;
  236. err = fetch_pixel (data);
  237. if (err)
  238. return err;
  239. #ifdef GRUB_CPU_WORDS_BIGENDIAN
  240. ptr[0] = data->pixel[0];
  241. ptr[1] = data->pixel[1];
  242. ptr[2] = data->pixel[2];
  243. ptr[3] = data->pixel[3];
  244. #else
  245. ptr[0] = data->pixel[2];
  246. ptr[1] = data->pixel[1];
  247. ptr[2] = data->pixel[0];
  248. ptr[3] = data->pixel[3];
  249. #endif
  250. ptr += 4;
  251. }
  252. }
  253. return GRUB_ERR_NONE;
  254. }
  255. static grub_err_t
  256. grub_video_reader_tga (struct grub_video_bitmap **bitmap,
  257. const char *filename)
  258. {
  259. grub_ssize_t pos;
  260. struct tga_data data;
  261. grub_memset (&data, 0, sizeof (data));
  262. data.file = grub_buffile_open (filename, 0);
  263. if (! data.file)
  264. return grub_errno;
  265. /* TGA Specification states that we SHOULD start by reading
  266. ID from end of file, but we really don't care about that as we are
  267. not going to support developer area & extensions at this point. */
  268. /* Read TGA header from beginning of file. */
  269. if (grub_file_read (data.file, &data.hdr, sizeof (data.hdr))
  270. != sizeof (data.hdr))
  271. {
  272. grub_file_close (data.file);
  273. return grub_errno;
  274. }
  275. /* Skip ID field. */
  276. pos = grub_file_tell (data.file);
  277. pos += data.hdr.id_length;
  278. grub_file_seek (data.file, pos);
  279. if (grub_errno != GRUB_ERR_NONE)
  280. {
  281. grub_file_close (data.file);
  282. return grub_errno;
  283. }
  284. grub_dprintf("tga", "tga: header\n");
  285. dump_int_field(data.hdr.id_length);
  286. dump_int_field(data.hdr.color_map_type);
  287. dump_int_field(data.hdr.image_type);
  288. dump_int_field(data.hdr.color_map_first_index);
  289. dump_int_field(data.hdr.color_map_length);
  290. dump_int_field(data.hdr.color_map_bpp);
  291. dump_int_field(data.hdr.image_x_origin);
  292. dump_int_field(data.hdr.image_y_origin);
  293. dump_int_field(data.hdr.image_width);
  294. dump_int_field(data.hdr.image_height);
  295. dump_int_field(data.hdr.image_bpp);
  296. dump_int_field(data.hdr.image_descriptor);
  297. data.image_width = grub_le_to_cpu16 (data.hdr.image_width);
  298. data.image_height = grub_le_to_cpu16 (data.hdr.image_height);
  299. /* Check that bitmap encoding is supported. */
  300. switch (data.hdr.image_type)
  301. {
  302. case GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR:
  303. case GRUB_TGA_IMAGE_TYPE_RLE_BLACK_AND_WHITE:
  304. case GRUB_TGA_IMAGE_TYPE_RLE_INDEXCOLOR:
  305. data.uses_rle = 1;
  306. break;
  307. case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR:
  308. case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_BLACK_AND_WHITE:
  309. case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_INDEXCOLOR:
  310. data.uses_rle = 0;
  311. break;
  312. default:
  313. grub_file_close (data.file);
  314. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  315. "unsupported bitmap format (unknown encoding %d)", data.hdr.image_type);
  316. }
  317. data.bpp = data.hdr.image_bpp / 8;
  318. /* Check that bitmap depth is supported. */
  319. switch (data.hdr.image_type)
  320. {
  321. case GRUB_TGA_IMAGE_TYPE_RLE_BLACK_AND_WHITE:
  322. case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_BLACK_AND_WHITE:
  323. if (data.hdr.image_bpp != 8)
  324. {
  325. grub_file_close (data.file);
  326. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  327. "unsupported bitmap format (bpp=%d)",
  328. data.hdr.image_bpp);
  329. }
  330. grub_video_bitmap_create (bitmap, data.image_width,
  331. data.image_height,
  332. GRUB_VIDEO_BLIT_FORMAT_RGB_888);
  333. if (grub_errno != GRUB_ERR_NONE)
  334. {
  335. grub_file_close (data.file);
  336. return grub_errno;
  337. }
  338. data.bitmap = *bitmap;
  339. /* Load bitmap data. */
  340. tga_load_grayscale (&data);
  341. break;
  342. case GRUB_TGA_IMAGE_TYPE_RLE_INDEXCOLOR:
  343. case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_INDEXCOLOR:
  344. if (data.hdr.image_bpp != 8
  345. || data.hdr.color_map_bpp != 24
  346. || data.hdr.color_map_first_index != 0)
  347. {
  348. grub_file_close (data.file);
  349. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  350. "unsupported bitmap format (bpp=%d)",
  351. data.hdr.image_bpp);
  352. }
  353. grub_video_bitmap_create (bitmap, data.image_width,
  354. data.image_height,
  355. GRUB_VIDEO_BLIT_FORMAT_RGB_888);
  356. if (grub_errno != GRUB_ERR_NONE)
  357. {
  358. grub_file_close (data.file);
  359. return grub_errno;
  360. }
  361. data.bitmap = *bitmap;
  362. /* Load bitmap data. */
  363. tga_load_palette (&data);
  364. tga_load_index_color (&data);
  365. break;
  366. case GRUB_TGA_IMAGE_TYPE_RLE_TRUECOLOR:
  367. case GRUB_TGA_IMAGE_TYPE_UNCOMPRESSED_TRUECOLOR:
  368. switch (data.hdr.image_bpp)
  369. {
  370. case 24:
  371. grub_video_bitmap_create (bitmap, data.image_width,
  372. data.image_height,
  373. GRUB_VIDEO_BLIT_FORMAT_RGB_888);
  374. if (grub_errno != GRUB_ERR_NONE)
  375. {
  376. grub_file_close (data.file);
  377. return grub_errno;
  378. }
  379. data.bitmap = *bitmap;
  380. /* Load bitmap data. */
  381. tga_load_truecolor_R8G8B8 (&data);
  382. break;
  383. case 32:
  384. grub_video_bitmap_create (bitmap, data.image_width,
  385. data.image_height,
  386. GRUB_VIDEO_BLIT_FORMAT_RGBA_8888);
  387. if (grub_errno != GRUB_ERR_NONE)
  388. {
  389. grub_file_close (data.file);
  390. return grub_errno;
  391. }
  392. data.bitmap = *bitmap;
  393. /* Load bitmap data. */
  394. tga_load_truecolor_R8G8B8A8 (&data);
  395. break;
  396. default:
  397. grub_file_close (data.file);
  398. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  399. "unsupported bitmap format (bpp=%d)",
  400. data.hdr.image_bpp);
  401. }
  402. }
  403. /* If there was a loading problem, destroy bitmap. */
  404. if (grub_errno != GRUB_ERR_NONE)
  405. {
  406. grub_video_bitmap_destroy (*bitmap);
  407. *bitmap = 0;
  408. }
  409. grub_file_close (data.file);
  410. return grub_errno;
  411. }
  412. #if defined(TGA_DEBUG)
  413. static grub_err_t
  414. grub_cmd_tgatest (grub_command_t cmd_d __attribute__ ((unused)),
  415. int argc, char **args)
  416. {
  417. struct grub_video_bitmap *bitmap = 0;
  418. if (argc != 1)
  419. return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
  420. grub_video_reader_tga (&bitmap, args[0]);
  421. if (grub_errno != GRUB_ERR_NONE)
  422. return grub_errno;
  423. grub_video_bitmap_destroy (bitmap);
  424. return GRUB_ERR_NONE;
  425. }
  426. #endif
  427. static struct grub_video_bitmap_reader tga_reader = {
  428. .extension = ".tga",
  429. .reader = grub_video_reader_tga,
  430. .next = 0
  431. };
  432. GRUB_MOD_INIT(tga)
  433. {
  434. grub_video_bitmap_reader_register (&tga_reader);
  435. #if defined(TGA_DEBUG)
  436. cmd = grub_register_command ("tgatest", grub_cmd_tgatest,
  437. "FILE", "Tests loading of TGA bitmap.");
  438. #endif
  439. }
  440. GRUB_MOD_FINI(tga)
  441. {
  442. #if defined(TGA_DEBUG)
  443. grub_unregister_command (cmd);
  444. #endif
  445. grub_video_bitmap_reader_unregister (&tga_reader);
  446. }