diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | include/libnsbmp.h | 2 | ||||
-rw-r--r-- | src/libnsbmp.c | 63 | ||||
-rw-r--r-- | test/decode_bmp.c | 14 | ||||
-rw-r--r-- | test/decode_ico.c | 10 | ||||
-rwxr-xr-x | test/runtest.sh | 4 |
6 files changed, 47 insertions, 50 deletions
@@ -2,11 +2,11 @@ # # Makefile for libnsbmp # -# Copyright 2009-2015 John-Mark Bell <jmb@netsurf-browser.org> +# Copyright 2009-2020 John-Mark Bell <jmb@netsurf-browser.org> # Component settings COMPONENT := nsbmp -COMPONENT_VERSION := 0.1.3 +COMPONENT_VERSION := 0.1.7 # Default to a static library COMPONENT_TYPE ?= lib-static diff --git a/include/libnsbmp.h b/include/libnsbmp.h index 7e90b4a..ad683f0 100644 --- a/include/libnsbmp.h +++ b/include/libnsbmp.h @@ -62,8 +62,6 @@ typedef struct bmp_bitmap_callback_vt_s { bmp_bitmap_cb_destroy bitmap_destroy; /** Return a pointer to the pixel data in a bitmap. */ bmp_bitmap_cb_get_buffer bitmap_get_buffer; - /** Find the width of a pixel row in bytes. */ - bmp_bitmap_cb_get_bpp bitmap_get_bpp; } bmp_bitmap_callback_vt; /** diff --git a/src/libnsbmp.c b/src/libnsbmp.c index 381fcf4..b4da553 100644 --- a/src/libnsbmp.c +++ b/src/libnsbmp.c @@ -64,11 +64,17 @@ static inline uint16_t read_uint16(uint8_t *data, unsigned int o) { } static inline int32_t read_int32(uint8_t *data, unsigned int o) { - return (int32_t) (data[o] | (data[o+1] << 8) | (data[o+2] << 16) | (data[o+3] << 24)); + return (int32_t) ((unsigned)data[o] | + ((unsigned)data[o+1] << 8) | + ((unsigned)data[o+2] << 16) | + ((unsigned)data[o+3] << 24)); } static inline uint32_t read_uint32(uint8_t *data, unsigned int o) { - return (uint32_t) (data[o] | (data[o+1] << 8) | (data[o+2] << 16) | (data[o+3] << 24)); + return (uint32_t) ((unsigned)data[o] | + ((unsigned)data[o+1] << 8) | + ((unsigned)data[o+2] << 16) | + ((unsigned)data[o+3] << 24)); } @@ -147,7 +153,8 @@ static bmp_result bmp_info_header_parse(bmp_image *bmp, uint8_t *data) (bmp->bpp != 24) && (bmp->bpp != 32)) return BMP_DATA_ERROR; - bmp->colours = (1 << bmp->bpp); + if (bmp->bpp < 16) + bmp->colours = (1 << bmp->bpp); palette_size = 3; } else if (header_size < 40) { return BMP_DATA_ERROR; @@ -265,6 +272,8 @@ static bmp_result bmp_info_header_parse(bmp_image *bmp, uint8_t *data) for (i = 0; i < 3; i++) bmp->mask[i] = read_uint32(data, 40 + (i << 2)); } else { + if (header_size < 56) + return BMP_INSUFFICIENT_DATA; for (i = 0; i < 4; i++) bmp->mask[i] = read_uint32(data, 40 + (i << 2)); } @@ -272,9 +281,9 @@ static bmp_result bmp_info_header_parse(bmp_image *bmp, uint8_t *data) if (bmp->mask[i] == 0) break; for (j = 31; j > 0; j--) - if (bmp->mask[i] & (1 << j)) { + if (bmp->mask[i] & ((unsigned)1 << j)) { if ((j - 7) > 0) - bmp->mask[i] &= 0xff << (j - 7); + bmp->mask[i] &= (unsigned)0xff << (j - 7); else bmp->mask[i] &= 0xff >> (-(j - 7)); bmp->shift[i] = (i << 3) - (j - 7); @@ -283,7 +292,7 @@ static bmp_result bmp_info_header_parse(bmp_image *bmp, uint8_t *data) } } bmp->colours = read_uint32(data, 32); - if (bmp->colours == 0) + if (bmp->colours == 0 && bmp->bpp < 16) bmp->colours = (1 << bmp->bpp); palette_size = 4; } @@ -316,11 +325,11 @@ static bmp_result bmp_info_header_parse(bmp_image *bmp, uint8_t *data) if (!bmp->colour_table) return BMP_INSUFFICIENT_MEMORY; for (i = 0; i < bmp->colours; i++) { - bmp->colour_table[i] = data[2] | (data[1] << 8) | (data[0] << 16); + uint32_t colour = data[2] | (data[1] << 8) | (data[0] << 16); if (bmp->opaque) - bmp->colour_table[i] |= (0xff << 24); + colour |= ((uint32_t)0xff << 24); data += palette_size; - bmp->colour_table[i] = read_uint32((uint8_t *)&bmp->colour_table[i],0); + bmp->colour_table[i] = read_uint32((uint8_t *)&colour,0); } /* some bitmaps have a bad offset if there is a pallete, work @@ -465,6 +474,9 @@ static bmp_result ico_header_parse(ico_collection *ico, uint8_t *data) image->bmp.height = 256; image->bmp.buffer_size = read_uint32(data, 8); image->bmp.bmp_data = ico->ico_data + read_uint32(data, 12); + if (image->bmp.bmp_data + image->bmp.buffer_size > + ico->ico_data + ico->buffer_size) + return BMP_INSUFFICIENT_DATA; image->bmp.ico = true; data += ICO_DIR_ENTRY_SIZE; @@ -518,7 +530,7 @@ static bmp_result bmp_decode_rgb32(bmp_image *bmp, uint8_t **start, int bytes) assert(bmp->bpp == 32); data = *start; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + swidth = sizeof(uint32_t) * bmp->width; top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); if (!top) return BMP_INSUFFICIENT_MEMORY; @@ -553,7 +565,7 @@ static bmp_result bmp_decode_rgb32(bmp_image *bmp, uint8_t **start, int bytes) scanline[x] |= ((word & bmp->mask[i]) >> (-bmp->shift[i])); /* 32-bit BMPs have alpha masks, but sometimes they're not utilized */ if (bmp->opaque) - scanline[x] |= (0xff << 24); + scanline[x] |= ((unsigned)0xff << 24); data += 4; scanline[x] = read_uint32((uint8_t *)&scanline[x],0); } @@ -564,9 +576,9 @@ static bmp_result bmp_decode_rgb32(bmp_image *bmp, uint8_t **start, int bytes) scanline[x] = bmp->trans_colour; } if (bmp->opaque) { - scanline[x] |= (0xff << 24); + scanline[x] |= ((unsigned)0xff << 24); } else { - scanline[x] |= data[3] << 24; + scanline[x] |= (unsigned)data[3] << 24; } data += 4; scanline[x] = read_uint32((uint8_t *)&scanline[x],0); @@ -600,7 +612,7 @@ static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t **start, int bytes) assert(bmp->bpp == 24); data = *start; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + swidth = sizeof(uint32_t) * bmp->width; top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); if (!top) { return BMP_INSUFFICIENT_MEMORY; @@ -636,7 +648,7 @@ static bmp_result bmp_decode_rgb24(bmp_image *bmp, uint8_t **start, int bytes) if ((bmp->limited_trans) && (scanline[x] == bmp->transparent_index)) { scanline[x] = bmp->trans_colour; } else { - scanline[x] |= (0xff << 24); + scanline[x] |= ((uint32_t)0xff << 24); } data += 3; scanline[x] = read_uint32((uint8_t *)&scanline[x],0); @@ -671,7 +683,7 @@ static bmp_result bmp_decode_rgb16(bmp_image *bmp, uint8_t **start, int bytes) uint16_t word; data = *start; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + swidth = sizeof(uint32_t) * bmp->width; top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); if (!top) return BMP_INSUFFICIENT_MEMORY; @@ -707,7 +719,7 @@ static bmp_result bmp_decode_rgb16(bmp_image *bmp, uint8_t **start, int bytes) else scanline[x] |= ((word & bmp->mask[i]) >> (-bmp->shift[i])); if (bmp->opaque) - scanline[x] |= (0xff << 24); + scanline[x] |= ((unsigned)0xff << 24); } data += 2; scanline[x] = read_uint32((uint8_t *)&scanline[x],0); @@ -724,7 +736,7 @@ static bmp_result bmp_decode_rgb16(bmp_image *bmp, uint8_t **start, int bytes) ((word & (31 << 10)) >> 7); } if (bmp->opaque) - scanline[x] |= (0xff << 24); + scanline[x] |= ((unsigned)0xff << 24); data += 2; scanline[x] = read_uint32((uint8_t *)&scanline[x],0); } @@ -758,11 +770,14 @@ static bmp_result bmp_decode_rgb(bmp_image *bmp, uint8_t **start, int bytes) uint8_t bit_mask = (1 << bmp->bpp) - 1; uint8_t cur_byte = 0, bit, i; + /* Belt and braces, we shouldn't get here unless this holds */ + assert(ppb >= 1); + for (i = 0; i < ppb; i++) bit_shifts[i] = 8 - ((i + 1) * bmp->bpp); data = *start; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + swidth = sizeof(uint32_t) * bmp->width; top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); if (!top) return BMP_INSUFFICIENT_MEMORY; @@ -781,7 +796,7 @@ static bmp_result bmp_decode_rgb(bmp_image *bmp, uint8_t **start, int bytes) for (y = 0; y < bmp->height; y++) { bit = 8; - if ((data + (bmp->width / ppb)) > end) + if ((data + ((bmp->width + ppb - 1) / ppb)) > end) return BMP_INSUFFICIENT_DATA; if (bmp->reversed) scanline = (void *)(top + (y * swidth)); @@ -827,7 +842,7 @@ static bmp_result bmp_decode_mask(bmp_image *bmp, uint8_t *data, int bytes) uint32_t x, y, swidth; uint32_t cur_byte = 0; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + swidth = sizeof(uint32_t) * bmp->width; top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); if (!top) return BMP_INSUFFICIENT_MEMORY; @@ -845,7 +860,7 @@ static bmp_result bmp_decode_mask(bmp_image *bmp, uint8_t *data, int bytes) cur_byte = *data++; scanline[x] = read_uint32((uint8_t *)&scanline[x], 0); if ((cur_byte & 128) == 0) { - scanline[x] |= (0xff << 24); + scanline[x] |= ((unsigned)0xff << 24); } else { scanline[x] &= 0xffffff; } @@ -882,7 +897,7 @@ bmp_decode_rle8(bmp_image *bmp, uint8_t *data, int bytes) if (bmp->ico) return BMP_DATA_ERROR; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + swidth = sizeof(uint32_t) * bmp->width; top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); if (!top) return BMP_INSUFFICIENT_MEMORY; @@ -1036,7 +1051,7 @@ bmp_decode_rle4(bmp_image *bmp, uint8_t *data, int bytes) if (bmp->ico) return BMP_DATA_ERROR; - swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * bmp->width; + swidth = sizeof(uint32_t) * bmp->width; top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap); if (!top) return BMP_INSUFFICIENT_MEMORY; diff --git a/test/decode_bmp.c b/test/decode_bmp.c index 68de542..a0b02e8 100644 --- a/test/decode_bmp.c +++ b/test/decode_bmp.c @@ -17,7 +17,7 @@ #include <sys/stat.h> #include "../include/libnsbmp.h" -#define BYTES_PER_PIXEL 4 +#define BYTES_PER_PIXEL sizeof(uint32_t) #define MAX_IMAGE_BYTES (48 * 1024 * 1024) #define TRANSPARENT_COLOR 0xffffffff @@ -25,8 +25,8 @@ static void *bitmap_create(int width, int height, unsigned int state) { (void) state; /* unused */ - /* ensure a stupidly large (>50Megs or so) bitmap is not created */ - if (((long long)width * (long long)height) > (MAX_IMAGE_BYTES/BYTES_PER_PIXEL)) { + /* Ensure a stupidly large bitmap is not created */ + if (width > 4096 || height > 4096) { return NULL; } return calloc(width * height, BYTES_PER_PIXEL); @@ -40,13 +40,6 @@ static unsigned char *bitmap_get_buffer(void *bitmap) } -static size_t bitmap_get_bpp(void *bitmap) -{ - (void) bitmap; /* unused */ - return BYTES_PER_PIXEL; -} - - static void bitmap_destroy(void *bitmap) { assert(bitmap); @@ -144,7 +137,6 @@ int main(int argc, char *argv[]) bitmap_create, bitmap_destroy, bitmap_get_buffer, - bitmap_get_bpp }; bmp_result code; bmp_image bmp; diff --git a/test/decode_ico.c b/test/decode_ico.c index 5dbc7a5..94db57e 100644 --- a/test/decode_ico.c +++ b/test/decode_ico.c @@ -24,7 +24,7 @@ /* Currently the library returns the data in RGBA format, * so there are 4 bytes per pixel */ -#define BYTES_PER_PIXEL 4 +#define BYTES_PER_PIXEL sizeof(uint32_t) /* White with alpha masking. */ #define TRANSPARENT_COLOR 0xffffffff @@ -43,13 +43,6 @@ static unsigned char *bitmap_get_buffer(void *bitmap) } -static size_t bitmap_get_bpp(void *bitmap) -{ - (void) bitmap; /* unused */ - return BYTES_PER_PIXEL; -} - - static void bitmap_destroy(void *bitmap) { assert(bitmap); @@ -175,7 +168,6 @@ int main(int argc, char *argv[]) bitmap_create, bitmap_destroy, bitmap_get_buffer, - bitmap_get_bpp }; uint16_t width, height; ico_collection ico; diff --git a/test/runtest.sh b/test/runtest.sh index f3c047d..544c262 100755 --- a/test/runtest.sh +++ b/test/runtest.sh @@ -67,7 +67,7 @@ for BMP in $(ls ${BMPTESTS});do BMPTESTTOTC=$((BMPTESTTOTC+1)) bmpdecode ${BMP} ECODE=$? - if [ "${ECODE}" -gt 127 ];then + if [ \( "${ECODE}" -gt 127 \) -o \( "${ECODE}" -eq 1 \) ];then BMPTESTERRC=$((BMPTESTERRC+1)) else BMPTESTPASSC=$((BMPTESTPASSC+1)) @@ -89,7 +89,7 @@ for ICO in $(ls ${ICOTESTS});do ICOTESTTOTC=$((ICOTESTTOTC+1)) icodecode ${ICO} ECODE=$? - if [ "${ECODE}" -gt 127 ];then + if [ \( "${ECODE}" -gt 127 \) -o \( "${ECODE}" -eq 1 \) ];then ICOTESTERRC=$((ICOTESTERRC+1)) else ICOTESTPASSC=$((ICOTESTPASSC+1)) |