diff --git a/src/MagnumPlugins/TgaImporter/Test/TgaImporterTest.cpp b/src/MagnumPlugins/TgaImporter/Test/TgaImporterTest.cpp index bff564ef1..23d647896 100644 --- a/src/MagnumPlugins/TgaImporter/Test/TgaImporterTest.cpp +++ b/src/MagnumPlugins/TgaImporter/Test/TgaImporterTest.cpp @@ -58,6 +58,7 @@ struct TgaImporterTest: TestSuite::Tester { void grayscale8Rle(); void tga2(); + void fileTooLong(); void openMemory(); void openTwice(); @@ -67,6 +68,13 @@ struct TgaImporterTest: TestSuite::Tester { PluginManager::Manager _manager{"nonexistent"}; }; +constexpr const char Grayscale8[]{ + 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 8, 0, + 1, 2, + 3, 4, + 5, 6, +}; + constexpr const char Grayscale8Rle[]{ 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 8, 0, /* 2 pixels as-is */ @@ -229,6 +237,20 @@ const struct { }}}, }; +const struct { + const char* name; + Containers::Array extra; +} FileTooLongData[]{ + {"", {InPlaceInit, { + 'e', 'x', 't', 'r', 'a' + }}}, + {"TGA 2", {InPlaceInit, { + 'e', 'x', 't', 'r', 'a', + 0, 0, 0, 0, 0, 0, 0, 0, + 'T', 'R', 'U', 'E', 'V', 'I', 'S', 'I', 'O', 'N', '-', 'X', 'F', 'I', 'L', 'E', '.', '\0' + }}}, +}; + /* Shared among all plugins that implement data copying optimizations */ const struct { const char* name; @@ -270,6 +292,9 @@ TgaImporterTest::TgaImporterTest() { addInstancedTests({&TgaImporterTest::tga2}, Containers::arraySize(Tga2Data)); + addInstancedTests({&TgaImporterTest::fileTooLong}, + Containers::arraySize(FileTooLongData)); + addInstancedTests({&TgaImporterTest::openMemory}, Containers::arraySize(OpenMemoryData)); @@ -464,13 +489,7 @@ void TgaImporterTest::color32Rle() { void TgaImporterTest::grayscale8() { Containers::Pointer importer = _manager.instantiate("TgaImporter"); - const char data[] = { - 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 8, 0, - 1, 2, - 3, 4, - 5, 6 - }; - CORRADE_VERIFY(importer->openData(data)); + CORRADE_VERIFY(importer->openData(Grayscale8)); Containers::Optional image = importer->image2D(0); CORRADE_VERIFY(image); @@ -526,6 +545,36 @@ void TgaImporterTest::tga2() { }), TestSuite::Compare::Container); } +void TgaImporterTest::fileTooLong() { + auto&& data = FileTooLongData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + + Containers::Pointer importer = _manager.instantiate("TgaImporter"); + + /* The actual image data is always the same, only the end differs */ + CORRADE_VERIFY(importer->openData( + Containers::StringView{Containers::arrayView(Grayscale8)} + + Containers::StringView{data.extra})); + + Containers::Optional image; + std::ostringstream out; + { + Warning redirectWarning{&out}; + image = importer->image2D(0); + } + CORRADE_VERIFY(image); + CORRADE_COMPARE(image->flags(), ImageFlags2D{}); + CORRADE_COMPARE(image->storage().alignment(), 1); + CORRADE_COMPARE(image->format(), PixelFormat::R8Unorm); + CORRADE_COMPARE(image->size(), Vector2i(2, 3)); + CORRADE_COMPARE_AS(image->data(), Containers::arrayView({ + 1, 2, + 3, 4, + 5, 6 + }), TestSuite::Compare::Container); + CORRADE_COMPARE(out.str(), "Trade::TgaImporter::image2D(): ignoring 5 extra bytes at the end of image data\n"); +} + void TgaImporterTest::openMemory() { /* same as dxt1() except that it uses openData() & openMemory() to test data copying on import */ diff --git a/src/MagnumPlugins/TgaImporter/TgaImporter.cpp b/src/MagnumPlugins/TgaImporter/TgaImporter.cpp index e43b734aa..643a560ce 100644 --- a/src/MagnumPlugins/TgaImporter/TgaImporter.cpp +++ b/src/MagnumPlugins/TgaImporter/TgaImporter.cpp @@ -188,12 +188,18 @@ Containers::Optional TgaImporter::doImage2D(UnsignedInt, UnsignedIn /* Copy data directly if not RLE */ Containers::Array data{outputSize}; if(!rle) { - /* Files that are larger are allowed in this case (but not for RLE) */ if(srcPixels.size() < outputSize) { Error{} << "Trade::TgaImporter::image2D(): file too short, expected" << outputSize + sizeof(Implementation::TgaHeader) << "bytes but got" << _in.size(); return {}; } + /* Image data that are larger are allowed in this case (even if there's + a TGA 2 footer after), as we get garbage back in the worst case. In + case of RLE this would be a failure. */ + if(srcPixels.size() > outputSize) { + Warning{} << "Trade::TgaImporter::image2D(): ignoring" << srcPixels.size() - outputSize << "extra bytes at the end of image data"; + } + Utility::copy(srcPixels.prefix(data.size()), data); /* Otherwise decode */