From be4c1161bda39fbd564ad0b2a1eb9673c8b5451c Mon Sep 17 00:00:00 2001 From: Rangi Date: Fri, 10 Jul 2026 17:27:26 -0400 Subject: [PATCH] Fix RGBGFX crash when trimming more tiles than exist after deduplication --- src/gfx/process.cpp | 38 ++++++++++++++++++++-------- test/gfx/trim_deduplicated.err | 1 + test/gfx/trim_deduplicated.flags | 3 +++ test/gfx/trim_deduplicated.out.2bpp | 0 test/gfx/trim_deduplicated.png | Bin 0 -> 111 bytes 5 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 test/gfx/trim_deduplicated.err create mode 100644 test/gfx/trim_deduplicated.flags create mode 100644 test/gfx/trim_deduplicated.out.2bpp create mode 100644 test/gfx/trim_deduplicated.png diff --git a/src/gfx/process.cpp b/src/gfx/process.cpp index 0b4459f1..56314b0f 100644 --- a/src/gfx/process.cpp +++ b/src/gfx/process.cpp @@ -853,20 +853,36 @@ static void outputTileData(UniqueTiles const &tiles) { // LCOV_EXCL_STOP } - uint16_t tileID = 0; - for (auto iter = tiles.begin(), end = tiles.end() - options.trim; iter != end; ++iter) { - TileData const *tile = *iter; - assume(tile->tileID == tileID); - ++tileID; - if (options.bitDepth == 2) { - output->sputn(reinterpret_cast(tile->data().data()), 16); - } else { - assume(options.bitDepth == 1); - for (size_t y = 0; y < 8; ++y) { - output->sputc(tile->data()[y * 2]); + uint64_t nbTiles = tiles.size(); + uint64_t nbKeptTiles = nbTiles > options.trim ? nbTiles - options.trim : 0; + uint64_t tileIdx = 0; + + for (TileData const *tile : tiles) { + assume(tile->tileID == tileIdx); + bool empty = true; + for (uint32_t y = 0; y < 8; ++y) { + uint8_t bitplane0 = tile->data()[y * 2]; + uint8_t bitplane1 = tile->data()[y * 2 + 1]; + if (bitplane0 || bitplane1) { + empty = false; + } + if (tileIdx < nbKeptTiles) { + output->sputc(bitplane0); + if (options.bitDepth == 2) { + output->sputc(bitplane1); + } } } + + if (!empty && tileIdx >= nbKeptTiles) { + warning( + WARNING_TRIM_NONEMPTY, "Trimming a nonempty tile (configure with '-x/--trim-end')" + ); + break; // Don't repeat the warning for subsequent tiles + } + ++tileIdx; } + assume(nbKeptTiles <= tileIdx && tileIdx <= nbTiles); } static void outputTilemap(std::vector const &attrmap) { diff --git a/test/gfx/trim_deduplicated.err b/test/gfx/trim_deduplicated.err new file mode 100644 index 00000000..d69b8db8 --- /dev/null +++ b/test/gfx/trim_deduplicated.err @@ -0,0 +1 @@ +warning: Trimming a nonempty tile (configure with '-x/--trim-end') [-Wtrim-nonempty] diff --git a/test/gfx/trim_deduplicated.flags b/test/gfx/trim_deduplicated.flags new file mode 100644 index 00000000..75cb327c --- /dev/null +++ b/test/gfx/trim_deduplicated.flags @@ -0,0 +1,3 @@ +-Wtrim-nonempty +-m +-x 3 diff --git a/test/gfx/trim_deduplicated.out.2bpp b/test/gfx/trim_deduplicated.out.2bpp new file mode 100644 index 00000000..e69de29b diff --git a/test/gfx/trim_deduplicated.png b/test/gfx/trim_deduplicated.png new file mode 100644 index 0000000000000000000000000000000000000000..a637853af32de1addb9365679f92abe8ba5d73f6 GIT binary patch literal 111 zcmeAS@N?(olHy`uVBq!ia0vp^0wBx;Bp3=bcE|uJGfx-CkcwNrXEt&&7;v~AWapbO zG3G9BjB0}RABD`Ebv7buw+g*vf^HmVmdK II;Vst0M_pyjsO4v literal 0 HcmV?d00001