png.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. /*
  2. * GRUB -- GRand Unified Bootloader
  3. * Copyright (C) 2008,2009 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 PNG debug. */
  26. //#define PNG_DEBUG
  27. #define PNG_COLOR_MASK_PALETTE 1
  28. #define PNG_COLOR_MASK_COLOR 2
  29. #define PNG_COLOR_MASK_ALPHA 4
  30. #define PNG_COLOR_TYPE_GRAY 0
  31. #define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
  32. #define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR)
  33. #define PNG_COLOR_TYPE_RGBA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
  34. #define PNG_COLOR_TYPE_GRAYA (PNG_COLOR_MASK_ALPHA)
  35. #define PNG_COMPRESSION_BASE 0
  36. #define PNG_INTERLACE_NONE 0
  37. #define PNG_INTERLACE_ADAM7 1
  38. #define PNG_FILTER_TYPE_BASE 0
  39. #define PNG_FILTER_VALUE_NONE 0
  40. #define PNG_FILTER_VALUE_SUB 1
  41. #define PNG_FILTER_VALUE_UP 2
  42. #define PNG_FILTER_VALUE_AVG 3
  43. #define PNG_FILTER_VALUE_PAETH 4
  44. #define PNG_FILTER_VALUE_LAST 5
  45. #define PNG_CHUNK_IHDR 0x49484452
  46. #define PNG_CHUNK_IDAT 0x49444154
  47. #define PNG_CHUNK_IEND 0x49454e44
  48. #define Z_DEFLATED 8
  49. #define Z_FLAG_DICT 32
  50. #define INFLATE_STORED 0
  51. #define INFLATE_FIXED 1
  52. #define INFLATE_DYNAMIC 2
  53. #define WSIZE 0x8000
  54. #define DEFLATE_HCLEN_BASE 4
  55. #define DEFLATE_HCLEN_MAX 19
  56. #define DEFLATE_HLIT_BASE 257
  57. #define DEFLATE_HLIT_MAX 288
  58. #define DEFLATE_HDIST_BASE 1
  59. #define DEFLATE_HDIST_MAX 30
  60. #define DEFLATE_HUFF_LEN 16
  61. #ifdef PNG_DEBUG
  62. static grub_command_t cmd;
  63. #endif
  64. struct huff_table
  65. {
  66. int *values, *maxval, *offset;
  67. int num_values, max_length;
  68. };
  69. struct grub_png_data
  70. {
  71. grub_file_t file;
  72. struct grub_video_bitmap **bitmap;
  73. int bit_count, bit_save;
  74. grub_uint32_t next_offset;
  75. int image_width, image_height, bpp, is_16bit, raw_bytes;
  76. grub_uint8_t *image_data;
  77. int inside_idat, idat_remain;
  78. int code_values[DEFLATE_HLIT_MAX];
  79. int code_maxval[DEFLATE_HUFF_LEN];
  80. int code_offset[DEFLATE_HUFF_LEN];
  81. int dist_values[DEFLATE_HDIST_MAX];
  82. int dist_maxval[DEFLATE_HUFF_LEN];
  83. int dist_offset[DEFLATE_HUFF_LEN];
  84. struct huff_table code_table;
  85. struct huff_table dist_table;
  86. grub_uint8_t slide[WSIZE];
  87. int wp;
  88. grub_uint8_t *cur_rgb;
  89. int cur_column, cur_filter, first_line;
  90. };
  91. static grub_uint32_t
  92. grub_png_get_dword (struct grub_png_data *data)
  93. {
  94. grub_uint32_t r;
  95. r = 0;
  96. grub_file_read (data->file, &r, sizeof (grub_uint32_t));
  97. return grub_be_to_cpu32 (r);
  98. }
  99. static grub_uint8_t
  100. grub_png_get_byte (struct grub_png_data *data)
  101. {
  102. grub_uint8_t r;
  103. if ((data->inside_idat) && (data->idat_remain == 0))
  104. {
  105. grub_uint32_t len, type;
  106. do
  107. {
  108. /* Skip crc checksum. */
  109. grub_png_get_dword (data);
  110. if (data->file->offset != data->next_offset)
  111. {
  112. grub_error (GRUB_ERR_BAD_FILE_TYPE,
  113. "png: chunk size error");
  114. return 0;
  115. }
  116. len = grub_png_get_dword (data);
  117. type = grub_png_get_dword (data);
  118. if (type != PNG_CHUNK_IDAT)
  119. {
  120. grub_error (GRUB_ERR_BAD_FILE_TYPE,
  121. "png: unexpected end of data");
  122. return 0;
  123. }
  124. data->next_offset = data->file->offset + len + 4;
  125. }
  126. while (len == 0);
  127. data->idat_remain = len;
  128. }
  129. r = 0;
  130. grub_file_read (data->file, &r, 1);
  131. if (data->inside_idat)
  132. data->idat_remain--;
  133. return r;
  134. }
  135. static int
  136. grub_png_get_bits (struct grub_png_data *data, int num)
  137. {
  138. int code, shift;
  139. if (data->bit_count == 0)
  140. {
  141. data->bit_save = grub_png_get_byte (data);
  142. data->bit_count = 8;
  143. }
  144. code = 0;
  145. shift = 0;
  146. while (grub_errno == 0)
  147. {
  148. int n;
  149. n = data->bit_count;
  150. if (n > num)
  151. n = num;
  152. code += (int) (data->bit_save & ((1 << n) - 1)) << shift;
  153. num -= n;
  154. if (!num)
  155. {
  156. data->bit_count -= n;
  157. data->bit_save >>= n;
  158. break;
  159. }
  160. shift += n;
  161. data->bit_save = grub_png_get_byte (data);
  162. data->bit_count = 8;
  163. }
  164. return code;
  165. }
  166. static grub_err_t
  167. grub_png_decode_image_header (struct grub_png_data *data)
  168. {
  169. int color_type;
  170. int color_bits;
  171. data->image_width = grub_png_get_dword (data);
  172. data->image_height = grub_png_get_dword (data);
  173. if ((!data->image_height) || (!data->image_width))
  174. return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size");
  175. color_bits = grub_png_get_byte (data);
  176. if ((color_bits != 8) && (color_bits != 16))
  177. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  178. "png: bit depth must be 8 or 16");
  179. data->is_16bit = (color_bits == 16);
  180. color_type = grub_png_get_byte (data);
  181. if (color_type == PNG_COLOR_TYPE_RGB)
  182. {
  183. if (grub_video_bitmap_create (data->bitmap, data->image_width,
  184. data->image_height,
  185. GRUB_VIDEO_BLIT_FORMAT_RGB_888))
  186. return grub_errno;
  187. data->bpp = 3;
  188. }
  189. else if (color_type == PNG_COLOR_TYPE_RGBA)
  190. {
  191. if (grub_video_bitmap_create (data->bitmap, data->image_width,
  192. data->image_height,
  193. GRUB_VIDEO_BLIT_FORMAT_RGBA_8888))
  194. return grub_errno;
  195. data->bpp = 4;
  196. }
  197. else
  198. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  199. "png: color type not supported");
  200. if (data->is_16bit)
  201. {
  202. data->bpp <<= 1;
  203. data->image_data = grub_malloc (data->image_height *
  204. data->image_width * data->bpp);
  205. if (grub_errno)
  206. return grub_errno;
  207. data->cur_rgb = data->image_data;
  208. }
  209. else
  210. {
  211. data->image_data = 0;
  212. data->cur_rgb = (*data->bitmap)->data;
  213. }
  214. data->raw_bytes = data->image_height * (data->image_width + 1) * data->bpp;
  215. data->cur_column = 0;
  216. data->first_line = 1;
  217. if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE)
  218. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  219. "png: compression method not supported");
  220. if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE)
  221. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  222. "png: filter method not supported");
  223. if (grub_png_get_byte (data) != PNG_INTERLACE_NONE)
  224. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  225. "png: interlace method not supported");
  226. /* Skip crc checksum. */
  227. grub_png_get_dword (data);
  228. return grub_errno;
  229. }
  230. /* Order of the bit length code lengths. */
  231. static const grub_uint8_t bitorder[] = {
  232. 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
  233. };
  234. /* Copy lengths for literal codes 257..285. */
  235. static const int cplens[] = {
  236. 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
  237. 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
  238. };
  239. /* Extra bits for literal codes 257..285. */
  240. static const grub_uint8_t cplext[] = {
  241. 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
  242. 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
  243. }; /* 99==invalid */
  244. /* Copy offsets for distance codes 0..29. */
  245. static const int cpdist[] = {
  246. 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
  247. 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
  248. 8193, 12289, 16385, 24577
  249. };
  250. /* Extra bits for distance codes. */
  251. static const grub_uint8_t cpdext[] = {
  252. 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
  253. 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
  254. 12, 12, 13, 13
  255. };
  256. static void
  257. grub_png_init_huff_table (struct huff_table *ht, int cur_maxlen,
  258. int *cur_values, int *cur_maxval, int *cur_offset)
  259. {
  260. ht->values = cur_values;
  261. ht->maxval = cur_maxval;
  262. ht->offset = cur_offset;
  263. ht->num_values = 0;
  264. ht->max_length = cur_maxlen;
  265. grub_memset (cur_maxval, 0, sizeof (int) * cur_maxlen);
  266. }
  267. static void
  268. grub_png_insert_huff_item (struct huff_table *ht, int code, int len)
  269. {
  270. int i, n;
  271. if (len == 0)
  272. return;
  273. if (len > ht->max_length)
  274. {
  275. grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid code length");
  276. return;
  277. }
  278. n = 0;
  279. for (i = len; i < ht->max_length; i++)
  280. n += ht->maxval[i];
  281. for (i = 0; i < n; i++)
  282. ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1];
  283. ht->values[ht->num_values - n] = code;
  284. ht->num_values++;
  285. ht->maxval[len - 1]++;
  286. }
  287. static void
  288. grub_png_build_huff_table (struct huff_table *ht)
  289. {
  290. int base, ofs, i;
  291. base = 0;
  292. ofs = 0;
  293. for (i = 0; i < ht->max_length; i++)
  294. {
  295. base += ht->maxval[i];
  296. ofs += ht->maxval[i];
  297. ht->maxval[i] = base;
  298. ht->offset[i] = ofs - base;
  299. base <<= 1;
  300. }
  301. }
  302. static int
  303. grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht)
  304. {
  305. int code, i;
  306. code = 0;
  307. for (i = 0; i < ht->max_length; i++)
  308. {
  309. code = (code << 1) + grub_png_get_bits (data, 1);
  310. if (code < ht->maxval[i])
  311. return ht->values[code + ht->offset[i]];
  312. }
  313. return 0;
  314. }
  315. static grub_err_t
  316. grub_png_init_fixed_block (struct grub_png_data *data)
  317. {
  318. int i;
  319. grub_png_init_huff_table (&data->code_table, DEFLATE_HUFF_LEN,
  320. data->code_values, data->code_maxval,
  321. data->code_offset);
  322. for (i = 0; i < 144; i++)
  323. grub_png_insert_huff_item (&data->code_table, i, 8);
  324. for (; i < 256; i++)
  325. grub_png_insert_huff_item (&data->code_table, i, 9);
  326. for (; i < 280; i++)
  327. grub_png_insert_huff_item (&data->code_table, i, 7);
  328. for (; i < DEFLATE_HLIT_MAX; i++)
  329. grub_png_insert_huff_item (&data->code_table, i, 8);
  330. grub_png_build_huff_table (&data->code_table);
  331. grub_png_init_huff_table (&data->dist_table, DEFLATE_HUFF_LEN,
  332. data->dist_values, data->dist_maxval,
  333. data->dist_offset);
  334. for (i = 0; i < DEFLATE_HDIST_MAX; i++)
  335. grub_png_insert_huff_item (&data->dist_table, i, 5);
  336. grub_png_build_huff_table (&data->dist_table);
  337. return grub_errno;
  338. }
  339. static grub_err_t
  340. grub_png_init_dynamic_block (struct grub_png_data *data)
  341. {
  342. int nl, nd, nb, i, prev;
  343. struct huff_table cl;
  344. int cl_values[sizeof (bitorder)];
  345. int cl_maxval[8];
  346. int cl_offset[8];
  347. grub_uint8_t lens[DEFLATE_HCLEN_MAX];
  348. nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5);
  349. nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5);
  350. nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4);
  351. if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) ||
  352. (nb > DEFLATE_HCLEN_MAX))
  353. return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: too much data");
  354. grub_png_init_huff_table (&cl, 8, cl_values, cl_maxval, cl_offset);
  355. for (i = 0; i < nb; i++)
  356. lens[bitorder[i]] = grub_png_get_bits (data, 3);
  357. for (; i < DEFLATE_HCLEN_MAX; i++)
  358. lens[bitorder[i]] = 0;
  359. for (i = 0; i < DEFLATE_HCLEN_MAX; i++)
  360. grub_png_insert_huff_item (&cl, i, lens[i]);
  361. grub_png_build_huff_table (&cl);
  362. grub_png_init_huff_table (&data->code_table, DEFLATE_HUFF_LEN,
  363. data->code_values, data->code_maxval,
  364. data->code_offset);
  365. grub_png_init_huff_table (&data->dist_table, DEFLATE_HUFF_LEN,
  366. data->dist_values, data->dist_maxval,
  367. data->dist_offset);
  368. prev = 0;
  369. for (i = 0; i < nl + nd; i++)
  370. {
  371. int n, code;
  372. struct huff_table *ht;
  373. if (grub_errno)
  374. return grub_errno;
  375. if (i < nl)
  376. {
  377. ht = &data->code_table;
  378. code = i;
  379. }
  380. else
  381. {
  382. ht = &data->dist_table;
  383. code = i - nl;
  384. }
  385. n = grub_png_get_huff_code (data, &cl);
  386. if (n < 16)
  387. {
  388. grub_png_insert_huff_item (ht, code, n);
  389. prev = n;
  390. }
  391. else if (n == 16)
  392. {
  393. int c;
  394. c = 3 + grub_png_get_bits (data, 2);
  395. while (c > 0)
  396. {
  397. grub_png_insert_huff_item (ht, code++, prev);
  398. i++;
  399. c--;
  400. }
  401. i--;
  402. }
  403. else if (n == 17)
  404. i += 3 + grub_png_get_bits (data, 3) - 1;
  405. else
  406. i += 11 + grub_png_get_bits (data, 7) - 1;
  407. }
  408. grub_png_build_huff_table (&data->code_table);
  409. grub_png_build_huff_table (&data->dist_table);
  410. return grub_errno;
  411. }
  412. static grub_err_t
  413. grub_png_output_byte (struct grub_png_data *data, grub_uint8_t n)
  414. {
  415. int row_bytes;
  416. if (--data->raw_bytes < 0)
  417. return grub_error (GRUB_ERR_BAD_FILE_TYPE, "image size overflown");
  418. if (data->cur_column == 0)
  419. {
  420. if (n >= PNG_FILTER_VALUE_LAST)
  421. return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid filter value");
  422. data->cur_filter = n;
  423. }
  424. else
  425. *(data->cur_rgb++) = n;
  426. data->cur_column++;
  427. row_bytes = data->image_width * data->bpp;
  428. if (data->cur_column == row_bytes + 1)
  429. {
  430. grub_uint8_t *blank_line = NULL;
  431. grub_uint8_t *cur = data->cur_rgb - row_bytes;
  432. grub_uint8_t *left = cur;
  433. grub_uint8_t *up;
  434. if (data->first_line)
  435. {
  436. blank_line = grub_zalloc (row_bytes);
  437. if (blank_line == NULL)
  438. return grub_errno;
  439. up = blank_line;
  440. }
  441. else
  442. up = cur - row_bytes;
  443. switch (data->cur_filter)
  444. {
  445. case PNG_FILTER_VALUE_SUB:
  446. {
  447. int i;
  448. cur += data->bpp;
  449. for (i = data->bpp; i < row_bytes; i++, cur++, left++)
  450. *cur += *left;
  451. break;
  452. }
  453. case PNG_FILTER_VALUE_UP:
  454. {
  455. int i;
  456. for (i = 0; i < row_bytes; i++, cur++, up++)
  457. *cur += *up;
  458. break;
  459. }
  460. case PNG_FILTER_VALUE_AVG:
  461. {
  462. int i;
  463. for (i = 0; i < data->bpp; i++, cur++, up++)
  464. *cur += *up >> 1;
  465. for (; i < row_bytes; i++, cur++, up++, left++)
  466. *cur += ((int) *up + (int) *left) >> 1;
  467. break;
  468. }
  469. case PNG_FILTER_VALUE_PAETH:
  470. {
  471. int i;
  472. grub_uint8_t *upper_left = up;
  473. for (i = 0; i < data->bpp; i++, cur++, up++)
  474. *cur += *up;
  475. for (; i < row_bytes; i++, cur++, up++, left++, upper_left++)
  476. {
  477. int a, b, c, pa, pb, pc;
  478. a = *left;
  479. b = *up;
  480. c = *upper_left;
  481. pa = b - c;
  482. pb = a - c;
  483. pc = pa + pb;
  484. if (pa < 0)
  485. pa = -pa;
  486. if (pb < 0)
  487. pb = -pb;
  488. if (pc < 0)
  489. pc = -pc;
  490. *cur += ((pa <= pb) && (pa <= pc)) ? a : (pb <= pc) ? b : c;
  491. }
  492. }
  493. }
  494. if (blank_line)
  495. grub_free (blank_line);
  496. data->cur_column = 0;
  497. data->first_line = 0;
  498. }
  499. return grub_errno;
  500. }
  501. static grub_err_t
  502. grub_png_read_dynamic_block (struct grub_png_data *data)
  503. {
  504. while (grub_errno == 0)
  505. {
  506. int n;
  507. n = grub_png_get_huff_code (data, &data->code_table);
  508. if (n < 256)
  509. {
  510. data->slide[data->wp] = n;
  511. grub_png_output_byte (data, n);
  512. data->wp++;
  513. if (data->wp >= WSIZE)
  514. data->wp = 0;
  515. }
  516. else if (n == 256)
  517. break;
  518. else
  519. {
  520. int len, dist, pos;
  521. n -= 257;
  522. len = cplens[n];
  523. if (cplext[n])
  524. len += grub_png_get_bits (data, cplext[n]);
  525. n = grub_png_get_huff_code (data, &data->dist_table);
  526. dist = cpdist[n];
  527. if (cpdext[n])
  528. dist += grub_png_get_bits (data, cpdext[n]);
  529. pos = data->wp - dist;
  530. if (pos < 0)
  531. pos += WSIZE;
  532. while (len > 0)
  533. {
  534. data->slide[data->wp] = data->slide[pos];
  535. grub_png_output_byte (data, data->slide[data->wp]);
  536. data->wp++;
  537. if (data->wp >= WSIZE)
  538. data->wp = 0;
  539. pos++;
  540. if (pos >= WSIZE)
  541. pos = 0;
  542. len--;
  543. }
  544. }
  545. }
  546. return grub_errno;
  547. }
  548. static grub_err_t
  549. grub_png_decode_image_data (struct grub_png_data *data)
  550. {
  551. grub_uint8_t cmf, flg;
  552. int final;
  553. cmf = grub_png_get_byte (data);
  554. flg = grub_png_get_byte (data);
  555. if ((cmf & 0xF) != Z_DEFLATED)
  556. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  557. "png: only support deflate compression method");
  558. if (flg & Z_FLAG_DICT)
  559. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  560. "png: dictionary not supported");
  561. do
  562. {
  563. int block_type;
  564. final = grub_png_get_bits (data, 1);
  565. block_type = grub_png_get_bits (data, 2);
  566. switch (block_type)
  567. {
  568. case INFLATE_STORED:
  569. {
  570. grub_uint16_t i, len;
  571. data->bit_count = 0;
  572. len = grub_png_get_byte (data);
  573. len += ((grub_uint16_t) grub_png_get_byte (data)) << 8;
  574. /* Skip NLEN field. */
  575. grub_png_get_byte (data);
  576. grub_png_get_byte (data);
  577. for (i = 0; i < len; i++)
  578. grub_png_output_byte (data, grub_png_get_byte (data));
  579. break;
  580. }
  581. case INFLATE_FIXED:
  582. grub_png_init_fixed_block (data);
  583. grub_png_read_dynamic_block (data);
  584. break;
  585. case INFLATE_DYNAMIC:
  586. grub_png_init_dynamic_block (data);
  587. grub_png_read_dynamic_block (data);
  588. break;
  589. default:
  590. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  591. "png: unknown block type");
  592. }
  593. }
  594. while ((!final) && (grub_errno == 0));
  595. /* Skip adler checksum. */
  596. grub_png_get_dword (data);
  597. /* Skip crc checksum. */
  598. grub_png_get_dword (data);
  599. return grub_errno;
  600. }
  601. static const grub_uint8_t png_magic[8] =
  602. { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0x0a };
  603. static void
  604. grub_png_convert_image (struct grub_png_data *data)
  605. {
  606. int i;
  607. grub_uint8_t *d1, *d2;
  608. d1 = (*data->bitmap)->data;
  609. d2 = data->image_data + 1;
  610. /* Only copy the upper 8 bit. */
  611. for (i = 0; i < (data->image_width * data->image_height * data->bpp >> 1);
  612. i++, d1++, d2+=2)
  613. *d1 = *d2;
  614. }
  615. static void
  616. grub_png_check_transparency (struct grub_png_data *data)
  617. {
  618. grub_uint8_t *p;
  619. int i;
  620. if (data->bpp != 4)
  621. return;
  622. p = (*data->bitmap)->data;
  623. for (i = 0, p += 3; i < data->image_width * data->image_height; i++, p += 4)
  624. if (*p != 255)
  625. {
  626. (*data->bitmap)->transparent = 1;
  627. break;
  628. }
  629. }
  630. static grub_err_t
  631. grub_png_decode_png (struct grub_png_data *data)
  632. {
  633. grub_uint8_t magic[8];
  634. if (grub_file_read (data->file, &magic[0], 8) != 8)
  635. return grub_errno;
  636. if (grub_memcmp (magic, png_magic, sizeof (png_magic)))
  637. return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: not a png file");
  638. while (1)
  639. {
  640. grub_uint32_t len, type;
  641. len = grub_png_get_dword (data);
  642. type = grub_png_get_dword (data);
  643. data->next_offset = data->file->offset + len + 4;
  644. switch (type)
  645. {
  646. case PNG_CHUNK_IHDR:
  647. grub_png_decode_image_header (data);
  648. break;
  649. case PNG_CHUNK_IDAT:
  650. data->inside_idat = 1;
  651. data->idat_remain = len;
  652. data->bit_count = 0;
  653. grub_png_decode_image_data (data);
  654. data->inside_idat = 0;
  655. break;
  656. case PNG_CHUNK_IEND:
  657. if (data->is_16bit)
  658. grub_png_convert_image (data);
  659. grub_png_check_transparency (data);
  660. return grub_errno;
  661. default:
  662. grub_file_seek (data->file, data->file->offset + len + 4);
  663. }
  664. if (grub_errno)
  665. break;
  666. if (data->file->offset != data->next_offset)
  667. return grub_error (GRUB_ERR_BAD_FILE_TYPE,
  668. "png: chunk size error");
  669. }
  670. return grub_errno;
  671. }
  672. static grub_err_t
  673. grub_video_reader_png (struct grub_video_bitmap **bitmap,
  674. const char *filename)
  675. {
  676. grub_file_t file;
  677. struct grub_png_data *data;
  678. file = grub_buffile_open (filename, 0);
  679. if (!file)
  680. return grub_errno;
  681. data = grub_zalloc (sizeof (*data));
  682. if (data != NULL)
  683. {
  684. data->file = file;
  685. data->bitmap = bitmap;
  686. grub_png_decode_png (data);
  687. grub_free (data->image_data);
  688. grub_free (data);
  689. }
  690. if (grub_errno != GRUB_ERR_NONE)
  691. {
  692. grub_video_bitmap_destroy (*bitmap);
  693. *bitmap = 0;
  694. }
  695. grub_file_close (file);
  696. return grub_errno;
  697. }
  698. #if defined(PNG_DEBUG)
  699. static grub_err_t
  700. grub_cmd_pngtest (grub_command_t cmd __attribute__ ((unused)),
  701. int argc, char **args)
  702. {
  703. struct grub_video_bitmap *bitmap = 0;
  704. if (argc != 1)
  705. return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
  706. grub_video_reader_png (&bitmap, args[0]);
  707. if (grub_errno != GRUB_ERR_NONE)
  708. return grub_errno;
  709. grub_video_bitmap_destroy (bitmap);
  710. return GRUB_ERR_NONE;
  711. }
  712. #endif
  713. static struct grub_video_bitmap_reader png_reader = {
  714. .extension = ".png",
  715. .reader = grub_video_reader_png,
  716. .next = 0
  717. };
  718. GRUB_MOD_INIT (png)
  719. {
  720. grub_video_bitmap_reader_register (&png_reader);
  721. #if defined(PNG_DEBUG)
  722. cmd = grub_register_command ("pngtest", grub_cmd_pngtest,
  723. "FILE",
  724. "Tests loading of PNG bitmap.");
  725. #endif
  726. }
  727. GRUB_MOD_FINI (png)
  728. {
  729. #if defined(PNG_DEBUG)
  730. grub_unregister_command (cmd);
  731. #endif
  732. grub_video_bitmap_reader_unregister (&png_reader);
  733. }