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