@@ -91,14 +91,8 @@ nsICODecoder::GetFinalStateFromContainedDecoder()
9191 return NS_OK ;
9292 }
9393
94- MOZ_ASSERT (mContainedSourceBuffer ,
95- " Should have a SourceBuffer if we have a decoder" );
96-
9794 // Let the contained decoder finish up if necessary.
98- if (!mContainedSourceBuffer ->IsComplete ()) {
99- mContainedSourceBuffer ->Complete (NS_OK );
100- mContainedDecoder ->Decode ();
101- }
95+ FlushContainedDecoder ();
10296
10397 // Make our state the same as the state of the contained decoder.
10498 mDecodeDone = mContainedDecoder ->GetDecodeDone ();
@@ -255,28 +249,26 @@ nsICODecoder::ReadDirEntry(const char* aData)
255249LexerTransition<ICOState>
256250nsICODecoder::SniffResource (const char * aData)
257251{
252+ // Prepare a new iterator for the contained decoder to advance as it wills.
253+ // Cloning at the point ensures it will begin at the resource offset.
254+ mContainedIterator .emplace (mLexer .Clone (*mIterator , mDirEntry .mBytesInRes ));
255+
258256 // We use the first PNGSIGNATURESIZE bytes to determine whether this resource
259257 // is a PNG or a BMP.
260258 bool isPNG = !memcmp (aData, nsPNGDecoder::pngSignatureBytes,
261259 PNGSIGNATURESIZE );
262260 if (isPNG) {
261+ if (mDirEntry .mBytesInRes <= PNGSIGNATURESIZE ) {
262+ return Transition::TerminateFailure ();
263+ }
264+
263265 // Create a PNG decoder which will do the rest of the work for us.
264- mContainedSourceBuffer = new SourceBuffer ();
265- mContainedSourceBuffer ->ExpectLength (mDirEntry .mBytesInRes );
266266 mContainedDecoder =
267267 DecoderFactory::CreateDecoderForICOResource (DecoderType::PNG ,
268- WrapNotNull ( mContainedSourceBuffer ),
268+ Move (* mContainedIterator ),
269269 WrapNotNull (this ),
270270 Some (GetRealSize ()));
271271
272- if (!WriteToContainedDecoder (aData, PNGSIGNATURESIZE )) {
273- return Transition::TerminateFailure ();
274- }
275-
276- if (mDirEntry .mBytesInRes <= PNGSIGNATURESIZE ) {
277- return Transition::TerminateFailure ();
278- }
279-
280272 // Read in the rest of the PNG unbuffered.
281273 size_t toRead = mDirEntry .mBytesInRes - PNGSIGNATURESIZE ;
282274 return Transition::ToUnbuffered (ICOState::FINISHED_RESOURCE ,
@@ -299,9 +291,9 @@ nsICODecoder::SniffResource(const char* aData)
299291}
300292
301293LexerTransition<ICOState>
302- nsICODecoder::ReadResource (const char * aData, uint32_t aLen )
294+ nsICODecoder::ReadResource ()
303295{
304- if (!WriteToContainedDecoder (aData, aLen )) {
296+ if (!FlushContainedDecoder ( )) {
305297 return Transition::TerminateFailure ();
306298 }
307299
@@ -334,19 +326,18 @@ nsICODecoder::ReadBIH(const char* aData)
334326
335327 // Create a BMP decoder which will do most of the work for us; the exception
336328 // is the AND mask, which isn't present in standalone BMPs.
337- mContainedSourceBuffer = new SourceBuffer ();
338- mContainedSourceBuffer ->ExpectLength (mDirEntry .mBytesInRes );
339329 mContainedDecoder =
340330 DecoderFactory::CreateDecoderForICOResource (DecoderType::BMP ,
341- WrapNotNull ( mContainedSourceBuffer ),
331+ Move (* mContainedIterator ),
342332 WrapNotNull (this ),
343333 Some (GetRealSize ()),
344334 Some (dataOffset));
335+
345336 RefPtr<nsBMPDecoder> bmpDecoder =
346337 static_cast <nsBMPDecoder*>(mContainedDecoder .get ());
347338
348- // Write out the BMP's bitmap info header.
349- if (!WriteToContainedDecoder ( mBIHraw , sizeof ( mBIHraw ) )) {
339+ // Ensure the decoder has parsed at least the BMP's bitmap info header.
340+ if (!FlushContainedDecoder ( )) {
350341 return Transition::TerminateFailure ();
351342 }
352343
@@ -372,6 +363,14 @@ nsICODecoder::ReadBIH(const char* aData)
372363LexerTransition<ICOState>
373364nsICODecoder::PrepareForMask ()
374365{
366+ // We have received all of the data required by the BMP decoder so flushing
367+ // here guarantees the decode has finished.
368+ if (!FlushContainedDecoder ()) {
369+ return Transition::TerminateFailure ();
370+ }
371+
372+ MOZ_ASSERT (mContainedDecoder ->GetDecodeDone ());
373+
375374 RefPtr<nsBMPDecoder> bmpDecoder =
376375 static_cast <nsBMPDecoder*>(mContainedDecoder .get ());
377376
@@ -517,6 +516,14 @@ nsICODecoder::FinishMask()
517516LexerTransition<ICOState>
518517nsICODecoder::FinishResource ()
519518{
519+ // We have received all of the data required by the PNG/BMP decoder so
520+ // flushing here guarantees the decode has finished.
521+ if (!FlushContainedDecoder ()) {
522+ return Transition::TerminateFailure ();
523+ }
524+
525+ MOZ_ASSERT (mContainedDecoder ->GetDecodeDone ());
526+
520527 // Make sure the actual size of the resource matches the size in the directory
521528 // entry. If not, we consider the image corrupt.
522529 if (mContainedDecoder ->HasSize () &&
@@ -559,7 +566,7 @@ nsICODecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
559566 case ICOState::SNIFF_RESOURCE :
560567 return SniffResource (aData);
561568 case ICOState::READ_RESOURCE :
562- return ReadResource (aData, aLength );
569+ return ReadResource ();
563570 case ICOState::READ_BIH :
564571 return ReadBIH (aData);
565572 case ICOState::PREPARE_FOR_MASK :
@@ -579,21 +586,16 @@ nsICODecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
579586}
580587
581588bool
582- nsICODecoder::WriteToContainedDecoder ( const char * aBuffer, uint32_t aCount )
589+ nsICODecoder::FlushContainedDecoder ( )
583590{
584591 MOZ_ASSERT (mContainedDecoder );
585- MOZ_ASSERT (mContainedSourceBuffer );
586-
587- // Append the provided data to the SourceBuffer that the contained decoder is
588- // reading from.
589- mContainedSourceBuffer ->Append (aBuffer, aCount);
590592
591593 bool succeeded = true ;
592594
593- // Write to the contained decoder. If we run out of data, the ICO decoder will
594- // get resumed when there's more data available, as usual, so we don't need
595- // the contained decoder to get resumed too. To avoid that, we provide an
596- // IResumable which just does nothing .
595+ // If we run out of data, the ICO decoder will get resumed when there's more
596+ // data available, as usual, so we don't need the contained decoder to get
597+ // resumed too. To avoid that, we provide an IResumable which just does
598+ // nothing. All the caller needs to do is flush when there is new data .
597599 LexerResult result = mContainedDecoder ->Decode ();
598600 if (result == LexerResult (TerminalState::FAILURE )) {
599601 succeeded = false ;
0 commit comments