Gitweb links:

...log 
http://git.netsurf-browser.org/libnsbmp.git/shortlog/8cdf3858127bbe1a23bd68546ddcb5b350a03904
...commit 
http://git.netsurf-browser.org/libnsbmp.git/commit/8cdf3858127bbe1a23bd68546ddcb5b350a03904
...tree 
http://git.netsurf-browser.org/libnsbmp.git/tree/8cdf3858127bbe1a23bd68546ddcb5b350a03904

The branch, master has been updated
       via  8cdf3858127bbe1a23bd68546ddcb5b350a03904 (commit)
       via  81e725731b2294d6d6dc41ee1c0df43302dbb1b7 (commit)
      from  cafff2d1c07a8cc5f212a6e46e7da619dea89cf2 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/libnsbmp.git/commit/?id=8cdf3858127bbe1a23bd68546ddcb5b350a03904
commit 8cdf3858127bbe1a23bd68546ddcb5b350a03904
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>

    do not stop bitmap decode on first out of range colour table index
    
    This changes behaviour to ignore image indices outside the range of
    entries in the colour table. This allows a greater number of "real
    world" bitmaps to be decoded which often have such bad palette
    references within them.

diff --git a/src/libnsbmp.c b/src/libnsbmp.c
index 1b28167..b4747f6 100644
--- a/src/libnsbmp.c
+++ b/src/libnsbmp.c
@@ -708,11 +708,14 @@ static bmp_result bmp_decode_rgb(bmp_image *bmp, uint8_t 
**start, int bytes)
                                 cur_byte = *data++;
                         }
                         idx = (cur_byte >> bit_shifts[bit++]) & bit_mask;
-                        if (idx >= bmp->colours)
-                                return BMP_DATA_ERROR;
-                        scanline[x] = bmp->colour_table[idx];
-                        if ((bmp->limited_trans) && (scanline[x] == 
bmp->transparent_index))
-                                scanline[x] = bmp->trans_colour;
+                        if (idx < bmp->colours) {
+                                /* ensure colour table index is in bounds */
+                                scanline[x] = bmp->colour_table[idx];
+                                if ((bmp->limited_trans) &&
+                                    (scanline[x] == bmp->transparent_index)) {
+                                        scanline[x] = bmp->trans_colour;
+                                }
+                        }
                 }
         }
         *start = data;


commitdiff 
http://git.netsurf-browser.org/libnsbmp.git/commit/?id=81e725731b2294d6d6dc41ee1c0df43302dbb1b7
commit 81e725731b2294d6d6dc41ee1c0df43302dbb1b7
Author: Vincent Sanders <[email protected]>
Commit: Vincent Sanders <[email protected]>

    Split RLE decoding into two separate less complex routines

diff --git a/src/libnsbmp.c b/src/libnsbmp.c
index 1a13ec8..1b28167 100644
--- a/src/libnsbmp.c
+++ b/src/libnsbmp.c
@@ -766,25 +766,24 @@ static bmp_result bmp_decode_mask(bmp_image *bmp, uint8_t 
*data, int bytes)
 
 
 /**
- * Decode BMP data stored encoded in either RLE4 or RLE8.
+ * Decode BMP data stored encoded in RLE8.
  *
  * \param bmp  the BMP image to decode
  * \param data the data to decode
  * \param bytes        the number of bytes of data available
- * \param size the size of the RLE tokens (4 or 8)
  * \return     BMP_OK on success
  *             BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
  *                     in this case, the image may be partially viewable
  */
 static bmp_result
-bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, int size)
+bmp_decode_rle8(bmp_image *bmp, uint8_t *data, int bytes)
 {
         uint8_t *top, *bottom, *end;
         uint32_t *scanline;
         uint32_t swidth;
         uint32_t i, length, pixels_left;
         uint32_t x = 0, y = 0, last_y = 0;
-        uint32_t pixel = 0, pixel2;
+        uint32_t pixel = 0;
 
         if (bmp->ico)
                 return BMP_DATA_ERROR;
@@ -803,7 +802,8 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                 length = *data++;
                 if (length == 0) {
                         length = *data++;
-                        if (length == 0) {
+                        switch (length) {
+                        case 0:
                                 /* 00 - 00 means end of scanline */
                                 x = 0;
                                 if (last_y == y) {
@@ -812,10 +812,13 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                                                 return BMP_DATA_ERROR;
                                 }
                                 last_y = y;
-                        } else if (length == 1) {
+                                break;
+
+                        case 1:
                                 /* 00 - 01 means end of RLE data */
                                 return BMP_OK;
-                        } else if (length == 2) {
+
+                        case 2:
                                 /* 00 - 02 - XX - YY means move cursor */
                                 if (data + 2 > end)
                                         return BMP_INSUFFICIENT_DATA;
@@ -825,7 +828,9 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                                 y += *data++;
                                 if (y >= bmp->height)
                                         return BMP_DATA_ERROR;
-                        } else {
+                                break;
+
+                        default:
                                 /* 00 - NN means escape NN pixels */
                                 if (bmp->reversed) {
                                         pixels_left = (bmp->height - y) * 
bmp->width - x;
@@ -836,65 +841,39 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                                 }
                                 if (length > pixels_left)
                                         length = pixels_left;
-                                if ((size == 4 && data + ((length + 1) / 2) > 
end) ||
-                                    (size == 8 && data + length > end))
+                                if (data + length > end)
                                         return BMP_INSUFFICIENT_DATA;
 
-                                /* the following code could be easily 
optimised by simply
-                                 * checking the bounds on entry and using some 
simply copying
-                                 * routines if so */
-                                if (size == 8) {
-                                        for (i = 0; i < length; i++) {
-                                                uint32_t idx = (uint32_t) 
*data++;
-                                                if (x >= bmp->width) {
-                                                        x = 0;
-                                                        y++;
-                                                        if (y >= bmp->height)
-                                                                return 
BMP_DATA_ERROR;
-                                                        if (bmp->reversed) {
-                                                                scanline += 
bmp->width;
-                                                        } else {
-                                                                scanline -= 
bmp->width;
-                                                        }
-                                                }
-                                                if (idx >= bmp->colours)
+                                /* the following code could be easily optimised
+                                 * by simply checking the bounds on entry and
+                                 * using some simple copying routines if so
+                                 */
+                                for (i = 0; i < length; i++) {
+                                        uint32_t idx = (uint32_t) *data++;
+                                        if (x >= bmp->width) {
+                                                x = 0;
+                                                y++;
+                                                if (y >= bmp->height)
                                                         return BMP_DATA_ERROR;
-                                                scanline[x++] = 
bmp->colour_table[idx];
-                                        }
-                                } else {
-                                        for (i = 0; i < length; i++) {
-                                                if (x >= bmp->width) {
-                                                        x = 0;
-                                                        y++;
-                                                        if (y >= bmp->height)
-                                                                return 
BMP_DATA_ERROR;
-                                                        if (bmp->reversed) {
-                                                                scanline += 
bmp->width;
-                                                        } else {
-                                                                scanline -= 
bmp->width;
-                                                        }
-
-                                                }
-                                                if ((i & 1) == 0) {
-                                                        pixel = *data++;
-                                                        if ((pixel >> 4) >= 
bmp->colours)
-                                                                return 
BMP_DATA_ERROR;
-                                                        scanline[x++] = 
bmp->colour_table
-                                                                        [pixel 
>> 4];
+                                                if (bmp->reversed) {
+                                                        scanline += bmp->width;
                                                 } else {
-                                                        if ((pixel & 0xf) >= 
bmp->colours)
-                                                                return 
BMP_DATA_ERROR;
-                                                        scanline[x++] = 
bmp->colour_table
-                                                                        [pixel 
& 0xf];
+                                                        scanline -= bmp->width;
                                                 }
                                         }
-                                        length = (length + 1) >> 1;
+                                        if (idx >= bmp->colours)
+                                                return BMP_DATA_ERROR;
+                                        scanline[x++] = bmp->colour_table[idx];
                                 }
+
                                 if ((length & 1) && (*data++ != 0x00))
                                         return BMP_DATA_ERROR;
 
+                                break;
                         }
                 } else {
+                        uint32_t idx;
+
                         /* NN means perform RLE for NN pixels */
                         if (bmp->reversed) {
                                 pixels_left = (bmp->height - y) * bmp->width - 
x;
@@ -910,14 +889,120 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                         if (data + 1 > end)
                                 return BMP_INSUFFICIENT_DATA;
 
-                        /* the following code could be easily optimised by 
simply
-                         * checking the bounds on entry and using some simply 
copying
-                         * routines if so */
-                        if (size == 8) {
-                                uint32_t idx = (uint32_t) *data++;
-                                if (idx >= bmp->colours)
+                        /* the following code could be easily optimised by
+                         * simply checking the bounds on entry and using some
+                         * simply copying routines if so
+                         */
+                        idx = (uint32_t) *data++;
+                        if (idx >= bmp->colours)
+                                return BMP_DATA_ERROR;
+
+                        pixel = bmp->colour_table[idx];
+                        for (i = 0; i < length; i++) {
+                                if (x >= bmp->width) {
+                                        x = 0;
+                                        y++;
+                                        if (y >= bmp->height)
+                                                return BMP_DATA_ERROR;
+                                        if (bmp->reversed) {
+                                                scanline += bmp->width;
+                                        } else {
+                                                scanline -= bmp->width;
+                                        }
+                                }
+                                scanline[x++] = pixel;
+                        }
+                }
+        } while (data < end);
+
+        return BMP_OK;
+}
+
+
+/**
+ * Decode BMP data stored encoded in RLE4.
+ *
+ * \param bmp  the BMP image to decode
+ * \param data the data to decode
+ * \param bytes        the number of bytes of data available
+ * \return     BMP_OK on success
+ *             BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
+ *                     in this case, the image may be partially viewable
+ */
+static bmp_result
+bmp_decode_rle4(bmp_image *bmp, uint8_t *data, int bytes)
+{
+        uint8_t *top, *bottom, *end;
+        uint32_t *scanline;
+        uint32_t swidth;
+        uint32_t i, length, pixels_left;
+        uint32_t x = 0, y = 0, last_y = 0;
+        uint32_t pixel = 0, pixel2;
+
+        if (bmp->ico)
+                return BMP_DATA_ERROR;
+
+        swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * 
bmp->width;
+        top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
+        if (!top)
+                return BMP_INSUFFICIENT_MEMORY;
+        bottom = top + (uint64_t)swidth * (bmp->height - 1);
+        end = data + bytes;
+        bmp->decoded = true;
+
+        do {
+                if (data + 2 > end)
+                        return BMP_INSUFFICIENT_DATA;
+                length = *data++;
+                if (length == 0) {
+                        length = *data++;
+                        switch (length) {
+                        case 0:
+                                /* 00 - 00 means end of scanline */
+                                x = 0;
+                                if (last_y == y) {
+                                        y++;
+                                        if (y >= bmp->height)
+                                                return BMP_DATA_ERROR;
+                                }
+                                last_y = y;
+                                break;
+
+                        case 1:
+                                /* 00 - 01 means end of RLE data */
+                                return BMP_OK;
+
+                        case 2:
+                                /* 00 - 02 - XX - YY means move cursor */
+                                if (data + 2 > end)
+                                        return BMP_INSUFFICIENT_DATA;
+                                x += *data++;
+                                if (x >= bmp->width)
+                                        return BMP_DATA_ERROR;
+                                y += *data++;
+                                if (y >= bmp->height)
                                         return BMP_DATA_ERROR;
-                                pixel = bmp->colour_table[idx];
+                                break;
+
+                        default:
+                                /* 00 - NN means escape NN pixels */
+                                if (bmp->reversed) {
+                                        pixels_left = (bmp->height - y) * 
bmp->width - x;
+                                        scanline = (void *)(top + (y * 
swidth));
+                                } else {
+                                        pixels_left = (y + 1) * bmp->width - x;
+                                        scanline = (void *)(bottom - (y * 
swidth));
+                                }
+                                if (length > pixels_left)
+                                        length = pixels_left;
+                                if (data + ((length + 1) / 2) > end)
+                                        return BMP_INSUFFICIENT_DATA;
+
+                                /* the following code could be easily optimised
+                                 * by simply checking the bounds on entry and
+                                 * using some simple copying routines
+                                 */
+
                                 for (i = 0; i < length; i++) {
                                         if (x >= bmp->width) {
                                                 x = 0;
@@ -929,36 +1014,76 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                                                 } else {
                                                         scanline -= bmp->width;
                                                 }
+
+                                        }
+                                        if ((i & 1) == 0) {
+                                                pixel = *data++;
+                                                if ((pixel >> 4) >= 
bmp->colours)
+                                                        return BMP_DATA_ERROR;
+                                                scanline[x++] = 
bmp->colour_table
+                                                                [pixel >> 4];
+                                        } else {
+                                                if ((pixel & 0xf) >= 
bmp->colours)
+                                                        return BMP_DATA_ERROR;
+                                                scanline[x++] = 
bmp->colour_table
+                                                                [pixel & 0xf];
                                         }
-                                        scanline[x++] = pixel;
                                 }
-                        } else {
-                                pixel2 = *data++;
-                                if ((pixel2 >> 4) >= bmp->colours ||
-                                    (pixel2 & 0xf) >= bmp->colours)
+                                length = (length + 1) >> 1;
+
+                                if ((length & 1) && (*data++ != 0x00))
                                         return BMP_DATA_ERROR;
-                                pixel = bmp->colour_table[pixel2 >> 4];
-                                pixel2 = bmp->colour_table[pixel2 & 0xf];
-                                for (i = 0; i < length; i++) {
-                                        if (x >= bmp->width) {
-                                                x = 0;
-                                                y++;
-                                                if (y >= bmp->height)
-                                                        return BMP_DATA_ERROR;
-                                                if (bmp->reversed) {
-                                                        scanline += bmp->width;
-                                                } else {
-                                                        scanline -= bmp->width;
-                                                }
+
+                                break;
+                        }
+                } else {
+                        /* NN means perform RLE for NN pixels */
+                        if (bmp->reversed) {
+                                pixels_left = (bmp->height - y) * bmp->width - 
x;
+                                scanline = (void *)(top + (y * swidth));
+                        } else {
+                                pixels_left = (y + 1) * bmp->width - x;
+                                scanline = (void *)(bottom - (y * swidth));
+                        }
+                        if (length > pixels_left)
+                                length = pixels_left;
+
+                        /* boundary checking */
+                        if (data + 1 > end)
+                                return BMP_INSUFFICIENT_DATA;
+
+                        /* the following code could be easily optimised by
+                         * simply checking the bounds on entry and using some
+                         * simple copying routines
+                         */
+
+                        pixel2 = *data++;
+                        if ((pixel2 >> 4) >= bmp->colours ||
+                            (pixel2 & 0xf) >= bmp->colours)
+                                return BMP_DATA_ERROR;
+                        pixel = bmp->colour_table[pixel2 >> 4];
+                        pixel2 = bmp->colour_table[pixel2 & 0xf];
+                        for (i = 0; i < length; i++) {
+                                if (x >= bmp->width) {
+                                        x = 0;
+                                        y++;
+                                        if (y >= bmp->height)
+                                                return BMP_DATA_ERROR;
+                                        if (bmp->reversed) {
+                                                scanline += bmp->width;
+                                        } else {
+                                                scanline -= bmp->width;
                                         }
-                                        if ((i & 1) == 0)
-                                                scanline[x++] = pixel;
-                                        else
-                                                scanline[x++] = pixel2;
                                 }
+                                if ((i & 1) == 0)
+                                        scanline[x++] = pixel;
+                                else
+                                        scanline[x++] = pixel2;
                         }
+
                 }
         } while (data < end);
+
         return BMP_OK;
 }
 
@@ -1039,26 +1164,32 @@ bmp_result bmp_decode(bmp_image *bmp)
 
         switch (bmp->encoding) {
         case BMP_ENCODING_RGB:
-                if ((bmp->bpp == 24) || (bmp->bpp == 32))
+                if ((bmp->bpp == 24) || (bmp->bpp == 32)) {
                         result = bmp_decode_rgb24(bmp, &data, bytes);
-                else if (bmp->bpp == 16)
+                } else if (bmp->bpp == 16) {
                         result = bmp_decode_rgb16(bmp, &data, bytes);
-                else
+                } else {
                         result = bmp_decode_rgb(bmp, &data, bytes);
+                }
                 break;
+
         case BMP_ENCODING_RLE8:
-                result = bmp_decode_rle(bmp, data, bytes, 8);
+                result = bmp_decode_rle8(bmp, data, bytes);
                 break;
+
         case BMP_ENCODING_RLE4:
-                result = bmp_decode_rle(bmp, data, bytes, 4);
+                result = bmp_decode_rle4(bmp, data, bytes);
                 break;
+
         case BMP_ENCODING_BITFIELDS:
-                if (bmp->bpp == 32)
+                if (bmp->bpp == 32) {
                         result = bmp_decode_rgb24(bmp, &data, bytes);
-                else if (bmp->bpp == 16)
+                } else if (bmp->bpp == 16) {
                         result = bmp_decode_rgb16(bmp, &data, bytes);
-                else
-                        return BMP_DATA_ERROR;
+                } else {
+                        result = BMP_DATA_ERROR;
+                }
+                break;
         }
 
         if ((!bmp->ico) || (result != BMP_OK))


-----------------------------------------------------------------------

Summary of changes:
 src/libnsbmp.c |  330 +++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 232 insertions(+), 98 deletions(-)

diff --git a/src/libnsbmp.c b/src/libnsbmp.c
index 1a13ec8..b4747f6 100644
--- a/src/libnsbmp.c
+++ b/src/libnsbmp.c
@@ -708,11 +708,14 @@ static bmp_result bmp_decode_rgb(bmp_image *bmp, uint8_t 
**start, int bytes)
                                 cur_byte = *data++;
                         }
                         idx = (cur_byte >> bit_shifts[bit++]) & bit_mask;
-                        if (idx >= bmp->colours)
-                                return BMP_DATA_ERROR;
-                        scanline[x] = bmp->colour_table[idx];
-                        if ((bmp->limited_trans) && (scanline[x] == 
bmp->transparent_index))
-                                scanline[x] = bmp->trans_colour;
+                        if (idx < bmp->colours) {
+                                /* ensure colour table index is in bounds */
+                                scanline[x] = bmp->colour_table[idx];
+                                if ((bmp->limited_trans) &&
+                                    (scanline[x] == bmp->transparent_index)) {
+                                        scanline[x] = bmp->trans_colour;
+                                }
+                        }
                 }
         }
         *start = data;
@@ -766,25 +769,24 @@ static bmp_result bmp_decode_mask(bmp_image *bmp, uint8_t 
*data, int bytes)
 
 
 /**
- * Decode BMP data stored encoded in either RLE4 or RLE8.
+ * Decode BMP data stored encoded in RLE8.
  *
  * \param bmp  the BMP image to decode
  * \param data the data to decode
  * \param bytes        the number of bytes of data available
- * \param size the size of the RLE tokens (4 or 8)
  * \return     BMP_OK on success
  *             BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
  *                     in this case, the image may be partially viewable
  */
 static bmp_result
-bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, int size)
+bmp_decode_rle8(bmp_image *bmp, uint8_t *data, int bytes)
 {
         uint8_t *top, *bottom, *end;
         uint32_t *scanline;
         uint32_t swidth;
         uint32_t i, length, pixels_left;
         uint32_t x = 0, y = 0, last_y = 0;
-        uint32_t pixel = 0, pixel2;
+        uint32_t pixel = 0;
 
         if (bmp->ico)
                 return BMP_DATA_ERROR;
@@ -803,7 +805,8 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                 length = *data++;
                 if (length == 0) {
                         length = *data++;
-                        if (length == 0) {
+                        switch (length) {
+                        case 0:
                                 /* 00 - 00 means end of scanline */
                                 x = 0;
                                 if (last_y == y) {
@@ -812,10 +815,13 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                                                 return BMP_DATA_ERROR;
                                 }
                                 last_y = y;
-                        } else if (length == 1) {
+                                break;
+
+                        case 1:
                                 /* 00 - 01 means end of RLE data */
                                 return BMP_OK;
-                        } else if (length == 2) {
+
+                        case 2:
                                 /* 00 - 02 - XX - YY means move cursor */
                                 if (data + 2 > end)
                                         return BMP_INSUFFICIENT_DATA;
@@ -825,7 +831,9 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                                 y += *data++;
                                 if (y >= bmp->height)
                                         return BMP_DATA_ERROR;
-                        } else {
+                                break;
+
+                        default:
                                 /* 00 - NN means escape NN pixels */
                                 if (bmp->reversed) {
                                         pixels_left = (bmp->height - y) * 
bmp->width - x;
@@ -836,65 +844,39 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                                 }
                                 if (length > pixels_left)
                                         length = pixels_left;
-                                if ((size == 4 && data + ((length + 1) / 2) > 
end) ||
-                                    (size == 8 && data + length > end))
+                                if (data + length > end)
                                         return BMP_INSUFFICIENT_DATA;
 
-                                /* the following code could be easily 
optimised by simply
-                                 * checking the bounds on entry and using some 
simply copying
-                                 * routines if so */
-                                if (size == 8) {
-                                        for (i = 0; i < length; i++) {
-                                                uint32_t idx = (uint32_t) 
*data++;
-                                                if (x >= bmp->width) {
-                                                        x = 0;
-                                                        y++;
-                                                        if (y >= bmp->height)
-                                                                return 
BMP_DATA_ERROR;
-                                                        if (bmp->reversed) {
-                                                                scanline += 
bmp->width;
-                                                        } else {
-                                                                scanline -= 
bmp->width;
-                                                        }
-                                                }
-                                                if (idx >= bmp->colours)
+                                /* the following code could be easily optimised
+                                 * by simply checking the bounds on entry and
+                                 * using some simple copying routines if so
+                                 */
+                                for (i = 0; i < length; i++) {
+                                        uint32_t idx = (uint32_t) *data++;
+                                        if (x >= bmp->width) {
+                                                x = 0;
+                                                y++;
+                                                if (y >= bmp->height)
                                                         return BMP_DATA_ERROR;
-                                                scanline[x++] = 
bmp->colour_table[idx];
-                                        }
-                                } else {
-                                        for (i = 0; i < length; i++) {
-                                                if (x >= bmp->width) {
-                                                        x = 0;
-                                                        y++;
-                                                        if (y >= bmp->height)
-                                                                return 
BMP_DATA_ERROR;
-                                                        if (bmp->reversed) {
-                                                                scanline += 
bmp->width;
-                                                        } else {
-                                                                scanline -= 
bmp->width;
-                                                        }
-
-                                                }
-                                                if ((i & 1) == 0) {
-                                                        pixel = *data++;
-                                                        if ((pixel >> 4) >= 
bmp->colours)
-                                                                return 
BMP_DATA_ERROR;
-                                                        scanline[x++] = 
bmp->colour_table
-                                                                        [pixel 
>> 4];
+                                                if (bmp->reversed) {
+                                                        scanline += bmp->width;
                                                 } else {
-                                                        if ((pixel & 0xf) >= 
bmp->colours)
-                                                                return 
BMP_DATA_ERROR;
-                                                        scanline[x++] = 
bmp->colour_table
-                                                                        [pixel 
& 0xf];
+                                                        scanline -= bmp->width;
                                                 }
                                         }
-                                        length = (length + 1) >> 1;
+                                        if (idx >= bmp->colours)
+                                                return BMP_DATA_ERROR;
+                                        scanline[x++] = bmp->colour_table[idx];
                                 }
+
                                 if ((length & 1) && (*data++ != 0x00))
                                         return BMP_DATA_ERROR;
 
+                                break;
                         }
                 } else {
+                        uint32_t idx;
+
                         /* NN means perform RLE for NN pixels */
                         if (bmp->reversed) {
                                 pixels_left = (bmp->height - y) * bmp->width - 
x;
@@ -910,14 +892,120 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                         if (data + 1 > end)
                                 return BMP_INSUFFICIENT_DATA;
 
-                        /* the following code could be easily optimised by 
simply
-                         * checking the bounds on entry and using some simply 
copying
-                         * routines if so */
-                        if (size == 8) {
-                                uint32_t idx = (uint32_t) *data++;
-                                if (idx >= bmp->colours)
+                        /* the following code could be easily optimised by
+                         * simply checking the bounds on entry and using some
+                         * simply copying routines if so
+                         */
+                        idx = (uint32_t) *data++;
+                        if (idx >= bmp->colours)
+                                return BMP_DATA_ERROR;
+
+                        pixel = bmp->colour_table[idx];
+                        for (i = 0; i < length; i++) {
+                                if (x >= bmp->width) {
+                                        x = 0;
+                                        y++;
+                                        if (y >= bmp->height)
+                                                return BMP_DATA_ERROR;
+                                        if (bmp->reversed) {
+                                                scanline += bmp->width;
+                                        } else {
+                                                scanline -= bmp->width;
+                                        }
+                                }
+                                scanline[x++] = pixel;
+                        }
+                }
+        } while (data < end);
+
+        return BMP_OK;
+}
+
+
+/**
+ * Decode BMP data stored encoded in RLE4.
+ *
+ * \param bmp  the BMP image to decode
+ * \param data the data to decode
+ * \param bytes        the number of bytes of data available
+ * \return     BMP_OK on success
+ *             BMP_INSUFFICIENT_DATA if the bitmap data ends unexpectedly;
+ *                     in this case, the image may be partially viewable
+ */
+static bmp_result
+bmp_decode_rle4(bmp_image *bmp, uint8_t *data, int bytes)
+{
+        uint8_t *top, *bottom, *end;
+        uint32_t *scanline;
+        uint32_t swidth;
+        uint32_t i, length, pixels_left;
+        uint32_t x = 0, y = 0, last_y = 0;
+        uint32_t pixel = 0, pixel2;
+
+        if (bmp->ico)
+                return BMP_DATA_ERROR;
+
+        swidth = bmp->bitmap_callbacks.bitmap_get_bpp(bmp->bitmap) * 
bmp->width;
+        top = bmp->bitmap_callbacks.bitmap_get_buffer(bmp->bitmap);
+        if (!top)
+                return BMP_INSUFFICIENT_MEMORY;
+        bottom = top + (uint64_t)swidth * (bmp->height - 1);
+        end = data + bytes;
+        bmp->decoded = true;
+
+        do {
+                if (data + 2 > end)
+                        return BMP_INSUFFICIENT_DATA;
+                length = *data++;
+                if (length == 0) {
+                        length = *data++;
+                        switch (length) {
+                        case 0:
+                                /* 00 - 00 means end of scanline */
+                                x = 0;
+                                if (last_y == y) {
+                                        y++;
+                                        if (y >= bmp->height)
+                                                return BMP_DATA_ERROR;
+                                }
+                                last_y = y;
+                                break;
+
+                        case 1:
+                                /* 00 - 01 means end of RLE data */
+                                return BMP_OK;
+
+                        case 2:
+                                /* 00 - 02 - XX - YY means move cursor */
+                                if (data + 2 > end)
+                                        return BMP_INSUFFICIENT_DATA;
+                                x += *data++;
+                                if (x >= bmp->width)
                                         return BMP_DATA_ERROR;
-                                pixel = bmp->colour_table[idx];
+                                y += *data++;
+                                if (y >= bmp->height)
+                                        return BMP_DATA_ERROR;
+                                break;
+
+                        default:
+                                /* 00 - NN means escape NN pixels */
+                                if (bmp->reversed) {
+                                        pixels_left = (bmp->height - y) * 
bmp->width - x;
+                                        scanline = (void *)(top + (y * 
swidth));
+                                } else {
+                                        pixels_left = (y + 1) * bmp->width - x;
+                                        scanline = (void *)(bottom - (y * 
swidth));
+                                }
+                                if (length > pixels_left)
+                                        length = pixels_left;
+                                if (data + ((length + 1) / 2) > end)
+                                        return BMP_INSUFFICIENT_DATA;
+
+                                /* the following code could be easily optimised
+                                 * by simply checking the bounds on entry and
+                                 * using some simple copying routines
+                                 */
+
                                 for (i = 0; i < length; i++) {
                                         if (x >= bmp->width) {
                                                 x = 0;
@@ -929,36 +1017,76 @@ bmp_decode_rle(bmp_image *bmp, uint8_t *data, int bytes, 
int size)
                                                 } else {
                                                         scanline -= bmp->width;
                                                 }
+
+                                        }
+                                        if ((i & 1) == 0) {
+                                                pixel = *data++;
+                                                if ((pixel >> 4) >= 
bmp->colours)
+                                                        return BMP_DATA_ERROR;
+                                                scanline[x++] = 
bmp->colour_table
+                                                                [pixel >> 4];
+                                        } else {
+                                                if ((pixel & 0xf) >= 
bmp->colours)
+                                                        return BMP_DATA_ERROR;
+                                                scanline[x++] = 
bmp->colour_table
+                                                                [pixel & 0xf];
                                         }
-                                        scanline[x++] = pixel;
                                 }
-                        } else {
-                                pixel2 = *data++;
-                                if ((pixel2 >> 4) >= bmp->colours ||
-                                    (pixel2 & 0xf) >= bmp->colours)
+                                length = (length + 1) >> 1;
+
+                                if ((length & 1) && (*data++ != 0x00))
                                         return BMP_DATA_ERROR;
-                                pixel = bmp->colour_table[pixel2 >> 4];
-                                pixel2 = bmp->colour_table[pixel2 & 0xf];
-                                for (i = 0; i < length; i++) {
-                                        if (x >= bmp->width) {
-                                                x = 0;
-                                                y++;
-                                                if (y >= bmp->height)
-                                                        return BMP_DATA_ERROR;
-                                                if (bmp->reversed) {
-                                                        scanline += bmp->width;
-                                                } else {
-                                                        scanline -= bmp->width;
-                                                }
+
+                                break;
+                        }
+                } else {
+                        /* NN means perform RLE for NN pixels */
+                        if (bmp->reversed) {
+                                pixels_left = (bmp->height - y) * bmp->width - 
x;
+                                scanline = (void *)(top + (y * swidth));
+                        } else {
+                                pixels_left = (y + 1) * bmp->width - x;
+                                scanline = (void *)(bottom - (y * swidth));
+                        }
+                        if (length > pixels_left)
+                                length = pixels_left;
+
+                        /* boundary checking */
+                        if (data + 1 > end)
+                                return BMP_INSUFFICIENT_DATA;
+
+                        /* the following code could be easily optimised by
+                         * simply checking the bounds on entry and using some
+                         * simple copying routines
+                         */
+
+                        pixel2 = *data++;
+                        if ((pixel2 >> 4) >= bmp->colours ||
+                            (pixel2 & 0xf) >= bmp->colours)
+                                return BMP_DATA_ERROR;
+                        pixel = bmp->colour_table[pixel2 >> 4];
+                        pixel2 = bmp->colour_table[pixel2 & 0xf];
+                        for (i = 0; i < length; i++) {
+                                if (x >= bmp->width) {
+                                        x = 0;
+                                        y++;
+                                        if (y >= bmp->height)
+                                                return BMP_DATA_ERROR;
+                                        if (bmp->reversed) {
+                                                scanline += bmp->width;
+                                        } else {
+                                                scanline -= bmp->width;
                                         }
-                                        if ((i & 1) == 0)
-                                                scanline[x++] = pixel;
-                                        else
-                                                scanline[x++] = pixel2;
                                 }
+                                if ((i & 1) == 0)
+                                        scanline[x++] = pixel;
+                                else
+                                        scanline[x++] = pixel2;
                         }
+
                 }
         } while (data < end);
+
         return BMP_OK;
 }
 
@@ -1039,26 +1167,32 @@ bmp_result bmp_decode(bmp_image *bmp)
 
         switch (bmp->encoding) {
         case BMP_ENCODING_RGB:
-                if ((bmp->bpp == 24) || (bmp->bpp == 32))
+                if ((bmp->bpp == 24) || (bmp->bpp == 32)) {
                         result = bmp_decode_rgb24(bmp, &data, bytes);
-                else if (bmp->bpp == 16)
+                } else if (bmp->bpp == 16) {
                         result = bmp_decode_rgb16(bmp, &data, bytes);
-                else
+                } else {
                         result = bmp_decode_rgb(bmp, &data, bytes);
+                }
                 break;
+
         case BMP_ENCODING_RLE8:
-                result = bmp_decode_rle(bmp, data, bytes, 8);
+                result = bmp_decode_rle8(bmp, data, bytes);
                 break;
+
         case BMP_ENCODING_RLE4:
-                result = bmp_decode_rle(bmp, data, bytes, 4);
+                result = bmp_decode_rle4(bmp, data, bytes);
                 break;
+
         case BMP_ENCODING_BITFIELDS:
-                if (bmp->bpp == 32)
+                if (bmp->bpp == 32) {
                         result = bmp_decode_rgb24(bmp, &data, bytes);
-                else if (bmp->bpp == 16)
+                } else if (bmp->bpp == 16) {
                         result = bmp_decode_rgb16(bmp, &data, bytes);
-                else
-                        return BMP_DATA_ERROR;
+                } else {
+                        result = BMP_DATA_ERROR;
+                }
+                break;
         }
 
         if ((!bmp->ico) || (result != BMP_OK))


-- 
NetSurf BMP Decoder

_______________________________________________
netsurf-commits mailing list
[email protected]
http://listmaster.pepperfish.net/cgi-bin/mailman/listinfo/netsurf-commits-netsurf-browser.org

Reply via email to