Index: src/codec/SkBmpRLECodec.cpp |
diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp |
index 828871cd547be98ef2b6bc537d2ec5c3b2b9e688..86b64e229fea27a0e84c2ae9a2970f35411226cf 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 |