JP2 - stronger checks on Signatuer and FileType boxes
This commit is contained in:
parent
2b9f6ccf6b
commit
1545a1bc4a
@ -17,6 +17,7 @@ add_library( exiv2lib_int OBJECT
|
||||
fujimn_int.cpp fujimn_int.hpp
|
||||
helper_functions.cpp helper_functions.hpp
|
||||
image_int.cpp image_int.hpp
|
||||
jp2image_int.cpp jp2image_int.hpp
|
||||
makernote_int.cpp makernote_int.hpp
|
||||
minoltamn_int.cpp minoltamn_int.hpp
|
||||
nikonmn_int.cpp nikonmn_int.hpp
|
||||
|
||||
125
src/jp2image.cpp
125
src/jp2image.cpp
@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// included header files
|
||||
#include "jp2image.hpp"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "basicio.hpp"
|
||||
@ -9,7 +11,7 @@
|
||||
#include "futils.hpp"
|
||||
#include "image.hpp"
|
||||
#include "image_int.hpp"
|
||||
#include "jp2image.hpp"
|
||||
#include "jp2image_int.hpp"
|
||||
#include "safe_op.hpp"
|
||||
#include "tiffimage.hpp"
|
||||
#include "types.hpp"
|
||||
@ -28,8 +30,6 @@ constexpr uint32_t kJp2BoxTypeColorSpec = 0x636f6c72; // Color Specification
|
||||
constexpr uint32_t kJp2BoxTypeUuid = 0x75756964; // 'uuid'
|
||||
constexpr uint32_t kJp2BoxTypeClose = 0x6a703263; // 'jp2c'
|
||||
|
||||
const uint32_t brandJp2 = 0x6a703220;
|
||||
|
||||
// JPEG-2000 UUIDs for embedded metadata
|
||||
//
|
||||
// See http://www.jpeg.org/public/wg1n2600.doc for information about embedding IPTC-NAA data in JPEG-2000 files
|
||||
@ -40,11 +40,11 @@ constexpr unsigned char kJp2UuidIptc[] = "\x33\xc7\xa4\xd2\xb8\x1d\x47\x23\xa0\x
|
||||
constexpr unsigned char kJp2UuidXmp[] = "\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac";
|
||||
|
||||
// See section B.1.1 (JPEG 2000 Signature box) of JPEG-2000 specification
|
||||
constexpr unsigned char Jp2Signature[] = {
|
||||
constexpr std::array<byte, 12> Jp2Signature{
|
||||
0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a,
|
||||
};
|
||||
|
||||
constexpr unsigned char Jp2Blank[] = {
|
||||
constexpr std::array<byte, 249> Jp2Blank{
|
||||
0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a, 0x00, 0x00, 0x00, 0x14, 0x66, 0x74,
|
||||
0x79, 0x70, 0x6a, 0x70, 0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x70, 0x32, 0x20, 0x00, 0x00, 0x00, 0x2d,
|
||||
0x6a, 0x70, 0x32, 0x68, 0x00, 0x00, 0x00, 0x16, 0x69, 0x68, 0x64, 0x72, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
||||
@ -61,26 +61,7 @@ constexpr unsigned char Jp2Blank[] = {
|
||||
0x00, 0x00, 0xff, 0x93, 0xcf, 0xb4, 0x04, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0xff, 0xd9,
|
||||
};
|
||||
|
||||
struct Jp2BoxHeader {
|
||||
uint32_t length;
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
struct Jp2ImageHeaderBox {
|
||||
uint32_t imageHeight;
|
||||
uint32_t imageWidth;
|
||||
uint16_t componentCount;
|
||||
uint8_t bpc; //<! Bits per component
|
||||
uint8_t c; //<! Compression type
|
||||
uint8_t unkC; //<! Colourspace unknown
|
||||
uint8_t ipr; //<! Intellectual property
|
||||
};
|
||||
|
||||
struct Jp2UuidBox {
|
||||
uint8_t uuid[16];
|
||||
};
|
||||
|
||||
const size_t boxHSize = sizeof(Jp2BoxHeader);
|
||||
const size_t boxHSize = sizeof(Internal::Jp2BoxHeader);
|
||||
|
||||
void lf(std::ostream& out, bool& bLF) {
|
||||
if (bLF) {
|
||||
@ -128,7 +109,7 @@ Jp2Image::Jp2Image(BasicIo::UniquePtr io, bool create) : Image(ImageType::jp2, m
|
||||
std::cerr << "Exiv2::Jp2Image:: Creating JPEG2000 image to memory" << std::endl;
|
||||
#endif
|
||||
IoCloser closer(*io_);
|
||||
if (io_->write(Jp2Blank, sizeof(Jp2Blank)) != sizeof(Jp2Blank)) {
|
||||
if (io_->write(Jp2Blank.data(), Jp2Blank.size()) != Jp2Blank.size()) {
|
||||
#ifdef EXIV2_DEBUG_MESSAGES
|
||||
std::cerr << "Exiv2::Jp2Image:: Failed to create JPEG2000 image on memory" << std::endl;
|
||||
#endif
|
||||
@ -153,16 +134,19 @@ void Jp2Image::readMetadata() {
|
||||
throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError());
|
||||
}
|
||||
IoCloser closer(*io_);
|
||||
if (!isJp2Type(*io_, true)) {
|
||||
if (!isJp2Type(*io_, false)) {
|
||||
throw Error(ErrorCode::kerNotAnImage, "JPEG-2000");
|
||||
}
|
||||
|
||||
Jp2BoxHeader box = {0, 0};
|
||||
Jp2BoxHeader subBox = {0, 0};
|
||||
Jp2ImageHeaderBox ihdr = {0, 0, 0, 0, 0, 0, 0};
|
||||
Jp2UuidBox uuid = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
Internal::Jp2BoxHeader box = {0, 0};
|
||||
Internal::Jp2BoxHeader subBox = {0, 0};
|
||||
Internal::Jp2ImageHeaderBox ihdr = {0, 0, 0, 0, 0, 0, 0};
|
||||
Internal::Jp2UuidBox uuid = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
size_t boxesCount = 0;
|
||||
size_t boxem = 1000; // boxes max
|
||||
const size_t boxem = 1000; // boxes max
|
||||
uint32_t lastBoxTypeRead = 0;
|
||||
bool boxSignatureFound = false;
|
||||
bool boxFileTypeFound = false;
|
||||
|
||||
while (io_->read(reinterpret_cast<byte*>(&box), boxHSize) == boxHSize) {
|
||||
boxes_check(boxesCount++, boxem);
|
||||
@ -180,30 +164,25 @@ void Jp2Image::readMetadata() {
|
||||
return;
|
||||
|
||||
if (box.length == 1) {
|
||||
/// \todo In this case, the real box size is given in bytes XLBox (bytes 8-15)
|
||||
/// \todo In this case, the real box size is given in XLBox (bytes 8-15)
|
||||
}
|
||||
|
||||
switch (box.type) {
|
||||
case kJp2BoxTypeSignature: {
|
||||
#ifdef EXIV2_DEBUG_MESSAGES
|
||||
std::cout << "Exiv2::Jp2Image::readMetadata: JPEG 2000 Signature box found" << std::endl;
|
||||
#endif
|
||||
if (boxSignatureFound) // Only one is allowed
|
||||
throw Error(ErrorCode::kerCorruptedMetadata);
|
||||
boxSignatureFound = true;
|
||||
break;
|
||||
}
|
||||
case kJp2BoxTypeFileTypeBox: {
|
||||
// This box shall immediately follow the JPEG 2000 Signature box
|
||||
/// \todo All files shall contain one and only one File Type box.
|
||||
assert(box.length >= 20); // 8 (box) + 4 (BR) + 4(MinV) + >=4 (CLn)
|
||||
DataBuf data(box.length - boxHSize);
|
||||
io_->read(data.data(), data.size());
|
||||
const uint32_t brand = data.read_uint32(0, bigEndian);
|
||||
const uint32_t minorVersion = data.read_uint32(4, bigEndian);
|
||||
const uint32_t compatibilityList = data.read_uint32(8, bigEndian);
|
||||
// const size_t clCount = (data.size() - 8) / 4;
|
||||
// for(size_t i = 0; i < clCount; i++) {
|
||||
// uint32_t compatibilityList = data.read_uint32(8 + i*4, bigEndian);
|
||||
// }
|
||||
if (brand != brandJp2 || minorVersion != 0 || compatibilityList != brandJp2)
|
||||
if (boxFileTypeFound || lastBoxTypeRead != kJp2BoxTypeSignature) { // Only one is allowed
|
||||
throw Error(ErrorCode::kerCorruptedMetadata);
|
||||
}
|
||||
boxFileTypeFound = true;
|
||||
std::vector<byte> boxData(box.length - boxHSize);
|
||||
io_->readOrThrow(boxData.data(), boxData.size(), ErrorCode::kerCorruptedMetadata);
|
||||
if (!Internal::isValidBoxFileType(boxData))
|
||||
throw Error(ErrorCode::kerCorruptedMetadata);
|
||||
break;
|
||||
}
|
||||
@ -397,6 +376,7 @@ void Jp2Image::readMetadata() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastBoxTypeRead = box.type;
|
||||
|
||||
// Move to the next box.
|
||||
io_->seek(static_cast<long>(position - boxHSize + box.length), BasicIo::beg);
|
||||
@ -422,6 +402,7 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, in
|
||||
bool bICC = option == kpsIccProfile;
|
||||
bool bXMP = option == kpsXMP;
|
||||
bool bIPTCErase = option == kpsIptcErase;
|
||||
bool boxSignatureFound = false;
|
||||
|
||||
if (bPrint) {
|
||||
out << "STRUCTURE OF JPEG2000 FILE: " << io_->path() << std::endl;
|
||||
@ -429,9 +410,9 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, in
|
||||
}
|
||||
|
||||
if (bPrint || bXMP || bICC || bIPTCErase) {
|
||||
Jp2BoxHeader box = {1, 1};
|
||||
Jp2BoxHeader subBox = {1, 1};
|
||||
Jp2UuidBox uuid = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
Internal::Jp2BoxHeader box = {1, 1};
|
||||
Internal::Jp2BoxHeader subBox = {1, 1};
|
||||
Internal::Jp2UuidBox uuid = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
bool bLF = false;
|
||||
|
||||
while (box.length && box.type != kJp2BoxTypeClose &&
|
||||
@ -453,24 +434,17 @@ void Jp2Image::printStructure(std::ostream& out, PrintStructureOption option, in
|
||||
|
||||
switch (box.type) {
|
||||
case kJp2BoxTypeSignature: {
|
||||
/// \todo we should make sure that only 1 of this boxes is found
|
||||
assert(box.length == 12);
|
||||
DataBuf data(4);
|
||||
io_->read(data.data(), data.size());
|
||||
if (data.read_uint32(0, bigEndian) != 0x0D0A870A) {
|
||||
if (boxSignatureFound) // Only one is allowed
|
||||
throw Error(ErrorCode::kerCorruptedMetadata);
|
||||
}
|
||||
boxSignatureFound = true;
|
||||
break;
|
||||
}
|
||||
case kJp2BoxTypeFileTypeBox: {
|
||||
// This box shall immediately follow the JPEG 2000 Signature box
|
||||
/// \todo All files shall contain one and only one File Type box.
|
||||
DataBuf data(12);
|
||||
io_->read(data.data(), data.size());
|
||||
uint32_t brand = data.read_uint32(0, bigEndian);
|
||||
uint32_t minorVersion = data.read_uint32(4, bigEndian);
|
||||
uint32_t compatibilityList = data.read_uint32(8, bigEndian);
|
||||
if (brand != brandJp2 || minorVersion != 0 || compatibilityList != brandJp2)
|
||||
std::vector<byte> boxData(box.length - boxHSize);
|
||||
io_->readOrThrow(boxData.data(), boxData.size(), ErrorCode::kerCorruptedMetadata);
|
||||
if (!Internal::isValidBoxFileType(boxData))
|
||||
throw Error(ErrorCode::kerCorruptedMetadata);
|
||||
break;
|
||||
}
|
||||
@ -629,7 +603,7 @@ void Jp2Image::encodeJp2Header(const DataBuf& boxBuf, DataBuf& outBuf) {
|
||||
size_t outlen = boxHSize; // now many bytes have we written to output?
|
||||
long inlen = boxHSize; // how many bytes have we read from boxBuf?
|
||||
enforce(boxHSize <= output.size(), ErrorCode::kerCorruptedMetadata);
|
||||
auto pBox = reinterpret_cast<const Jp2BoxHeader*>(boxBuf.c_data());
|
||||
auto pBox = reinterpret_cast<const Internal::Jp2BoxHeader*>(boxBuf.c_data());
|
||||
uint32_t length = getLong(reinterpret_cast<const byte*>(&pBox->length), bigEndian);
|
||||
enforce(length <= output.size(), ErrorCode::kerCorruptedMetadata);
|
||||
uint32_t count = boxHSize;
|
||||
@ -638,12 +612,12 @@ void Jp2Image::encodeJp2Header(const DataBuf& boxBuf, DataBuf& outBuf) {
|
||||
|
||||
while (count < length && !bWroteColor) {
|
||||
enforce(boxHSize <= length - count, ErrorCode::kerCorruptedMetadata);
|
||||
auto pSubBox = reinterpret_cast<const Jp2BoxHeader*>(p + count);
|
||||
auto pSubBox = reinterpret_cast<const Internal::Jp2BoxHeader*>(p + count);
|
||||
|
||||
// copy data. pointer could be into a memory mapped file which we will decode!
|
||||
Jp2BoxHeader subBox;
|
||||
Internal::Jp2BoxHeader subBox;
|
||||
memcpy(&subBox, pSubBox, boxHSize);
|
||||
Jp2BoxHeader newBox = subBox;
|
||||
Internal::Jp2BoxHeader newBox = subBox;
|
||||
|
||||
if (count < length) {
|
||||
subBox.length = getLong(reinterpret_cast<byte*>(&subBox.length), bigEndian);
|
||||
@ -696,7 +670,7 @@ void Jp2Image::encodeJp2Header(const DataBuf& boxBuf, DataBuf& outBuf) {
|
||||
// allocate the correct number of bytes, copy the data and update the box header
|
||||
outBuf.alloc(outlen);
|
||||
outBuf.copyBytes(0, output.c_data(), outlen);
|
||||
auto oBox = reinterpret_cast<Jp2BoxHeader*>(outBuf.data());
|
||||
auto oBox = reinterpret_cast<Internal::Jp2BoxHeader*>(outBuf.data());
|
||||
ul2Data(reinterpret_cast<byte*>(&oBox->type), kJp2BoxTypeHeader, bigEndian);
|
||||
ul2Data(reinterpret_cast<byte*>(&oBox->length), static_cast<uint32_t>(outlen), bigEndian);
|
||||
}
|
||||
@ -722,14 +696,14 @@ void Jp2Image::doWriteMetadata(BasicIo& outIo) {
|
||||
}
|
||||
|
||||
// Write JPEG2000 Signature (This is the 1st box)
|
||||
if (outIo.write(Jp2Signature, 12) != 12)
|
||||
if (outIo.write(Jp2Signature.data(), Jp2Signature.size()) != 12)
|
||||
throw Error(ErrorCode::kerImageWriteFailed);
|
||||
|
||||
#ifdef EXIV2_DEBUG_MESSAGES
|
||||
std::cout << "Jp2Image::doWriteMetadata: JPEG 2000 Signature box written" << std::endl;
|
||||
#endif
|
||||
|
||||
Jp2BoxHeader box = {0, 0};
|
||||
Internal::Jp2BoxHeader box = {0, 0};
|
||||
|
||||
byte boxDataSize[4];
|
||||
byte boxUUIDtype[4];
|
||||
@ -917,15 +891,14 @@ Image::UniquePtr newJp2Instance(BasicIo::UniquePtr io, bool create) {
|
||||
}
|
||||
|
||||
bool isJp2Type(BasicIo& iIo, bool advance) {
|
||||
const int32_t len = 12;
|
||||
byte buf[len];
|
||||
const size_t bytesRead = iIo.read(buf, len);
|
||||
if (iIo.error() || iIo.eof() || bytesRead != len) {
|
||||
byte buf[Jp2Signature.size()];
|
||||
const size_t bytesRead = iIo.read(buf, Jp2Signature.size());
|
||||
if (iIo.error() || iIo.eof() || bytesRead != Jp2Signature.size()) {
|
||||
return false;
|
||||
}
|
||||
bool matched = (memcmp(buf, Jp2Signature, len) == 0);
|
||||
bool matched = (memcmp(buf, Jp2Signature.data(), Jp2Signature.size()) == 0);
|
||||
if (!advance || !matched) {
|
||||
iIo.seek(-len, BasicIo::cur); // Return to original position
|
||||
iIo.seek(-Jp2Signature.size(), BasicIo::cur); // Return to original position
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
32
src/jp2image_int.cpp
Normal file
32
src/jp2image_int.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "jp2image_int.hpp"
|
||||
|
||||
#include "error.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace Exiv2::Internal {
|
||||
|
||||
bool isValidBoxFileType(const std::vector<uint8_t> &boxData) {
|
||||
// BR & MinV are obligatory (4 + 4 bytes). Afterwards we have N compatibility lists (of size 4)
|
||||
if ((boxData.size() - 8u) % 4u != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t N = (boxData.size() - 8u) / 4u;
|
||||
const uint32_t brand = getULong(boxData.data(), bigEndian);
|
||||
const uint32_t minorVersion = getULong(boxData.data() + 4, bigEndian);
|
||||
|
||||
bool clWithRightBrand = false;
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
uint32_t compatibilityList = getULong(boxData.data() + 8 + i * 4, bigEndian);
|
||||
if (compatibilityList == brandJp2) {
|
||||
clWithRightBrand = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (brand == brandJp2 && minorVersion == 0 && clWithRightBrand);
|
||||
}
|
||||
} // namespace Exiv2::Internal
|
||||
36
src/jp2image_int.hpp
Normal file
36
src/jp2image_int.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#ifndef JP2IMAGE_INT_HPP
|
||||
#define JP2IMAGE_INT_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace Exiv2::Internal {
|
||||
|
||||
struct Jp2BoxHeader {
|
||||
uint32_t length;
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
struct Jp2ImageHeaderBox {
|
||||
uint32_t imageHeight;
|
||||
uint32_t imageWidth;
|
||||
uint16_t componentCount;
|
||||
uint8_t bpc; //<! Bits per component
|
||||
uint8_t c; //<! Compression type
|
||||
uint8_t unkC; //<! Colourspace unknown
|
||||
uint8_t ipr; //<! Intellectual property
|
||||
};
|
||||
|
||||
struct Jp2UuidBox {
|
||||
uint8_t uuid[16];
|
||||
};
|
||||
|
||||
constexpr uint32_t brandJp2{0x6a703220};
|
||||
|
||||
/// @brief Determines if the File Type box is valid
|
||||
bool isValidBoxFileType(const std::vector<std::uint8_t>& boxData);
|
||||
} // namespace Exiv2::Internal
|
||||
|
||||
#endif // JP2IMAGE_INT_HPP
|
||||
@ -15,6 +15,7 @@ add_executable(unit_tests
|
||||
test_image_int.cpp
|
||||
test_ImageFactory.cpp
|
||||
test_jp2image.cpp
|
||||
test_jp2image_int.cpp
|
||||
test_IptcKey.cpp
|
||||
test_LangAltValueRead.cpp
|
||||
test_pngimage.cpp
|
||||
|
||||
78
unitTests/test_jp2image_int.cpp
Normal file
78
unitTests/test_jp2image_int.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "jp2image_int.hpp" // Internals of JPEG-2000 standard
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace Exiv2::Internal;
|
||||
|
||||
namespace {
|
||||
void setValidValues(std::vector<std::uint8_t>& boxData) {
|
||||
// The first 4 bytes correspond to the BR (Brand). It must have the value 'jp2\040'
|
||||
boxData[0] = 'j';
|
||||
boxData[1] = 'p';
|
||||
boxData[2] = '2';
|
||||
boxData[3] = '\040';
|
||||
|
||||
// The next 4 bytes correspond to the MinV (Minor version). It is a 4-byte unsigned int with value 0
|
||||
|
||||
// The only available Compatibility list also has the value 'jp2\040'
|
||||
boxData[8] = 'j';
|
||||
boxData[9] = 'p';
|
||||
boxData[10] = '2';
|
||||
boxData[11] = '\040';
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(Jp2_FileTypeBox, isNotValidWithoutProperValuesSet) {
|
||||
const std::vector<std::uint8_t> boxData(12);
|
||||
ASSERT_FALSE(isValidBoxFileType(boxData));
|
||||
}
|
||||
|
||||
TEST(Jp2_FileTypeBox, isValidWithMinimumPossibleSizeAndValidValues) {
|
||||
std::vector<std::uint8_t> boxData(12);
|
||||
setValidValues(boxData);
|
||||
ASSERT_TRUE(isValidBoxFileType(boxData));
|
||||
}
|
||||
|
||||
TEST(Jp2_FileTypeBox, isNotValidWithMinimumPossibleSizeButInvalidBrand) {
|
||||
std::vector<std::uint8_t> boxData(12);
|
||||
setValidValues(boxData);
|
||||
boxData[2] = '3'; // Change byte in the brand field
|
||||
|
||||
ASSERT_FALSE(isValidBoxFileType(boxData));
|
||||
}
|
||||
|
||||
TEST(Jp2_FileTypeBox, isNotValidWithMinimumPossibleSizeButInvalidCL1) {
|
||||
std::vector<std::uint8_t> boxData(12);
|
||||
setValidValues(boxData);
|
||||
boxData[10] = '3'; // Change byte in the CL1
|
||||
|
||||
ASSERT_FALSE(isValidBoxFileType(boxData));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
|
||||
TEST(Jp2_FileTypeBox, withInvalidBoxDataSizeIsInvalid) {
|
||||
std::vector<std::uint8_t> boxData(13); // 12 + 1 (the extra byte causes problems)
|
||||
ASSERT_FALSE(isValidBoxFileType(boxData));
|
||||
}
|
||||
|
||||
TEST(Jp2_FileTypeBox, with2CLs_lastOneWithBrandValue_isValid) {
|
||||
std::vector<std::uint8_t> boxData(16);
|
||||
// The first 4 bytes correspond to the BR (Brand). It must have the value 'jp2\040'
|
||||
boxData[0] = 'j';
|
||||
boxData[1] = 'p';
|
||||
boxData[2] = '2';
|
||||
boxData[3] = '\040';
|
||||
|
||||
// The next 4 bytes correspond to the MinV (Minor version). It is a 4-byte unsigned int with value 0
|
||||
|
||||
// The 2nd Compatibility list has the value 'jp2\040'
|
||||
boxData[12] = 'j';
|
||||
boxData[13] = 'p';
|
||||
boxData[14] = '2';
|
||||
boxData[15] = '\040';
|
||||
|
||||
ASSERT_TRUE(isValidBoxFileType(boxData));
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user