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

« back to all changes in this revision

Viewing changes to 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
 
}