mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-04-19 12:39:55 +08:00
Allow zero-sized BIN chunk. Fixes #440
This commit is contained in:
parent
c5641f2c22
commit
4fea26f6c8
BIN
models/regression/zero-sized-bin-chunk-issue-440.glb
Normal file
BIN
models/regression/zero-sized-bin-chunk-issue-440.glb
Normal file
Binary file not shown.
@ -902,3 +902,27 @@ TEST_CASE("serialize-empty-scene", "[issue-464]") {
|
||||
CHECK(m.scenes[0] == scene);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("zero-sized-bin-chunk-glb", "[issue-440]") {
|
||||
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
// Input glb has zero-sized data in bin chunk(8 bytes for BIN chunk, and chunksize == 0)
|
||||
// The spec https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#binary-buffer says
|
||||
//
|
||||
// When the binary buffer is empty or when it is stored by other means, this chunk SHOULD be omitted.
|
||||
//
|
||||
// 'SHOULD' mean 'RECOMMENDED', so we'll need to allow such zero-sized bin chunk is NOT omitted.
|
||||
bool ret = ctx.LoadBinaryFromFile(&model, &err, &warn, "../models/regression/zero-sized-bin-chunk-issue-440.glb");
|
||||
if (!warn.empty()) {
|
||||
std::cout << "WARN: " << warn << "\n";
|
||||
}
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
|
||||
REQUIRE(true == ret);
|
||||
}
|
||||
|
88
tiny_gltf.h
88
tiny_gltf.h
@ -6652,7 +6652,7 @@ bool TinyGLTF::LoadBinaryFromMemory(Model *model, std::string *err,
|
||||
|
||||
memcpy(&version, bytes + 4, 4);
|
||||
swap4(&version);
|
||||
memcpy(&length, bytes + 8, 4);
|
||||
memcpy(&length, bytes + 8, 4); // Total glb size, including header and all chunks.
|
||||
swap4(&length);
|
||||
memcpy(&chunk0_length, bytes + 12, 4); // JSON data length
|
||||
swap4(&chunk0_length);
|
||||
@ -6708,69 +6708,87 @@ bool TinyGLTF::LoadBinaryFromMemory(Model *model, std::string *err,
|
||||
bin_size_ = 0;
|
||||
} else {
|
||||
// Read Chunk1 info(BIN data)
|
||||
// At least Chunk1 should have 12 bytes(8 bytes(header) + 4 bytes(bin
|
||||
// payload could be 1~3 bytes, but need to be aligned to 4 bytes)
|
||||
if ((header_and_json_size + 12ull) > uint64_t(length)) {
|
||||
//
|
||||
// issue-440:
|
||||
// 'SHOULD' in glTF spec means 'RECOMMENDED',
|
||||
// So there is a situation that Chunk1(BIN) is composed of zero-sized BIN data
|
||||
// (chunksize(0) + binformat(BIN) = 8bytes).
|
||||
//
|
||||
if ((header_and_json_size + 8ull) > uint64_t(length)) {
|
||||
if (err) {
|
||||
(*err) =
|
||||
"Insufficient storage space for Chunk1(BIN data). At least Chunk1 "
|
||||
"Must have 4 or more bytes, but got " +
|
||||
"Must have 8 or more bytes, but got " +
|
||||
std::to_string((header_and_json_size + 8ull) - uint64_t(length)) +
|
||||
".\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int chunk1_length; // 4 bytes
|
||||
unsigned int chunk1_format; // 4 bytes;
|
||||
unsigned int chunk1_length{0}; // 4 bytes
|
||||
unsigned int chunk1_format{0}; // 4 bytes;
|
||||
memcpy(&chunk1_length, bytes + header_and_json_size,
|
||||
4); // JSON data length
|
||||
4); // Bin data length
|
||||
swap4(&chunk1_length);
|
||||
memcpy(&chunk1_format, bytes + header_and_json_size + 4, 4);
|
||||
swap4(&chunk1_format);
|
||||
|
||||
// std::cout << "chunk1_length = " << chunk1_length << "\n";
|
||||
|
||||
if (chunk1_length < 4) {
|
||||
if (chunk1_format != 0x004e4942) {
|
||||
if (err) {
|
||||
(*err) = "Insufficient Chunk1(BIN) data size.";
|
||||
(*err) = "Invalid chunkType for Chunk1.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((chunk1_length % 4) != 0) {
|
||||
if (strictness_==ParseStrictness::Permissive) {
|
||||
if (warn) {
|
||||
(*warn) += "BIN Chunk end is not aligned to a 4-byte boundary.\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (chunk1_length == 0) {
|
||||
|
||||
if (header_and_json_size + 8 > uint64_t(length)) {
|
||||
if (err) {
|
||||
(*err) = "BIN Chunk end is not aligned to a 4-byte boundary.";
|
||||
(*err) = "BIN Chunk header location exceeds the GLB size.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (uint64_t(chunk1_length) + header_and_json_size > uint64_t(length)) {
|
||||
if (err) {
|
||||
(*err) = "BIN Chunk data length exceeds the GLB size.";
|
||||
bin_data_ = nullptr;
|
||||
|
||||
} else {
|
||||
|
||||
// When BIN chunk size is not zero, at least Chunk1 should have 12 bytes(8 bytes(header) + 4 bytes(bin
|
||||
// payload could be 1~3 bytes, but need to be aligned to 4 bytes)
|
||||
|
||||
if (chunk1_length < 4) {
|
||||
if (err) {
|
||||
(*err) = "Insufficient Chunk1(BIN) data size.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chunk1_format != 0x004e4942) {
|
||||
if (err) {
|
||||
(*err) = "Invalid type for chunk1 data.";
|
||||
if ((chunk1_length % 4) != 0) {
|
||||
if (strictness_==ParseStrictness::Permissive) {
|
||||
if (warn) {
|
||||
(*warn) += "BIN Chunk end is not aligned to a 4-byte boundary.\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (err) {
|
||||
(*err) = "BIN Chunk end is not aligned to a 4-byte boundary.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
// +8 chunk1 header size.
|
||||
if (uint64_t(chunk1_length) + header_and_json_size + 8 > uint64_t(length)) {
|
||||
if (err) {
|
||||
(*err) = "BIN Chunk data length exceeds the GLB size.";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bin_data_ = bytes + header_and_json_size +
|
||||
8; // 4 bytes (bin_buffer_length) + 4 bytes(bin_buffer_format)
|
||||
}
|
||||
|
||||
// std::cout << "chunk1_length = " << chunk1_length << "\n";
|
||||
|
||||
bin_data_ = bytes + header_and_json_size +
|
||||
8; // 4 bytes (bin_buffer_length) + 4 bytes(bin_buffer_format)
|
||||
|
||||
bin_size_ = size_t(chunk1_length);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user