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 40 static inline int8_t read_int8(uint8_t *data, unsigned int o) { 41 return (int8_t) data[o]; 42 } 43 #endif 44 45 static inline uint8_t read_uint8(uint8_t *data, unsigned int o) { 46 return (uint8_t) data[o]; 47 } 48 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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