Browse Source

TgaImporter: print a warning for files that are too long.

Until now this was silently ignored with the assumption that there
*might* be a TGA 2 header. But now that we actually recognize it, any
extra data are an error in the file, and so it should print a warning.

Since it's not an error that could potentially lead to a crash, it's
just a warning and not a hard failure. Same is done in ASTC, DDS and
KTX file parsing.
pull/605/head
Vladimír Vondruš 4 years ago
parent
commit
b5d1b6b443
  1. 63
      src/MagnumPlugins/TgaImporter/Test/TgaImporterTest.cpp
  2. 8
      src/MagnumPlugins/TgaImporter/TgaImporter.cpp

63
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<AbstractImporter> _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<char> 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<AbstractImporter> 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<Trade::ImageData2D> 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<AbstractImporter> 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<Trade::ImageData2D> 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<char>({
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 */

8
src/MagnumPlugins/TgaImporter/TgaImporter.cpp

@ -188,12 +188,18 @@ Containers::Optional<ImageData2D> TgaImporter::doImage2D(UnsignedInt, UnsignedIn
/* Copy data directly if not RLE */
Containers::Array<char> 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 */

Loading…
Cancel
Save