diff --git a/image/Decoder.cpp b/image/Decoder.cpp index cbe7ce9fb214..9f177998b467 100644 --- a/image/Decoder.cpp +++ b/image/Decoder.cpp @@ -190,6 +190,7 @@ void Decoder::CompleteDecode() { // Implementation-specific finalization + BeforeFinishInternal(); if (!HasError()) { FinishInternal(); } else { @@ -393,6 +394,7 @@ Decoder::AllocateFrameInternal(uint32_t aFrameNum, */ void Decoder::InitInternal() { } +void Decoder::BeforeFinishInternal() { } void Decoder::FinishInternal() { } void Decoder::FinishWithErrorInternal() { } diff --git a/image/Decoder.h b/image/Decoder.h index a88ff846ed84..f5295f6ecc0a 100644 --- a/image/Decoder.h +++ b/image/Decoder.h @@ -283,9 +283,14 @@ protected: /* * Internal hooks. Decoder implementations may override these and * only these methods. + * + * BeforeFinishInternal() can be used to detect if decoding is in an + * incomplete state, e.g. due to file truncation, in which case it should + * call PostDataError(). */ virtual void InitInternal(); virtual void WriteInternal(const char* aBuffer, uint32_t aCount) = 0; + virtual void BeforeFinishInternal(); virtual void FinishInternal(); virtual void FinishWithErrorInternal(); diff --git a/image/decoders/nsBMPDecoder.cpp b/image/decoders/nsBMPDecoder.cpp index 0c6aac9fa68c..97ad31265e1d 100644 --- a/image/decoders/nsBMPDecoder.cpp +++ b/image/decoders/nsBMPDecoder.cpp @@ -220,6 +220,14 @@ nsBMPDecoder::GetCompressedImageSize() const : mH.mImageSize; } +void +nsBMPDecoder::BeforeFinishInternal() +{ + if (!IsMetadataDecode() && !mImageData) { + PostDataError(); + } +} + void nsBMPDecoder::FinishInternal() { @@ -232,17 +240,18 @@ nsBMPDecoder::FinishInternal() // Send notifications if appropriate. if (!IsMetadataDecode() && HasSize()) { + // We should have image data. + MOZ_ASSERT(mImageData); + // If it was truncated, fill in the missing pixels as black. - if (mImageData) { - while (mCurrentRow > 0) { - uint32_t* dst = RowBuffer(); - while (mCurrentPos < mH.mWidth) { - SetPixel(dst, 0, 0, 0); - mCurrentPos++; - } - mCurrentPos = 0; - FinishRow(); + while (mCurrentRow > 0) { + uint32_t* dst = RowBuffer(); + while (mCurrentPos < mH.mWidth) { + SetPixel(dst, 0, 0, 0); + mCurrentPos++; } + mCurrentPos = 0; + FinishRow(); } // Invalidate. @@ -492,7 +501,7 @@ nsBMPDecoder::ReadInfoHeaderSize(const char* aData, size_t aLength) PostDataError(); return Transition::TerminateFailure(); } - // ICO BMPs must have a WinVMPv3 header. nsICODecoder should have already + // ICO BMPs must have a WinBMPv3 header. nsICODecoder should have already // terminated decoding if this isn't the case. MOZ_ASSERT_IF(mIsWithinICO, mH.mBIHSize == InfoHeaderLength::WIN_V3); diff --git a/image/decoders/nsBMPDecoder.h b/image/decoders/nsBMPDecoder.h index 28ff43f1c90e..f5773656f655 100644 --- a/image/decoders/nsBMPDecoder.h +++ b/image/decoders/nsBMPDecoder.h @@ -151,6 +151,7 @@ public: virtual void WriteInternal(const char* aBuffer, uint32_t aCount) override; + virtual void BeforeFinishInternal() override; virtual void FinishInternal() override; private: