From 17d342bc4bca4b026588a3315ecf33a6b178ed5b Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 23 Feb 2022 13:04:20 +1100 Subject: [PATCH 1/2] Simplified code as both values are 7 bit --- src/libImaging/TgaRleDecode.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/libImaging/TgaRleDecode.c b/src/libImaging/TgaRleDecode.c index 273ecdffd6b..d5976693393 100644 --- a/src/libImaging/TgaRleDecode.c +++ b/src/libImaging/TgaRleDecode.c @@ -42,15 +42,13 @@ ImagingTgaRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t return ptr - buf; } + n = depth * ((ptr[0] & 0x7f) + 1); if (ptr[0] & 0x80) { /* Run (1 + pixelsize bytes) */ - if (bytes < 1 + depth) { break; } - n = depth * ((ptr[0] & 0x7f) + 1); - if (state->x + n > state->bytes) { state->errcode = IMAGING_CODEC_OVERRUN; return -1; @@ -67,11 +65,8 @@ ImagingTgaRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t ptr += 1 + depth; bytes -= 1 + depth; - } else { /* Literal (1+n+1 bytes block) */ - n = depth * (ptr[0] + 1); - if (bytes < 1 + n) { break; } From 0d729941a89af9e00d9d01d14ec144ab358410cd Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Wed, 23 Feb 2022 15:08:33 +1100 Subject: [PATCH 2/2] Handle packets that cross scan lines --- Tests/images/cross_scan_line.png | Bin 0 -> 71 bytes Tests/images/cross_scan_line.tga | Bin 0 -> 49 bytes Tests/test_file_tga.py | 5 +++ src/libImaging/TgaRleDecode.c | 53 ++++++++++++++++++++++--------- 4 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 Tests/images/cross_scan_line.png create mode 100644 Tests/images/cross_scan_line.tga diff --git a/Tests/images/cross_scan_line.png b/Tests/images/cross_scan_line.png new file mode 100644 index 0000000000000000000000000000000000000000..64b68ed338db798dcfbff07af1b1b96c2a0003e6 GIT binary patch literal 71 zcmeAS@N?(olHy`uVBq!ia0vp^Od!kwBpAZ)2K@k1e4Z|jAr*6yf1E#X;DbB^8w2D2 SikNMUAQhgjelF{r5}E)PRuX6c literal 0 HcmV?d00001 diff --git a/Tests/images/cross_scan_line.tga b/Tests/images/cross_scan_line.tga new file mode 100644 index 0000000000000000000000000000000000000000..5ef8c8154d4380052ca904932189383f02512d88 GIT binary patch literal 49 qcmZQz;AVgUCI%)34j}&jA11;O5)|qh<{9ki@24B#=IP_A#{d9u2nPcI literal 0 HcmV?d00001 diff --git a/Tests/test_file_tga.py b/Tests/test_file_tga.py index e2351d72362..aeea3fb42bb 100644 --- a/Tests/test_file_tga.py +++ b/Tests/test_file_tga.py @@ -97,6 +97,11 @@ def test_id_field_rle(): assert im.size == (199, 199) +def test_cross_scan_line(): + with Image.open("Tests/images/cross_scan_line.tga") as im: + assert_image_equal_tofile(im, "Tests/images/cross_scan_line.png") + + def test_save(tmp_path): test_file = "Tests/images/tga_id_field.tga" with Image.open(test_file) as im: diff --git a/src/libImaging/TgaRleDecode.c b/src/libImaging/TgaRleDecode.c index d5976693393..77248d1457c 100644 --- a/src/libImaging/TgaRleDecode.c +++ b/src/libImaging/TgaRleDecode.c @@ -20,6 +20,8 @@ int ImagingTgaRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes) { int n, depth; UINT8 *ptr; + UINT8 extra_data = 0; + int extra_bytes = 0; ptr = buf; @@ -72,8 +74,10 @@ ImagingTgaRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t } if (state->x + n > state->bytes) { - state->errcode = IMAGING_CODEC_OVERRUN; - return -1; + extra_bytes = n; /* full value */ + n = state->bytes - state->x; + extra_bytes -= n; + extra_data = ptr[1]; } memcpy(state->buffer + state->x, ptr + 1, n); @@ -82,24 +86,43 @@ ImagingTgaRleDecode(Imaging im, ImagingCodecState state, UINT8 *buf, Py_ssize_t bytes -= 1 + n; } - state->x += n; + for (;;) { + state->x += n; - if (state->x >= state->bytes) { - /* Got a full line, unpack it */ - state->shuffle( - (UINT8 *)im->image[state->y + state->yoff] + - state->xoff * im->pixelsize, - state->buffer, - state->xsize); + if (state->x >= state->bytes) { + /* Got a full line, unpack it */ + state->shuffle( + (UINT8 *)im->image[state->y + state->yoff] + + state->xoff * im->pixelsize, + state->buffer, + state->xsize); - state->x = 0; + state->x = 0; - state->y += state->ystep; + state->y += state->ystep; - if (state->y < 0 || state->y >= state->ysize) { - /* End of file (errcode = 0) */ - return -1; + if (state->y < 0 || state->y >= state->ysize) { + /* End of file (errcode = 0) */ + return -1; + } + } + + if (extra_bytes == 0) { + break; + } + + if (state->x > 0) { + break; // assert + } + + if (extra_bytes >= state->bytes) { + n = state->bytes; + } else { + n = extra_bytes; } + memcpy(state->buffer + state->x, ptr, n); + ptr += n; + extra_bytes -= n; } }