1 /*
2 * Copyright 2006 Richard Wilson <richard.wilson@netsurf-browser.org>
3 * Copyright 2008 Sean Fox <dyntryx@gmail.com>
4 *
5 * This file is part of NetSurf's libnsbmp, http://www.netsurf-browser.org/
6 * Licenced under the MIT License,
7 * http://www.opensource.org/licenses/mit-license.php
8 */
9
10 /**
11 * \file
12 * BMP decoding implementation
13 *
14 * This library decode windows bitmaps and icons from their disc images.
15 *
16 * The image format is described in several documents:
17 * https://msdn.microsoft.com/en-us/library/dd183391(v=vs.85).aspx
18 * http://www.fileformat.info/format/bmp/egff.htm
19 * https://en.wikipedia.org/wiki/BMP_file_format
20 *
21 * Despite the format being clearly defined many bitmaps found on the web are
22 * not compliant and this implementation attempts to cope with as many issues
23 * as possible rather than simply failing.
24 */
25
26 #include <assert.h>
27 #include <stdbool.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32
33 #include <libnsbmp.h>
34
35 #include "utils/log.h"
36
37 /* squashes unused variable compiler warnings */
38 #define UNUSED(x) ((x)=(x))
39
40 /* BMP entry sizes */
41 #define BMP_FILE_HEADER_SIZE 14
42 #define ICO_FILE_HEADER_SIZE 6
43 #define ICO_DIR_ENTRY_SIZE 16
44
45 /* the bitmap information header types (encoded as lengths) */
46 #define BITMAPCOREHEADER 12
47
48 #ifdef WE_NEED_INT8_READING_NOW
read_int8(uint8_t * data,unsigned int o)49 static inline int8_t read_int8(uint8_t *data, unsigned int o) {
50 return (int8_t) data[o];
51 }
52 #endif
53
read_uint8(uint8_t * data,unsigned int o)54 static inline uint8_t read_uint8(uint8_t *data, unsigned int o) {
55 return (uint8_t) data[o];
56 }
57
read_int16(uint8_t * data,unsigned int o)58 static inline int16_t read_int16(uint8_t *data, unsigned int o) {
59 return (int16_t) (data[o] | (data[o+1] << 8));
60 }
61
read_uint16(uint8_t * data,unsigned int o)62 static inline uint16_t read_uint16(uint8_t *data, unsigned int o) {
63 return (uint16_t) (data[o] | (data[o+1] << 8));
64 }
65
read_int32(uint8_t * data,unsigned int o)66 static inline int32_t read_int32(uint8_t *data, unsigned int o) {
67 return (int32_t) ((unsigned)data[o] |
68 ((unsigned)data[o+1] << 8) |
69 ((unsigned)data[o+2] << 16) |
70 ((unsigned)data[o+3] << 24));
71 }
72
read_uint32(uint8_t * data,unsigned int o)73 static inline uint32_t read_uint32(uint8_t *data, unsigned int o) {
74 return (uint32_t) ((unsigned)data[o] |
75 ((unsigned)data[o+1] << 8) |
76 ((unsigned)data[o+2] << 16) |
77 ((unsigned)data[o+3] << 24));
78 }
79
80
81 /**
82 * Parse the bitmap info header
83 */
bmp_info_header_parse(bmp_image * bmp,uint8_t * data)84 static bmp_result bmp_info_header_parse(bmp_image *bmp, uint8_t *data)
85 {
86 uint32_t header_size;
87 uint32_t i;
88 uint8_t j;
89 int32_t width, height;
90 uint8_t palette_size;
91 unsigned int flags = 0;
92
93 /* must be at least enough data for a core header */
94 if (bmp->buffer_size < (BMP_FILE_HEADER_SIZE + BITMAPCOREHEADER)) {
95 return BMP_INSUFFICIENT_DATA;
96 }
97
98 header_size = read_uint32(data, 0);
99
100 /* ensure there is enough data for the declared header size*/
101 if ((bmp->buffer_size - BMP_FILE_HEADER_SIZE) < header_size) {
102 return BMP_INSUFFICIENT_DATA;
103 }
104
105 /* a variety of different bitmap headers can follow, depending
106 * on the BMP variant. The header length field determines the type.
107 */
108 if (header_size == BITMAPCOREHEADER) {
109 /* the following header is for os/2 and windows 2.x and consists of:
110 *
111 * +0 UINT32 size of this header (in bytes)
112 * +4 INT16 image width (in pixels)
113 * +6 INT16 image height (in pixels)
114 * +8 UINT16 number of colour planes (always 1)
115 * +10 UINT16 number of bits per pixel
116 */
117 width = read_int16(data, 4);
118 height = read_int16(data, 6);
119 if ((width <= 0) || (height == 0))
120 return BMP_DATA_ERROR;
121 if (height < 0) {
122 bmp->reversed = true;
123 height = -height;
124 }
125 /* ICOs only support 256*256 resolutions
126 * In the case of the ICO header, the height is actually the added
127 * height of XOR-Bitmap and AND-Bitmap (double the visible height)
128 * Technically we could remove this check and ICOs with bitmaps
129 * of any size could be processed; this is to conform to the spec.
130 */
131 if (bmp->ico) {
132 if ((width > 256) || (height > 512)) {
133 return BMP_DATA_ERROR;
134 } else {
135 bmp->width = width;
136 bmp->height = height / 2;
137 }
138 } else {
139 bmp->width = width;
140 bmp->height = height;
141 }
142 if (read_uint16(data, 8) != 1)
143 return BMP_DATA_ERROR;
144 bmp->bpp = read_uint16(data, 10);
145 /**
146 * The bpp value should be in the range 1-32, but the only
147 * values considered legal are:
148 * RGB ENCODING: 1, 4, 8, 16, 24 and 32
149 */
150 if ((bmp->bpp != 1) && (bmp->bpp != 4) &&
151 (bmp->bpp != 8) &&
152 (bmp->bpp != 16) &&
153 (bmp->bpp != 24) &&
154 (bmp->bpp != 32))
155 return BMP_DATA_ERROR;
156 if (bmp->bpp < 16)
157 bmp->colours = (1 << bmp->bpp);
158 palette_size = 3;
159 } else if (header_size < 40) {
160 return BMP_DATA_ERROR;
161 } else {
162 /* the following header is for windows 3.x and onwards. it is a
163 * minimum of 40 bytes and (as of Windows 95) a maximum of 108 bytes.
164 *
165 * +0 UINT32 size of this header (in bytes)
166 * +4 INT32 image width (in pixels)
167 * +8 INT32 image height (in pixels)
168 * +12 UINT16 number of colour planes (always 1)
169 * +14 UINT16 number of bits per pixel
170 * +16 UINT32 compression methods used
171 * +20 UINT32 size of bitmap (in bytes)
172 * +24 UINT32 horizontal resolution (in pixels per meter)
173 * +28 UINT32 vertical resolution (in pixels per meter)
174 * +32 UINT32 number of colours in the image
175 * +36 UINT32 number of important colours
176 * +40 UINT32 mask identifying bits of red component
177 * +44 UINT32 mask identifying bits of green component
178 * +48 UINT32 mask identifying bits of blue component
179 * +52 UINT32 mask identifying bits of alpha component
180 * +56 UINT32 color space type
181 * +60 UINT32 x coordinate of red endpoint
182 * +64 UINT32 y coordinate of red endpoint
183 * +68 UINT32 z coordinate of red endpoint
184 * +72 UINT32 x coordinate of green endpoint
185 * +76 UINT32 y coordinate of green endpoint
186 * +80 UINT32 z coordinate of green endpoint
187 * +84 UINT32 x coordinate of blue endpoint
188 * +88 UINT32 y coordinate of blue endpoint
189 * +92 UINT32 z coordinate of blue endpoint
190 * +96 UINT32 gamma red coordinate scale value
191 * +100 UINT32 gamma green coordinate scale value
192 * +104 UINT32 gamma blue coordinate scale value
193 */
194 width = read_int32(data, 4);
195 height = read_int32(data, 8);
196 if ((width <= 0) || (height == 0))
197 return BMP_DATA_ERROR;
198 if (height < 0) {
199 bmp->reversed = true;
200 if (height <= -INT32_MAX) {
201 height = INT32_MAX;
202 } else {
203 height = -height;
204 }
205 }
206 /* ICOs only support 256*256 resolutions
207 * In the case of the ICO header, the height is actually the added
208 * height of XOR-Bitmap and AND-Bitmap (double the visible height)
209 * Technically we could remove this check and ICOs with bitmaps
210 * of any size could be processed; this is to conform to the spec.
211 */
212 if (bmp->ico) {
213 if ((width > 256) || (height > 512)) {
214 return BMP_DATA_ERROR;
215 } else {
216 bmp->width = width;
217 bmp->height = height / 2;
218 }
219 } else {
220 bmp->width = width;
221 bmp->height = height;
222 }
223 if (read_uint16(data, 12) != 1)
224 return BMP_DATA_ERROR;
225 bmp->bpp = read_uint16(data, 14);
226 if (bmp->bpp == 0)
227 bmp->bpp = 8;
228 bmp->encoding = read_uint32(data, 16);
229 /**
230 * The bpp value should be in the range 1-32, but the only
231 * values considered legal are:
232 * RGB ENCODING: 1, 4, 8, 16, 24 and 32
233 * RLE4 ENCODING: 4
234 * RLE8 ENCODING: 8
235 * BITFIELD ENCODING: 16 and 32
236 */
237 switch (bmp->encoding) {
238 case BMP_ENCODING_RGB:
239 if ((bmp->bpp != 1) && (bmp->bpp != 4) &&
240 (bmp->bpp != 8) &&
241 (bmp->bpp != 16) &&
242 (bmp->bpp != 24) &&
243 (bmp->bpp != 32))
244 return BMP_DATA_ERROR;
245 break;
246 case BMP_ENCODING_RLE8:
247 if (bmp->bpp != 8)
248 return BMP_DATA_ERROR;
249 break;
250 case BMP_ENCODING_RLE4:
251 if (bmp->bpp != 4)
252 return BMP_DATA_ERROR;
253 break;
254 case BMP_ENCODING_BITFIELDS:
255 if ((bmp->bpp != 16) && (bmp->bpp != 32))
256 return BMP_DATA_ERROR;
257 break;
258 /* invalid encoding */
259 default:
260 return BMP_DATA_ERROR;
261 break;
262 }
263 /* Bitfield encoding means we have red, green, blue, and alpha masks.
264 * Here we acquire the masks and determine the required bit shift to
265 * align them in our 24-bit color 8-bit alpha format.
266 */
267 if (bmp->encoding == BMP_ENCODING_BITFIELDS) {
268 if (header_size == 40) {
269 header_size += 12;
270 if (bmp->buffer_size < (14 + header_size))
271 return BMP_INSUFFICIENT_DATA;
272 for (i = 0; i < 3; i++)
273 bmp->mask[i] = read_uint32(data, 40 + (i << 2));
274 } else {
275 if (header_size < 56)
276 return BMP_INSUFFICIENT_DATA;
277 for (i = 0; i < 4; i++)
278 bmp->mask[i] = read_uint32(data, 40 + (i << 2));
279 }
280 for (i = 0; i < 4; i++) {
281 if (bmp->mask[i] == 0)
282 break;
283 for (j = 31; j > 0; j--)
284 if (bmp->mask[i] & ((unsigned)1 << j)) {
285 if ((j - 7) > 0)
286 bmp->mask[i] &= (unsigned)0xff << (j - 7);
287 else
288 bmp->mask[i] &= 0xff >> (-(j - 7));
289 bmp->shift[i] = (i << 3) - (j - 7);
290 break;
291 }
292 }
293 }
294 bmp->colours = read_uint32(data, 32);
295 if (bmp->colours == 0 && bmp->bpp < 16)
296 bmp->colours = (1 << bmp->bpp);
297 palette_size = 4;
298 }
299 data += header_size;
300
301 /* if there's no alpha mask, flag the bmp opaque */
302 if ((!bmp->ico) && (bmp->mask[3] == 0)) {
303 flags |= BMP_OPAQUE;
304 bmp->opaque = true;
305 }
306
307 /* we only have a palette for <16bpp */
308 if (bmp->bpp < 16) {
309 /* we now have a series of palette entries of the format:
310 *
311 * +0 BYTE blue
312 * +1 BYTE green
313 * +2 BYTE red
314 *
315 * if the palette is from an OS/2 or Win2.x file then the entries
316 * are padded with an extra byte.
317 */
318
319 /* boundary checking */
320 if (bmp->buffer_size < (14 + header_size + ((uint64_t)4 * bmp->colours)))
321 return BMP_INSUFFICIENT_DATA;
322
323 /* create the colour table */
324 bmp->colour_table = (uint32_t *)malloc(bmp->colours * 4);
325 if (!bmp->colour_table)
326 return BMP_INSUFFICIENT_MEMORY;
327 for (i = 0; i < bmp->colours; i++) {
328 uint32_t colour = data[2] | (data[1] << 8) | (data[0] << 16);
329 if (bmp->opaque)
330 colour |= ((uint32_t)0xff << 24);
331 data += palette_size;
332 bmp->colour_table[i] = read_uint32((uint8_t *)&colour,0);
333 }
334
335 /* some bitmaps have a bad offset if there is a pallete, work
336 * round this by fixing up the data offset to after the palette
337 * but only if there is data following the palette as some
338 * bitmaps encode data in the palette!
339 */
340 if ((bmp->bitmap_offset < (uint32_t)(data - bmp->bmp_data)) &&
341 ((bmp->buffer_size - (data - bmp->bmp_data)) > 0)) {
342 bmp->bitmap_offset = data - bmp->bmp_data;
343 }
344 }
345
346 /* create our bitmap */
347 flags |= BMP_NEW | BMP_CLEAR_MEMORY;
348 bmp->bitmap = bmp->bitmap_callbacks.bitmap_create(bmp->width, bmp->height, flags);
349 if (!bmp->bitmap) {
350 if (bmp->colour_table)
351 free(bmp->colour_table);
352 bmp->colour_table = NULL;
353 return BMP_INSUFFICIENT_MEMORY;
354 }
355 /* BMPs within ICOs don't have BMP file headers, so the image data should
356 * always be right after the colour table.
357 */
358 if (bmp->ico)
359 bmp->bitmap_offset = (intptr_t)data - (intptr_t)bmp->bmp_data;
360 return BMP_OK;
361 }
362
363
364 /**
365 * Parse the bitmap file header
366 *
367 * \param bmp The bitmap.
368 * \param data The data for the file header
369 * \return BMP_OK on success or error code on faliure
370 */
bmp_file_header_parse(bmp_image * bmp,uint8_t * data)371 static bmp_result bmp_file_header_parse(bmp_image *bmp, uint8_t *data)
372 {
373 /* standard 14-byte BMP file header is:
374 *
375 * +0 UINT16 File Type ('BM')
376 * +2 UINT32 Size of File (in bytes)
377 * +6 INT16 Reserved Field (1)
378 * +8 INT16 Reserved Field (2)
379 * +10 UINT32 Starting Position of Image Data (offset in bytes)
380 */
381 if (bmp->buffer_size < BMP_FILE_HEADER_SIZE)
382 return BMP_INSUFFICIENT_DATA;
383
384 if ((data[0] != (uint8_t)'B') || (data[1] != (uint8_t)'M'))
385 return BMP_DATA_ERROR;
386
387 bmp->bitmap_offset = read_uint32(data, 10);
388
389 /* check the offset to data lies within the file */
390 if (bmp->bitmap_offset >= bmp->buffer_size) {
391 return BMP_INSUFFICIENT_DATA;
392 }
393
394 return BMP_OK;
395 }
396
397
398 /**
399 * Allocates memory for the next BMP in an ICO collection
400 *
401 * Sets proper structure values
402 *
403 * \param ico the ICO collection to add the image to
404 * \param image a pointer to the ICO image to be initialised
405 */
next_ico_image(ico_collection * ico,ico_image * image)406 static bmp_result next_ico_image(ico_collection *ico, ico_image *image) {
407 bmp_create(&image->bmp, &ico->bitmap_callbacks);
408 image->next = ico->first;
409 ico->first = image;
410 return BMP_OK;
411 }
412
413
414 /**
415 * Parse the icon file header
416 *
417 * \param ico The icon collection.
418 * \param data The header data to parse.
419 * \return BMP_OK on successful parse else error code
420 */
ico_header_parse(ico_collection * ico,uint8_t * data)421 static bmp_result ico_header_parse(ico_collection *ico, uint8_t *data)
422 {
423 uint16_t count, i;
424 bmp_result result;
425 int area, max_area = 0;
426
427 /* 6-byte ICO file header is:
428 *
429 * +0 INT16 Reserved (should be 0)
430 * +2 UINT16 Type (1 for ICO, 2 for CUR)
431 * +4 UINT16 Number of BMPs to follow
432 */
433 if (ico->buffer_size < ICO_FILE_HEADER_SIZE)
434 return BMP_INSUFFICIENT_DATA;
435 // if (read_int16(data, 2) != 0x0000)
436 // return BMP_DATA_ERROR;
437 if (read_uint16(data, 2) != 0x0001)
438 return BMP_DATA_ERROR;
439 count = read_uint16(data, 4);
440 if (count == 0)
441 return BMP_DATA_ERROR;
442 data += ICO_FILE_HEADER_SIZE;
443
444 /* check if we have enough data for the directory */
445 if (ico->buffer_size < (uint32_t)(ICO_FILE_HEADER_SIZE + (ICO_DIR_ENTRY_SIZE * count)))
446 return BMP_INSUFFICIENT_DATA;
447
448 /* Decode the BMP files.
449 *
450 * 16-byte ICO directory entry is:
451 *
452 * +0 UINT8 Width (0 for 256 pixels)
453 * +1 UINT8 Height (0 for 256 pixels)
454 * +2 UINT8 Colour count (0 if more than 256 colours)
455 * +3 INT8 Reserved (should be 0, but may not be)
456 * +4 UINT16 Colour Planes (should be 0 or 1)
457 * +6 UINT16 Bits Per Pixel
458 * +8 UINT32 Size of BMP info header + bitmap data in bytes
459 * +12 UINT32 Offset (points to the BMP info header, not the bitmap data)
460 */
461 for (i = 0; i < count; i++) {
462 ico_image *image;
463 image = calloc(1, sizeof(ico_image));
464 if (!image)
465 return BMP_INSUFFICIENT_MEMORY;
466 result = next_ico_image(ico, image);
467 if (result != BMP_OK)
468 return result;
469 image->bmp.width = read_uint8(data, 0);
470 if (image->bmp.width == 0)
471 image->bmp.width = 256;
472 image->bmp.height = read_uint8(data, 1);
473 if (image->bmp.height == 0)
474 image->bmp.height = 256;
475 image->bmp.buffer_size = read_uint32(data, 8);
476 image->bmp.bmp_data = ico->ico_data + read_uint32(data, 12);
477 if (image->bmp.bmp_data + image->bmp.buffer_size >
478 ico->ico_data + ico->buffer_size)
479 return BMP_INSUFFICIENT_DATA;
480 image->bmp.ico = true;
481 data += ICO_DIR_ENTRY_SIZE;
482
483 /* Ensure that the bitmap data resides in the buffer */
484 if (image->bmp.bmp_data - ico->ico_data >= 0 &&
485 (uint32_t)(image->bmp.bmp_data -
486 ico->ico_data) >= ico->buffer_size)
487 return BMP_DATA_ERROR;
488
489 /* Ensure that we have sufficient data to read the bitmap */
490 if (image->bmp.buffer_size - ICO_DIR_ENTRY_SIZE >=
491 ico->buffer_size - (ico->ico_data - data))
492 return BMP_INSUFFICIENT_DATA;
493
494 result = bmp_info_header_parse(&image->bmp,
495 image->bmp.bmp_data);
496 if (result != BMP_OK)
497 return result;
498
499 /* adjust the size based on the images available */
500 area = image->bmp.width * image->bmp.height;
501 if (area > max_area) {
502 ico->width = image->bmp.width;
503 ico->height = image->bmp.height;
504 max_area = area;
505 }
506 }
507 return BMP_OK;
508 }
509
510
511 /**
512 * Decode BMP data stored in 32bpp colour.
513 *
514 * \param bmp the BMP image to decode
515 * \param start the data to decode, updated to last byte read on success
516 * \param bytes the number of bytes of data available
517 * \return BMP_OK on success
518 * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
519 * in this case, the image may be partially viewable
520 */
bmp_decode_rgb32(bmp_image * bmp,uint8_t ** start,int bytes)521 static bmp_result bmp_decode_rgb32(bmp_image *bmp, uint8_t **start, int bytes)
522 {
523 uint8_t *top, *bottom, *end, *data;
524 uint32_t *scanline;
525 uint32_t x, y;
526 uint32_t swidth;
527 uint8_t i;
528 uint32_t word;
529
530 assert(bmp->bpp == 32);
531
532 data = *start;
533 swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width;
534 top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
535 if (!top)
536 return BMP_INSUFFICIENT_MEMORY;
537 bottom = top + (uint64_t)swidth * (bmp->height - 1);
538 end = data + bytes;
539 bmp->decoded = true;
540
541 /* Determine transparent index */
542 if (bmp->limited_trans) {
543 if ((data + 4) > end)
544 return BMP_INSUFFICIENT_DATA;
545 if (bmp->encoding == BMP_ENCODING_BITFIELDS)
546 bmp->transparent_index = read_uint32(data, 0);
547 else
548 bmp->transparent_index = data[2] | (data[1] << 8) | (data[0] << 16);
549 }
550
551 for (y = 0; y < bmp->height; y++) {
552 if ((data + (4 * bmp->width)) > end)
553 return BMP_INSUFFICIENT_DATA;
554 if (bmp->reversed)
555 scanline = (void *)(top + (y * swidth));
556 else
557 scanline = (void *)(bottom - (y * swidth));
558 if (bmp->encoding == BMP_ENCODING_BITFIELDS) {
559 for (x = 0; x < bmp->width; x++) {
560 word = read_uint32(data, 0);
561 for (i = 0; i < 4; i++)
562 if (bmp->shift[i] > 0)
563 scanline[x] |= ((word & bmp->mask[i]) << bmp->shift[i]);
564 else
565 scanline[x] |= ((word & bmp->mask[i]) >> (-bmp->shift[i]));
566 /* 32-bit BMPs have alpha masks, but sometimes they're not utilized */
567 if (bmp->opaque)
568 scanline[x] |= ((unsigned)0xff << 24);
569 data += 4;
570 scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
571 }
572 } else {
573 for (x = 0; x < bmp->width; x++) {
574 scanline[x] = data[2] | (data[1] << 8) | (data[0] << 16);
575 if ((bmp->limited_trans) && (scanline[x] == bmp->transparent_index)) {
576 scanline[x] = bmp->trans_colour;
577 }
578 if (bmp->opaque) {
579 scanline[x] |= ((unsigned)0xff << 24);
580 } else {
581 scanline[x] |= (unsigned)data[3] << 24;
582 }
583 data += 4;
584 scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
585 }
586 }
587 }
588 *start = data;
589 return BMP_OK;
590 }
591
592
593 /**
594 * Decode BMP data stored in 24bpp colour.
595 *
596 * \param bmp the BMP image to decode
597 * \param start the data to decode, updated to last byte read on success
598 * \param bytes the number of bytes of data available
599 * \return BMP_OK on success
600 * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
601 * in this case, the image may be partially viewable
602 */
bmp_decode_rgb24(bmp_image * bmp,uint8_t ** start,int bytes)603 static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t **start, int bytes)
604 {
605 uint8_t *top, *bottom, *end, *data;
606 uint32_t *scanline;
607 uint32_t x, y;
608 uint32_t swidth;
609 intptr_t addr;
610
611 assert(bmp->encoding == BMP_ENCODING_RGB);
612 assert(bmp->bpp == 24);
613
614 data = *start;
615 swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width;
616 top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
617 if (!top) {
618 return BMP_INSUFFICIENT_MEMORY;
619 }
620
621 bottom = top + (uint64_t)swidth * (bmp->height - 1);
622 end = data + bytes;
623 addr = ((intptr_t)data) & 3;
624 bmp->decoded = true;
625
626 /* Determine transparent index */
627 if (bmp->limited_trans) {
628 if ((data + 3) > end) {
629 return BMP_INSUFFICIENT_DATA;
630 }
631
632 bmp->transparent_index = data[2] | (data[1] << 8) | (data[0] << 16);
633 }
634
635 for (y = 0; y < bmp->height; y++) {
636 if ((data + (3 * bmp->width)) > end) {
637 return BMP_INSUFFICIENT_DATA;
638 }
639
640 if (bmp->reversed) {
641 scanline = (void *)(top + (y * swidth));
642 } else {
643 scanline = (void *)(bottom - (y * swidth));
644 }
645
646 for (x = 0; x < bmp->width; x++) {
647 scanline[x] = data[2] | (data[1] << 8) | (data[0] << 16);
648 if ((bmp->limited_trans) && (scanline[x] == bmp->transparent_index)) {
649 scanline[x] = bmp->trans_colour;
650 } else {
651 scanline[x] |= ((uint32_t)0xff << 24);
652 }
653 data += 3;
654 scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
655 }
656
657 while (addr != (((intptr_t)data) & 3)) {
658 data++;
659 }
660 }
661 *start = data;
662 return BMP_OK;
663 }
664
665
666 /**
667 * Decode BMP data stored in 16bpp colour.
668 *
669 * \param bmp the BMP image to decode
670 * \param start the data to decode, updated to last byte read on success
671 * \param bytes the number of bytes of data available
672 * \return BMP_OK on success
673 * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
674 * in this case, the image may be partially viewable
675 */
bmp_decode_rgb16(bmp_image * bmp,uint8_t ** start,int bytes)676 static bmp_result bmp_decode_rgb16(bmp_image *bmp, uint8_t **start, int bytes)
677 {
678 uint8_t *top, *bottom, *end, *data;
679 uint32_t *scanline;
680 uint32_t x, y, swidth;
681 intptr_t addr;
682 uint8_t i;
683 uint16_t word;
684
685 data = *start;
686 swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width;
687 top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
688 if (!top)
689 return BMP_INSUFFICIENT_MEMORY;
690 bottom = top + (uint64_t)swidth * (bmp->height - 1);
691 end = data + bytes;
692 addr = ((intptr_t)data) & 3;
693 bmp->decoded = true;
694
695 /* Determine transparent index */
696 if (bmp->limited_trans) {
697 if ((data + 2) > end)
698 return BMP_INSUFFICIENT_DATA;
699 bmp->transparent_index = read_uint16(data, 0);
700 }
701
702 for (y = 0; y < bmp->height; y++) {
703 if ((data + (2 * bmp->width)) > end)
704 return BMP_INSUFFICIENT_DATA;
705 if (bmp->reversed)
706 scanline = (void *)(top + (y * swidth));
707 else
708 scanline = (void *)(bottom - (y * swidth));
709 if (bmp->encoding == BMP_ENCODING_BITFIELDS) {
710 for (x = 0; x < bmp->width; x++) {
711 word = read_uint16(data, 0);
712 if ((bmp->limited_trans) && (word == bmp->transparent_index))
713 scanline[x] = bmp->trans_colour;
714 else {
715 scanline[x] = 0;
716 for (i = 0; i < 4; i++)
717 if (bmp->shift[i] > 0)
718 scanline[x] |= ((word & bmp->mask[i]) << bmp->shift[i]);
719 else
720 scanline[x] |= ((word & bmp->mask[i]) >> (-bmp->shift[i]));
721 if (bmp->opaque)
722 scanline[x] |= ((unsigned)0xff << 24);
723 }
724 data += 2;
725 scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
726 }
727 } else {
728 for (x = 0; x < bmp->width; x++) {
729 word = read_uint16(data, 0);
730 if ((bmp->limited_trans) && (word == bmp->transparent_index))
731 scanline[x] = bmp->trans_colour;
732 else {
733 /* 16-bit RGB defaults to RGB555 */
734 scanline[x] = ((word & (31 << 0)) << 19) |
735 ((word & (31 << 5)) << 6) |
736 ((word & (31 << 10)) >> 7);
737 }
738 if (bmp->opaque)
739 scanline[x] |= ((unsigned)0xff << 24);
740 data += 2;
741 scanline[x] = read_uint32((uint8_t *)&scanline[x],0);
742 }
743 }
744 while (addr != (((intptr_t)data) & 3))
745 data += 2;
746 }
747 *start = data;
748 return BMP_OK;
749 }
750
751
752 /**
753 * Decode BMP data stored with a palette and in 8bpp colour or less.
754 *
755 * \param bmp the BMP image to decode
756 * \param start the data to decode, updated to last byte read on success
757 * \param bytes the number of bytes of data available
758 * \return BMP_OK on success
759 * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
760 * in this case, the image may be partially viewable
761 */
bmp_decode_rgb(bmp_image * bmp,uint8_t ** start,int bytes)762 static bmp_result bmp_decode_rgb(bmp_image *bmp, uint8_t **start, int bytes)
763 {
764 uint8_t *top, *bottom, *end, *data;
765 uint32_t *scanline;
766 intptr_t addr;
767 uint32_t x, y, swidth;
768 uint8_t bit_shifts[8];
769 uint8_t ppb = 8 / bmp->bpp;
770 uint8_t bit_mask = (1 << bmp->bpp) - 1;
771 uint8_t cur_byte = 0, bit, i;
772
773 /* Belt and braces, we shouldn't get here unless this holds */
774 assert(ppb >= 1);
775
776 for (i = 0; i < ppb; i++)
777 bit_shifts[i] = 8 - ((i + 1) * bmp->bpp);
778
779 data = *start;
780 swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width;
781 top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
782 if (!top)
783 return BMP_INSUFFICIENT_MEMORY;
784 bottom = top + (uint64_t)swidth * (bmp->height - 1);
785 end = data + bytes;
786 addr = ((intptr_t)data) & 3;
787 bmp->decoded = true;
788
789 /* Determine transparent index */
790 if (bmp->limited_trans) {
791 uint32_t idx = (*data >> bit_shifts[0]) & bit_mask;
792 if (idx >= bmp->colours)
793 return BMP_DATA_ERROR;
794 bmp->transparent_index = bmp->colour_table[idx];
795 }
796
797 for (y = 0; y < bmp->height; y++) {
798 bit = 8;
799 if ((data + ((bmp->width + ppb - 1) / ppb)) > end)
800 return BMP_INSUFFICIENT_DATA;
801 if (bmp->reversed)
802 scanline = (void *)(top + (y * swidth));
803 else
804 scanline = (void *)(bottom - (y * swidth));
805 for (x = 0; x < bmp->width; x++) {
806 uint32_t idx;
807 if (bit >= ppb) {
808 bit = 0;
809 cur_byte = *data++;
810 }
811 idx = (cur_byte >> bit_shifts[bit++]) & bit_mask;
812 if (idx < bmp->colours) {
813 /* ensure colour table index is in bounds */
814 scanline[x] = bmp->colour_table[idx];
815 if ((bmp->limited_trans) &&
816 (scanline[x] == bmp->transparent_index)) {
817 scanline[x] = bmp->trans_colour;
818 }
819 }
820 }
821 while (addr != (((intptr_t)data) & 3))
822 data++;
823 }
824 *start = data;
825 return BMP_OK;
826 }
827
828
829 /**
830 * Decode a 1bpp mask for an ICO
831 *
832 * \param bmp the BMP image to decode
833 * \param data the data to decode
834 * \param bytes the number of bytes of data available
835 * \return BMP_OK on success
836 */
bmp_decode_mask(bmp_image * bmp,uint8_t * data,int bytes)837 static bmp_result bmp_decode_mask(bmp_image *bmp, uint8_t *data, int bytes)
838 {
839 uint8_t *top, *bottom, *end;
840 uint32_t *scanline;
841 intptr_t addr;
842 uint32_t x, y, swidth;
843 uint32_t cur_byte = 0;
844
845 swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width;
846 top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
847 if (!top)
848 return BMP_INSUFFICIENT_MEMORY;
849 bottom = top + (uint64_t)swidth * (bmp->height - 1);
850 end = data + bytes;
851
852 addr = ((intptr_t)data) & 3;
853
854 for (y = 0; y < bmp->height; y++) {
855 if ((data + (bmp->width >> 3)) > end)
856 return BMP_INSUFFICIENT_DATA;
857 scanline = (void *)(bottom - (y * swidth));
858 for (x = 0; x < bmp->width; x++) {
859 if ((x & 7) == 0)
860 cur_byte = *data++;
861 scanline[x] = read_uint32((uint8_t *)&scanline[x], 0);
862 if ((cur_byte & 128) == 0) {
863 scanline[x] |= ((unsigned)0xff << 24);
864 } else {
865 scanline[x] &= 0xffffff;
866 }
867 scanline[x] = read_uint32((uint8_t *)&scanline[x], 0);
868 cur_byte = cur_byte << 1;
869 }
870 while (addr != (((intptr_t)data) & 3))
871 data++;
872 }
873 return BMP_OK;
874 }
875
876
877 /**
878 * Decode BMP data stored encoded in RLE8.
879 *
880 * \param bmp the BMP image to decode
881 * \param data the data to decode
882 * \param bytes the number of bytes of data available
883 * \return BMP_OK on success
884 * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
885 * in this case, the image may be partially viewable
886 */
887 static bmp_result
bmp_decode_rle8(bmp_image * bmp,uint8_t * data,int bytes)888 bmp_decode_rle8(bmp_image *bmp, uint8_t *data, int bytes)
889 {
890 uint8_t *top, *bottom, *end;
891 uint32_t *scanline;
892 uint32_t swidth;
893 uint32_t i, length, pixels_left;
894 uint32_t x = 0, y = 0, last_y = 0;
895 uint32_t pixel = 0;
896
897 if (bmp->ico)
898 return BMP_DATA_ERROR;
899
900 swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width;
901 top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
902 if (!top)
903 return BMP_INSUFFICIENT_MEMORY;
904 bottom = top + (uint64_t)swidth * (bmp->height - 1);
905 end = data + bytes;
906 bmp->decoded = true;
907
908 do {
909 if (data + 2 > end)
910 return BMP_INSUFFICIENT_DATA;
911 length = *data++;
912 if (length == 0) {
913 length = *data++;
914 switch (length) {
915 case 0:
916 /* 00 - 00 means end of scanline */
917 x = 0;
918 if (last_y == y) {
919 y++;
920 if (y >= bmp->height)
921 return BMP_DATA_ERROR;
922 }
923 last_y = y;
924 break;
925
926 case 1:
927 /* 00 - 01 means end of RLE data */
928 return BMP_OK;
929
930 case 2:
931 /* 00 - 02 - XX - YY means move cursor */
932 if (data + 2 > end)
933 return BMP_INSUFFICIENT_DATA;
934 x += *data++;
935 if (x >= bmp->width)
936 return BMP_DATA_ERROR;
937 y += *data++;
938 if (y >= bmp->height)
939 return BMP_DATA_ERROR;
940 break;
941
942 default:
943 /* 00 - NN means escape NN pixels */
944 if (bmp->reversed) {
945 pixels_left = (bmp->height - y) * bmp->width - x;
946 scanline = (void *)(top + (y * swidth));
947 } else {
948 pixels_left = (y + 1) * bmp->width - x;
949 scanline = (void *)(bottom - (y * swidth));
950 }
951 if (length > pixels_left)
952 length = pixels_left;
953 if (data + length > end)
954 return BMP_INSUFFICIENT_DATA;
955
956 /* the following code could be easily optimised
957 * by simply checking the bounds on entry and
958 * using some simple copying routines if so
959 */
960 for (i = 0; i < length; i++) {
961 uint32_t idx = (uint32_t) *data++;
962 if (x >= bmp->width) {
963 x = 0;
964 y++;
965 if (y >= bmp->height)
966 return BMP_DATA_ERROR;
967 if (bmp->reversed) {
968 scanline += bmp->width;
969 } else {
970 scanline -= bmp->width;
971 }
972 }
973 if (idx >= bmp->colours)
974 return BMP_DATA_ERROR;
975 scanline[x++] = bmp->colour_table[idx];
976 }
977
978 if ((length & 1) && (*data++ != 0x00))
979 return BMP_DATA_ERROR;
980
981 break;
982 }
983 } else {
984 uint32_t idx;
985
986 /* NN means perform RLE for NN pixels */
987 if (bmp->reversed) {
988 pixels_left = (bmp->height - y) * bmp->width - x;
989 scanline = (void *)(top + (y * swidth));
990 } else {
991 pixels_left = (y + 1) * bmp->width - x;
992 scanline = (void *)(bottom - (y * swidth));
993 }
994 if (length > pixels_left)
995 length = pixels_left;
996
997 /* boundary checking */
998 if (data + 1 > end)
999 return BMP_INSUFFICIENT_DATA;
1000
1001 /* the following code could be easily optimised by
1002 * simply checking the bounds on entry and using some
1003 * simply copying routines if so
1004 */
1005 idx = (uint32_t) *data++;
1006 if (idx >= bmp->colours)
1007 return BMP_DATA_ERROR;
1008
1009 pixel = bmp->colour_table[idx];
1010 for (i = 0; i < length; i++) {
1011 if (x >= bmp->width) {
1012 x = 0;
1013 y++;
1014 if (y >= bmp->height)
1015 return BMP_DATA_ERROR;
1016 if (bmp->reversed) {
1017 scanline += bmp->width;
1018 } else {
1019 scanline -= bmp->width;
1020 }
1021 }
1022 scanline[x++] = pixel;
1023 }
1024 }
1025 } while (data < end);
1026
1027 return BMP_OK;
1028 }
1029
1030
1031 /**
1032 * Decode BMP data stored encoded in RLE4.
1033 *
1034 * \param bmp the BMP image to decode
1035 * \param data the data to decode
1036 * \param bytes the number of bytes of data available
1037 * \return BMP_OK on success
1038 * BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
1039 * in this case, the image may be partially viewable
1040 */
1041 static bmp_result
bmp_decode_rle4(bmp_image * bmp,uint8_t * data,int bytes)1042 bmp_decode_rle4(bmp_image *bmp, uint8_t *data, int bytes)
1043 {
1044 uint8_t *top, *bottom, *end;
1045 uint32_t *scanline;
1046 uint32_t swidth;
1047 uint32_t i, length, pixels_left;
1048 uint32_t x = 0, y = 0, last_y = 0;
1049 uint32_t pixel = 0, pixel2;
1050
1051 if (bmp->ico)
1052 return BMP_DATA_ERROR;
1053
1054 swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width;
1055 top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
1056 if (!top)
1057 return BMP_INSUFFICIENT_MEMORY;
1058 bottom = top + (uint64_t)swidth * (bmp->height - 1);
1059 end = data + bytes;
1060 bmp->decoded = true;
1061
1062 do {
1063 if (data + 2 > end)
1064 return BMP_INSUFFICIENT_DATA;
1065 length = *data++;
1066 if (length == 0) {
1067 length = *data++;
1068 switch (length) {
1069 case 0:
1070 /* 00 - 00 means end of scanline */
1071 x = 0;
1072 if (last_y == y) {
1073 y++;
1074 if (y >= bmp->height)
1075 return BMP_DATA_ERROR;
1076 }
1077 last_y = y;
1078 break;
1079
1080 case 1:
1081 /* 00 - 01 means end of RLE data */
1082 return BMP_OK;
1083
1084 case 2:
1085 /* 00 - 02 - XX - YY means move cursor */
1086 if (data + 2 > end)
1087 return BMP_INSUFFICIENT_DATA;
1088 x += *data++;
1089 if (x >= bmp->width)
1090 return BMP_DATA_ERROR;
1091 y += *data++;
1092 if (y >= bmp->height)
1093 return BMP_DATA_ERROR;
1094 break;
1095
1096 default:
1097 /* 00 - NN means escape NN pixels */
1098 if (bmp->reversed) {
1099 pixels_left = (bmp->height - y) * bmp->width - x;
1100 scanline = (void *)(top + (y * swidth));
1101 } else {
1102 pixels_left = (y + 1) * bmp->width - x;
1103 scanline = (void *)(bottom - (y * swidth));
1104 }
1105 if (length > pixels_left)
1106 length = pixels_left;
1107 if (data + ((length + 1) / 2) > end)
1108 return BMP_INSUFFICIENT_DATA;
1109
1110 /* the following code could be easily optimised
1111 * by simply checking the bounds on entry and
1112 * using some simple copying routines
1113 */
1114
1115 for (i = 0; i < length; i++) {
1116 if (x >= bmp->width) {
1117 x = 0;
1118 y++;
1119 if (y >= bmp->height)
1120 return BMP_DATA_ERROR;
1121 if (bmp->reversed) {
1122 scanline += bmp->width;
1123 } else {
1124 scanline -= bmp->width;
1125 }
1126
1127 }
1128 if ((i & 1) == 0) {
1129 pixel = *data++;
1130 if ((pixel >> 4) >= bmp->colours)
1131 return BMP_DATA_ERROR;
1132 scanline[x++] = bmp->colour_table
1133 [pixel >> 4];
1134 } else {
1135 if ((pixel & 0xf) >= bmp->colours)
1136 return BMP_DATA_ERROR;
1137 scanline[x++] = bmp->colour_table
1138 [pixel & 0xf];
1139 }
1140 }
1141 length = (length + 1) >> 1;
1142
1143 if ((length & 1) && (*data++ != 0x00))
1144 return BMP_DATA_ERROR;
1145
1146 break;
1147 }
1148 } else {
1149 /* NN means perform RLE for NN pixels */
1150 if (bmp->reversed) {
1151 pixels_left = (bmp->height - y) * bmp->width - x;
1152 scanline = (void *)(top + (y * swidth));
1153 } else {
1154 pixels_left = (y + 1) * bmp->width - x;
1155 scanline = (void *)(bottom - (y * swidth));
1156 }
1157 if (length > pixels_left)
1158 length = pixels_left;
1159
1160 /* boundary checking */
1161 if (data + 1 > end)
1162 return BMP_INSUFFICIENT_DATA;
1163
1164 /* the following code could be easily optimised by
1165 * simply checking the bounds on entry and using some
1166 * simple copying routines
1167 */
1168
1169 pixel2 = *data++;
1170 if ((pixel2 >> 4) >= bmp->colours ||
1171 (pixel2 & 0xf) >= bmp->colours)
1172 return BMP_DATA_ERROR;
1173 pixel = bmp->colour_table[pixel2 >> 4];
1174 pixel2 = bmp->colour_table[pixel2 & 0xf];
1175 for (i = 0; i < length; i++) {
1176 if (x >= bmp->width) {
1177 x = 0;
1178 y++;
1179 if (y >= bmp->height)
1180 return BMP_DATA_ERROR;
1181 if (bmp->reversed) {
1182 scanline += bmp->width;
1183 } else {
1184 scanline -= bmp->width;
1185 }
1186 }
1187 if ((i & 1) == 0)
1188 scanline[x++] = pixel;
1189 else
1190 scanline[x++] = pixel2;
1191 }
1192
1193 }
1194 } while (data < end);
1195
1196 return BMP_OK;
1197 }
1198
1199
1200 /* exported interface documented in libnsbmp.h */
1201 bmp_result
bmp_create(bmp_image * bmp,bmp_bitmap_callback_vt * bitmap_callbacks)1202 bmp_create(bmp_image *bmp,
1203 bmp_bitmap_callback_vt *bitmap_callbacks)
1204 {
1205 memset(bmp, 0, sizeof(bmp_image));
1206 bmp->bitmap_callbacks = *bitmap_callbacks;
1207
1208 return BMP_OK;
1209 }
1210
1211
1212 /* exported interface documented in libnsbmp.h */
1213 bmp_result
ico_collection_create(ico_collection * ico,bmp_bitmap_callback_vt * bitmap_callbacks)1214 ico_collection_create(ico_collection *ico,
1215 bmp_bitmap_callback_vt *bitmap_callbacks)
1216 {
1217
1218 memset(ico, 0, sizeof(ico_collection));
1219 ico->bitmap_callbacks = *bitmap_callbacks;
1220
1221 return BMP_OK;
1222 }
1223
1224
1225 /* exported interface documented in libnsbmp.h */
bmp_analyse(bmp_image * bmp,size_t size,uint8_t * data)1226 bmp_result bmp_analyse(bmp_image *bmp, size_t size, uint8_t *data)
1227 {
1228 bmp_result res;
1229
1230 /* ensure we aren't already initialised */
1231 if (bmp->bitmap) {
1232 return BMP_OK;
1233 }
1234
1235 /* initialize source data values */
1236 bmp->buffer_size = size;
1237 bmp->bmp_data = data;
1238
1239 res = bmp_file_header_parse(bmp, data);
1240 if (res == BMP_OK) {
1241 res = bmp_info_header_parse(bmp, data + BMP_FILE_HEADER_SIZE);
1242 }
1243 return res;
1244 }
1245
1246
1247 /* exported interface documented in libnsbmp.h */
ico_analyse(ico_collection * ico,size_t size,uint8_t * data)1248 bmp_result ico_analyse(ico_collection *ico, size_t size, uint8_t *data)
1249 {
1250 /* ensure we aren't already initialised */
1251 if (ico->first)
1252 return BMP_OK;
1253
1254 /* initialize values */
1255 ico->buffer_size = size;
1256 ico->ico_data = data;
1257
1258 return ico_header_parse(ico, data);
1259 }
1260
1261
1262 /* exported interface documented in libnsbmp.h */
bmp_decode(bmp_image * bmp)1263 bmp_result bmp_decode(bmp_image *bmp)
1264 {
1265 uint8_t *data;
1266 uint32_t bytes;
1267 bmp_result result = BMP_OK;
1268
1269 assert(bmp->bitmap);
1270
1271 data = bmp->bmp_data + bmp->bitmap_offset;
1272 bytes = bmp->buffer_size - bmp->bitmap_offset;
1273
1274 switch (bmp->encoding) {
1275 case BMP_ENCODING_RGB:
1276 switch (bmp->bpp) {
1277 case 32:
1278 result = bmp_decode_rgb32(bmp, &data, bytes);
1279 break;
1280
1281 case 24:
1282 result = bmp_decode_rgb24(bmp, &data, bytes);
1283 break;
1284
1285 case 16:
1286 result = bmp_decode_rgb16(bmp, &data, bytes);
1287 break;
1288
1289 default:
1290 result = bmp_decode_rgb(bmp, &data, bytes);
1291 break;
1292 }
1293 break;
1294
1295 case BMP_ENCODING_RLE8:
1296 result = bmp_decode_rle8(bmp, data, bytes);
1297 break;
1298
1299 case BMP_ENCODING_RLE4:
1300 result = bmp_decode_rle4(bmp, data, bytes);
1301 break;
1302
1303 case BMP_ENCODING_BITFIELDS:
1304 switch (bmp->bpp) {
1305 case 32:
1306 result = bmp_decode_rgb32(bmp, &data, bytes);
1307 break;
1308
1309 case 16:
1310 result = bmp_decode_rgb16(bmp, &data, bytes);
1311 break;
1312
1313 default:
1314 result = BMP_DATA_ERROR;
1315 break;
1316 }
1317 break;
1318 }
1319
1320 /* icons with less than 32bpp have a 1bpp alpha mask */
1321 if ((result == BMP_OK) && (bmp->ico) && (bmp->bpp != 32)) {
1322 bytes = (uintptr_t)bmp->bmp_data + bmp->buffer_size - (uintptr_t)data;
1323 result = bmp_decode_mask(bmp, data, bytes);
1324 }
1325 return result;
1326 }
1327
1328
1329 /* exported interface documented in libnsbmp.h */
bmp_decode_trans(bmp_image * bmp,uint32_t colour)1330 bmp_result bmp_decode_trans(bmp_image *bmp, uint32_t colour)
1331 {
1332 bmp->limited_trans = true;
1333 bmp->trans_colour = colour;
1334 return bmp_decode(bmp);
1335 }
1336
1337
1338 /* exported interface documented in libnsbmp.h */
ico_find(ico_collection * ico,uint16_t width,uint16_t height)1339 bmp_image *ico_find(ico_collection *ico, uint16_t width, uint16_t height)
1340 {
1341 bmp_image *bmp = NULL;
1342 ico_image *image;
1343 int x, y, cur, distance = (1 << 24);
1344
1345 if (width == 0)
1346 width = ico->width;
1347 if (height == 0)
1348 height = ico->height;
1349 for (image = ico->first; image; image = image->next) {
1350 if ((image->bmp.width == width) && (image->bmp.height == height))
1351 return &image->bmp;
1352 x = image->bmp.width - width;
1353 y = image->bmp.height - height;
1354 cur = (x * x) + (y * y);
1355 if (cur < distance) {
1356 distance = cur;
1357 bmp = &image->bmp;
1358 }
1359 }
1360 return bmp;
1361 }
1362
1363
1364 /* exported interface documented in libnsbmp.h */
bmp_finalise(bmp_image * bmp)1365 void bmp_finalise(bmp_image *bmp)
1366 {
1367 if (bmp->bitmap)
1368 bmp->bitmap_callbacks.bitmap_destroy(bmp->bitmap);
1369 bmp->bitmap = NULL;
1370 if (bmp->colour_table)
1371 free(bmp->colour_table);
1372 bmp->colour_table = NULL;
1373 }
1374
1375
1376 /* exported interface documented in libnsbmp.h */
ico_finalise(ico_collection * ico)1377 void ico_finalise(ico_collection *ico)
1378 {
1379 ico_image *image;
1380
1381 for (image = ico->first; image; image = image->next)
1382 bmp_finalise(&image->bmp);
1383 while (ico->first) {
1384 image = ico->first;
1385 ico->first = image->next;
1386 free(image);
1387 }
1388 }
1389