| // Copyright 2023 Google LLC | |
| // SPDX-License-Identifier: BSD-2-Clause | |
| #include <algorithm> | |
| #include <cstdint> | |
| #include <limits> | |
| #include <numeric> | |
| #include <vector> | |
| #include "avif/internal.h" | |
| #include "aviftest_helpers.h" | |
| #include "gtest/gtest.h" | |
| namespace avif { | |
| namespace { | |
| // Taken from stream.c. | |
| static const int VARINT_DEPTH_0 = 7; | |
| static const int VARINT_DEPTH_1 = 3; | |
| static const int VARINT_DEPTH_2 = 18; | |
| //------------------------------------------------------------------------------ | |
| TEST(StreamTest, Roundtrip) { | |
| // Write some fields. | |
| testutil::AvifRwData rw_data; | |
| avifRWStream rw_stream; | |
| avifRWStreamStart(&rw_stream, &rw_data); | |
| EXPECT_EQ(avifRWStreamOffset(&rw_stream), size_t{0}); | |
| const uint8_t rw_somedata[] = {3, 1, 4}; | |
| EXPECT_EQ(avifRWStreamWrite(&rw_stream, rw_somedata, sizeof(rw_somedata)), | |
| AVIF_RESULT_OK); | |
| const char rw_somechars[] = "somechars"; | |
| EXPECT_EQ( | |
| avifRWStreamWriteChars(&rw_stream, rw_somechars, sizeof(rw_somechars)), | |
| AVIF_RESULT_OK); | |
| const char rw_box_type[] = "type"; | |
| avifBoxMarker rw_box_marker; | |
| EXPECT_EQ(avifRWStreamWriteBox(&rw_stream, rw_box_type, /*contentSize=*/0, | |
| &rw_box_marker), | |
| AVIF_RESULT_OK); | |
| const uint8_t rw_someu8 = 0xAA; | |
| EXPECT_EQ(avifRWStreamWriteU8(&rw_stream, rw_someu8), AVIF_RESULT_OK); | |
| const int rw_full_box_version = 7; | |
| const uint32_t rw_full_box_flags = 0x555; | |
| avifBoxMarker rw_full_box_marker; | |
| EXPECT_EQ(avifRWStreamWriteFullBox(&rw_stream, rw_box_type, /*contentSize=*/0, | |
| rw_full_box_version, rw_full_box_flags, | |
| &rw_full_box_marker), | |
| AVIF_RESULT_OK); | |
| const uint16_t rw_someu16 = 0xAABB; | |
| EXPECT_EQ(avifRWStreamWriteU16(&rw_stream, rw_someu16), AVIF_RESULT_OK); | |
| avifRWStreamFinishBox(&rw_stream, rw_full_box_marker); | |
| avifRWStreamFinishBox(&rw_stream, rw_box_marker); | |
| const uint32_t rw_someu32 = 0xAABBCCDD; | |
| EXPECT_EQ(avifRWStreamWriteU32(&rw_stream, rw_someu32), AVIF_RESULT_OK); | |
| size_t offset = avifRWStreamOffset(&rw_stream); | |
| const uint32_t rw_somevarint_1byte = (1 << VARINT_DEPTH_0) - 1; | |
| EXPECT_EQ(avifRWStreamWriteVarInt(&rw_stream, rw_somevarint_1byte), | |
| AVIF_RESULT_OK); | |
| EXPECT_EQ(avifRWStreamOffset(&rw_stream), offset + 1); | |
| offset = avifRWStreamOffset(&rw_stream); | |
| const uint32_t rw_somevarint_2bytes = (1 << VARINT_DEPTH_0); | |
| EXPECT_EQ(avifRWStreamWriteVarInt(&rw_stream, rw_somevarint_2bytes), | |
| AVIF_RESULT_OK); | |
| EXPECT_EQ(avifRWStreamOffset(&rw_stream), offset + 2); | |
| // Pad till byte alignment. | |
| EXPECT_EQ(avifRWStreamWriteBits(&rw_stream, 0, | |
| 8 - rw_stream.numUsedBitsInPartialByte), | |
| AVIF_RESULT_OK); | |
| const uint64_t rw_someu64 = 0xAABBCCDDEEFF0011; | |
| EXPECT_EQ(avifRWStreamWriteU64(&rw_stream, rw_someu64), AVIF_RESULT_OK); | |
| const size_t rw_somebitcount = 6; | |
| const uint32_t rw_somebits = (1 << rw_somebitcount) - 2; | |
| EXPECT_EQ(avifRWStreamWriteBits(&rw_stream, rw_somebits, rw_somebitcount), | |
| AVIF_RESULT_OK); | |
| const size_t rw_maxbitcount = sizeof(uint32_t) * 8; | |
| const uint32_t rw_maxbits = std::numeric_limits<uint32_t>::max(); | |
| EXPECT_EQ(avifRWStreamWriteBits(&rw_stream, rw_maxbits, rw_maxbitcount), | |
| AVIF_RESULT_OK); | |
| offset = avifRWStreamOffset(&rw_stream); | |
| const uint32_t rw_somevarint_4bytes = 1 << VARINT_DEPTH_2; | |
| EXPECT_EQ(avifRWStreamWriteVarInt(&rw_stream, rw_somevarint_4bytes), | |
| AVIF_RESULT_OK); | |
| EXPECT_EQ(avifRWStreamOffset(&rw_stream), offset + 4); | |
| const uint32_t rw_somebit = 1; | |
| EXPECT_EQ(avifRWStreamWriteBits(&rw_stream, rw_somebit, /*bitCount=*/1), | |
| AVIF_RESULT_OK); | |
| // Pad till byte alignment. | |
| EXPECT_EQ(avifRWStreamWriteBits(&rw_stream, 0, | |
| 8 - rw_stream.numUsedBitsInPartialByte), | |
| AVIF_RESULT_OK); | |
| const size_t num_zeros = 10000; | |
| EXPECT_EQ(avifRWStreamWriteZeros(&rw_stream, /*byteCount=*/num_zeros), | |
| AVIF_RESULT_OK); | |
| avifRWStreamFinishWrite(&rw_stream); | |
| // Read and compare the fields. | |
| avifDiagnostics diag; | |
| avifDiagnosticsClearError(&diag); | |
| avifROData ro_data = {rw_data.data, rw_data.size}; | |
| avifROStream ro_stream; | |
| avifROStreamStart(&ro_stream, &ro_data, &diag, "diagContext"); | |
| EXPECT_EQ(avifROStreamCurrent(&ro_stream), ro_data.data); | |
| EXPECT_EQ(avifROStreamOffset(&ro_stream), size_t{0}); | |
| EXPECT_TRUE(avifROStreamHasBytesLeft(&ro_stream, rw_data.size)); | |
| EXPECT_FALSE(avifROStreamHasBytesLeft(&ro_stream, rw_data.size + 1)); | |
| EXPECT_EQ(avifROStreamRemainingBytes(&ro_stream), rw_data.size); | |
| std::vector<uint8_t> ro_somedata(sizeof(rw_somedata)); | |
| EXPECT_TRUE( | |
| avifROStreamRead(&ro_stream, ro_somedata.data(), ro_somedata.size())); | |
| EXPECT_TRUE(std::equal(rw_somedata, rw_somedata + sizeof(rw_somedata), | |
| ro_somedata.data())); | |
| std::vector<char> ro_somechars(sizeof(rw_somechars)); | |
| EXPECT_TRUE(avifROStreamReadString(&ro_stream, ro_somechars.data(), | |
| ro_somechars.size())); | |
| EXPECT_TRUE(std::equal(rw_somechars, rw_somechars + sizeof(rw_somechars), | |
| ro_somechars.data())); | |
| avifBoxHeader ro_box_header; | |
| EXPECT_TRUE(avifROStreamReadBoxHeader(&ro_stream, &ro_box_header)); | |
| EXPECT_TRUE(std::equal(rw_box_type, rw_box_type + 4, ro_box_header.type)); | |
| uint8_t ro_someu8; | |
| EXPECT_TRUE(avifROStreamRead(&ro_stream, &ro_someu8, /*size=*/1)); | |
| EXPECT_EQ(rw_someu8, ro_someu8); | |
| avifBoxHeader ro_full_box_header; | |
| EXPECT_TRUE(avifROStreamReadBoxHeader(&ro_stream, &ro_full_box_header)); | |
| EXPECT_TRUE( | |
| std::equal(rw_box_type, rw_box_type + 4, ro_full_box_header.type)); | |
| uint8_t ro_full_box_version; | |
| uint32_t ro_full_box_flags; | |
| EXPECT_TRUE(avifROStreamReadVersionAndFlags(&ro_stream, &ro_full_box_version, | |
| &ro_full_box_flags)); | |
| EXPECT_EQ(rw_full_box_version, ro_full_box_version); | |
| EXPECT_EQ(rw_full_box_flags, ro_full_box_flags); | |
| uint16_t ro_someu16; | |
| EXPECT_TRUE(avifROStreamReadU16(&ro_stream, &ro_someu16)); | |
| EXPECT_EQ(rw_someu16, ro_someu16); | |
| uint32_t ro_someu32; | |
| EXPECT_TRUE(avifROStreamReadU32(&ro_stream, &ro_someu32)); | |
| EXPECT_EQ(rw_someu32, ro_someu32); | |
| uint32_t ro_somevarint_1byte; | |
| EXPECT_TRUE(avifROStreamReadVarInt(&ro_stream, &ro_somevarint_1byte)); | |
| EXPECT_EQ(rw_somevarint_1byte, ro_somevarint_1byte); | |
| uint32_t ro_somevarint_2bytes; | |
| EXPECT_TRUE(avifROStreamReadVarInt(&ro_stream, &ro_somevarint_2bytes)); | |
| EXPECT_EQ(rw_somevarint_2bytes, ro_somevarint_2bytes); | |
| // Pad till byte alignment. | |
| EXPECT_TRUE(avifROStreamReadBits8(&ro_stream, &ro_someu8, | |
| 8 - ro_stream.numUsedBitsInPartialByte)); | |
| uint64_t ro_someu64; | |
| EXPECT_TRUE(avifROStreamReadU64(&ro_stream, &ro_someu64)); | |
| EXPECT_EQ(rw_someu64, ro_someu64); | |
| uint32_t ro_somebits; | |
| EXPECT_TRUE(avifROStreamReadBits(&ro_stream, &ro_somebits, rw_somebitcount)); | |
| EXPECT_EQ(rw_somebits, ro_somebits); | |
| uint32_t ro_maxbits; | |
| EXPECT_TRUE(avifROStreamReadBits(&ro_stream, &ro_maxbits, rw_maxbitcount)); | |
| EXPECT_EQ(rw_maxbits, ro_maxbits); | |
| uint32_t ro_somevarint_4bytes; | |
| EXPECT_TRUE(avifROStreamReadVarInt(&ro_stream, &ro_somevarint_4bytes)); | |
| EXPECT_EQ(rw_somevarint_4bytes, ro_somevarint_4bytes); | |
| uint8_t ro_somebit; | |
| EXPECT_TRUE(avifROStreamReadBits8(&ro_stream, &ro_somebit, /*bitCount=*/1)); | |
| EXPECT_EQ(rw_somebit, ro_somebit); | |
| // Pad till byte alignment. | |
| EXPECT_TRUE(avifROStreamReadBits8(&ro_stream, &ro_someu8, | |
| 8 - ro_stream.numUsedBitsInPartialByte)); | |
| EXPECT_TRUE(avifROStreamSkip(&ro_stream, /*byteCount=*/num_zeros)); | |
| EXPECT_FALSE(avifROStreamSkip(&ro_stream, /*byteCount=*/1)); | |
| } | |
| //------------------------------------------------------------------------------ | |
| // Variable length integer implementation | |
| constexpr uint32_t kMaxVarint = | |
| (1 << (VARINT_DEPTH_2 + VARINT_DEPTH_1 + VARINT_DEPTH_0)) + | |
| (1 << (VARINT_DEPTH_1 + VARINT_DEPTH_0)) + (1 << VARINT_DEPTH_0) - 1; | |
| TEST(StreamTest, VarIntEncDecRoundtrip) { | |
| std::vector<uint32_t> values(1 << 12); | |
| std::iota(values.begin(), values.end(), 0u); | |
| for (int depth = 13; depth <= 28; ++depth) { | |
| values.push_back(1 << depth); | |
| } | |
| values.push_back(kMaxVarint - 1); | |
| values.push_back(kMaxVarint); | |
| testutil::AvifRwData rw_data; | |
| avifRWStream rw_stream; | |
| avifRWStreamStart(&rw_stream, &rw_data); | |
| for (uint32_t rw_value : values) { | |
| EXPECT_EQ(avifRWStreamWriteVarInt(&rw_stream, rw_value), AVIF_RESULT_OK); | |
| } | |
| avifRWStreamFinishWrite(&rw_stream); | |
| avifROData ro_data = {rw_data.data, rw_data.size}; | |
| avifROStream ro_stream; | |
| avifROStreamStart(&ro_stream, &ro_data, /*diag=*/nullptr, | |
| /*diagContext=*/nullptr); | |
| uint32_t ro_value; | |
| for (uint32_t rw_value : values) { | |
| EXPECT_TRUE(avifROStreamReadVarInt(&ro_stream, &ro_value)); | |
| ASSERT_EQ(rw_value, ro_value); | |
| } | |
| } | |
| TEST(StreamTest, VarIntLimit) { | |
| testutil::AvifRwData rw_data; | |
| avifRWStream rw_stream; | |
| avifRWStreamStart(&rw_stream, &rw_data); | |
| EXPECT_EQ(avifRWStreamWriteVarInt(&rw_stream, kMaxVarint + 1), | |
| AVIF_RESULT_INVALID_ARGUMENT); | |
| } | |
| //------------------------------------------------------------------------------ | |
| } // namespace | |
| } // namespace avif |