aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/codec/SkBmpRLECodec.cpp
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2015-08-12 08:08:56 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-08-12 08:08:56 -0700
commitd0375bc4607f9d3f2ec427771e90ec7d284c174d (patch)
tree0fca66621db65f4f8c4d7a4ae09222ba672dda09 /src/codec/SkBmpRLECodec.cpp
parente14c1fe04fc72ec9bcf55820b5c65a71d7d0a764 (diff)
Fix bmp RLE "bug"
Chromium's test suite contains an RLE image that reports a certain file size in the header, but then contains additional encoded data. Our bmp decoder would only decode half of the image, before stopping. With this fix, we check for additional data before returning kIncompleteInput. If this lands, I will upload the test image to the bots. Also adding an invalid image test to CodexTest. BUG=skia: Review URL: https://codereview.chromium.org/1273853004
Diffstat (limited to 'src/codec/SkBmpRLECodec.cpp')
-rw-r--r--src/codec/SkBmpRLECodec.cpp73
1 files changed, 60 insertions, 13 deletions
diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp
index 6be7449ed8..c71a5409d2 100644
--- a/src/codec/SkBmpRLECodec.cpp
+++ b/src/codec/SkBmpRLECodec.cpp
@@ -183,6 +183,41 @@ bool SkBmpRLECodec::initializeStreamBuffer() {
}
/*
+ * Before signalling kIncompleteInput, we should attempt to load the
+ * stream buffer with additional data.
+ *
+ * @return the number of bytes remaining in the stream buffer after
+ * attempting to read more bytes from the stream
+ */
+size_t SkBmpRLECodec::checkForMoreData() {
+ const size_t remainingBytes = fRLEBytes - fCurrRLEByte;
+ uint8_t* buffer = fStreamBuffer.get();
+
+ // We will be reusing the same buffer, starting over from the beginning.
+ // Move any remaining bytes to the start of the buffer.
+ // We use memmove() instead of memcpy() because there is risk that the dst
+ // and src memory will overlap in corrupt images.
+ memmove(buffer, SkTAddOffset<uint8_t>(buffer, fCurrRLEByte), remainingBytes);
+
+ // Adjust the buffer ptr to the start of the unfilled data.
+ buffer += remainingBytes;
+
+ // Try to read additional bytes from the stream. There are fCurrRLEByte
+ // bytes of additional space remaining in the buffer, assuming that we
+ // have already copied remainingBytes to the start of the buffer.
+ size_t additionalBytes = this->stream()->read(buffer, fCurrRLEByte);
+
+ // Update counters and return the number of bytes we currently have
+ // available. We are at the start of the buffer again.
+ fCurrRLEByte = 0;
+ // If we were unable to fill the buffer, fRLEBytes is no longer equal to
+ // the size of the buffer. There will be unused space at the end. This
+ // should be fine, given that there are no more bytes in the stream.
+ fRLEBytes = remainingBytes + additionalBytes;
+ return fRLEBytes;
+}
+
+/*
* Set an RLE pixel using the color table
*/
void SkBmpRLECodec::setPixel(void* dst, size_t dstRowBytes,
@@ -287,8 +322,10 @@ SkCodec::Result SkBmpRLECodec::decode(const SkImageInfo& dstInfo,
// Every entry takes at least two bytes
if ((int) fRLEBytes - fCurrRLEByte < 2) {
- SkCodecPrintf("Warning: incomplete RLE input.\n");
- return kIncompleteInput;
+ SkCodecPrintf("Warning: might be incomplete RLE input.\n");
+ if (this->checkForMoreData() < 2) {
+ return kIncompleteInput;
+ }
}
// Read the next two bytes. These bytes have different meanings
@@ -310,8 +347,10 @@ SkCodec::Result SkBmpRLECodec::decode(const SkImageInfo& dstInfo,
case RLE_DELTA: {
// Two bytes are needed to specify delta
if ((int) fRLEBytes - fCurrRLEByte < 2) {
- SkCodecPrintf("Warning: incomplete RLE input\n");
- return kIncompleteInput;
+ SkCodecPrintf("Warning: might be incomplete RLE input.\n");
+ if (this->checkForMoreData() < 2) {
+ return kIncompleteInput;
+ }
}
// Modify x and y
const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++];
@@ -319,8 +358,8 @@ SkCodec::Result SkBmpRLECodec::decode(const SkImageInfo& dstInfo,
x += dx;
y += dy;
if (x > width || y > height) {
- SkCodecPrintf("Warning: invalid RLE input 1.\n");
- return kIncompleteInput;
+ SkCodecPrintf("Warning: invalid RLE input.\n");
+ return kInvalidInput;
}
break;
}
@@ -333,12 +372,18 @@ SkCodec::Result SkBmpRLECodec::decode(const SkImageInfo& dstInfo,
const size_t rowBytes = compute_row_bytes(numPixels,
this->bitsPerPixel());
// Abort if setting numPixels moves us off the edge of the
- // image. Also abort if there are not enough bytes
+ // image.
+ if (x + numPixels > width) {
+ SkCodecPrintf("Warning: invalid RLE input.\n");
+ return kInvalidInput;
+ }
+ // Also abort if there are not enough bytes
// remaining in the stream to set numPixels.
- if (x + numPixels > width ||
- (int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) {
- SkCodecPrintf("Warning: invalid RLE input 2.\n");
- return kIncompleteInput;
+ if ((int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) {
+ SkCodecPrintf("Warning: might be incomplete RLE input.\n");
+ if (this->checkForMoreData() < SkAlign2(rowBytes)) {
+ return kIncompleteInput;
+ }
}
// Set numPixels number of pixels
while (numPixels > 0) {
@@ -394,8 +439,10 @@ SkCodec::Result SkBmpRLECodec::decode(const SkImageInfo& dstInfo,
// There are two more required bytes to finish encoding the
// color.
if ((int) fRLEBytes - fCurrRLEByte < 2) {
- SkCodecPrintf("Warning: incomplete RLE input\n");
- return kIncompleteInput;
+ SkCodecPrintf("Warning: might be incomplete RLE input.\n");
+ if (this->checkForMoreData() < 2) {
+ return kIncompleteInput;
+ }
}
// Fill the pixels up to endX with the specified color