blob: 61ee71af4ab4efc6f214727b515281664f417639 [file] [log] [blame]
// Copyright 2024 Google LLC
// SPDX-License-Identifier: BSD-2-Clause
#include <algorithm>
#include <cstring>
#include <iostream>
#include <string>
#include "avif/avif.h"
#include "aviftest_helpers.h"
#include "gtest/gtest.h"
namespace avif {
namespace {
// Used to pass the data folder path to the GoogleTest suites.
const char* data_path = nullptr;
//------------------------------------------------------------------------------
TEST(AvifDecodeTest, SingleWhitePixel) {
const char* file_name = "white_1x1.avif";
DecoderPtr decoder(avifDecoderCreate());
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(avifDecoderSetIOFile(decoder.get(),
(std::string(data_path) + file_name).c_str()),
AVIF_RESULT_OK);
ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_OK);
if (testutil::Av1DecoderAvailable()) {
EXPECT_EQ(avifDecoderNextImage(decoder.get()), AVIF_RESULT_OK);
}
}
TEST(AvifDecodeTest, MdatSize0) {
testutil::AvifRwData avif =
testutil::ReadFile(std::string(data_path) + "white_1x1.avif");
// Edit the file to simulate an 'mdat' box with size 0 (meaning ending at EOF)
const uint8_t* kMdat = reinterpret_cast<const uint8_t*>("mdat");
uint8_t* mdat_position =
std::search(avif.data, avif.data + avif.size, kMdat, kMdat + 4);
ASSERT_NE(mdat_position, avif.data + avif.size);
mdat_position[-1] = '\0';
DecoderPtr decoder(avifDecoderCreate());
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(avifDecoderSetIOMemory(decoder.get(), avif.data, avif.size),
AVIF_RESULT_OK);
ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_OK);
if (testutil::Av1DecoderAvailable()) {
EXPECT_EQ(avifDecoderNextImage(decoder.get()), AVIF_RESULT_OK);
}
}
TEST(AvifDecodeTest, MetaSize0) {
testutil::AvifRwData avif =
testutil::ReadFile(std::string(data_path) + "white_1x1.avif");
// Edit the file to simulate a 'meta' box with size 0 (invalid).
const uint8_t* kMeta = reinterpret_cast<const uint8_t*>("meta");
uint8_t* meta_position =
std::search(avif.data, avif.data + avif.size, kMeta, kMeta + 4);
ASSERT_NE(meta_position, avif.data + avif.size);
meta_position[-1] = '\0';
DecoderPtr decoder(avifDecoderCreate());
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(avifDecoderSetIOMemory(decoder.get(), avif.data, avif.size),
AVIF_RESULT_OK);
// This should fail because the meta box contains the mdat box.
// However, the section 8.11.3.1 of ISO/IEC 14496-12 does not explicitly
// require the coded image item extents to be read from the MediaDataBox if
// the construction_method is 0.
// Maybe another section or specification enforces that.
ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_OK);
if (testutil::Av1DecoderAvailable()) {
EXPECT_EQ(avifDecoderNextImage(decoder.get()), AVIF_RESULT_OK);
}
}
TEST(AvifDecodeTest, FtypSize0) {
testutil::AvifRwData avif =
testutil::ReadFile(std::string(data_path) + "white_1x1.avif");
// Edit the file to simulate a 'ftyp' box with size 0 (invalid).
avif.data[3] = '\0';
DecoderPtr decoder(avifDecoderCreate());
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(avifDecoderSetIOMemory(decoder.get(), avif.data, avif.size),
AVIF_RESULT_OK);
ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_BMFF_PARSE_FAILED);
}
TEST(AvifDecodeTest, UnknownTopLevelBoxSize0) {
testutil::AvifRwData avif =
testutil::ReadFile(std::string(data_path) + "white_1x1.avif");
// Edit the file to insert an unknown top level box with size 0 after ftyp
// (invalid).
testutil::AvifRwData avif_edited;
ASSERT_EQ(avifRWDataRealloc(&avif_edited, avif.size + 8), AVIF_RESULT_OK);
// Copy the ftyp box.
std::memcpy(avif_edited.data, avif.data, 32);
// Set 8 bytes to 0 (box type and size all 0s).
std::memset(avif_edited.data + 32, 0, 8);
// Copy the other boxes.
std::memcpy(avif_edited.data + 40, avif.data + 32, avif.size - 32);
DecoderPtr decoder(avifDecoderCreate());
ASSERT_NE(decoder, nullptr);
ASSERT_EQ(
avifDecoderSetIOMemory(decoder.get(), avif_edited.data, avif_edited.size),
AVIF_RESULT_OK);
ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_BMFF_PARSE_FAILED);
}
//------------------------------------------------------------------------------
} // namespace
} // namespace avif
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
if (argc != 2) {
std::cerr << "There must be exactly one argument containing the path to "
"the test data folder"
<< std::endl;
return 1;
}
avif::data_path = argv[1];
return RUN_ALL_TESTS();
}