tga.c 13 KB

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