Skip to content

Commit 2f023a5

Browse files
committed
1 parent 7a3730b commit 2f023a5

1 file changed

Lines changed: 54 additions & 11 deletions

File tree

Source/Plugins/PSDParser.cpp

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,9 @@ _Format(-1), _Width(-1), _Height(-1), _WidthBytes(-1), _Size(-1), _CompressedSiz
713713
}
714714

715715
psdThumbnail::~psdThumbnail() {
716-
if (_owned) FreeImage_Unload(_dib);
716+
if (_owned) {
717+
FreeImage_Unload(_dib);
718+
}
717719
}
718720

719721
void
@@ -771,15 +773,23 @@ int psdThumbnail::Read(FreeImageIO *io, fi_handle handle, int iResourceSize, boo
771773
nBytes += n * sizeof(ShortValue);
772774
_Planes = (short)psdGetValue(ShortValue, sizeof(_Planes) );
773775

776+
if (_WidthBytes * 8 < _Width * _BitPerPixel) {
777+
throw "Invalid PSD image";
778+
}
779+
774780
const long JFIF_startpos = io->tell_proc(handle);
775781

776782
if (_dib) {
777783
FreeImage_Unload(_dib);
784+
_dib = nullptr;
778785
}
779786

780787
if (_Format == 1) {
781788
// kJpegRGB thumbnail image
782789
_dib = FreeImage_LoadFromHandle(FIF_JPEG, io, handle);
790+
if (!_dib) {
791+
throw "Invalid PSD thumbnail";
792+
}
783793
if (isBGR) {
784794
SwapRedBlue32(_dib);
785795
}
@@ -789,6 +799,12 @@ int psdThumbnail::Read(FreeImageIO *io, fi_handle handle, int iResourceSize, boo
789799
else {
790800
// kRawRGB thumbnail image
791801
_dib = FreeImage_Allocate(_Width, _Height, _BitPerPixel);
802+
if (!_dib) {
803+
throw "Invalid PSD thumbnail";
804+
}
805+
if (_BitPerPixel != FreeImage_GetBPP(_dib)) {
806+
throw "Invalid BPP in PSD thumbnail";
807+
}
792808
uint8_t* dst_line_start = FreeImage_GetScanLine(_dib, _Height - 1);//<*** flipped
793809
auto line_start = std::make_unique<uint8_t[]>(_WidthBytes);
794810
const unsigned dstLineSize = FreeImage_GetPitch(_dib);
@@ -1304,45 +1320,49 @@ void psdParser::ReadImageLine(uint8_t* dst, const uint8_t* src, unsigned lineSiz
13041320
}
13051321

13061322
void psdParser::UnpackRLE(uint8_t* line, const uint8_t* rle_line, const uint8_t* line_end, unsigned srcSize) {
1307-
while (srcSize > 0) {
1323+
while (srcSize > 1) {
1324+
if (line >= line_end) {
1325+
return;
1326+
}
13081327

1309-
int len = *rle_line++;
1328+
const uint8_t len_byte = *rle_line++;
13101329
srcSize--;
13111330

13121331
// NOTE len is signed byte in PackBits RLE
13131332

1314-
if ( len < 128 ) { //<- MSB is not set
1333+
if ( len_byte < 128 ) { //<- MSB is not set
13151334
// uncompressed packet
13161335

13171336
// (len + 1) bytes of data are copied
1318-
++len;
1337+
const uint32_t len = std::min(static_cast<uint32_t>(len_byte + 1), srcSize);
13191338

13201339
// assert we don't write beyound eol
13211340
memcpy(line, rle_line, line + len > line_end ? line_end - line : len);
13221341
line += len;
13231342
rle_line += len;
13241343
srcSize -= len;
13251344
}
1326-
else if ( len > 128 ) { //< MSB is set
1345+
else if ( len_byte > 128 ) { //< MSB is set
13271346
// RLE compressed packet
13281347

13291348
// One byte of data is repeated (-len + 1) times
13301349

1331-
len ^= 0xFF; // same as (-len + 1) & 0xFF
1332-
len += 2; //
1350+
// same as (-len + 1) & 0xFF
1351+
const uint32_t len = (len_byte ^ 0xFF) + 2;
13331352

13341353
// assert we don't write beyound eol
13351354
memset(line, *rle_line++, line + len > line_end ? line_end - line : len);
13361355
line += len;
13371356
srcSize--;
13381357
}
1339-
else if ( 128 == len ) {
1358+
else {
1359+
// 128 == len
13401360
// Do nothing
13411361
}
13421362
}//< rle_line
13431363
}
13441364

1345-
FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) {
1365+
FIBITMAP* psdParser::ReadImageData(FreeImageIO* io, fi_handle handle) {
13461366
if (!handle) {
13471367
return nullptr;
13481368
}
@@ -1361,7 +1381,7 @@ FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) {
13611381
// PSDP_COMPRESSION_ZIP and PSDP_COMPRESSION_ZIP_PREDICTION
13621382
// are only valid for layer data, not the composited data.
13631383
if (nCompression != PSDP_COMPRESSION_NONE &&
1364-
nCompression != PSDP_COMPRESSION_RLE) {
1384+
nCompression != PSDP_COMPRESSION_RLE) {
13651385
FreeImage_OutputMessageProc(_fi_format_id, "Unsupported compression %d", nCompression);
13661386
return nullptr;
13671387
}
@@ -1372,6 +1392,25 @@ FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) {
13721392
const unsigned depth = _headerInfo._BitsPerChannel;
13731393
const unsigned bytes = (depth == 1) ? 1 : depth / 8;
13741394

1395+
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
1396+
if (nChannels < 1 || nChannels > 56) {
1397+
throw "Invalid channels value in PSD header";
1398+
}
1399+
1400+
if (nWidth < 1 || nWidth > 30000 || nHeight < 1 || nHeight > 30000) {
1401+
throw "Invalid width or height value in PSD header";
1402+
}
1403+
1404+
switch (depth) {
1405+
case 1:
1406+
case 8:
1407+
case 16:
1408+
case 32:
1409+
break;
1410+
default:
1411+
throw "Invalid depth value in PSD header";
1412+
}
1413+
13751414
// channel(plane) line (uint8_t aligned)
13761415
const unsigned lineSize = (_headerInfo._BitsPerChannel == 1) ? (nWidth + 7) / 8 : nWidth * bytes;
13771416

@@ -1460,6 +1499,10 @@ FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) {
14601499
const unsigned dstLineSize = FreeImage_GetPitch(bitmap);
14611500
uint8_t* const dst_first_line = FreeImage_GetScanLine(bitmap, nHeight - 1);//<*** flipped
14621501

1502+
if (lineSize > dstLineSize) {
1503+
throw "Invalid source size";
1504+
}
1505+
14631506
auto line_start = std::make_unique<uint8_t[]>(lineSize); //< fileline cache
14641507

14651508
switch ( nCompression ) {

0 commit comments

Comments
 (0)