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