Merge "Handle 64b box sizes" into main
diff --git a/avifinfo.c b/avifinfo.c
index 62ace0c..a66a825 100644
--- a/avifinfo.c
+++ b/avifinfo.c
@@ -100,18 +100,32 @@
const uint8_t* bytes, uint32_t num_bytes, uint32_t max_num_bytes,
uint32_t position, uint32_t* num_parsed_boxes, AvifInfoInternalBox* box) {
// See ISO/IEC 14496-12:2012(E) 4.2
- AVIFINFO_CHECK(position <= kAvifInfoInternalMaxSize - 8, kAborted);
- AVIFINFO_CHECK(position + 8 <= max_num_bytes, kInvalid); // box size+type
- AVIFINFO_CHECK(position + 4 <= num_bytes, kTruncated); // 32b size
+ uint32_t box_header_size = 8; // box 32b size + 32b type (at least)
+ AVIFINFO_CHECK(position <= kAvifInfoInternalMaxSize - box_header_size,
+ kAborted);
+ AVIFINFO_CHECK(position + box_header_size <= max_num_bytes, kInvalid);
+ AVIFINFO_CHECK(position + box_header_size <= num_bytes, kTruncated);
box->size = AvifInfoInternalReadBigEndian(bytes + position, sizeof(uint32_t));
- // Note: 'box->size==1' means 64b size should be read.
- // 'box->size==0' means this box extends to all remaining bytes.
- // These two use cases are not handled here for simplicity.
- AVIFINFO_CHECK(box->size >= 2, kAborted);
- AVIFINFO_CHECK(box->size >= 8, kInvalid); // box 32b size + 32b type
+ // 'box->size==1' means 64-bit size should be read after the box type.
+ // 'box->size==0' means this box extends to all remaining bytes.
+ if (box->size == 1) {
+ box_header_size += 8;
+ AVIFINFO_CHECK(position + box_header_size <= max_num_bytes, kInvalid);
+ AVIFINFO_CHECK(position + box_header_size <= num_bytes, kTruncated);
+ // Stop the parsing if any box has a size greater than 4GB.
+ AVIFINFO_CHECK(AvifInfoInternalReadBigEndian(bytes + position + 8,
+ sizeof(uint32_t)) == 0,
+ kAborted);
+ // Read the 32 least-significant bits.
+ box->size =
+ AvifInfoInternalReadBigEndian(bytes + position + 12, sizeof(uint32_t));
+ } else if (box->size == 0) {
+ box->size = max_num_bytes - position;
+ }
+ AVIFINFO_CHECK(box->size >= box_header_size, kInvalid);
AVIFINFO_CHECK(box->size <= kAvifInfoInternalMaxSize - position, kAborted);
AVIFINFO_CHECK(position + box->size <= max_num_bytes, kInvalid);
- AVIFINFO_CHECK(position + 8 <= num_bytes, kTruncated);
+ AVIFINFO_CHECK(position + box_header_size <= num_bytes, kTruncated);
box->type = bytes + position + 4;
const int has_fullbox_header =
@@ -119,7 +133,7 @@
!memcmp(box->type, "ipma", 4) || !memcmp(box->type, "ispe", 4) ||
!memcmp(box->type, "pixi", 4) || !memcmp(box->type, "iref", 4) ||
!memcmp(box->type, "auxC", 4);
- const uint32_t box_header_size = (has_fullbox_header ? 12 : 8);
+ if (has_fullbox_header) box_header_size += 4;
AVIFINFO_CHECK(box->size >= box_header_size, kInvalid);
box->content_position = position + box_header_size;
AVIFINFO_CHECK(box->content_position <= num_bytes, kTruncated);
@@ -153,7 +167,7 @@
// Returns kFound if 'min_size' bytes can be read from the 'box.content' now.
// 'num_bytes' is the number of available bytes of the parent of the 'box'.
-static AvifInfoInternalStatus AccessContent(AvifInfoInternalBox* box,
+static AvifInfoInternalStatus AccessContent(const AvifInfoInternalBox* box,
uint32_t num_bytes,
uint32_t min_size) {
AVIFINFO_CHECK(box->content_size >= min_size, kInvalid);
diff --git a/tests/avifinfo_test.cc b/tests/avifinfo_test.cc
index de28ba8..fe59b14 100644
--- a/tests/avifinfo_test.cc
+++ b/tests/avifinfo_test.cc
@@ -44,6 +44,22 @@
EXPECT_EQ(features.num_channels, 3u);
}
+TEST(AvifInfoGetTest, NoPixi10b) {
+ // Same as above but "meta" box size is stored as 64 bits, "av1C" has
+ // 'high_bitdepth' set to true, "pixi" was renamed to "pixy" and "mdat" size
+ // is 0 (extends to the end of the file).
+ const Data input =
+ LoadFile("avifinfo_test_1x1_10b_nopixi_metasize64b_mdatsize0.avif");
+ ASSERT_FALSE(input.empty());
+
+ AvifInfoFeatures features;
+ EXPECT_EQ(AvifInfoGet(input.data(), input.size(), &features), kAvifInfoOk);
+ EXPECT_EQ(features.width, 1u);
+ EXPECT_EQ(features.height, 1u);
+ EXPECT_EQ(features.bit_depth, 10u);
+ EXPECT_EQ(features.num_channels, 3u);
+}
+
TEST(AvifInfoGetTest, WithFileSize) {
const Data input = LoadFile("avifinfo_test_1x1.avif");
ASSERT_FALSE(input.empty());
diff --git a/tests/avifinfo_test_1x1_10b_nopixi_metasize64b_mdatsize0.avif b/tests/avifinfo_test_1x1_10b_nopixi_metasize64b_mdatsize0.avif
new file mode 100644
index 0000000..64d5377
--- /dev/null
+++ b/tests/avifinfo_test_1x1_10b_nopixi_metasize64b_mdatsize0.avif
Binary files differ