Skip to content

Commit 4e748c6

Browse files
committed
Fix IFF palette size access
1 parent 1d96560 commit 4e748c6

1 file changed

Lines changed: 97 additions & 65 deletions

File tree

Source/Amiga/Graphics_Amiga.cpp

Lines changed: 97 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -506,31 +506,58 @@ void cGraphics_Amiga::PaletteSet(cSurface* pTarget) {
506506
sImage 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

Comments
 (0)