~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/video/readers/png.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

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