@@ -506,31 +506,58 @@ void cGraphics_Amiga::PaletteSet(cSurface* pTarget) {
506506sImage cGraphics_Amiga::DecodeIFF (const std::string& pFilename) {
507507 sImage Result;
508508 auto File = g_Resource->fileGet (pFilename);
509- auto DataPtr = File->data ();
509+ if (!File || File->empty ())
510+ return Result;
511+
512+ const uint8* DataBegin = File->data ();
513+ const uint8* DataPtr = DataBegin;
514+ const uint8* DataEnd = DataBegin + File->size ();
515+
516+ auto ReadAvailable = [&](size_t pSize) {
517+ return (DataEnd >= DataPtr) && (static_cast <size_t >(DataEnd - DataPtr) >= pSize);
518+ };
510519
511- if (!DataPtr || readBEDWord (DataPtr) != ' FORM' )
520+ auto SkipBytes = [&](size_t pSize) {
521+ if (!ReadAvailable (pSize))
522+ return false ;
523+ DataPtr += pSize;
524+ return true ;
525+ };
526+
527+ if (!ReadAvailable (12 ) || readBEDWord (DataPtr) != ' FORM' )
512528 return Result;
513529 DataPtr += 4 ;
514- size_t FileSize = readBEDWord (DataPtr);
530+ uint32 FormSize = readBEDWord (DataPtr);
515531 DataPtr += 4 ;
516532
517533 if (readBEDWord (DataPtr) != ' ILBM' )
518534 return Result;
519535
520536 DataPtr += 4 ;
521- FileSize -= 4 ;
537+ size_t FileSize = std::min< size_t >(FormSize >= 4 ? FormSize - 4 : 0 , static_cast < size_t >(DataEnd - DataPtr)) ;
522538
523539 uint32 Header = 0 ;
524540 uint32 Size = 0 ;
541+ bool GotHeader = false ;
525542
526543 while (FileSize > 8 ) {
544+ if (!ReadAvailable (8 ))
545+ return Result;
546+
527547 Header = readBEDWord (DataPtr);
528548 DataPtr += 4 ; FileSize -= 4 ;
529549 Size = readBEDWord (DataPtr);
530550 DataPtr += 4 ; FileSize -= 4 ;
551+ size_t ChunkSize = static_cast <size_t >(Size);
552+ size_t ChunkPaddedSize = ChunkSize + (ChunkSize & 1 );
553+ if (ChunkPaddedSize > FileSize || !ReadAvailable (ChunkPaddedSize))
554+ return Result;
531555
532556 switch (Header) {
533557 case ' BMHD' :
558+ if (ChunkSize < 20 )
559+ return Result;
560+
534561 Result.mDimension .mWidth = readBEWord (DataPtr); DataPtr += 2 ;
535562 Result.mDimension .mHeight = readBEWord (DataPtr); DataPtr += 2 ;
536563 DataPtr += 2 ; DataPtr += 2 ; // X, Y
@@ -539,77 +566,85 @@ sImage cGraphics_Amiga::DecodeIFF(const std::string& pFilename) {
539566 DataPtr++; // Compression
540567 DataPtr += 2 ; ++DataPtr; ++DataPtr; ++DataPtr;
541568 DataPtr += 2 ; DataPtr += 2 ;
542- FileSize -= Size;
569+ if (ChunkSize > 20 )
570+ DataPtr += ChunkSize - 20 ;
571+ if (ChunkSize & 1 )
572+ ++DataPtr;
573+ FileSize -= ChunkPaddedSize;
574+ GotHeader = true ;
543575 break ;
544576
545577 case ' BODY' : {
546- // + 2 is because the amiga does writing after the end of the image
547- Result.mData ->resize (Result.mDimension .WidthByHeight () * (Result.mPlanes + 2 ));
548-
549- int16 Width = Result.mDimension .mWidth + 0x0F ;
550- Width >>= 4 ;
551- Width <<= 1 ;
552-
553- int16 Height = Result.mDimension .mHeight - 1 ;
554-
555- uint8* pDataDest = Result.mData ->data ();
556-
557- for (int16 Y = Height; Y >= 0 ; --Y) {
558- uint8* DataDest = pDataDest;
559-
560- for (int8 Plane = 0 ; Plane < Result.mPlanes ; ++Plane) {
561-
562- for (int16 X = Width; X > 0 ;) {
563- --FileSize;
564- int8 d0 = *DataPtr++;
578+ if (!GotHeader || Result.mDimension .mWidth == 0 || Result.mDimension .mHeight == 0 || Result.mPlanes == 0 )
579+ return Result;
580+
581+ const size_t Width = ((static_cast <size_t >(Result.mDimension .mWidth ) + 0x0F ) >> 4 ) << 1 ;
582+ const size_t Height = static_cast <size_t >(Result.mDimension .mHeight );
583+ const size_t Planes = static_cast <size_t >(Result.mPlanes );
584+ if (Planes > 8 || Width == 0 || Height == 0 )
585+ return Result;
586+ if (Width > (SIZE_MAX / Height))
587+ return Result;
588+ size_t PlaneSize = Width * Height;
589+ if (Planes > (SIZE_MAX / PlaneSize))
590+ return Result;
591+ size_t DataSize = PlaneSize * Planes;
592+ Result.mData ->assign (DataSize, 0 );
593+
594+ for (size_t Y = 0 ; Y < Height; ++Y) {
595+ for (size_t Plane = 0 ; Plane < Planes; ++Plane) {
596+ uint8* DataDest = Result.mData ->data () + (Plane * PlaneSize) + (Y * Width);
597+ size_t X = Width;
598+
599+ while (X > 0 ) {
600+ if (ChunkSize == 0 || !ReadAvailable (1 ))
601+ return Result;
602+
603+ int8 d0 = static_cast <int8>(*DataPtr++);
604+ --ChunkSize;
565605
566606 if (d0 < 0 ) {
567607 if (d0 == -128 )
568608 continue ;
569609
570- int8 d1 = -d0;
571-
572- --FileSize;
573- d0 = *DataPtr++;
574-
575- do {
576- *DataDest++ = d0;
577- --X;
578- } while (d1-- > 0 );
579-
580- continue ;
610+ size_t Count = static_cast <size_t >(-d0) + 1 ;
611+ if (Count > X || ChunkSize == 0 || !ReadAvailable (1 ))
612+ return Result;
581613
614+ uint8 Fill = *DataPtr++;
615+ --ChunkSize;
616+ memset (DataDest, Fill, Count);
617+ DataDest += Count;
618+ X -= Count;
582619 }
583620 else {
584-
585- do {
586- *DataDest++ = *DataPtr++;
587- --X;
588- --FileSize;
589- } while (d0-- > 0 );
590-
621+ size_t Count = static_cast <size_t >(d0) + 1 ;
622+ if (Count > X || ChunkSize < Count || !ReadAvailable (Count))
623+ return Result;
624+ memcpy (DataDest, DataPtr, Count);
625+ DataDest += Count;
626+ DataPtr += Count;
627+ ChunkSize -= Count;
628+ X -= Count;
591629 }
592630 }
593-
594- // Move the destination back to start of row
595- DataDest -= Width;
596-
597- // Move it to the next plane
598- DataDest += (Width * Result.mDimension .mHeight );
599631 }
600-
601- // Next Row
602- pDataDest += Width;
603632 }
604633
634+ if (!SkipBytes (ChunkSize))
635+ return Result;
636+ if (Size & 1 )
637+ ++DataPtr;
638+ FileSize -= ChunkPaddedSize;
639+
605640 break ;
606641 }
607642
608643 case ' CMAP' : {
609644 size_t Colors = Size / 3 ;
610- size_t ColorsToRead = std::min<size_t >(Colors,sizeof (Result.mPalette ) / sizeof (Result.mPalette [0 ]));
645+ size_t ColorsToRead = std::min<size_t >(Colors, sizeof (Result.mPalette ) / sizeof (Result.mPalette [0 ]));
611646
612- for (size_t i = 0 ; i < ColorsToRead && FileSize >= 3 ; ++i) {
647+ for (size_t i = 0 ; i < ColorsToRead; ++i) {
613648 int16 d0 = (int16)*DataPtr++;
614649 int16 Final = 0 ;
615650
@@ -634,23 +669,20 @@ sImage cGraphics_Amiga::DecodeIFF(const std::string& pFilename) {
634669 Result.mPalette [i].mGreen = ((Final >> 4 ) & 0xF ) << 2 ;
635670 Result.mPalette [i].mBlue = ((Final >> 0 ) & 0xF ) << 2 ;
636671 }
637-
638- FileSize -= 3 ;
639672 }
640673
641- size_t BytesRead = ColorsToRead * 3 ;
642- size_t BytesRemaining = Size > BytesRead ? Size - BytesRead : 0 ;
643- DataPtr += BytesRemaining;
644- FileSize -= std::min (FileSize, BytesRemaining);
674+ if (!SkipBytes (ChunkSize - ((ChunkSize / 3 ) * 3 )))
675+ return Result;
676+ if (Size & 1 )
677+ ++DataPtr;
678+ FileSize -= ChunkPaddedSize;
645679 break ;
646- }
680+ }
647681
648682 default :
649- if (Size & 1 )
650- ++Size;
651-
652- DataPtr += Size;
653- FileSize -= Size;
683+ if (!SkipBytes (ChunkPaddedSize))
684+ return Result;
685+ FileSize -= ChunkPaddedSize;
654686 break ;
655687 }
656688 }
0 commit comments