mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-09-17 01:23:15 +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);
|
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);
|
memcpy(&version, bytes + 4, 4);
|
||||||
swap4(&version);
|
swap4(&version);
|
||||||
memcpy(&length, bytes + 8, 4);
|
memcpy(&length, bytes + 8, 4); // Total glb size, including header and all chunks.
|
||||||
swap4(&length);
|
swap4(&length);
|
||||||
memcpy(&chunk0_length, bytes + 12, 4); // JSON data length
|
memcpy(&chunk0_length, bytes + 12, 4); // JSON data length
|
||||||
swap4(&chunk0_length);
|
swap4(&chunk0_length);
|
||||||
@ -6708,69 +6708,87 @@ bool TinyGLTF::LoadBinaryFromMemory(Model *model, std::string *err,
|
|||||||
bin_size_ = 0;
|
bin_size_ = 0;
|
||||||
} else {
|
} else {
|
||||||
// Read Chunk1 info(BIN data)
|
// 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)
|
// issue-440:
|
||||||
if ((header_and_json_size + 12ull) > uint64_t(length)) {
|
// '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) {
|
if (err) {
|
||||||
(*err) =
|
(*err) =
|
||||||
"Insufficient storage space for Chunk1(BIN data). At least Chunk1 "
|
"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)) +
|
std::to_string((header_and_json_size + 8ull) - uint64_t(length)) +
|
||||||
".\n";
|
".\n";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int chunk1_length; // 4 bytes
|
unsigned int chunk1_length{0}; // 4 bytes
|
||||||
unsigned int chunk1_format; // 4 bytes;
|
unsigned int chunk1_format{0}; // 4 bytes;
|
||||||
memcpy(&chunk1_length, bytes + header_and_json_size,
|
memcpy(&chunk1_length, bytes + header_and_json_size,
|
||||||
4); // JSON data length
|
4); // Bin data length
|
||||||
swap4(&chunk1_length);
|
swap4(&chunk1_length);
|
||||||
memcpy(&chunk1_format, bytes + header_and_json_size + 4, 4);
|
memcpy(&chunk1_format, bytes + header_and_json_size + 4, 4);
|
||||||
swap4(&chunk1_format);
|
swap4(&chunk1_format);
|
||||||
|
|
||||||
// std::cout << "chunk1_length = " << chunk1_length << "\n";
|
if (chunk1_format != 0x004e4942) {
|
||||||
|
|
||||||
if (chunk1_length < 4) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
(*err) = "Insufficient Chunk1(BIN) data size.";
|
(*err) = "Invalid chunkType for Chunk1.";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((chunk1_length % 4) != 0) {
|
if (chunk1_length == 0) {
|
||||||
if (strictness_==ParseStrictness::Permissive) {
|
|
||||||
if (warn) {
|
if (header_and_json_size + 8 > uint64_t(length)) {
|
||||||
(*warn) += "BIN Chunk end is not aligned to a 4-byte boundary.\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (err) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (uint64_t(chunk1_length) + header_and_json_size > uint64_t(length)) {
|
bin_data_ = nullptr;
|
||||||
if (err) {
|
|
||||||
(*err) = "BIN Chunk data length exceeds the GLB size.";
|
} 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 ((chunk1_length % 4) != 0) {
|
||||||
if (err) {
|
if (strictness_==ParseStrictness::Permissive) {
|
||||||
(*err) = "Invalid type for chunk1 data.";
|
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);
|
bin_size_ = size_t(chunk1_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user