mirror of
https://git.mirrors.martin98.com/https://github.com/syoyo/tinygltf.git
synced 2025-08-14 00:45:54 +08:00
Merge pull request #160 from jwmcglynn/parse-integer
Parse integers directly instead of casting doubles
This commit is contained in:
commit
d11a4c4d71
67
models/BoundsChecking/integer-out-of-bounds.gltf
Normal file
67
models/BoundsChecking/integer-out-of-bounds.gltf
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"nodes": [0]
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"mesh": 0
|
||||
}
|
||||
],
|
||||
"meshes": [
|
||||
{
|
||||
"primitives": [
|
||||
{
|
||||
"attributes": {
|
||||
"POSITION": 1
|
||||
},
|
||||
"indices": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"buffers": [
|
||||
{
|
||||
"uri": "simpleTriangle.bin",
|
||||
"byteLength": 44
|
||||
}
|
||||
],
|
||||
"bufferViews": [
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 0,
|
||||
"byteLength": 1e300,
|
||||
"target": 34963
|
||||
},
|
||||
{
|
||||
"buffer": 0,
|
||||
"byteOffset": 8,
|
||||
"byteLength": 36,
|
||||
"target": 34962
|
||||
}
|
||||
],
|
||||
"accessors": [
|
||||
{
|
||||
"bufferView": 0,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5123,
|
||||
"count": 3,
|
||||
"type": "SCALAR",
|
||||
"max": [2],
|
||||
"min": [0]
|
||||
},
|
||||
{
|
||||
"bufferView": 1,
|
||||
"byteOffset": 0,
|
||||
"componentType": 5126,
|
||||
"count": 3,
|
||||
"type": "VEC3",
|
||||
"max": [1, 1, 0],
|
||||
"min": [0, 0, 0]
|
||||
}
|
||||
],
|
||||
"asset": {
|
||||
"version": "2.0"
|
||||
}
|
||||
}
|
133
tests/tester.cc
133
tests/tester.cc
@ -37,7 +37,7 @@ TEST_CASE("datauri-in-glb", "[issue-79]") {
|
||||
if (!err.empty()) {
|
||||
std::cerr << err << std::endl;
|
||||
}
|
||||
|
||||
|
||||
REQUIRE(true == ret);
|
||||
}
|
||||
|
||||
@ -148,3 +148,134 @@ TEST_CASE("glb-invalid-length", "[bounds-checking]") {
|
||||
REQUIRE_THAT(err, Catch::Contains("Invalid glTF binary."));
|
||||
REQUIRE_FALSE(ret);
|
||||
}
|
||||
|
||||
TEST_CASE("integer-out-of-bounds", "[bounds-checking]") {
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF ctx;
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
||||
// Loading is expected to fail, but not crash.
|
||||
bool ret = ctx.LoadASCIIFromFile(
|
||||
&model, &err, &warn,
|
||||
"../models/BoundsChecking/integer-out-of-bounds.gltf");
|
||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||
REQUIRE_FALSE(ret);
|
||||
}
|
||||
|
||||
TEST_CASE("parse-integer", "[bounds-checking]") {
|
||||
SECTION("parses valid numbers") {
|
||||
std::string err;
|
||||
int result = 123;
|
||||
CHECK(tinygltf::ParseIntegerProperty(&result, &err, {{"zero", 0}}, "zero",
|
||||
true));
|
||||
REQUIRE(err == "");
|
||||
REQUIRE(result == 0);
|
||||
|
||||
CHECK(tinygltf::ParseIntegerProperty(&result, &err, {{"int", -1234}}, "int",
|
||||
true));
|
||||
REQUIRE(err == "");
|
||||
REQUIRE(result == -1234);
|
||||
}
|
||||
|
||||
SECTION("detects missing properties") {
|
||||
std::string err;
|
||||
int result = -1;
|
||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {}, "int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("'int' property is missing"));
|
||||
REQUIRE(result == -1);
|
||||
}
|
||||
|
||||
SECTION("handled missing but not required properties") {
|
||||
std::string err;
|
||||
int result = -1;
|
||||
CHECK_FALSE(
|
||||
tinygltf::ParseIntegerProperty(&result, &err, {}, "int", false));
|
||||
REQUIRE(err == "");
|
||||
REQUIRE(result == -1);
|
||||
}
|
||||
|
||||
SECTION("invalid integers") {
|
||||
std::string err;
|
||||
int result = -1;
|
||||
|
||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {{"int", 0.5}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||
|
||||
// Excessively large values and NaN aren't allowed either.
|
||||
err.clear();
|
||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(&result, &err, {{"int", 1e300}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||
|
||||
err.clear();
|
||||
CHECK_FALSE(tinygltf::ParseIntegerProperty(
|
||||
&result, &err, {{"int", std::numeric_limits<double>::quiet_NaN()}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("parse-unsigned", "[bounds-checking]") {
|
||||
SECTION("parses valid unsigned integers") {
|
||||
// Use string-based parsing here, using the initializer list syntax doesn't
|
||||
// parse 0 as unsigned.
|
||||
json zero_obj = json::parse("{\"zero\": 0}");
|
||||
|
||||
std::string err;
|
||||
size_t result = 123;
|
||||
CHECK(
|
||||
tinygltf::ParseUnsignedProperty(&result, &err, zero_obj, "zero", true));
|
||||
REQUIRE(err == "");
|
||||
REQUIRE(result == 0);
|
||||
}
|
||||
|
||||
SECTION("invalid integers") {
|
||||
std::string err;
|
||||
size_t result = -1;
|
||||
|
||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", -1234}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||
|
||||
err.clear();
|
||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", 0.5}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||
|
||||
// Excessively large values and NaN aren't allowed either.
|
||||
err.clear();
|
||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(&result, &err, {{"int", 1e300}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||
|
||||
err.clear();
|
||||
CHECK_FALSE(tinygltf::ParseUnsignedProperty(
|
||||
&result, &err, {{"int", std::numeric_limits<double>::quiet_NaN()}},
|
||||
"int", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not a positive integer"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("parse-integer-array", "[bounds-checking]") {
|
||||
SECTION("parses valid integers") {
|
||||
std::string err;
|
||||
std::vector<int> result;
|
||||
CHECK(tinygltf::ParseIntegerArrayProperty(&result, &err,
|
||||
{{"x", {-1, 2, 3}}}, "x", true));
|
||||
REQUIRE(err == "");
|
||||
REQUIRE(result.size() == 3);
|
||||
REQUIRE(result[0] == -1);
|
||||
REQUIRE(result[1] == 2);
|
||||
REQUIRE(result[2] == 3);
|
||||
}
|
||||
|
||||
SECTION("invalid integers") {
|
||||
std::string err;
|
||||
std::vector<int> result;
|
||||
CHECK_FALSE(tinygltf::ParseIntegerArrayProperty(
|
||||
&result, &err, {{"x", {-1, 1e300, 3}}}, "x", true));
|
||||
REQUIRE_THAT(err, Catch::Contains("not an integer type"));
|
||||
}
|
||||
}
|
||||
|
439
tiny_gltf.h
439
tiny_gltf.h
@ -2271,6 +2271,74 @@ static bool ParseBooleanProperty(bool *ret, std::string *err, const json &o,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseIntegerProperty(int *ret, std::string *err, const json &o,
|
||||
const std::string &property,
|
||||
const bool required,
|
||||
const std::string &parent_node = "") {
|
||||
json::const_iterator it = o.find(property);
|
||||
if (it == o.end()) {
|
||||
if (required) {
|
||||
if (err) {
|
||||
(*err) += "'" + property + "' property is missing";
|
||||
if (!parent_node.empty()) {
|
||||
(*err) += " in " + parent_node;
|
||||
}
|
||||
(*err) += ".\n";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!it.value().is_number_integer()) {
|
||||
if (required) {
|
||||
if (err) {
|
||||
(*err) += "'" + property + "' property is not an integer type.\n";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
(*ret) = it.value().get<int>();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseUnsignedProperty(size_t *ret, std::string *err, const json &o,
|
||||
const std::string &property,
|
||||
const bool required,
|
||||
const std::string &parent_node = "") {
|
||||
json::const_iterator it = o.find(property);
|
||||
if (it == o.end()) {
|
||||
if (required) {
|
||||
if (err) {
|
||||
(*err) += "'" + property + "' property is missing";
|
||||
if (!parent_node.empty()) {
|
||||
(*err) += " in " + parent_node;
|
||||
}
|
||||
(*err) += ".\n";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!it.value().is_number_unsigned()) {
|
||||
if (required) {
|
||||
if (err) {
|
||||
(*err) += "'" + property + "' property is not a positive integer.\n";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
(*ret) = it.value().get<size_t>();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseNumberProperty(double *ret, std::string *err, const json &o,
|
||||
const std::string &property,
|
||||
const bool required,
|
||||
@ -2357,6 +2425,59 @@ static bool ParseNumberArrayProperty(std::vector<double> *ret, std::string *err,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseIntegerArrayProperty(std::vector<int> *ret, std::string *err,
|
||||
const json &o,
|
||||
const std::string &property,
|
||||
bool required,
|
||||
const std::string &parent_node = "") {
|
||||
json::const_iterator it = o.find(property);
|
||||
if (it == o.end()) {
|
||||
if (required) {
|
||||
if (err) {
|
||||
(*err) += "'" + property + "' property is missing";
|
||||
if (!parent_node.empty()) {
|
||||
(*err) += " in " + parent_node;
|
||||
}
|
||||
(*err) += ".\n";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!it.value().is_array()) {
|
||||
if (required) {
|
||||
if (err) {
|
||||
(*err) += "'" + property + "' property is not an array";
|
||||
if (!parent_node.empty()) {
|
||||
(*err) += " in " + parent_node;
|
||||
}
|
||||
(*err) += ".\n";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ret->clear();
|
||||
for (json::const_iterator i = it.value().begin(); i != it.value().end();
|
||||
i++) {
|
||||
if (!i.value().is_number_integer()) {
|
||||
if (required) {
|
||||
if (err) {
|
||||
(*err) += "'" + property + "' property is not an integer type.\n";
|
||||
if (!parent_node.empty()) {
|
||||
(*err) += " in " + parent_node;
|
||||
}
|
||||
(*err) += ".\n";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ret->push_back(i.value());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseStringProperty(
|
||||
std::string *ret, std::string *err, const json &o,
|
||||
const std::string &property, bool required,
|
||||
@ -2392,10 +2513,11 @@ static bool ParseStringProperty(
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ParseStringIntProperty(std::map<std::string, int> *ret,
|
||||
std::string *err, const json &o,
|
||||
const std::string &property, bool required,
|
||||
const std::string &parent = "") {
|
||||
static bool ParseStringIntegerProperty(std::map<std::string, int> *ret,
|
||||
std::string *err, const json &o,
|
||||
const std::string &property,
|
||||
bool required,
|
||||
const std::string &parent = "") {
|
||||
json::const_iterator it = o.find(property);
|
||||
if (it == o.end()) {
|
||||
if (required) {
|
||||
@ -2428,17 +2550,17 @@ static bool ParseStringIntProperty(std::map<std::string, int> *ret,
|
||||
json::const_iterator dictItEnd(dict.end());
|
||||
|
||||
for (; dictIt != dictItEnd; ++dictIt) {
|
||||
if (!dictIt.value().is_number()) {
|
||||
if (!dictIt.value().is_number_integer()) {
|
||||
if (required) {
|
||||
if (err) {
|
||||
(*err) += "'" + property + "' value is not an int.\n";
|
||||
(*err) += "'" + property + "' value is not an integer type.\n";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Insert into the list.
|
||||
(*ret)[dictIt.key()] = static_cast<int>(dictIt.value());
|
||||
(*ret)[dictIt.key()] = dictIt.value();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -2589,8 +2711,8 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
|
||||
ParseExtrasProperty(&image->extras, o);
|
||||
|
||||
if (hasBufferView) {
|
||||
double bufferView = -1;
|
||||
if (!ParseNumberProperty(&bufferView, err, o, "bufferView", true)) {
|
||||
int bufferView = -1;
|
||||
if (!ParseIntegerProperty(&bufferView, err, o, "bufferView", true)) {
|
||||
if (err) {
|
||||
(*err) += "Failed to parse `bufferView` for image[" +
|
||||
std::to_string(image_idx) + "] name = \"" + image->name +
|
||||
@ -2602,18 +2724,18 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
|
||||
std::string mime_type;
|
||||
ParseStringProperty(&mime_type, err, o, "mimeType", false);
|
||||
|
||||
double width = 0.0;
|
||||
ParseNumberProperty(&width, err, o, "width", false);
|
||||
int width = 0;
|
||||
ParseIntegerProperty(&width, err, o, "width", false);
|
||||
|
||||
double height = 0.0;
|
||||
ParseNumberProperty(&height, err, o, "height", false);
|
||||
int height = 0;
|
||||
ParseIntegerProperty(&height, err, o, "height", false);
|
||||
|
||||
// Just only save some information here. Loading actual image data from
|
||||
// bufferView is done after this `ParseImage` function.
|
||||
image->bufferView = static_cast<int>(bufferView);
|
||||
image->bufferView = bufferView;
|
||||
image->mimeType = mime_type;
|
||||
image->width = static_cast<int>(width);
|
||||
image->height = static_cast<int>(height);
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2681,14 +2803,14 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err,
|
||||
static bool ParseTexture(Texture *texture, std::string *err, const json &o,
|
||||
const std::string &basedir) {
|
||||
(void)basedir;
|
||||
double sampler = -1.0;
|
||||
double source = -1.0;
|
||||
ParseNumberProperty(&sampler, err, o, "sampler", false);
|
||||
int sampler = -1;
|
||||
int source = -1;
|
||||
ParseIntegerProperty(&sampler, err, o, "sampler", false);
|
||||
|
||||
ParseNumberProperty(&source, err, o, "source", false);
|
||||
ParseIntegerProperty(&source, err, o, "source", false);
|
||||
|
||||
texture->sampler = static_cast<int>(sampler);
|
||||
texture->source = static_cast<int>(source);
|
||||
texture->sampler = sampler;
|
||||
texture->source = source;
|
||||
|
||||
ParseExtensionsProperty(&texture->extensions, err, o);
|
||||
ParseExtrasProperty(&texture->extras, o);
|
||||
@ -2703,8 +2825,9 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
||||
bool is_binary = false,
|
||||
const unsigned char *bin_data = nullptr,
|
||||
size_t bin_size = 0) {
|
||||
double byteLength;
|
||||
if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true, "Buffer")) {
|
||||
size_t byteLength;
|
||||
if (!ParseUnsignedProperty(&byteLength, err, o, "byteLength", true,
|
||||
"Buffer")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2729,14 +2852,13 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
||||
}
|
||||
}
|
||||
|
||||
size_t bytes = static_cast<size_t>(byteLength);
|
||||
if (is_binary) {
|
||||
// Still binary glTF accepts external dataURI.
|
||||
if (!buffer->uri.empty()) {
|
||||
// First try embedded data URI.
|
||||
if (IsDataURI(buffer->uri)) {
|
||||
std::string mime_type;
|
||||
if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, bytes,
|
||||
if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, byteLength,
|
||||
true)) {
|
||||
if (err) {
|
||||
(*err) +=
|
||||
@ -2747,7 +2869,8 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
||||
} else {
|
||||
// External .bin file.
|
||||
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr,
|
||||
buffer->uri, basedir, true, bytes, true, fs)) {
|
||||
buffer->uri, basedir, true, byteLength, true,
|
||||
fs)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -2780,7 +2903,8 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
||||
} else {
|
||||
if (IsDataURI(buffer->uri)) {
|
||||
std::string mime_type;
|
||||
if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, bytes, true)) {
|
||||
if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, byteLength,
|
||||
true)) {
|
||||
if (err) {
|
||||
(*err) += "Failed to decode 'uri' : " + buffer->uri + " in Buffer\n";
|
||||
}
|
||||
@ -2789,7 +2913,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
||||
} else {
|
||||
// Assume external .bin file.
|
||||
if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, buffer->uri,
|
||||
basedir, true, bytes, true, fs)) {
|
||||
basedir, true, byteLength, true, fs)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -2802,31 +2926,28 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o,
|
||||
|
||||
static bool ParseBufferView(BufferView *bufferView, std::string *err,
|
||||
const json &o) {
|
||||
double buffer = -1.0;
|
||||
if (!ParseNumberProperty(&buffer, err, o, "buffer", true, "BufferView")) {
|
||||
int buffer = -1;
|
||||
if (!ParseIntegerProperty(&buffer, err, o, "buffer", true, "BufferView")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double byteOffset = 0.0;
|
||||
ParseNumberProperty(&byteOffset, err, o, "byteOffset", false);
|
||||
size_t byteOffset = 0;
|
||||
ParseUnsignedProperty(&byteOffset, err, o, "byteOffset", false);
|
||||
|
||||
double byteLength = 1.0;
|
||||
if (!ParseNumberProperty(&byteLength, err, o, "byteLength", true,
|
||||
"BufferView")) {
|
||||
size_t byteLength = 1;
|
||||
if (!ParseUnsignedProperty(&byteLength, err, o, "byteLength", true,
|
||||
"BufferView")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t byteStride = 0;
|
||||
double byteStrideValue = 0.0;
|
||||
if (!ParseNumberProperty(&byteStrideValue, err, o, "byteStride", false)) {
|
||||
if (!ParseUnsignedProperty(&byteStride, err, o, "byteStride", false)) {
|
||||
// Spec says: When byteStride of referenced bufferView is not defined, it
|
||||
// means that accessor elements are tightly packed, i.e., effective stride
|
||||
// equals the size of the element.
|
||||
// We cannot determine the actual byteStride until Accessor are parsed, thus
|
||||
// set 0(= tightly packed) here(as done in OpenGL's VertexAttribPoiner)
|
||||
byteStride = 0;
|
||||
} else {
|
||||
byteStride = static_cast<size_t>(byteStrideValue);
|
||||
}
|
||||
|
||||
if ((byteStride > 252) || ((byteStride % 4) != 0)) {
|
||||
@ -2841,23 +2962,22 @@ static bool ParseBufferView(BufferView *bufferView, std::string *err,
|
||||
return false;
|
||||
}
|
||||
|
||||
double target = 0.0;
|
||||
ParseNumberProperty(&target, err, o, "target", false);
|
||||
int targetValue = static_cast<int>(target);
|
||||
if ((targetValue == TINYGLTF_TARGET_ARRAY_BUFFER) ||
|
||||
(targetValue == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)) {
|
||||
int target = 0;
|
||||
ParseIntegerProperty(&target, err, o, "target", false);
|
||||
if ((target == TINYGLTF_TARGET_ARRAY_BUFFER) ||
|
||||
(target == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)) {
|
||||
// OK
|
||||
} else {
|
||||
targetValue = 0;
|
||||
target = 0;
|
||||
}
|
||||
bufferView->target = targetValue;
|
||||
bufferView->target = target;
|
||||
|
||||
ParseStringProperty(&bufferView->name, err, o, "name", false);
|
||||
|
||||
bufferView->buffer = static_cast<int>(buffer);
|
||||
bufferView->byteOffset = static_cast<size_t>(byteOffset);
|
||||
bufferView->byteLength = static_cast<size_t>(byteLength);
|
||||
bufferView->byteStride = static_cast<size_t>(byteStride);
|
||||
bufferView->buffer = buffer;
|
||||
bufferView->byteOffset = byteOffset;
|
||||
bufferView->byteLength = byteLength;
|
||||
bufferView->byteStride = byteStride;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2865,8 +2985,8 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
||||
const json &o) {
|
||||
accessor->sparse.isSparse = true;
|
||||
|
||||
double count = 0.0;
|
||||
ParseNumberProperty(&count, err, o, "count", true);
|
||||
int count = 0;
|
||||
ParseIntegerProperty(&count, err, o, "count", true);
|
||||
|
||||
const auto indices_iterator = o.find("indices");
|
||||
const auto values_iterator = o.find("values");
|
||||
@ -2883,24 +3003,26 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
||||
const json &indices_obj = *indices_iterator;
|
||||
const json &values_obj = *values_iterator;
|
||||
|
||||
double indices_buffer_view = 0.0, indices_byte_offset = 0.0,
|
||||
component_type = 0.0;
|
||||
ParseNumberProperty(&indices_buffer_view, err, indices_obj, "bufferView",
|
||||
true);
|
||||
ParseNumberProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
|
||||
true);
|
||||
ParseNumberProperty(&component_type, err, indices_obj, "componentType", true);
|
||||
int indices_buffer_view = 0, indices_byte_offset = 0, component_type = 0;
|
||||
ParseIntegerProperty(&indices_buffer_view, err, indices_obj, "bufferView",
|
||||
true);
|
||||
ParseIntegerProperty(&indices_byte_offset, err, indices_obj, "byteOffset",
|
||||
true);
|
||||
ParseIntegerProperty(&component_type, err, indices_obj, "componentType",
|
||||
true);
|
||||
|
||||
double values_buffer_view = 0.0, values_byte_offset = 0.0;
|
||||
ParseNumberProperty(&values_buffer_view, err, values_obj, "bufferView", true);
|
||||
ParseNumberProperty(&values_byte_offset, err, values_obj, "byteOffset", true);
|
||||
int values_buffer_view = 0, values_byte_offset = 0;
|
||||
ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView",
|
||||
true);
|
||||
ParseIntegerProperty(&values_byte_offset, err, values_obj, "byteOffset",
|
||||
true);
|
||||
|
||||
accessor->sparse.count = static_cast<int>(count);
|
||||
accessor->sparse.indices.bufferView = static_cast<int>(indices_buffer_view);
|
||||
accessor->sparse.indices.byteOffset = static_cast<int>(indices_byte_offset);
|
||||
accessor->sparse.indices.componentType = static_cast<int>(component_type);
|
||||
accessor->sparse.values.bufferView = static_cast<int>(values_buffer_view);
|
||||
accessor->sparse.values.byteOffset = static_cast<int>(values_byte_offset);
|
||||
accessor->sparse.count = count;
|
||||
accessor->sparse.indices.bufferView = indices_buffer_view;
|
||||
accessor->sparse.indices.byteOffset = indices_byte_offset;
|
||||
accessor->sparse.indices.componentType = component_type;
|
||||
accessor->sparse.values.bufferView = values_buffer_view;
|
||||
accessor->sparse.values.byteOffset = values_byte_offset;
|
||||
|
||||
// todo check theses values
|
||||
|
||||
@ -2908,23 +3030,23 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err,
|
||||
}
|
||||
|
||||
static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
|
||||
double bufferView = -1.0;
|
||||
ParseNumberProperty(&bufferView, err, o, "bufferView", false, "Accessor");
|
||||
int bufferView = -1;
|
||||
ParseIntegerProperty(&bufferView, err, o, "bufferView", false, "Accessor");
|
||||
|
||||
double byteOffset = 0.0;
|
||||
ParseNumberProperty(&byteOffset, err, o, "byteOffset", false, "Accessor");
|
||||
size_t byteOffset = 0;
|
||||
ParseUnsignedProperty(&byteOffset, err, o, "byteOffset", false, "Accessor");
|
||||
|
||||
bool normalized = false;
|
||||
ParseBooleanProperty(&normalized, err, o, "normalized", false, "Accessor");
|
||||
|
||||
double componentType = 0.0;
|
||||
if (!ParseNumberProperty(&componentType, err, o, "componentType", true,
|
||||
"Accessor")) {
|
||||
size_t componentType = 0;
|
||||
if (!ParseUnsignedProperty(&componentType, err, o, "componentType", true,
|
||||
"Accessor")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double count = 0.0;
|
||||
if (!ParseNumberProperty(&count, err, o, "count", true, "Accessor")) {
|
||||
size_t count = 0;
|
||||
if (!ParseUnsignedProperty(&count, err, o, "count", true, "Accessor")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2966,19 +3088,19 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o) {
|
||||
ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false,
|
||||
"Accessor");
|
||||
|
||||
accessor->count = static_cast<size_t>(count);
|
||||
accessor->bufferView = static_cast<int>(bufferView);
|
||||
accessor->byteOffset = static_cast<size_t>(byteOffset);
|
||||
accessor->count = count;
|
||||
accessor->bufferView = bufferView;
|
||||
accessor->byteOffset = byteOffset;
|
||||
accessor->normalized = normalized;
|
||||
{
|
||||
int comp = static_cast<int>(componentType);
|
||||
if (comp >= TINYGLTF_COMPONENT_TYPE_BYTE &&
|
||||
comp <= TINYGLTF_COMPONENT_TYPE_DOUBLE) {
|
||||
if (componentType >= TINYGLTF_COMPONENT_TYPE_BYTE &&
|
||||
componentType <= TINYGLTF_COMPONENT_TYPE_DOUBLE) {
|
||||
// OK
|
||||
accessor->componentType = comp;
|
||||
accessor->componentType = componentType;
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
ss << "Invalid `componentType` in accessor. Got " << comp << "\n";
|
||||
ss << "Invalid `componentType` in accessor. Got " << componentType
|
||||
<< "\n";
|
||||
if (err) {
|
||||
(*err) += ss.str();
|
||||
}
|
||||
@ -3192,21 +3314,19 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model,
|
||||
|
||||
static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err,
|
||||
const json &o) {
|
||||
double material = -1.0;
|
||||
ParseNumberProperty(&material, err, o, "material", false);
|
||||
primitive->material = static_cast<int>(material);
|
||||
int material = -1;
|
||||
ParseIntegerProperty(&material, err, o, "material", false);
|
||||
primitive->material = material;
|
||||
|
||||
double mode = static_cast<double>(TINYGLTF_MODE_TRIANGLES);
|
||||
ParseNumberProperty(&mode, err, o, "mode", false);
|
||||
int mode = TINYGLTF_MODE_TRIANGLES;
|
||||
ParseIntegerProperty(&mode, err, o, "mode", false);
|
||||
primitive->mode = mode; // Why only triangled were supported ?
|
||||
|
||||
int primMode = static_cast<int>(mode);
|
||||
primitive->mode = primMode; // Why only triangled were supported ?
|
||||
|
||||
double indices = -1.0;
|
||||
ParseNumberProperty(&indices, err, o, "indices", false);
|
||||
primitive->indices = static_cast<int>(indices);
|
||||
if (!ParseStringIntProperty(&primitive->attributes, err, o, "attributes",
|
||||
true, "Primitive")) {
|
||||
int indices = -1;
|
||||
ParseIntegerProperty(&indices, err, o, "indices", false);
|
||||
primitive->indices = indices;
|
||||
if (!ParseStringIntegerProperty(&primitive->attributes, err, o, "attributes",
|
||||
true, "Primitive")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3299,9 +3419,9 @@ static bool ParseLight(Light *light, std::string *err, const json &o) {
|
||||
static bool ParseNode(Node *node, std::string *err, const json &o) {
|
||||
ParseStringProperty(&node->name, err, o, "name", false);
|
||||
|
||||
double skin = -1.0;
|
||||
ParseNumberProperty(&skin, err, o, "skin", false);
|
||||
node->skin = static_cast<int>(skin);
|
||||
int skin = -1;
|
||||
ParseIntegerProperty(&skin, err, o, "skin", false);
|
||||
node->skin = skin;
|
||||
|
||||
// Matrix and T/R/S are exclusive
|
||||
if (!ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false)) {
|
||||
@ -3310,29 +3430,16 @@ static bool ParseNode(Node *node, std::string *err, const json &o) {
|
||||
ParseNumberArrayProperty(&node->translation, err, o, "translation", false);
|
||||
}
|
||||
|
||||
double camera = -1.0;
|
||||
ParseNumberProperty(&camera, err, o, "camera", false);
|
||||
node->camera = static_cast<int>(camera);
|
||||
int camera = -1;
|
||||
ParseIntegerProperty(&camera, err, o, "camera", false);
|
||||
node->camera = camera;
|
||||
|
||||
double mesh = -1.0;
|
||||
ParseNumberProperty(&mesh, err, o, "mesh", false);
|
||||
node->mesh = int(mesh);
|
||||
int mesh = -1;
|
||||
ParseIntegerProperty(&mesh, err, o, "mesh", false);
|
||||
node->mesh = mesh;
|
||||
|
||||
node->children.clear();
|
||||
json::const_iterator childrenObject = o.find("children");
|
||||
if ((childrenObject != o.end()) && childrenObject.value().is_array()) {
|
||||
for (json::const_iterator i = childrenObject.value().begin();
|
||||
i != childrenObject.value().end(); i++) {
|
||||
if (!i.value().is_number()) {
|
||||
if (err) {
|
||||
(*err) += "Invalid `children` array.\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const int &childrenNode = static_cast<int>(i.value());
|
||||
node->children.push_back(childrenNode);
|
||||
}
|
||||
}
|
||||
ParseIntegerArrayProperty(&node->children, err, o, "children", false);
|
||||
|
||||
ParseExtensionsProperty(&node->extensions, err, o);
|
||||
ParseExtrasProperty(&(node->extras), o);
|
||||
@ -3383,10 +3490,10 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o) {
|
||||
|
||||
static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err,
|
||||
const json &o) {
|
||||
double samplerIndex = -1.0;
|
||||
double targetIndex = -1.0;
|
||||
if (!ParseNumberProperty(&samplerIndex, err, o, "sampler", true,
|
||||
"AnimationChannel")) {
|
||||
int samplerIndex = -1;
|
||||
int targetIndex = -1;
|
||||
if (!ParseIntegerProperty(&samplerIndex, err, o, "sampler", true,
|
||||
"AnimationChannel")) {
|
||||
if (err) {
|
||||
(*err) += "`sampler` field is missing in animation channels\n";
|
||||
}
|
||||
@ -3397,7 +3504,7 @@ static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err,
|
||||
if ((targetIt != o.end()) && targetIt.value().is_object()) {
|
||||
const json &target_object = targetIt.value();
|
||||
|
||||
if (!ParseNumberProperty(&targetIndex, err, target_object, "node", true)) {
|
||||
if (!ParseIntegerProperty(&targetIndex, err, target_object, "node", true)) {
|
||||
if (err) {
|
||||
(*err) += "`node` field is missing in animation.channels.target\n";
|
||||
}
|
||||
@ -3413,8 +3520,8 @@ static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err,
|
||||
}
|
||||
}
|
||||
|
||||
channel->sampler = static_cast<int>(samplerIndex);
|
||||
channel->target_node = static_cast<int>(targetIndex);
|
||||
channel->sampler = samplerIndex;
|
||||
channel->target_node = targetIndex;
|
||||
|
||||
ParseExtrasProperty(&(channel->extras), o);
|
||||
|
||||
@ -3449,9 +3556,9 @@ static bool ParseAnimation(Animation *animation, std::string *err,
|
||||
const json &s = it->get<json>();
|
||||
|
||||
AnimationSampler sampler;
|
||||
double inputIndex = -1.0;
|
||||
double outputIndex = -1.0;
|
||||
if (!ParseNumberProperty(&inputIndex, err, s, "input", true)) {
|
||||
int inputIndex = -1;
|
||||
int outputIndex = -1;
|
||||
if (!ParseIntegerProperty(&inputIndex, err, s, "input", true)) {
|
||||
if (err) {
|
||||
(*err) += "`input` field is missing in animation.sampler\n";
|
||||
}
|
||||
@ -3459,14 +3566,14 @@ static bool ParseAnimation(Animation *animation, std::string *err,
|
||||
}
|
||||
ParseStringProperty(&sampler.interpolation, err, s, "interpolation",
|
||||
false);
|
||||
if (!ParseNumberProperty(&outputIndex, err, s, "output", true)) {
|
||||
if (!ParseIntegerProperty(&outputIndex, err, s, "output", true)) {
|
||||
if (err) {
|
||||
(*err) += "`output` field is missing in animation.sampler\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
sampler.input = static_cast<int>(inputIndex);
|
||||
sampler.output = static_cast<int>(outputIndex);
|
||||
sampler.input = inputIndex;
|
||||
sampler.output = outputIndex;
|
||||
ParseExtrasProperty(&(sampler.extras), s);
|
||||
animation->samplers.push_back(sampler);
|
||||
}
|
||||
@ -3483,20 +3590,19 @@ static bool ParseAnimation(Animation *animation, std::string *err,
|
||||
static bool ParseSampler(Sampler *sampler, std::string *err, const json &o) {
|
||||
ParseStringProperty(&sampler->name, err, o, "name", false);
|
||||
|
||||
double minFilter =
|
||||
static_cast<double>(TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR);
|
||||
double magFilter = static_cast<double>(TINYGLTF_TEXTURE_FILTER_LINEAR);
|
||||
double wrapS = static_cast<double>(TINYGLTF_TEXTURE_WRAP_REPEAT);
|
||||
double wrapT = static_cast<double>(TINYGLTF_TEXTURE_WRAP_REPEAT);
|
||||
ParseNumberProperty(&minFilter, err, o, "minFilter", false);
|
||||
ParseNumberProperty(&magFilter, err, o, "magFilter", false);
|
||||
ParseNumberProperty(&wrapS, err, o, "wrapS", false);
|
||||
ParseNumberProperty(&wrapT, err, o, "wrapT", false);
|
||||
int minFilter = TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR;
|
||||
int magFilter = TINYGLTF_TEXTURE_FILTER_LINEAR;
|
||||
int wrapS = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
||||
int wrapT = TINYGLTF_TEXTURE_WRAP_REPEAT;
|
||||
ParseIntegerProperty(&minFilter, err, o, "minFilter", false);
|
||||
ParseIntegerProperty(&magFilter, err, o, "magFilter", false);
|
||||
ParseIntegerProperty(&wrapS, err, o, "wrapS", false);
|
||||
ParseIntegerProperty(&wrapT, err, o, "wrapT", false);
|
||||
|
||||
sampler->minFilter = static_cast<int>(minFilter);
|
||||
sampler->magFilter = static_cast<int>(magFilter);
|
||||
sampler->wrapS = static_cast<int>(wrapS);
|
||||
sampler->wrapT = static_cast<int>(wrapT);
|
||||
sampler->minFilter = minFilter;
|
||||
sampler->magFilter = magFilter;
|
||||
sampler->wrapS = wrapS;
|
||||
sampler->wrapT = wrapT;
|
||||
|
||||
ParseExtrasProperty(&(sampler->extras), o);
|
||||
|
||||
@ -3506,23 +3612,19 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o) {
|
||||
static bool ParseSkin(Skin *skin, std::string *err, const json &o) {
|
||||
ParseStringProperty(&skin->name, err, o, "name", false, "Skin");
|
||||
|
||||
std::vector<double> joints;
|
||||
if (!ParseNumberArrayProperty(&joints, err, o, "joints", false, "Skin")) {
|
||||
std::vector<int> joints;
|
||||
if (!ParseIntegerArrayProperty(&joints, err, o, "joints", false, "Skin")) {
|
||||
return false;
|
||||
}
|
||||
skin->joints = std::move(joints);
|
||||
|
||||
double skeleton = -1.0;
|
||||
ParseNumberProperty(&skeleton, err, o, "skeleton", false, "Skin");
|
||||
skin->skeleton = static_cast<int>(skeleton);
|
||||
int skeleton = -1;
|
||||
ParseIntegerProperty(&skeleton, err, o, "skeleton", false, "Skin");
|
||||
skin->skeleton = skeleton;
|
||||
|
||||
skin->joints.resize(joints.size());
|
||||
for (size_t i = 0; i < joints.size(); i++) {
|
||||
skin->joints[i] = static_cast<int>(joints[i]);
|
||||
}
|
||||
|
||||
double invBind = -1.0;
|
||||
ParseNumberProperty(&invBind, err, o, "inverseBindMatrices", true, "Skin");
|
||||
skin->inverseBindMatrices = static_cast<int>(invBind);
|
||||
int invBind = -1;
|
||||
ParseIntegerProperty(&invBind, err, o, "inverseBindMatrices", true, "Skin");
|
||||
skin->inverseBindMatrices = invBind;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -3999,18 +4101,15 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
||||
return false;
|
||||
}
|
||||
const json &o = it->get<json>();
|
||||
std::vector<double> nodes;
|
||||
if (!ParseNumberArrayProperty(&nodes, err, o, "nodes", false)) {
|
||||
std::vector<int> nodes;
|
||||
if (!ParseIntegerArrayProperty(&nodes, err, o, "nodes", false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scene scene;
|
||||
scene.nodes = std::move(nodes);
|
||||
|
||||
ParseStringProperty(&scene.name, err, o, "name", false);
|
||||
std::vector<int> nodesIds;
|
||||
for (size_t i = 0; i < nodes.size(); i++) {
|
||||
nodesIds.push_back(static_cast<int>(nodes[i]));
|
||||
}
|
||||
scene.nodes = nodesIds;
|
||||
|
||||
ParseExtensionsProperty(&scene.extensions, err, o);
|
||||
ParseExtrasProperty(&scene.extras, o);
|
||||
@ -4023,10 +4122,10 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn,
|
||||
// 9. Parse default scenes.
|
||||
{
|
||||
json::const_iterator rootIt = v.find("scene");
|
||||
if ((rootIt != v.end()) && rootIt.value().is_number()) {
|
||||
if ((rootIt != v.end()) && rootIt.value().is_number_integer()) {
|
||||
const int defaultScene = rootIt.value();
|
||||
|
||||
model->defaultScene = static_cast<int>(defaultScene);
|
||||
model->defaultScene = defaultScene;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user