Browse Source

LiGfx/ILBMLoader: Don't throw if malformed bitplane can be decoded

Some apps seem to generate malformed images that are accepted
by most readers. We now only throw if malformed data would lead to
a write outside the chunky buffer.
Nicolas Ramz 1 year ago
parent
commit
fc5b6e4dda

+ 11 - 0
Tests/LibGfx/TestImageDecoder.cpp

@@ -243,6 +243,17 @@ TEST_CASE(test_24bit)
     EXPECT_EQ(frame.image->get_pixel(158, 270), Gfx::Color(0xee, 0x3d, 0x3c, 255));
 }
 
+TEST_CASE(test_brush_transparent_color)
+{
+    auto file = MUST(Core::MappedFile::map(TEST_INPUT("ilbm/brush-transparent-color.iff"sv)));
+    EXPECT(Gfx::ILBMImageDecoderPlugin::sniff(file->bytes()));
+    auto plugin_decoder = TRY_OR_FAIL(Gfx::ILBMImageDecoderPlugin::create(file->bytes()));
+
+    auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 266, 309 }));
+
+    EXPECT_EQ(frame.image->get_pixel(114, 103), Gfx::Color::NamedColor::Black);
+}
+
 TEST_CASE(test_ilbm_malformed_header)
 {
     Array test_inputs = {

BIN
Tests/LibGfx/test-inputs/ilbm/brush-transparent-color.iff


+ 7 - 1
Userland/Libraries/LibGfx/ImageFormats/ILBMLoader.cpp

@@ -211,13 +211,19 @@ static ErrorOr<ByteBuffer> planar_to_chunky(ReadonlyBytes bitplanes, ILBMLoading
         for (u8 p = 0; p < planes; p++) {
             u8 const plane_mask = 1 << (p % 8);
             size_t offset_base = (pitch * planes * y) + (p * pitch);
-            if (offset_base + pitch > bitplanes.size() || scanline + ((pitch - 1) * 8) + 7 >= chunky.size())
+            if (offset_base + pitch > bitplanes.size())
                 return Error::from_string_literal("Malformed bitplane data");
 
             for (u16 i = 0; i < pitch; i++) {
                 u8 bit = bitplanes[offset_base + i];
                 u8 rgb_shift = p / 8;
 
+                // Only throw an error if we would actually attempt to write
+                // outside of the chunky buffer. Some apps like PPaint produce
+                // malformed bitplane data but files are still accepted by most readers.
+                if (bit && scanline + ((pitch - 1) * 8) + 7 >= chunky.size())
+                    return Error::from_string_literal("Malformed bitplane data");
+
                 for (u8 b = 0; b < 8; b++) {
                     u8 mask = 1 << (7 - b);
                     // get current plane