Coverage Report

Created: 2024-02-11 07:19

/src/tinygltf/tiny_gltf.h
Line
Count
Source (jump to first uncovered line)
1
//
2
// Header-only tiny glTF 2.0 loader and serializer.
3
//
4
//
5
// The MIT License (MIT)
6
//
7
// Copyright (c) 2015 - Present Syoyo Fujita, Aurélien Chatelain and many
8
// contributors.
9
//
10
// Permission is hereby granted, free of charge, to any person obtaining a copy
11
// of this software and associated documentation files (the "Software"), to deal
12
// in the Software without restriction, including without limitation the rights
13
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
// copies of the Software, and to permit persons to whom the Software is
15
// furnished to do so, subject to the following conditions:
16
//
17
// The above copyright notice and this permission notice shall be included in
18
// all copies or substantial portions of the Software.
19
//
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26
// THE SOFTWARE.
27
28
// Version: - v2.8.10
29
// See https://github.com/syoyo/tinygltf/releases for release history.
30
//
31
// Tiny glTF loader is using following third party libraries:
32
//
33
//  - jsonhpp: C++ JSON library.
34
//  - base64: base64 decode/encode library.
35
//  - stb_image: Image loading library.
36
//
37
#ifndef TINY_GLTF_H_
38
#define TINY_GLTF_H_
39
40
#include <array>
41
#include <cassert>
42
#include <cmath>  // std::fabs
43
#include <cstdint>
44
#include <cstdlib>
45
#include <cstring>
46
#include <limits>
47
#include <map>
48
#include <string>
49
#include <vector>
50
51
// Auto-detect C++14 standard version
52
#if !defined(TINYGLTF_USE_CPP14) && defined(__cplusplus) && \
53
    (__cplusplus >= 201402L)
54
#define TINYGLTF_USE_CPP14
55
#endif
56
57
#ifdef __ANDROID__
58
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
59
#include <android/asset_manager.h>
60
#endif
61
#endif
62
63
#ifdef __GNUC__
64
#if (__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ <= 8))
65
#define TINYGLTF_NOEXCEPT
66
#else
67
#define TINYGLTF_NOEXCEPT noexcept
68
#endif
69
#else
70
#define TINYGLTF_NOEXCEPT noexcept
71
#endif
72
73
#define DEFAULT_METHODS(x)             \
74
31.1M
  ~x() = default;                      \
tinygltf::Value::~Value()
Line
Count
Source
74
17.2M
  ~x() = default;                      \
Unexecuted instantiation: tinygltf::Light::~Light()
Unexecuted instantiation: tinygltf::SpotLight::~SpotLight()
Unexecuted instantiation: tinygltf::AudioEmitter::~AudioEmitter()
Unexecuted instantiation: tinygltf::PositionalEmitter::~PositionalEmitter()
tinygltf::AudioSource::~AudioSource()
Line
Count
Source
74
2.40M
  ~x() = default;                      \
tinygltf::AnimationChannel::~AnimationChannel()
Line
Count
Source
74
12.1k
  ~x() = default;                      \
Unexecuted instantiation: tinygltf::AnimationSampler::~AnimationSampler()
tinygltf::Scene::~Scene()
Line
Count
Source
74
265k
  ~x() = default;                      \
tinygltf::Camera::~Camera()
Line
Count
Source
74
28
  ~x() = default;                      \
tinygltf::OrthographicCamera::~OrthographicCamera()
Line
Count
Source
74
28
  ~x() = default;                      \
tinygltf::PerspectiveCamera::~PerspectiveCamera()
Line
Count
Source
74
28
  ~x() = default;                      \
tinygltf::Sampler::~Sampler()
Line
Count
Source
74
1.10M
  ~x() = default;                      \
Unexecuted instantiation: tinygltf::Skin::~Skin()
tinygltf::Image::~Image()
Line
Count
Source
74
229k
  ~x() = default;                      \
tinygltf::Texture::~Texture()
Line
Count
Source
74
534k
  ~x() = default;                      \
tinygltf::Node::~Node()
Line
Count
Source
74
284k
  ~x() = default;                      \
tinygltf::Mesh::~Mesh()
Line
Count
Source
74
1.07M
  ~x() = default;                      \
tinygltf::Primitive::~Primitive()
Line
Count
Source
74
12.0k
  ~x() = default;                      \
tinygltf::Material::~Material()
Line
Count
Source
74
1.13M
  ~x() = default;                      \
tinygltf::Parameter::~Parameter()
Line
Count
Source
74
32.4k
  ~x() = default;                      \
tinygltf::TextureInfo::~TextureInfo()
Line
Count
Source
74
3.41M
  ~x() = default;                      \
tinygltf::OcclusionTextureInfo::~OcclusionTextureInfo()
Line
Count
Source
74
1.13M
  ~x() = default;                      \
tinygltf::NormalTextureInfo::~NormalTextureInfo()
Line
Count
Source
74
1.13M
  ~x() = default;                      \
tinygltf::PbrMetallicRoughness::~PbrMetallicRoughness()
Line
Count
Source
74
1.13M
  ~x() = default;                      \
Unexecuted instantiation: tinygltf::BufferView::~BufferView()
Unexecuted instantiation: tinygltf::Buffer::~Buffer()
tinygltf::Animation::~Animation()
Line
Count
Source
74
43.0k
  ~x() = default;                      \
Unexecuted instantiation: tinygltf::Accessor::~Accessor()
tinygltf::Model::~Model()
Line
Count
Source
74
1.82k
  ~x() = default;                      \
tinygltf::Asset::~Asset()
Line
Count
Source
74
1.82k
  ~x() = default;                      \
75
0
  x(const x &) = default;              \
Unexecuted instantiation: tinygltf::Value::Value(tinygltf::Value const&)
Unexecuted instantiation: tinygltf::AnimationChannel::AnimationChannel(tinygltf::AnimationChannel const&)
Unexecuted instantiation: tinygltf::AnimationSampler::AnimationSampler(tinygltf::AnimationSampler const&)
76
20.9M
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::Value::Value(tinygltf::Value&&)
Line
Count
Source
76
10.8M
  x(x &&) TINYGLTF_NOEXCEPT = default; \
Unexecuted instantiation: tinygltf::Buffer::Buffer(tinygltf::Buffer&&)
Unexecuted instantiation: tinygltf::BufferView::BufferView(tinygltf::BufferView&&)
Unexecuted instantiation: tinygltf::Accessor::Accessor(tinygltf::Accessor&&)
tinygltf::Primitive::Primitive(tinygltf::Primitive&&)
Line
Count
Source
76
8.00k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::Mesh::Mesh(tinygltf::Mesh&&)
Line
Count
Source
76
800k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::Node::Node(tinygltf::Node&&)
Line
Count
Source
76
210k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::Scene::Scene(tinygltf::Scene&&)
Line
Count
Source
76
197k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::Parameter::Parameter(tinygltf::Parameter&&)
Line
Count
Source
76
14.9k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::Material::Material(tinygltf::Material&&)
Line
Count
Source
76
826k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::PbrMetallicRoughness::PbrMetallicRoughness(tinygltf::PbrMetallicRoughness&&)
Line
Count
Source
76
826k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::NormalTextureInfo::NormalTextureInfo(tinygltf::NormalTextureInfo&&)
Line
Count
Source
76
826k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::OcclusionTextureInfo::OcclusionTextureInfo(tinygltf::OcclusionTextureInfo&&)
Line
Count
Source
76
826k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::TextureInfo::TextureInfo(tinygltf::TextureInfo&&)
Line
Count
Source
76
2.47M
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::Image::Image(tinygltf::Image&&)
Line
Count
Source
76
168k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::Texture::Texture(tinygltf::Texture&&)
Line
Count
Source
76
398k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
tinygltf::AnimationChannel::AnimationChannel(tinygltf::AnimationChannel&&)
Line
Count
Source
76
5.06k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
Unexecuted instantiation: tinygltf::AnimationSampler::AnimationSampler(tinygltf::AnimationSampler&&)
tinygltf::Animation::Animation(tinygltf::Animation&&)
Line
Count
Source
76
31.9k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
Unexecuted instantiation: tinygltf::Skin::Skin(tinygltf::Skin&&)
tinygltf::Sampler::Sampler(tinygltf::Sampler&&)
Line
Count
Source
76
811k
  x(x &&) TINYGLTF_NOEXCEPT = default; \
Unexecuted instantiation: tinygltf::Camera::Camera(tinygltf::Camera&&)
Unexecuted instantiation: tinygltf::PerspectiveCamera::PerspectiveCamera(tinygltf::PerspectiveCamera&&)
Unexecuted instantiation: tinygltf::OrthographicCamera::OrthographicCamera(tinygltf::OrthographicCamera&&)
Unexecuted instantiation: tinygltf::Light::Light(tinygltf::Light&&)
Unexecuted instantiation: tinygltf::SpotLight::SpotLight(tinygltf::SpotLight&&)
Unexecuted instantiation: tinygltf::AudioEmitter::AudioEmitter(tinygltf::AudioEmitter&&)
Unexecuted instantiation: tinygltf::PositionalEmitter::PositionalEmitter(tinygltf::PositionalEmitter&&)
tinygltf::AudioSource::AudioSource(tinygltf::AudioSource&&)
Line
Count
Source
76
1.63M
  x(x &&) TINYGLTF_NOEXCEPT = default; \
77
  x &operator=(const x &) = default;   \
78
1.64M
  x &operator=(x &&) TINYGLTF_NOEXCEPT = default;
79
80
namespace tinygltf {
81
82
#define TINYGLTF_MODE_POINTS (0)
83
#define TINYGLTF_MODE_LINE (1)
84
#define TINYGLTF_MODE_LINE_LOOP (2)
85
#define TINYGLTF_MODE_LINE_STRIP (3)
86
4.09k
#define TINYGLTF_MODE_TRIANGLES (4)
87
#define TINYGLTF_MODE_TRIANGLE_STRIP (5)
88
#define TINYGLTF_MODE_TRIANGLE_FAN (6)
89
90
0
#define TINYGLTF_COMPONENT_TYPE_BYTE (5120)
91
19.0k
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE (5121)
92
#define TINYGLTF_COMPONENT_TYPE_SHORT (5122)
93
1.37k
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT (5123)
94
#define TINYGLTF_COMPONENT_TYPE_INT (5124)
95
#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT (5125)
96
0
#define TINYGLTF_COMPONENT_TYPE_FLOAT (5126)
97
#define TINYGLTF_COMPONENT_TYPE_DOUBLE \
98
0
  (5130)  // OpenGL double type. Note that some of glTF 2.0 validator does not
99
          // support double type even the schema seems allow any value of
100
          // integer:
101
          // https://github.com/KhronosGroup/glTF/blob/b9884a2fd45130b4d673dd6c8a706ee21ee5c5f7/specification/2.0/schema/accessor.schema.json#L22
102
103
#define TINYGLTF_TEXTURE_FILTER_NEAREST (9728)
104
#define TINYGLTF_TEXTURE_FILTER_LINEAR (9729)
105
#define TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST (9984)
106
#define TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST (9985)
107
#define TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR (9986)
108
#define TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR (9987)
109
110
588k
#define TINYGLTF_TEXTURE_WRAP_REPEAT (10497)
111
#define TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE (33071)
112
#define TINYGLTF_TEXTURE_WRAP_MIRRORED_REPEAT (33648)
113
114
// Redeclarations of the above for technique.parameters.
115
#define TINYGLTF_PARAMETER_TYPE_BYTE (5120)
116
#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE (5121)
117
#define TINYGLTF_PARAMETER_TYPE_SHORT (5122)
118
#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT (5123)
119
#define TINYGLTF_PARAMETER_TYPE_INT (5124)
120
#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT (5125)
121
#define TINYGLTF_PARAMETER_TYPE_FLOAT (5126)
122
123
#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC2 (35664)
124
#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC3 (35665)
125
#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC4 (35666)
126
127
#define TINYGLTF_PARAMETER_TYPE_INT_VEC2 (35667)
128
#define TINYGLTF_PARAMETER_TYPE_INT_VEC3 (35668)
129
#define TINYGLTF_PARAMETER_TYPE_INT_VEC4 (35669)
130
131
#define TINYGLTF_PARAMETER_TYPE_BOOL (35670)
132
#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC2 (35671)
133
#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC3 (35672)
134
#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC4 (35673)
135
136
#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT2 (35674)
137
#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT3 (35675)
138
#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT4 (35676)
139
140
#define TINYGLTF_PARAMETER_TYPE_SAMPLER_2D (35678)
141
142
// End parameter types
143
144
0
#define TINYGLTF_TYPE_VEC2 (2)
145
0
#define TINYGLTF_TYPE_VEC3 (3)
146
0
#define TINYGLTF_TYPE_VEC4 (4)
147
0
#define TINYGLTF_TYPE_MAT2 (32 + 2)
148
0
#define TINYGLTF_TYPE_MAT3 (32 + 3)
149
0
#define TINYGLTF_TYPE_MAT4 (32 + 4)
150
0
#define TINYGLTF_TYPE_SCALAR (64 + 1)
151
#define TINYGLTF_TYPE_VECTOR (64 + 4)
152
#define TINYGLTF_TYPE_MATRIX (64 + 16)
153
154
#define TINYGLTF_IMAGE_FORMAT_JPEG (0)
155
#define TINYGLTF_IMAGE_FORMAT_PNG (1)
156
#define TINYGLTF_IMAGE_FORMAT_BMP (2)
157
#define TINYGLTF_IMAGE_FORMAT_GIF (3)
158
159
#define TINYGLTF_TEXTURE_FORMAT_ALPHA (6406)
160
#define TINYGLTF_TEXTURE_FORMAT_RGB (6407)
161
#define TINYGLTF_TEXTURE_FORMAT_RGBA (6408)
162
#define TINYGLTF_TEXTURE_FORMAT_LUMINANCE (6409)
163
#define TINYGLTF_TEXTURE_FORMAT_LUMINANCE_ALPHA (6410)
164
165
#define TINYGLTF_TEXTURE_TARGET_TEXTURE2D (3553)
166
#define TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE (5121)
167
168
0
#define TINYGLTF_TARGET_ARRAY_BUFFER (34962)
169
0
#define TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER (34963)
170
171
#define TINYGLTF_SHADER_TYPE_VERTEX_SHADER (35633)
172
#define TINYGLTF_SHADER_TYPE_FRAGMENT_SHADER (35632)
173
174
0
#define TINYGLTF_DOUBLE_EPS (1.e-12)
175
0
#define TINYGLTF_DOUBLE_EQUAL(a, b) (std::fabs((b) - (a)) < TINYGLTF_DOUBLE_EPS)
176
177
#ifdef __ANDROID__
178
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
179
#ifdef TINYGLTF_IMPLEMENTATION
180
AAssetManager *asset_manager = nullptr;
181
#else
182
extern AAssetManager *asset_manager;
183
#endif
184
#endif
185
#endif
186
187
typedef enum {
188
  NULL_TYPE,
189
  REAL_TYPE,
190
  INT_TYPE,
191
  BOOL_TYPE,
192
  STRING_TYPE,
193
  ARRAY_TYPE,
194
  BINARY_TYPE,
195
  OBJECT_TYPE
196
} Type;
197
198
typedef enum {
199
  Permissive,
200
  Strict
201
} ParseStrictness;
202
203
0
static inline int32_t GetComponentSizeInBytes(uint32_t componentType) {
204
0
  if (componentType == TINYGLTF_COMPONENT_TYPE_BYTE) {
205
0
    return 1;
206
0
  } else if (componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
207
0
    return 1;
208
0
  } else if (componentType == TINYGLTF_COMPONENT_TYPE_SHORT) {
209
0
    return 2;
210
0
  } else if (componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
211
0
    return 2;
212
0
  } else if (componentType == TINYGLTF_COMPONENT_TYPE_INT) {
213
0
    return 4;
214
0
  } else if (componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
215
0
    return 4;
216
0
  } else if (componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) {
217
0
    return 4;
218
0
  } else if (componentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) {
219
0
    return 8;
220
0
  } else {
221
0
    // Unknown component type
222
0
    return -1;
223
0
  }
224
0
}
225
226
0
static inline int32_t GetNumComponentsInType(uint32_t ty) {
227
0
  if (ty == TINYGLTF_TYPE_SCALAR) {
228
0
    return 1;
229
0
  } else if (ty == TINYGLTF_TYPE_VEC2) {
230
0
    return 2;
231
0
  } else if (ty == TINYGLTF_TYPE_VEC3) {
232
0
    return 3;
233
0
  } else if (ty == TINYGLTF_TYPE_VEC4) {
234
0
    return 4;
235
0
  } else if (ty == TINYGLTF_TYPE_MAT2) {
236
0
    return 4;
237
0
  } else if (ty == TINYGLTF_TYPE_MAT3) {
238
0
    return 9;
239
0
  } else if (ty == TINYGLTF_TYPE_MAT4) {
240
0
    return 16;
241
0
  } else {
242
0
    // Unknown component type
243
0
    return -1;
244
0
  }
245
0
}
246
247
// TODO(syoyo): Move these functions to TinyGLTF class
248
bool IsDataURI(const std::string &in);
249
bool DecodeDataURI(std::vector<unsigned char> *out, std::string &mime_type,
250
                   const std::string &in, size_t reqBytes, bool checkSize);
251
252
#ifdef __clang__
253
#pragma clang diagnostic push
254
// Suppress warning for : static Value null_value
255
#pragma clang diagnostic ignored "-Wexit-time-destructors"
256
#pragma clang diagnostic ignored "-Wpadded"
257
#endif
258
259
// Simple class to represent JSON object
260
class Value {
261
 public:
262
  typedef std::vector<Value> Array;
263
  typedef std::map<std::string, Value> Object;
264
265
5.57M
  Value() = default;
266
267
198
  explicit Value(bool b) : type_(BOOL_TYPE) { boolean_value_ = b; }
268
775k
  explicit Value(int i) : type_(INT_TYPE) {
269
775k
    int_value_ = i;
270
775k
    real_value_ = i;
271
775k
  }
272
4.56k
  explicit Value(double n) : type_(REAL_TYPE) { real_value_ = n; }
273
0
  explicit Value(const std::string &s) : type_(STRING_TYPE) {
274
0
    string_value_ = s;
275
0
  }
276
  explicit Value(std::string &&s)
277
2.90k
      : type_(STRING_TYPE), string_value_(std::move(s)) {}
278
0
  explicit Value(const char *s) : type_(STRING_TYPE) { string_value_ = s; }
279
0
  explicit Value(const unsigned char *p, size_t n) : type_(BINARY_TYPE) {
280
0
    binary_value_.resize(n);
281
0
    memcpy(binary_value_.data(), p, n);
282
0
  }
283
  explicit Value(std::vector<unsigned char> &&v) noexcept
284
      : type_(BINARY_TYPE),
285
0
        binary_value_(std::move(v)) {}
286
0
  explicit Value(const Array &a) : type_(ARRAY_TYPE) { array_value_ = a; }
287
  explicit Value(Array &&a) noexcept : type_(ARRAY_TYPE),
288
823
                                       array_value_(std::move(a)) {}
289
290
0
  explicit Value(const Object &o) : type_(OBJECT_TYPE) { object_value_ = o; }
291
  explicit Value(Object &&o) noexcept : type_(OBJECT_TYPE),
292
15.1k
                                        object_value_(std::move(o)) {}
293
294
  DEFAULT_METHODS(Value)
295
296
1.67M
  char Type() const { return static_cast<char>(type_); }
297
298
0
  bool IsBool() const { return (type_ == BOOL_TYPE); }
299
300
0
  bool IsInt() const { return (type_ == INT_TYPE); }
301
302
0
  bool IsNumber() const { return (type_ == REAL_TYPE) || (type_ == INT_TYPE); }
303
304
0
  bool IsReal() const { return (type_ == REAL_TYPE); }
305
306
0
  bool IsString() const { return (type_ == STRING_TYPE); }
307
308
0
  bool IsBinary() const { return (type_ == BINARY_TYPE); }
309
310
0
  bool IsArray() const { return (type_ == ARRAY_TYPE); }
311
312
3.99k
  bool IsObject() const { return (type_ == OBJECT_TYPE); }
313
314
  // Use this function if you want to have number value as double.
315
0
  double GetNumberAsDouble() const {
316
0
    if (type_ == INT_TYPE) {
317
0
      return double(int_value_);
318
0
    } else {
319
0
      return real_value_;
320
0
    }
321
0
  }
322
323
  // Use this function if you want to have number value as int.
324
  // TODO(syoyo): Support int value larger than 32 bits
325
1.98k
  int GetNumberAsInt() const {
326
1.98k
    if (type_ == REAL_TYPE) {
327
1.06k
      return int(real_value_);
328
1.06k
    } else {
329
922
      return int_value_;
330
922
    }
331
1.98k
  }
332
333
  // Accessor
334
  template <typename T>
335
  const T &Get() const;
336
  template <typename T>
337
  T &Get();
338
339
  // Lookup value from an array
340
0
  const Value &Get(int idx) const {
341
0
    static Value null_value;
342
0
    assert(IsArray());
343
0
    assert(idx >= 0);
344
0
    return (static_cast<size_t>(idx) < array_value_.size())
345
0
               ? array_value_[static_cast<size_t>(idx)]
346
0
               : null_value;
347
0
  }
348
349
  // Lookup value from a key-value pair
350
1.98k
  const Value &Get(const std::string &key) const {
351
1.98k
    static Value null_value;
352
1.98k
    assert(IsObject());
353
0
    Object::const_iterator it = object_value_.find(key);
354
1.98k
    return (it != object_value_.end()) ? it->second : null_value;
355
1.98k
  }
356
357
0
  size_t ArrayLen() const {
358
0
    if (!IsArray()) return 0;
359
0
    return array_value_.size();
360
0
  }
361
362
  // Valid only for object type.
363
2.00k
  bool Has(const std::string &key) const {
364
2.00k
    if (!IsObject()) return false;
365
2.00k
    Object::const_iterator it = object_value_.find(key);
366
2.00k
    return (it != object_value_.end()) ? true : false;
367
2.00k
  }
368
369
  // List keys
370
0
  std::vector<std::string> Keys() const {
371
0
    std::vector<std::string> keys;
372
0
    if (!IsObject()) return keys;  // empty
373
374
0
    for (Object::const_iterator it = object_value_.begin();
375
0
         it != object_value_.end(); ++it) {
376
0
      keys.push_back(it->first);
377
0
    }
378
379
0
    return keys;
380
0
  }
381
382
0
  size_t Size() const { return (IsArray() ? ArrayLen() : Keys().size()); }
383
384
  bool operator==(const tinygltf::Value &other) const;
385
386
 protected:
387
  int type_ = NULL_TYPE;
388
389
  int int_value_ = 0;
390
  double real_value_ = 0.0;
391
  std::string string_value_;
392
  std::vector<unsigned char> binary_value_;
393
  Array array_value_;
394
  Object object_value_;
395
  bool boolean_value_ = false;
396
};
397
398
#ifdef __clang__
399
#pragma clang diagnostic pop
400
#endif
401
402
#define TINYGLTF_VALUE_GET(ctype, var)            \
403
  template <>                                     \
404
0
  inline const ctype &Value::Get<ctype>() const { \
405
0
    return var;                                   \
406
0
  }                                               \
Unexecuted instantiation: bool const& tinygltf::Value::Get<bool>() const
Unexecuted instantiation: double const& tinygltf::Value::Get<double>() const
Unexecuted instantiation: int const& tinygltf::Value::Get<int>() const
Unexecuted instantiation: std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, tinygltf::Value, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, tinygltf::Value> > > const& tinygltf::Value::Get<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, tinygltf::Value, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, tinygltf::Value> > > >() const
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const& tinygltf::Value::Get<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >() const
Unexecuted instantiation: std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > const& tinygltf::Value::Get<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >() const
Unexecuted instantiation: std::__1::vector<tinygltf::Value, std::__1::allocator<tinygltf::Value> > const& tinygltf::Value::Get<std::__1::vector<tinygltf::Value, std::__1::allocator<tinygltf::Value> > >() const
407
  template <>                                     \
408
0
  inline ctype &Value::Get<ctype>() {             \
409
0
    return var;                                   \
410
0
  }
Unexecuted instantiation: bool& tinygltf::Value::Get<bool>()
Unexecuted instantiation: double& tinygltf::Value::Get<double>()
Unexecuted instantiation: int& tinygltf::Value::Get<int>()
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >& tinygltf::Value::Get<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >()
Unexecuted instantiation: std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >& tinygltf::Value::Get<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > >()
Unexecuted instantiation: std::__1::vector<tinygltf::Value, std::__1::allocator<tinygltf::Value> >& tinygltf::Value::Get<std::__1::vector<tinygltf::Value, std::__1::allocator<tinygltf::Value> > >()
Unexecuted instantiation: std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, tinygltf::Value, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, tinygltf::Value> > >& tinygltf::Value::Get<std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, tinygltf::Value, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, tinygltf::Value> > > >()
411
TINYGLTF_VALUE_GET(bool, boolean_value_)
412
TINYGLTF_VALUE_GET(double, real_value_)
413
TINYGLTF_VALUE_GET(int, int_value_)
414
TINYGLTF_VALUE_GET(std::string, string_value_)
415
TINYGLTF_VALUE_GET(std::vector<unsigned char>, binary_value_)
416
TINYGLTF_VALUE_GET(Value::Array, array_value_)
417
TINYGLTF_VALUE_GET(Value::Object, object_value_)
418
#undef TINYGLTF_VALUE_GET
419
420
#ifdef __clang__
421
#pragma clang diagnostic push
422
#pragma clang diagnostic ignored "-Wc++98-compat"
423
#pragma clang diagnostic ignored "-Wpadded"
424
#endif
425
426
/// Aggregate object for representing a color
427
using ColorValue = std::array<double, 4>;
428
429
// === legacy interface ====
430
// TODO(syoyo): Deprecate `Parameter` class.
431
struct Parameter {
432
  bool bool_value = false;
433
  bool has_number_value = false;
434
  std::string string_value;
435
  std::vector<double> number_array;
436
  std::map<std::string, double> json_double_value;
437
  double number_value = 0.0;
438
439
  // context sensitive methods. depending the type of the Parameter you are
440
  // accessing, these are either valid or not
441
  // If this parameter represent a texture map in a material, will return the
442
  // texture index
443
444
  /// Return the index of a texture if this Parameter is a texture map.
445
  /// Returned value is only valid if the parameter represent a texture from a
446
  /// material
447
0
  int TextureIndex() const {
448
0
    const auto it = json_double_value.find("index");
449
0
    if (it != std::end(json_double_value)) {
450
0
      return int(it->second);
451
0
    }
452
0
    return -1;
453
0
  }
454
455
  /// Return the index of a texture coordinate set if this Parameter is a
456
  /// texture map. Returned value is only valid if the parameter represent a
457
  /// texture from a material
458
0
  int TextureTexCoord() const {
459
0
    const auto it = json_double_value.find("texCoord");
460
0
    if (it != std::end(json_double_value)) {
461
0
      return int(it->second);
462
0
    }
463
0
    // As per the spec, if texCoord is omitted, this parameter is 0
464
0
    return 0;
465
0
  }
466
467
  /// Return the scale of a texture if this Parameter is a normal texture map.
468
  /// Returned value is only valid if the parameter represent a normal texture
469
  /// from a material
470
0
  double TextureScale() const {
471
0
    const auto it = json_double_value.find("scale");
472
0
    if (it != std::end(json_double_value)) {
473
0
      return it->second;
474
0
    }
475
0
    // As per the spec, if scale is omitted, this parameter is 1
476
0
    return 1;
477
0
  }
478
479
  /// Return the strength of a texture if this Parameter is a an occlusion map.
480
  /// Returned value is only valid if the parameter represent an occlusion map
481
  /// from a material
482
0
  double TextureStrength() const {
483
0
    const auto it = json_double_value.find("strength");
484
0
    if (it != std::end(json_double_value)) {
485
0
      return it->second;
486
0
    }
487
0
    // As per the spec, if strength is omitted, this parameter is 1
488
0
    return 1;
489
0
  }
490
491
  /// Material factor, like the roughness or metalness of a material
492
  /// Returned value is only valid if the parameter represent a texture from a
493
  /// material
494
0
  double Factor() const { return number_value; }
495
496
  /// Return the color of a material
497
  /// Returned value is only valid if the parameter represent a texture from a
498
  /// material
499
0
  ColorValue ColorFactor() const {
500
0
    return {
501
0
        {// this aggregate initialize the std::array object, and uses C++11 RVO.
502
0
         number_array[0], number_array[1], number_array[2],
503
0
         (number_array.size() > 3 ? number_array[3] : 1.0)}};
504
0
  }
505
506
17.5k
  Parameter() = default;
507
  DEFAULT_METHODS(Parameter)
508
  bool operator==(const Parameter &) const;
509
};
510
511
#ifdef __clang__
512
#pragma clang diagnostic pop
513
#endif
514
515
#ifdef __clang__
516
#pragma clang diagnostic push
517
#pragma clang diagnostic ignored "-Wpadded"
518
#endif
519
520
typedef std::map<std::string, Parameter> ParameterMap;
521
typedef std::map<std::string, Value> ExtensionMap;
522
523
struct AnimationChannel {
524
  int sampler{-1};          // required
525
  int target_node{-1};      // optional index of the node to target (alternative
526
                            // target should be provided by extension)
527
  std::string target_path;  // required with standard values of ["translation",
528
                            // "rotation", "scale", "weights"]
529
  Value extras;
530
  ExtensionMap extensions;
531
  Value target_extras;
532
  ExtensionMap target_extensions;
533
534
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
535
  std::string extras_json_string;
536
  std::string extensions_json_string;
537
  std::string target_extras_json_string;
538
  std::string target_extensions_json_string;
539
540
7.11k
  AnimationChannel() = default;
541
  DEFAULT_METHODS(AnimationChannel)
542
  bool operator==(const AnimationChannel &) const;
543
};
544
545
struct AnimationSampler {
546
  int input{-1};              // required
547
  int output{-1};             // required
548
  std::string interpolation;  // "LINEAR", "STEP","CUBICSPLINE" or user defined
549
                              // string. default "LINEAR"
550
  Value extras;
551
  ExtensionMap extensions;
552
553
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
554
  std::string extras_json_string;
555
  std::string extensions_json_string;
556
557
0
  AnimationSampler() : interpolation("LINEAR") {}
558
  DEFAULT_METHODS(AnimationSampler)
559
  bool operator==(const AnimationSampler &) const;
560
};
561
562
struct Animation {
563
  std::string name;
564
  std::vector<AnimationChannel> channels;
565
  std::vector<AnimationSampler> samplers;
566
  Value extras;
567
  ExtensionMap extensions;
568
569
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
570
  std::string extras_json_string;
571
  std::string extensions_json_string;
572
573
11.1k
  Animation() = default;
574
  DEFAULT_METHODS(Animation)
575
  bool operator==(const Animation &) const;
576
};
577
578
struct Skin {
579
  std::string name;
580
  int inverseBindMatrices{-1};  // required here but not in the spec
581
  int skeleton{-1};             // The index of the node used as a skeleton root
582
  std::vector<int> joints;      // Indices of skeleton nodes
583
584
  Value extras;
585
  ExtensionMap extensions;
586
587
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
588
  std::string extras_json_string;
589
  std::string extensions_json_string;
590
591
0
  Skin() = default;
592
  DEFAULT_METHODS(Skin)
593
  bool operator==(const Skin &) const;
594
};
595
596
struct Sampler {
597
  std::string name;
598
  // glTF 2.0 spec does not define default value for `minFilter` and
599
  // `magFilter`. Set -1 in TinyGLTF(issue #186)
600
  int minFilter =
601
      -1;  // optional. -1 = no filter defined. ["NEAREST", "LINEAR",
602
           // "NEAREST_MIPMAP_NEAREST", "LINEAR_MIPMAP_NEAREST",
603
           // "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_LINEAR"]
604
  int magFilter =
605
      -1;  // optional. -1 = no filter defined. ["NEAREST", "LINEAR"]
606
  int wrapS =
607
      TINYGLTF_TEXTURE_WRAP_REPEAT;  // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT",
608
                                     // "REPEAT"], default "REPEAT"
609
  int wrapT =
610
      TINYGLTF_TEXTURE_WRAP_REPEAT;  // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT",
611
                                     // "REPEAT"], default "REPEAT"
612
  // int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT;  // TinyGLTF extension. currently
613
  // not used.
614
615
  Value extras;
616
  ExtensionMap extensions;
617
618
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
619
  std::string extras_json_string;
620
  std::string extensions_json_string;
621
622
294k
  Sampler() = default;
623
  DEFAULT_METHODS(Sampler)
624
  bool operator==(const Sampler &) const;
625
};
626
627
struct Image {
628
  std::string name;
629
  int width{-1};
630
  int height{-1};
631
  int component{-1};
632
  int bits{-1};        // bit depth per channel. 8(byte), 16 or 32.
633
  int pixel_type{-1};  // pixel type(TINYGLTF_COMPONENT_TYPE_***). usually
634
                       // UBYTE(bits = 8) or USHORT(bits = 16)
635
  std::vector<unsigned char> image;
636
  int bufferView{-1};    // (required if no uri)
637
  std::string mimeType;  // (required if no uri) ["image/jpeg", "image/png",
638
                         // "image/bmp", "image/gif"]
639
  std::string uri;       // (required if no mimeType) uri is not decoded(e.g.
640
                         // whitespace may be represented as %20)
641
  Value extras;
642
  ExtensionMap extensions;
643
644
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
645
  std::string extras_json_string;
646
  std::string extensions_json_string;
647
648
  // When this flag is true, data is stored to `image` in as-is format(e.g. jpeg
649
  // compressed for "image/jpeg" mime) This feature is good if you use custom
650
  // image loader function. (e.g. delayed decoding of images for faster glTF
651
  // parsing) Default parser for Image does not provide as-is loading feature at
652
  // the moment. (You can manipulate this by providing your own LoadImageData
653
  // function)
654
  bool as_is{false};
655
656
61.2k
  Image() = default;
657
  DEFAULT_METHODS(Image)
658
659
  bool operator==(const Image &) const;
660
};
661
662
struct Texture {
663
  std::string name;
664
665
  int sampler{-1};
666
  int source{-1};
667
  Value extras;
668
  ExtensionMap extensions;
669
670
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
671
  std::string extras_json_string;
672
  std::string extensions_json_string;
673
674
135k
  Texture() = default;
675
  DEFAULT_METHODS(Texture)
676
677
  bool operator==(const Texture &) const;
678
};
679
680
struct TextureInfo {
681
  int index{-1};    // required.
682
  int texCoord{0};  // The set index of texture's TEXCOORD attribute used for
683
                    // texture coordinate mapping.
684
685
  Value extras;
686
  ExtensionMap extensions;
687
688
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
689
  std::string extras_json_string;
690
  std::string extensions_json_string;
691
692
935k
  TextureInfo() = default;
693
  DEFAULT_METHODS(TextureInfo)
694
  bool operator==(const TextureInfo &) const;
695
};
696
697
struct NormalTextureInfo {
698
  int index{-1};    // required
699
  int texCoord{0};  // The set index of texture's TEXCOORD attribute used for
700
                    // texture coordinate mapping.
701
  double scale{
702
      1.0};  // scaledNormal = normalize((<sampled normal texture value>
703
             // * 2.0 - 1.0) * vec3(<normal scale>, <normal scale>, 1.0))
704
705
  Value extras;
706
  ExtensionMap extensions;
707
708
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
709
  std::string extras_json_string;
710
  std::string extensions_json_string;
711
712
311k
  NormalTextureInfo() = default;
713
  DEFAULT_METHODS(NormalTextureInfo)
714
  bool operator==(const NormalTextureInfo &) const;
715
};
716
717
struct OcclusionTextureInfo {
718
  int index{-1};    // required
719
  int texCoord{0};  // The set index of texture's TEXCOORD attribute used for
720
                    // texture coordinate mapping.
721
  double strength{1.0};  // occludedColor = lerp(color, color * <sampled
722
                         // occlusion texture value>, <occlusion strength>)
723
724
  Value extras;
725
  ExtensionMap extensions;
726
727
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
728
  std::string extras_json_string;
729
  std::string extensions_json_string;
730
731
311k
  OcclusionTextureInfo() = default;
732
  DEFAULT_METHODS(OcclusionTextureInfo)
733
  bool operator==(const OcclusionTextureInfo &) const;
734
};
735
736
// pbrMetallicRoughness class defined in glTF 2.0 spec.
737
struct PbrMetallicRoughness {
738
  std::vector<double> baseColorFactor{1.0, 1.0, 1.0, 1.0};  // len = 4. default [1,1,1,1]
739
  TextureInfo baseColorTexture;
740
  double metallicFactor{1.0};   // default 1
741
  double roughnessFactor{1.0};  // default 1
742
  TextureInfo metallicRoughnessTexture;
743
744
  Value extras;
745
  ExtensionMap extensions;
746
747
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
748
  std::string extras_json_string;
749
  std::string extensions_json_string;
750
751
311k
  PbrMetallicRoughness() = default;
752
  DEFAULT_METHODS(PbrMetallicRoughness)
753
754
  bool operator==(const PbrMetallicRoughness &) const;
755
};
756
757
// Each extension should be stored in a ParameterMap.
758
// members not in the values could be included in the ParameterMap
759
// to keep a single material model
760
struct Material {
761
  std::string name;
762
763
  std::vector<double> emissiveFactor{0.0, 0.0, 0.0};  // length 3. default [0, 0, 0]
764
  std::string alphaMode{"OPAQUE"}; // default "OPAQUE"
765
  double alphaCutoff{0.5};        // default 0.5
766
  bool doubleSided{false};        // default false
767
  std::vector<int> lods;          // level of detail materials (MSFT_lod)
768
769
  PbrMetallicRoughness pbrMetallicRoughness;
770
771
  NormalTextureInfo normalTexture;
772
  OcclusionTextureInfo occlusionTexture;
773
  TextureInfo emissiveTexture;
774
775
  // For backward compatibility
776
  // TODO(syoyo): Remove `values` and `additionalValues` in the next release.
777
  ParameterMap values;
778
  ParameterMap additionalValues;
779
780
  ExtensionMap extensions;
781
  Value extras;
782
783
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
784
  std::string extras_json_string;
785
  std::string extensions_json_string;
786
787
311k
  Material() = default;
788
  DEFAULT_METHODS(Material)
789
790
  bool operator==(const Material &) const;
791
};
792
793
struct BufferView {
794
  std::string name;
795
  int buffer{-1};        // Required
796
  size_t byteOffset{0};  // minimum 0, default 0
797
  size_t byteLength{0};  // required, minimum 1. 0 = invalid
798
  size_t byteStride{0};  // minimum 4, maximum 252 (multiple of 4), default 0 =
799
                         // understood to be tightly packed
800
  int target{0};  // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"] for vertex indices
801
                  // or attribs. Could be 0 for other data
802
  Value extras;
803
  ExtensionMap extensions;
804
805
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
806
  std::string extras_json_string;
807
  std::string extensions_json_string;
808
809
  bool dracoDecoded{false};  // Flag indicating this has been draco decoded
810
811
0
  BufferView() = default;
812
  DEFAULT_METHODS(BufferView)
813
  bool operator==(const BufferView &) const;
814
};
815
816
struct Accessor {
817
  int bufferView{-1};  // optional in spec but required here since sparse
818
                       // accessor are not supported
819
  std::string name;
820
  size_t byteOffset{0};
821
  bool normalized{false};  // optional.
822
  int componentType{-1};   // (required) One of TINYGLTF_COMPONENT_TYPE_***
823
  size_t count{0};         // required
824
  int type{-1};            // (required) One of TINYGLTF_TYPE_***   ..
825
  Value extras;
826
  ExtensionMap extensions;
827
828
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
829
  std::string extras_json_string;
830
  std::string extensions_json_string;
831
832
  std::vector<double>
833
      minValues;  // optional. integer value is promoted to double
834
  std::vector<double>
835
      maxValues;  // optional. integer value is promoted to double
836
837
  struct Sparse {
838
    int count;
839
    bool isSparse;
840
    struct {
841
      size_t byteOffset;
842
      int bufferView;
843
      int componentType;  // a TINYGLTF_COMPONENT_TYPE_ value
844
      Value extras;
845
      ExtensionMap extensions;
846
      std::string extras_json_string;
847
      std::string extensions_json_string;
848
    } indices;
849
    struct {
850
      int bufferView;
851
      size_t byteOffset;
852
      Value extras;
853
      ExtensionMap extensions;
854
      std::string extras_json_string;
855
      std::string extensions_json_string;
856
    } values;
857
    Value extras;
858
    ExtensionMap extensions;
859
    std::string extras_json_string;
860
    std::string extensions_json_string;
861
  };
862
863
  Sparse sparse;
864
865
  ///
866
  /// Utility function to compute byteStride for a given bufferView object.
867
  /// Returns -1 upon invalid glTF value or parameter configuration.
868
  ///
869
0
  int ByteStride(const BufferView &bufferViewObject) const {
870
0
    if (bufferViewObject.byteStride == 0) {
871
0
      // Assume data is tightly packed.
872
0
      int componentSizeInBytes =
873
0
          GetComponentSizeInBytes(static_cast<uint32_t>(componentType));
874
0
      if (componentSizeInBytes <= 0) {
875
0
        return -1;
876
0
      }
877
0
878
0
      int numComponents = GetNumComponentsInType(static_cast<uint32_t>(type));
879
0
      if (numComponents <= 0) {
880
0
        return -1;
881
0
      }
882
0
883
0
      return componentSizeInBytes * numComponents;
884
0
    } else {
885
0
      // Check if byteStride is a multiple of the size of the accessor's
886
0
      // component type.
887
0
      int componentSizeInBytes =
888
0
          GetComponentSizeInBytes(static_cast<uint32_t>(componentType));
889
0
      if (componentSizeInBytes <= 0) {
890
0
        return -1;
891
0
      }
892
0
893
0
      if ((bufferViewObject.byteStride % uint32_t(componentSizeInBytes)) != 0) {
894
0
        return -1;
895
0
      }
896
0
      return static_cast<int>(bufferViewObject.byteStride);
897
0
    }
898
0
899
0
    // unreachable return 0;
900
0
  }
901
902
  Accessor()
903
904
0
  {
905
0
    sparse.isSparse = false;
906
0
  }
907
  DEFAULT_METHODS(Accessor)
908
  bool operator==(const tinygltf::Accessor &) const;
909
};
910
911
struct PerspectiveCamera {
912
  double aspectRatio{0.0};  // min > 0
913
  double yfov{0.0};         // required. min > 0
914
  double zfar{0.0};         // min > 0
915
  double znear{0.0};        // required. min > 0
916
917
28
  PerspectiveCamera() = default;
918
  DEFAULT_METHODS(PerspectiveCamera)
919
  bool operator==(const PerspectiveCamera &) const;
920
921
  ExtensionMap extensions;
922
  Value extras;
923
924
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
925
  std::string extras_json_string;
926
  std::string extensions_json_string;
927
};
928
929
struct OrthographicCamera {
930
  double xmag{0.0};   // required. must not be zero.
931
  double ymag{0.0};   // required. must not be zero.
932
  double zfar{0.0};   // required. `zfar` must be greater than `znear`.
933
  double znear{0.0};  // required
934
935
28
  OrthographicCamera() = default;
936
  DEFAULT_METHODS(OrthographicCamera)
937
  bool operator==(const OrthographicCamera &) const;
938
939
  ExtensionMap extensions;
940
  Value extras;
941
942
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
943
  std::string extras_json_string;
944
  std::string extensions_json_string;
945
};
946
947
struct Camera {
948
  std::string type;  // required. "perspective" or "orthographic"
949
  std::string name;
950
951
  PerspectiveCamera perspective;
952
  OrthographicCamera orthographic;
953
954
28
  Camera() = default;
955
  DEFAULT_METHODS(Camera)
956
  bool operator==(const Camera &) const;
957
958
  ExtensionMap extensions;
959
  Value extras;
960
961
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
962
  std::string extras_json_string;
963
  std::string extensions_json_string;
964
};
965
966
struct Primitive {
967
  std::map<std::string, int> attributes;  // (required) A dictionary object of
968
                                          // integer, where each integer
969
                                          // is the index of the accessor
970
                                          // containing an attribute.
971
  int material{-1};  // The index of the material to apply to this primitive
972
                     // when rendering.
973
  int indices{-1};   // The index of the accessor that contains the indices.
974
  int mode{-1};      // one of TINYGLTF_MODE_***
975
  std::vector<std::map<std::string, int> > targets;  // array of morph targets,
976
  // where each target is a dict with attributes in ["POSITION, "NORMAL",
977
  // "TANGENT"] pointing
978
  // to their corresponding accessors
979
  ExtensionMap extensions;
980
  Value extras;
981
982
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
983
  std::string extras_json_string;
984
  std::string extensions_json_string;
985
986
4.09k
  Primitive() = default;
987
  DEFAULT_METHODS(Primitive)
988
  bool operator==(const Primitive &) const;
989
};
990
991
struct Mesh {
992
  std::string name;
993
  std::vector<Primitive> primitives;
994
  std::vector<double> weights;  // weights to be applied to the Morph Targets
995
  ExtensionMap extensions;
996
  Value extras;
997
998
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
999
  std::string extras_json_string;
1000
  std::string extensions_json_string;
1001
1002
272k
  Mesh() = default;
1003
  DEFAULT_METHODS(Mesh)
1004
  bool operator==(const Mesh &) const;
1005
};
1006
1007
class Node {
1008
 public:
1009
73.4k
  Node() = default;
1010
1011
  DEFAULT_METHODS(Node)
1012
1013
  bool operator==(const Node &) const;
1014
1015
  int camera{-1};  // the index of the camera referenced by this node
1016
1017
  std::string name;
1018
  int skin{-1};
1019
  int mesh{-1};
1020
  int light{-1};    // light source index (KHR_lights_punctual)
1021
  int emitter{-1};  // audio emitter index (KHR_audio)
1022
  std::vector<int> lods; // level of detail nodes (MSFT_lod)
1023
  std::vector<int> children;
1024
  std::vector<double> rotation;     // length must be 0 or 4
1025
  std::vector<double> scale;        // length must be 0 or 3
1026
  std::vector<double> translation;  // length must be 0 or 3
1027
  std::vector<double> matrix;       // length must be 0 or 16
1028
  std::vector<double> weights;  // The weights of the instantiated Morph Target
1029
1030
  ExtensionMap extensions;
1031
  Value extras;
1032
1033
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1034
  std::string extras_json_string;
1035
  std::string extensions_json_string;
1036
};
1037
1038
struct Buffer {
1039
  std::string name;
1040
  std::vector<unsigned char> data;
1041
  std::string
1042
      uri;  // considered as required here but not in the spec (need to clarify)
1043
            // uri is not decoded(e.g. whitespace may be represented as %20)
1044
  Value extras;
1045
  ExtensionMap extensions;
1046
1047
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1048
  std::string extras_json_string;
1049
  std::string extensions_json_string;
1050
1051
0
  Buffer() = default;
1052
  DEFAULT_METHODS(Buffer)
1053
  bool operator==(const Buffer &) const;
1054
};
1055
1056
struct Asset {
1057
  std::string version = "2.0";  // required
1058
  std::string generator;
1059
  std::string minVersion;
1060
  std::string copyright;
1061
  ExtensionMap extensions;
1062
  Value extras;
1063
1064
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1065
  std::string extras_json_string;
1066
  std::string extensions_json_string;
1067
1068
1.82k
  Asset() = default;
1069
  DEFAULT_METHODS(Asset)
1070
  bool operator==(const Asset &) const;
1071
};
1072
1073
struct Scene {
1074
  std::string name;
1075
  std::vector<int> nodes;
1076
  std::vector<int> audioEmitters;  // KHR_audio global emitters
1077
1078
  ExtensionMap extensions;
1079
  Value extras;
1080
1081
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1082
  std::string extras_json_string;
1083
  std::string extensions_json_string;
1084
1085
67.7k
  Scene() = default;
1086
  DEFAULT_METHODS(Scene)
1087
  bool operator==(const Scene &) const;
1088
};
1089
1090
struct SpotLight {
1091
  double innerConeAngle{0.0};
1092
  double outerConeAngle{0.7853981634};
1093
1094
0
  SpotLight() = default;
1095
  DEFAULT_METHODS(SpotLight)
1096
  bool operator==(const SpotLight &) const;
1097
1098
  ExtensionMap extensions;
1099
  Value extras;
1100
1101
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1102
  std::string extras_json_string;
1103
  std::string extensions_json_string;
1104
};
1105
1106
struct Light {
1107
  std::string name;
1108
  std::vector<double> color;
1109
  double intensity{1.0};
1110
  std::string type;
1111
  double range{0.0};  // 0.0 = infinite
1112
  SpotLight spot;
1113
1114
0
  Light() = default;
1115
  DEFAULT_METHODS(Light)
1116
1117
  bool operator==(const Light &) const;
1118
1119
  ExtensionMap extensions;
1120
  Value extras;
1121
1122
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1123
  std::string extras_json_string;
1124
  std::string extensions_json_string;
1125
};
1126
1127
struct PositionalEmitter {
1128
  double coneInnerAngle{6.283185307179586};
1129
  double coneOuterAngle{6.283185307179586};
1130
  double coneOuterGain{0.0};
1131
  double maxDistance{100.0};
1132
  double refDistance{1.0};
1133
  double rolloffFactor{1.0};
1134
1135
0
  PositionalEmitter() = default;
1136
  DEFAULT_METHODS(PositionalEmitter)
1137
  bool operator==(const PositionalEmitter &) const;
1138
1139
  ExtensionMap extensions;
1140
  Value extras;
1141
1142
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1143
  std::string extras_json_string;
1144
  std::string extensions_json_string;
1145
};
1146
1147
struct AudioEmitter {
1148
  std::string name;
1149
  double gain{1.0};
1150
  bool loop{false};
1151
  bool playing{false};
1152
  std::string
1153
      type;  // positional - Positional audio emitters. Using sound cones, the
1154
             // orientation is +Z having the same front side for a glTF asset.
1155
             // global - Global audio emitters are not affected by the position
1156
             // of audio listeners. coneInnerAngle, coneOuterAngle,
1157
             // coneOuterGain, distanceModel, maxDistance, refDistance, and
1158
             // rolloffFactor should all be ignored when set.
1159
  std::string
1160
      distanceModel;  // linear - A linear distance model calculating the
1161
                      // gain induced by the distance according to: 1.0
1162
                      // - rolloffFactor * (distance - refDistance) /
1163
                      // (maxDistance - refDistance)
1164
                      // inverse - (default) An inverse distance model
1165
                      // calculating the gain induced by the distance according
1166
                      // to: refDistance / (refDistance + rolloffFactor *
1167
                      // (Math.max(distance, refDistance) - refDistance))
1168
                      // exponential - An exponential distance model calculating
1169
                      // the gain induced by the distance according to:
1170
                      // pow((Math.max(distance, refDistance) / refDistance,
1171
                      // -rolloffFactor))
1172
  PositionalEmitter positional;
1173
  int source{-1};
1174
1175
0
  AudioEmitter() : type("global"), distanceModel("inverse") {}
1176
  DEFAULT_METHODS(AudioEmitter)
1177
1178
  bool operator==(const AudioEmitter &) const;
1179
1180
  ExtensionMap extensions;
1181
  Value extras;
1182
1183
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1184
  std::string extras_json_string;
1185
  std::string extensions_json_string;
1186
};
1187
1188
struct AudioSource {
1189
  std::string name;
1190
  std::string uri;
1191
  int bufferView{-1};  // (required if no uri)
1192
  std::string
1193
      mimeType;  // (required if no uri) The audio's MIME type. Required if
1194
                 // bufferView is defined. Unless specified by another
1195
                 // extension, the only supported mimeType is audio/mpeg.
1196
1197
769k
  AudioSource() = default;
1198
  DEFAULT_METHODS(AudioSource)
1199
1200
  bool operator==(const AudioSource &) const;
1201
1202
  Value extras;
1203
  ExtensionMap extensions;
1204
1205
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1206
  std::string extras_json_string;
1207
  std::string extensions_json_string;
1208
};
1209
1210
class Model {
1211
 public:
1212
1.82k
  Model() = default;
1213
  DEFAULT_METHODS(Model)
1214
1215
  bool operator==(const Model &) const;
1216
1217
  std::vector<Accessor> accessors;
1218
  std::vector<Animation> animations;
1219
  std::vector<Buffer> buffers;
1220
  std::vector<BufferView> bufferViews;
1221
  std::vector<Material> materials;
1222
  std::vector<Mesh> meshes;
1223
  std::vector<Node> nodes;
1224
  std::vector<Texture> textures;
1225
  std::vector<Image> images;
1226
  std::vector<Skin> skins;
1227
  std::vector<Sampler> samplers;
1228
  std::vector<Camera> cameras;
1229
  std::vector<Scene> scenes;
1230
  std::vector<Light> lights;
1231
  std::vector<AudioEmitter> audioEmitters;
1232
  std::vector<AudioSource> audioSources;
1233
1234
  int defaultScene{-1};
1235
  std::vector<std::string> extensionsUsed;
1236
  std::vector<std::string> extensionsRequired;
1237
1238
  Asset asset;
1239
1240
  Value extras;
1241
  ExtensionMap extensions;
1242
1243
  // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled.
1244
  std::string extras_json_string;
1245
  std::string extensions_json_string;
1246
};
1247
1248
enum SectionCheck {
1249
  NO_REQUIRE = 0x00,
1250
  REQUIRE_VERSION = 0x01,
1251
  REQUIRE_SCENE = 0x02,
1252
  REQUIRE_SCENES = 0x04,
1253
  REQUIRE_NODES = 0x08,
1254
  REQUIRE_ACCESSORS = 0x10,
1255
  REQUIRE_BUFFERS = 0x20,
1256
  REQUIRE_BUFFER_VIEWS = 0x40,
1257
  REQUIRE_ALL = 0x7f
1258
};
1259
1260
///
1261
/// URIEncodeFunction type. Signature for custom URI encoding of external
1262
/// resources such as .bin and image files. Used by tinygltf to re-encode the
1263
/// final location of saved files. object_type may be used to encode buffer and
1264
/// image URIs differently, for example. See
1265
/// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#uris
1266
///
1267
typedef bool (*URIEncodeFunction)(const std::string &in_uri,
1268
                                  const std::string &object_type,
1269
                                  std::string *out_uri, void *user_data);
1270
1271
///
1272
/// URIDecodeFunction type. Signature for custom URI decoding of external
1273
/// resources such as .bin and image files. Used by tinygltf when computing
1274
/// filenames to write resources.
1275
///
1276
typedef bool (*URIDecodeFunction)(const std::string &in_uri,
1277
                                  std::string *out_uri, void *user_data);
1278
1279
// Declaration of default uri decode function
1280
bool URIDecode(const std::string &in_uri, std::string *out_uri,
1281
               void *user_data);
1282
1283
///
1284
/// A structure containing URI callbacks and a pointer to their user data.
1285
///
1286
struct URICallbacks {
1287
  URIEncodeFunction encode;  // Optional encode method
1288
  URIDecodeFunction decode;  // Required decode method
1289
1290
  void *user_data;  // An argument that is passed to all uri callbacks
1291
};
1292
1293
///
1294
/// LoadImageDataFunction type. Signature for custom image loading callbacks.
1295
///
1296
typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *,
1297
                                      std::string *, int, int,
1298
                                      const unsigned char *, int,
1299
                                      void *user_pointer);
1300
1301
///
1302
/// WriteImageDataFunction type. Signature for custom image writing callbacks.
1303
/// The out_uri parameter becomes the URI written to the gltf and may reference
1304
/// a file or contain a data URI.
1305
///
1306
typedef bool (*WriteImageDataFunction)(const std::string *basepath,
1307
                                       const std::string *filename,
1308
                                       const Image *image, bool embedImages,
1309
                                       const URICallbacks *uri_cb,
1310
                                       std::string *out_uri,
1311
                                       void *user_pointer);
1312
1313
#ifndef TINYGLTF_NO_STB_IMAGE
1314
// Declaration of default image loader callback
1315
bool LoadImageData(Image *image, const int image_idx, std::string *err,
1316
                   std::string *warn, int req_width, int req_height,
1317
                   const unsigned char *bytes, int size, void *);
1318
#endif
1319
1320
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
1321
// Declaration of default image writer callback
1322
bool WriteImageData(const std::string *basepath, const std::string *filename,
1323
                    const Image *image, bool embedImages,
1324
                    const URICallbacks *uri_cb, std::string *out_uri, void *);
1325
#endif
1326
1327
///
1328
/// FilExistsFunction type. Signature for custom filesystem callbacks.
1329
///
1330
typedef bool (*FileExistsFunction)(const std::string &abs_filename, void *);
1331
1332
///
1333
/// ExpandFilePathFunction type. Signature for custom filesystem callbacks.
1334
///
1335
typedef std::string (*ExpandFilePathFunction)(const std::string &, void *);
1336
1337
///
1338
/// ReadWholeFileFunction type. Signature for custom filesystem callbacks.
1339
///
1340
typedef bool (*ReadWholeFileFunction)(std::vector<unsigned char> *,
1341
                                      std::string *, const std::string &,
1342
                                      void *);
1343
1344
///
1345
/// WriteWholeFileFunction type. Signature for custom filesystem callbacks.
1346
///
1347
typedef bool (*WriteWholeFileFunction)(std::string *, const std::string &,
1348
                                       const std::vector<unsigned char> &,
1349
                                       void *);
1350
1351
///
1352
/// GetFileSizeFunction type. Signature for custom filesystem callbacks.
1353
///
1354
typedef bool (*GetFileSizeFunction)(size_t *filesize_out, std::string *err,
1355
                                    const std::string &abs_filename,
1356
                                    void *userdata);
1357
1358
///
1359
/// A structure containing all required filesystem callbacks and a pointer to
1360
/// their user data.
1361
///
1362
struct FsCallbacks {
1363
  FileExistsFunction FileExists;
1364
  ExpandFilePathFunction ExpandFilePath;
1365
  ReadWholeFileFunction ReadWholeFile;
1366
  WriteWholeFileFunction WriteWholeFile;
1367
  GetFileSizeFunction GetFileSizeInBytes;  // To avoid GetFileSize Win32 API,
1368
                                           // add `InBytes` suffix.
1369
1370
  void *user_data;  // An argument that is passed to all fs callbacks
1371
};
1372
1373
#ifndef TINYGLTF_NO_FS
1374
// Declaration of default filesystem callbacks
1375
1376
bool FileExists(const std::string &abs_filename, void *);
1377
1378
///
1379
/// Expand file path(e.g. `~` to home directory on posix, `%APPDATA%` to
1380
/// `C:\\Users\\tinygltf\\AppData`)
1381
///
1382
/// @param[in] filepath File path string. Assume UTF-8
1383
/// @param[in] userdata User data. Set to `nullptr` if you don't need it.
1384
///
1385
std::string ExpandFilePath(const std::string &filepath, void *userdata);
1386
1387
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
1388
                   const std::string &filepath, void *);
1389
1390
bool WriteWholeFile(std::string *err, const std::string &filepath,
1391
                    const std::vector<unsigned char> &contents, void *);
1392
1393
bool GetFileSizeInBytes(size_t *filesize_out, std::string *err,
1394
                        const std::string &filepath, void *);
1395
#endif
1396
1397
///
1398
/// glTF Parser/Serializer context.
1399
///
1400
class TinyGLTF {
1401
 public:
1402
#ifdef __clang__
1403
#pragma clang diagnostic push
1404
#pragma clang diagnostic ignored "-Wc++98-compat"
1405
#endif
1406
1407
1.82k
  TinyGLTF() = default;
1408
1409
#ifdef __clang__
1410
#pragma clang diagnostic pop
1411
#endif
1412
1413
1.82k
  ~TinyGLTF() = default;
1414
1415
  ///
1416
  /// Loads glTF ASCII asset from a file.
1417
  /// Set warning message to `warn` for example it fails to load asserts.
1418
  /// Returns false and set error string to `err` if there's an error.
1419
  ///
1420
  bool LoadASCIIFromFile(Model *model, std::string *err, std::string *warn,
1421
                         const std::string &filename,
1422
                         unsigned int check_sections = REQUIRE_VERSION);
1423
1424
  ///
1425
  /// Loads glTF ASCII asset from string(memory).
1426
  /// `length` = strlen(str);
1427
  /// `base_dir` is a search path of glTF asset(e.g. images). Path Must be an
1428
  /// expanded path (e.g. no tilde(`~`), no environment variables). Set warning
1429
  /// message to `warn` for example it fails to load asserts. Returns false and
1430
  /// set error string to `err` if there's an error.
1431
  ///
1432
  bool LoadASCIIFromString(Model *model, std::string *err, std::string *warn,
1433
                           const char *str, const unsigned int length,
1434
                           const std::string &base_dir,
1435
                           unsigned int check_sections = REQUIRE_VERSION);
1436
1437
  ///
1438
  /// Loads glTF binary asset from a file.
1439
  /// Set warning message to `warn` for example it fails to load asserts.
1440
  /// Returns false and set error string to `err` if there's an error.
1441
  ///
1442
  bool LoadBinaryFromFile(Model *model, std::string *err, std::string *warn,
1443
                          const std::string &filename,
1444
                          unsigned int check_sections = REQUIRE_VERSION);
1445
1446
  ///
1447
  /// Loads glTF binary asset from memory.
1448
  /// `length` = strlen(str);
1449
  /// `base_dir` is a search path of glTF asset(e.g. images). Path Must be an
1450
  /// expanded path (e.g. no tilde(`~`), no environment variables).
1451
  /// Set warning message to `warn` for example it fails to load asserts.
1452
  /// Returns false and set error string to `err` if there's an error.
1453
  ///
1454
  bool LoadBinaryFromMemory(Model *model, std::string *err, std::string *warn,
1455
                            const unsigned char *bytes,
1456
                            const unsigned int length,
1457
                            const std::string &base_dir = "",
1458
                            unsigned int check_sections = REQUIRE_VERSION);
1459
1460
  ///
1461
  /// Write glTF to stream, buffers and images will be embedded
1462
  ///
1463
  bool WriteGltfSceneToStream(const Model *model, std::ostream &stream,
1464
                              bool prettyPrint, bool writeBinary);
1465
1466
  ///
1467
  /// Write glTF to file.
1468
  ///
1469
  bool WriteGltfSceneToFile(const Model *model, const std::string &filename,
1470
                            bool embedImages, bool embedBuffers,
1471
                            bool prettyPrint, bool writeBinary);
1472
1473
  ///
1474
  /// Sets the parsing strictness.
1475
  ///
1476
  void SetParseStrictness(ParseStrictness strictness);
1477
1478
  ///
1479
  /// Set callback to use for loading image data
1480
  ///
1481
  void SetImageLoader(LoadImageDataFunction LoadImageData, void *user_data);
1482
1483
  ///
1484
  /// Unset(remove) callback of loading image data
1485
  ///
1486
  void RemoveImageLoader();
1487
1488
  ///
1489
  /// Set callback to use for writing image data
1490
  ///
1491
  void SetImageWriter(WriteImageDataFunction WriteImageData, void *user_data);
1492
1493
  ///
1494
  /// Set callbacks to use for URI encoding and decoding and their user data
1495
  ///
1496
  void SetURICallbacks(URICallbacks callbacks);
1497
1498
  ///
1499
  /// Set callbacks to use for filesystem (fs) access and their user data
1500
  ///
1501
  void SetFsCallbacks(FsCallbacks callbacks);
1502
1503
  ///
1504
  /// Set serializing default values(default = false).
1505
  /// When true, default values are force serialized to .glTF.
1506
  /// This may be helpful if you want to serialize a full description of glTF
1507
  /// data.
1508
  ///
1509
  /// TODO(LTE): Supply parsing option as function arguments to
1510
  /// `LoadASCIIFromFile()` and others, not by a class method
1511
  ///
1512
0
  void SetSerializeDefaultValues(const bool enabled) {
1513
0
    serialize_default_values_ = enabled;
1514
0
  }
1515
1516
0
  bool GetSerializeDefaultValues() const { return serialize_default_values_; }
1517
1518
  ///
1519
  /// Store original JSON string for `extras` and `extensions`.
1520
  /// This feature will be useful when the user want to reconstruct custom data
1521
  /// structure from JSON string.
1522
  ///
1523
0
  void SetStoreOriginalJSONForExtrasAndExtensions(const bool enabled) {
1524
0
    store_original_json_for_extras_and_extensions_ = enabled;
1525
0
  }
1526
1527
0
  bool GetStoreOriginalJSONForExtrasAndExtensions() const {
1528
0
    return store_original_json_for_extras_and_extensions_;
1529
0
  }
1530
1531
  ///
1532
  /// Specify whether preserve image channels when loading images or not.
1533
  /// (Not effective when the user supplies their own LoadImageData callbacks)
1534
  ///
1535
0
  void SetPreserveImageChannels(bool onoff) {
1536
0
    preserve_image_channels_ = onoff;
1537
0
  }
1538
1539
  ///
1540
  /// Set maximum allowed external file size in bytes.
1541
  /// Default: 2GB
1542
  /// Only effective for built-in ReadWholeFileFunction FS function.
1543
  ///
1544
0
  void SetMaxExternalFileSize(size_t max_bytes) {
1545
0
    max_external_file_size_ = max_bytes;
1546
0
  }
1547
1548
0
  size_t GetMaxExternalFileSize() const { return max_external_file_size_; }
1549
1550
0
  bool GetPreserveImageChannels() const { return preserve_image_channels_; }
1551
1552
 private:
1553
  ///
1554
  /// Loads glTF asset from string(memory).
1555
  /// `length` = strlen(str);
1556
  /// Set warning message to `warn` for example it fails to load asserts
1557
  /// Returns false and set error string to `err` if there's an error.
1558
  ///
1559
  bool LoadFromString(Model *model, std::string *err, std::string *warn,
1560
                      const char *str, const unsigned int length,
1561
                      const std::string &base_dir, unsigned int check_sections);
1562
1563
  const unsigned char *bin_data_ = nullptr;
1564
  size_t bin_size_ = 0;
1565
  bool is_binary_ = false;
1566
1567
  ParseStrictness strictness_ = ParseStrictness::Strict;
1568
1569
  bool serialize_default_values_ = false;  ///< Serialize default values?
1570
1571
  bool store_original_json_for_extras_and_extensions_ = false;
1572
1573
  bool preserve_image_channels_ = false;  /// Default false(expand channels to
1574
                                          /// RGBA) for backward compatibility.
1575
1576
  size_t max_external_file_size_{
1577
      size_t((std::numeric_limits<int32_t>::max)())};  // Default 2GB
1578
1579
  // Warning & error messages
1580
  std::string warn_;
1581
  std::string err_;
1582
1583
  FsCallbacks fs = {
1584
#ifndef TINYGLTF_NO_FS
1585
      &tinygltf::FileExists,
1586
      &tinygltf::ExpandFilePath,
1587
      &tinygltf::ReadWholeFile,
1588
      &tinygltf::WriteWholeFile,
1589
      &tinygltf::GetFileSizeInBytes,
1590
1591
      nullptr  // Fs callback user data
1592
#else
1593
      nullptr, nullptr, nullptr, nullptr, nullptr,
1594
1595
      nullptr  // Fs callback user data
1596
#endif
1597
  };
1598
1599
  URICallbacks uri_cb = {
1600
      // Use paths as-is by default. This will use JSON string escaping.
1601
      nullptr,
1602
      // Decode all URIs before using them as paths as the application may have
1603
      // percent encoded them.
1604
      &tinygltf::URIDecode,
1605
      // URI callback user data
1606
      nullptr};
1607
1608
  LoadImageDataFunction LoadImageData =
1609
#ifndef TINYGLTF_NO_STB_IMAGE
1610
      &tinygltf::LoadImageData;
1611
#else
1612
      nullptr;
1613
#endif
1614
  void *load_image_user_data_{nullptr};
1615
  bool user_image_loader_{false};
1616
1617
  WriteImageDataFunction WriteImageData =
1618
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
1619
      &tinygltf::WriteImageData;
1620
#else
1621
      nullptr;
1622
#endif
1623
  void *write_image_user_data_{nullptr};
1624
};
1625
1626
#ifdef __clang__
1627
#pragma clang diagnostic pop  // -Wpadded
1628
#endif
1629
1630
}  // namespace tinygltf
1631
1632
#endif  // TINY_GLTF_H_
1633
1634
#if defined(TINYGLTF_IMPLEMENTATION) || defined(__INTELLISENSE__)
1635
#include <algorithm>
1636
// #include <cassert>
1637
#ifndef TINYGLTF_NO_FS
1638
#include <sys/stat.h>  // for is_directory check
1639
1640
#include <cstdio>
1641
#include <fstream>
1642
#endif
1643
#include <sstream>
1644
1645
#ifdef __clang__
1646
// Disable some warnings for external files.
1647
#pragma clang diagnostic push
1648
#pragma clang diagnostic ignored "-Wfloat-equal"
1649
#pragma clang diagnostic ignored "-Wexit-time-destructors"
1650
#pragma clang diagnostic ignored "-Wconversion"
1651
#pragma clang diagnostic ignored "-Wold-style-cast"
1652
#pragma clang diagnostic ignored "-Wglobal-constructors"
1653
#if __has_warning("-Wreserved-id-macro")
1654
#pragma clang diagnostic ignored "-Wreserved-id-macro"
1655
#endif
1656
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
1657
#pragma clang diagnostic ignored "-Wpadded"
1658
#pragma clang diagnostic ignored "-Wc++98-compat"
1659
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
1660
#pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
1661
#pragma clang diagnostic ignored "-Wswitch-enum"
1662
#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
1663
#pragma clang diagnostic ignored "-Wweak-vtables"
1664
#pragma clang diagnostic ignored "-Wcovered-switch-default"
1665
#if __has_warning("-Wdouble-promotion")
1666
#pragma clang diagnostic ignored "-Wdouble-promotion"
1667
#endif
1668
#if __has_warning("-Wcomma")
1669
#pragma clang diagnostic ignored "-Wcomma"
1670
#endif
1671
#if __has_warning("-Wzero-as-null-pointer-constant")
1672
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
1673
#endif
1674
#if __has_warning("-Wcast-qual")
1675
#pragma clang diagnostic ignored "-Wcast-qual"
1676
#endif
1677
#if __has_warning("-Wmissing-variable-declarations")
1678
#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
1679
#endif
1680
#if __has_warning("-Wmissing-prototypes")
1681
#pragma clang diagnostic ignored "-Wmissing-prototypes"
1682
#endif
1683
#if __has_warning("-Wcast-align")
1684
#pragma clang diagnostic ignored "-Wcast-align"
1685
#endif
1686
#if __has_warning("-Wnewline-eof")
1687
#pragma clang diagnostic ignored "-Wnewline-eof"
1688
#endif
1689
#if __has_warning("-Wunused-parameter")
1690
#pragma clang diagnostic ignored "-Wunused-parameter"
1691
#endif
1692
#if __has_warning("-Wmismatched-tags")
1693
#pragma clang diagnostic ignored "-Wmismatched-tags"
1694
#endif
1695
#if __has_warning("-Wextra-semi-stmt")
1696
#pragma clang diagnostic ignored "-Wextra-semi-stmt"
1697
#endif
1698
#endif
1699
1700
// Disable GCC warnings
1701
#ifdef __GNUC__
1702
#pragma GCC diagnostic push
1703
#pragma GCC diagnostic ignored "-Wtype-limits"
1704
#endif  // __GNUC__
1705
1706
#ifndef TINYGLTF_NO_INCLUDE_JSON
1707
#ifndef TINYGLTF_USE_RAPIDJSON
1708
#include "json.hpp"
1709
#else
1710
#ifndef TINYGLTF_NO_INCLUDE_RAPIDJSON
1711
#include "document.h"
1712
#include "prettywriter.h"
1713
#include "rapidjson.h"
1714
#include "stringbuffer.h"
1715
#include "writer.h"
1716
#endif
1717
#endif
1718
#endif
1719
1720
#ifdef TINYGLTF_ENABLE_DRACO
1721
#include "draco/compression/decode.h"
1722
#include "draco/core/decoder_buffer.h"
1723
#endif
1724
1725
#ifndef TINYGLTF_NO_STB_IMAGE
1726
#ifndef TINYGLTF_NO_INCLUDE_STB_IMAGE
1727
#include "stb_image.h"
1728
#endif
1729
#endif
1730
1731
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
1732
#ifndef TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE
1733
#include "stb_image_write.h"
1734
#endif
1735
#endif
1736
1737
#ifdef __clang__
1738
#pragma clang diagnostic pop
1739
#endif
1740
1741
#ifdef __GNUC__
1742
#pragma GCC diagnostic pop
1743
#endif
1744
1745
#ifdef _WIN32
1746
1747
// issue 143.
1748
// Define NOMINMAX to avoid min/max defines,
1749
// but undef it after included Windows.h
1750
#ifndef NOMINMAX
1751
#define TINYGLTF_INTERNAL_NOMINMAX
1752
#define NOMINMAX
1753
#endif
1754
1755
#ifndef WIN32_LEAN_AND_MEAN
1756
#define WIN32_LEAN_AND_MEAN
1757
#define TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
1758
#endif
1759
#ifndef __MINGW32__
1760
#include <Windows.h>  // include API for expanding a file path
1761
#else
1762
#include <windows.h>
1763
#endif
1764
1765
#ifdef TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN
1766
#undef WIN32_LEAN_AND_MEAN
1767
#endif
1768
1769
#if defined(TINYGLTF_INTERNAL_NOMINMAX)
1770
#undef NOMINMAX
1771
#endif
1772
1773
#if defined(__GLIBCXX__)  // mingw
1774
1775
#include <fcntl.h>  // _O_RDONLY
1776
1777
#include <ext/stdio_filebuf.h>  // fstream (all sorts of IO stuff) + stdio_filebuf (=streambuf)
1778
1779
#endif
1780
1781
#elif !defined(__ANDROID__) && !defined(__OpenBSD__)
1782
// #include <wordexp.h>
1783
#endif
1784
1785
#if defined(__sparcv9) || defined(__powerpc__)
1786
// Big endian
1787
#else
1788
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
1789
#define TINYGLTF_LITTLE_ENDIAN 1
1790
#endif
1791
#endif
1792
1793
namespace tinygltf {
1794
namespace detail {
1795
#ifdef TINYGLTF_USE_RAPIDJSON
1796
1797
#ifdef TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
1798
// This uses the RapidJSON CRTAllocator.  It is thread safe and multiple
1799
// documents may be active at once.
1800
using json =
1801
    rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator>;
1802
using json_iterator = json::MemberIterator;
1803
using json_const_iterator = json::ConstMemberIterator;
1804
using json_const_array_iterator = json const *;
1805
using JsonDocument =
1806
    rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator>;
1807
rapidjson::CrtAllocator s_CrtAllocator;  // stateless and thread safe
1808
rapidjson::CrtAllocator &GetAllocator() { return s_CrtAllocator; }
1809
#else
1810
// This uses the default RapidJSON MemoryPoolAllocator.  It is very fast, but
1811
// not thread safe. Only a single JsonDocument may be active at any one time,
1812
// meaning only a single gltf load/save can be active any one time.
1813
using json = rapidjson::Value;
1814
using json_iterator = json::MemberIterator;
1815
using json_const_iterator = json::ConstMemberIterator;
1816
using json_const_array_iterator = json const *;
1817
rapidjson::Document *s_pActiveDocument = nullptr;
1818
rapidjson::Document::AllocatorType &GetAllocator() {
1819
  assert(s_pActiveDocument);  // Root json node must be JsonDocument type
1820
  return s_pActiveDocument->GetAllocator();
1821
}
1822
1823
#ifdef __clang__
1824
#pragma clang diagnostic push
1825
// Suppress JsonDocument(JsonDocument &&rhs) noexcept
1826
#pragma clang diagnostic ignored "-Wunused-member-function"
1827
#endif
1828
1829
struct JsonDocument : public rapidjson::Document {
1830
  JsonDocument() {
1831
    assert(s_pActiveDocument ==
1832
           nullptr);  // When using default allocator, only one document can be
1833
                      // active at a time, if you need multiple active at once,
1834
                      // define TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
1835
    s_pActiveDocument = this;
1836
  }
1837
  JsonDocument(const JsonDocument &) = delete;
1838
  JsonDocument(JsonDocument &&rhs) noexcept
1839
      : rapidjson::Document(std::move(rhs)) {
1840
    s_pActiveDocument = this;
1841
    rhs.isNil = true;
1842
  }
1843
  ~JsonDocument() {
1844
    if (!isNil) {
1845
      s_pActiveDocument = nullptr;
1846
    }
1847
  }
1848
1849
 private:
1850
  bool isNil = false;
1851
};
1852
1853
#ifdef __clang__
1854
#pragma clang diagnostic pop
1855
#endif
1856
1857
#endif  // TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR
1858
1859
#else
1860
using nlohmann::json;
1861
using json_iterator = json::iterator;
1862
using json_const_iterator = json::const_iterator;
1863
using json_const_array_iterator = json_const_iterator;
1864
using JsonDocument = json;
1865
#endif
1866
1867
void JsonParse(JsonDocument &doc, const char *str, size_t length,
1868
1.82k
               bool throwExc = false) {
1869
#ifdef TINYGLTF_USE_RAPIDJSON
1870
  (void)throwExc;
1871
  doc.Parse(str, length);
1872
#else
1873
1.82k
  doc = detail::json::parse(str, str + length, nullptr, throwExc);
1874
1.82k
#endif
1875
1.82k
}
1876
}  // namespace detail
1877
}  // namespace tinygltf
1878
1879
#ifdef __APPLE__
1880
#include "TargetConditionals.h"
1881
#endif
1882
1883
#ifdef __clang__
1884
#pragma clang diagnostic push
1885
#pragma clang diagnostic ignored "-Wc++98-compat"
1886
#endif
1887
1888
namespace tinygltf {
1889
1890
///
1891
/// Internal LoadImageDataOption struct.
1892
/// This struct is passed through `user_pointer` in LoadImageData.
1893
/// The struct is not passed when the user supply their own LoadImageData
1894
/// callbacks.
1895
///
1896
struct LoadImageDataOption {
1897
  // true: preserve image channels(e.g. load as RGB image if the image has RGB
1898
  // channels) default `false`(channels are expanded to RGBA for backward
1899
  // compatibility).
1900
  bool preserve_channels{false};
1901
};
1902
1903
// Equals function for Value, for recursivity
1904
0
static bool Equals(const tinygltf::Value &one, const tinygltf::Value &other) {
1905
0
  if (one.Type() != other.Type()) return false;
1906
1907
0
  switch (one.Type()) {
1908
0
    case NULL_TYPE:
1909
0
      return true;
1910
0
    case BOOL_TYPE:
1911
0
      return one.Get<bool>() == other.Get<bool>();
1912
0
    case REAL_TYPE:
1913
0
      return TINYGLTF_DOUBLE_EQUAL(one.Get<double>(), other.Get<double>());
1914
0
    case INT_TYPE:
1915
0
      return one.Get<int>() == other.Get<int>();
1916
0
    case OBJECT_TYPE: {
1917
0
      auto oneObj = one.Get<tinygltf::Value::Object>();
1918
0
      auto otherObj = other.Get<tinygltf::Value::Object>();
1919
0
      if (oneObj.size() != otherObj.size()) return false;
1920
0
      for (auto &it : oneObj) {
1921
0
        auto otherIt = otherObj.find(it.first);
1922
0
        if (otherIt == otherObj.end()) return false;
1923
1924
0
        if (!Equals(it.second, otherIt->second)) return false;
1925
0
      }
1926
0
      return true;
1927
0
    }
1928
0
    case ARRAY_TYPE: {
1929
0
      if (one.Size() != other.Size()) return false;
1930
0
      for (int i = 0; i < int(one.Size()); ++i)
1931
0
        if (!Equals(one.Get(i), other.Get(i))) return false;
1932
0
      return true;
1933
0
    }
1934
0
    case STRING_TYPE:
1935
0
      return one.Get<std::string>() == other.Get<std::string>();
1936
0
    case BINARY_TYPE:
1937
0
      return one.Get<std::vector<unsigned char> >() ==
1938
0
             other.Get<std::vector<unsigned char> >();
1939
0
    default: {
1940
      // unhandled type
1941
0
      return false;
1942
0
    }
1943
0
  }
1944
0
}
1945
1946
// Equals function for std::vector<double> using TINYGLTF_DOUBLE_EPSILON
1947
static bool Equals(const std::vector<double> &one,
1948
0
                   const std::vector<double> &other) {
1949
0
  if (one.size() != other.size()) return false;
1950
0
  for (int i = 0; i < int(one.size()); ++i) {
1951
0
    if (!TINYGLTF_DOUBLE_EQUAL(one[size_t(i)], other[size_t(i)])) return false;
1952
0
  }
1953
0
  return true;
1954
0
}
1955
1956
0
bool Accessor::operator==(const Accessor &other) const {
1957
0
  return this->bufferView == other.bufferView &&
1958
0
         this->byteOffset == other.byteOffset &&
1959
0
         this->componentType == other.componentType &&
1960
0
         this->count == other.count && this->extensions == other.extensions &&
1961
0
         this->extras == other.extras &&
1962
0
         Equals(this->maxValues, other.maxValues) &&
1963
0
         Equals(this->minValues, other.minValues) && this->name == other.name &&
1964
0
         this->normalized == other.normalized && this->type == other.type;
1965
0
}
1966
0
bool Animation::operator==(const Animation &other) const {
1967
0
  return this->channels == other.channels &&
1968
0
         this->extensions == other.extensions && this->extras == other.extras &&
1969
0
         this->name == other.name && this->samplers == other.samplers;
1970
0
}
1971
0
bool AnimationChannel::operator==(const AnimationChannel &other) const {
1972
0
  return this->extensions == other.extensions && this->extras == other.extras &&
1973
0
         this->target_node == other.target_node &&
1974
0
         this->target_path == other.target_path &&
1975
0
         this->sampler == other.sampler;
1976
0
}
1977
0
bool AnimationSampler::operator==(const AnimationSampler &other) const {
1978
0
  return this->extras == other.extras && this->extensions == other.extensions &&
1979
0
         this->input == other.input &&
1980
0
         this->interpolation == other.interpolation &&
1981
0
         this->output == other.output;
1982
0
}
1983
0
bool Asset::operator==(const Asset &other) const {
1984
0
  return this->copyright == other.copyright &&
1985
0
         this->extensions == other.extensions && this->extras == other.extras &&
1986
0
         this->generator == other.generator &&
1987
0
         this->minVersion == other.minVersion && this->version == other.version;
1988
0
}
1989
0
bool Buffer::operator==(const Buffer &other) const {
1990
0
  return this->data == other.data && this->extensions == other.extensions &&
1991
0
         this->extras == other.extras && this->name == other.name &&
1992
0
         this->uri == other.uri;
1993
0
}
1994
0
bool BufferView::operator==(const BufferView &other) const {
1995
0
  return this->buffer == other.buffer && this->byteLength == other.byteLength &&
1996
0
         this->byteOffset == other.byteOffset &&
1997
0
         this->byteStride == other.byteStride && this->name == other.name &&
1998
0
         this->target == other.target && this->extensions == other.extensions &&
1999
0
         this->extras == other.extras &&
2000
0
         this->dracoDecoded == other.dracoDecoded;
2001
0
}
2002
0
bool Camera::operator==(const Camera &other) const {
2003
0
  return this->name == other.name && this->extensions == other.extensions &&
2004
0
         this->extras == other.extras &&
2005
0
         this->orthographic == other.orthographic &&
2006
0
         this->perspective == other.perspective && this->type == other.type;
2007
0
}
2008
0
bool Image::operator==(const Image &other) const {
2009
0
  return this->bufferView == other.bufferView &&
2010
0
         this->component == other.component &&
2011
0
         this->extensions == other.extensions && this->extras == other.extras &&
2012
0
         this->height == other.height && this->image == other.image &&
2013
0
         this->mimeType == other.mimeType && this->name == other.name &&
2014
0
         this->uri == other.uri && this->width == other.width;
2015
0
}
2016
0
bool Light::operator==(const Light &other) const {
2017
0
  return Equals(this->color, other.color) && this->name == other.name &&
2018
0
         this->type == other.type;
2019
0
}
2020
0
bool AudioEmitter::operator==(const AudioEmitter &other) const {
2021
0
  return this->name == other.name &&
2022
0
         TINYGLTF_DOUBLE_EQUAL(this->gain, other.gain) &&
2023
0
         this->loop == other.loop && this->playing == other.playing &&
2024
0
         this->type == other.type &&
2025
0
         this->distanceModel == other.distanceModel &&
2026
0
         this->source == other.source;
2027
0
}
2028
0
bool AudioSource::operator==(const AudioSource &other) const {
2029
0
  return this->name == other.name && this->uri == other.uri;
2030
0
}
2031
0
bool Material::operator==(const Material &other) const {
2032
0
  return (this->pbrMetallicRoughness == other.pbrMetallicRoughness) &&
2033
0
         (this->normalTexture == other.normalTexture) &&
2034
0
         (this->occlusionTexture == other.occlusionTexture) &&
2035
0
         (this->emissiveTexture == other.emissiveTexture) &&
2036
0
         Equals(this->emissiveFactor, other.emissiveFactor) &&
2037
0
         (this->alphaMode == other.alphaMode) &&
2038
0
         TINYGLTF_DOUBLE_EQUAL(this->alphaCutoff, other.alphaCutoff) &&
2039
0
         (this->doubleSided == other.doubleSided) &&
2040
0
         (this->extensions == other.extensions) &&
2041
0
         (this->extras == other.extras) && (this->values == other.values) &&
2042
0
         (this->additionalValues == other.additionalValues) &&
2043
0
         (this->name == other.name);
2044
0
}
2045
0
bool Mesh::operator==(const Mesh &other) const {
2046
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2047
0
         this->name == other.name && Equals(this->weights, other.weights) &&
2048
0
         this->primitives == other.primitives;
2049
0
}
2050
0
bool Model::operator==(const Model &other) const {
2051
0
  return this->accessors == other.accessors &&
2052
0
         this->animations == other.animations && this->asset == other.asset &&
2053
0
         this->buffers == other.buffers &&
2054
0
         this->bufferViews == other.bufferViews &&
2055
0
         this->cameras == other.cameras &&
2056
0
         this->defaultScene == other.defaultScene &&
2057
0
         this->extensions == other.extensions &&
2058
0
         this->extensionsRequired == other.extensionsRequired &&
2059
0
         this->extensionsUsed == other.extensionsUsed &&
2060
0
         this->extras == other.extras && this->images == other.images &&
2061
0
         this->lights == other.lights && this->materials == other.materials &&
2062
0
         this->meshes == other.meshes && this->nodes == other.nodes &&
2063
0
         this->samplers == other.samplers && this->scenes == other.scenes &&
2064
0
         this->skins == other.skins && this->textures == other.textures;
2065
0
}
2066
0
bool Node::operator==(const Node &other) const {
2067
0
  return this->camera == other.camera && this->children == other.children &&
2068
0
         this->extensions == other.extensions && this->extras == other.extras &&
2069
0
         Equals(this->matrix, other.matrix) && this->mesh == other.mesh &&
2070
0
         (this->light == other.light) && (this->emitter == other.emitter) &&
2071
0
         this->name == other.name && Equals(this->rotation, other.rotation) &&
2072
0
         Equals(this->scale, other.scale) && this->skin == other.skin &&
2073
0
         Equals(this->translation, other.translation) &&
2074
0
         Equals(this->weights, other.weights);
2075
0
}
2076
0
bool SpotLight::operator==(const SpotLight &other) const {
2077
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2078
0
         TINYGLTF_DOUBLE_EQUAL(this->innerConeAngle, other.innerConeAngle) &&
2079
0
         TINYGLTF_DOUBLE_EQUAL(this->outerConeAngle, other.outerConeAngle);
2080
0
}
2081
0
bool PositionalEmitter::operator==(const PositionalEmitter &other) const {
2082
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2083
0
         TINYGLTF_DOUBLE_EQUAL(this->coneInnerAngle, other.coneInnerAngle) &&
2084
0
         TINYGLTF_DOUBLE_EQUAL(this->coneOuterAngle, other.coneOuterAngle) &&
2085
0
         TINYGLTF_DOUBLE_EQUAL(this->coneOuterGain, other.coneOuterGain) &&
2086
0
         TINYGLTF_DOUBLE_EQUAL(this->maxDistance, other.maxDistance) &&
2087
0
         TINYGLTF_DOUBLE_EQUAL(this->refDistance, other.refDistance) &&
2088
0
         TINYGLTF_DOUBLE_EQUAL(this->rolloffFactor, other.rolloffFactor);
2089
0
}
2090
0
bool OrthographicCamera::operator==(const OrthographicCamera &other) const {
2091
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2092
0
         TINYGLTF_DOUBLE_EQUAL(this->xmag, other.xmag) &&
2093
0
         TINYGLTF_DOUBLE_EQUAL(this->ymag, other.ymag) &&
2094
0
         TINYGLTF_DOUBLE_EQUAL(this->zfar, other.zfar) &&
2095
0
         TINYGLTF_DOUBLE_EQUAL(this->znear, other.znear);
2096
0
}
2097
0
bool Parameter::operator==(const Parameter &other) const {
2098
0
  if (this->bool_value != other.bool_value ||
2099
0
      this->has_number_value != other.has_number_value)
2100
0
    return false;
2101
2102
0
  if (!TINYGLTF_DOUBLE_EQUAL(this->number_value, other.number_value))
2103
0
    return false;
2104
2105
0
  if (this->json_double_value.size() != other.json_double_value.size())
2106
0
    return false;
2107
0
  for (auto &it : this->json_double_value) {
2108
0
    auto otherIt = other.json_double_value.find(it.first);
2109
0
    if (otherIt == other.json_double_value.end()) return false;
2110
2111
0
    if (!TINYGLTF_DOUBLE_EQUAL(it.second, otherIt->second)) return false;
2112
0
  }
2113
2114
0
  if (!Equals(this->number_array, other.number_array)) return false;
2115
2116
0
  if (this->string_value != other.string_value) return false;
2117
2118
0
  return true;
2119
0
}
2120
0
bool PerspectiveCamera::operator==(const PerspectiveCamera &other) const {
2121
0
  return TINYGLTF_DOUBLE_EQUAL(this->aspectRatio, other.aspectRatio) &&
2122
0
         this->extensions == other.extensions && this->extras == other.extras &&
2123
0
         TINYGLTF_DOUBLE_EQUAL(this->yfov, other.yfov) &&
2124
0
         TINYGLTF_DOUBLE_EQUAL(this->zfar, other.zfar) &&
2125
0
         TINYGLTF_DOUBLE_EQUAL(this->znear, other.znear);
2126
0
}
2127
0
bool Primitive::operator==(const Primitive &other) const {
2128
0
  return this->attributes == other.attributes && this->extras == other.extras &&
2129
0
         this->indices == other.indices && this->material == other.material &&
2130
0
         this->mode == other.mode && this->targets == other.targets;
2131
0
}
2132
0
bool Sampler::operator==(const Sampler &other) const {
2133
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2134
0
         this->magFilter == other.magFilter &&
2135
0
         this->minFilter == other.minFilter && this->name == other.name &&
2136
0
         this->wrapS == other.wrapS && this->wrapT == other.wrapT;
2137
2138
  // this->wrapR == other.wrapR
2139
0
}
2140
0
bool Scene::operator==(const Scene &other) const {
2141
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2142
0
         this->name == other.name && this->nodes == other.nodes;
2143
0
}
2144
0
bool Skin::operator==(const Skin &other) const {
2145
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2146
0
         this->inverseBindMatrices == other.inverseBindMatrices &&
2147
0
         this->joints == other.joints && this->name == other.name &&
2148
0
         this->skeleton == other.skeleton;
2149
0
}
2150
0
bool Texture::operator==(const Texture &other) const {
2151
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2152
0
         this->name == other.name && this->sampler == other.sampler &&
2153
0
         this->source == other.source;
2154
0
}
2155
0
bool TextureInfo::operator==(const TextureInfo &other) const {
2156
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2157
0
         this->index == other.index && this->texCoord == other.texCoord;
2158
0
}
2159
0
bool NormalTextureInfo::operator==(const NormalTextureInfo &other) const {
2160
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2161
0
         this->index == other.index && this->texCoord == other.texCoord &&
2162
0
         TINYGLTF_DOUBLE_EQUAL(this->scale, other.scale);
2163
0
}
2164
0
bool OcclusionTextureInfo::operator==(const OcclusionTextureInfo &other) const {
2165
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2166
0
         this->index == other.index && this->texCoord == other.texCoord &&
2167
0
         TINYGLTF_DOUBLE_EQUAL(this->strength, other.strength);
2168
0
}
2169
0
bool PbrMetallicRoughness::operator==(const PbrMetallicRoughness &other) const {
2170
0
  return this->extensions == other.extensions && this->extras == other.extras &&
2171
0
         (this->baseColorTexture == other.baseColorTexture) &&
2172
0
         (this->metallicRoughnessTexture == other.metallicRoughnessTexture) &&
2173
0
         Equals(this->baseColorFactor, other.baseColorFactor) &&
2174
0
         TINYGLTF_DOUBLE_EQUAL(this->metallicFactor, other.metallicFactor) &&
2175
0
         TINYGLTF_DOUBLE_EQUAL(this->roughnessFactor, other.roughnessFactor);
2176
0
}
2177
0
bool Value::operator==(const Value &other) const {
2178
0
  return Equals(*this, other);
2179
0
}
2180
2181
0
static void swap4(unsigned int *val) {
2182
0
#ifdef TINYGLTF_LITTLE_ENDIAN
2183
0
  (void)val;
2184
#else
2185
  unsigned int tmp = *val;
2186
  unsigned char *dst = reinterpret_cast<unsigned char *>(val);
2187
  unsigned char *src = reinterpret_cast<unsigned char *>(&tmp);
2188
2189
  dst[0] = src[3];
2190
  dst[1] = src[2];
2191
  dst[2] = src[1];
2192
  dst[3] = src[0];
2193
#endif
2194
0
}
2195
2196
static std::string JoinPath(const std::string &path0,
2197
28.1k
                            const std::string &path1) {
2198
28.1k
  if (path0.empty()) {
2199
14.0k
    return path1;
2200
14.0k
  } else {
2201
    // check '/'
2202
14.0k
    char lastChar = *path0.rbegin();
2203
14.0k
    if (lastChar != '/') {
2204
14.0k
      return path0 + std::string("/") + path1;
2205
14.0k
    } else {
2206
0
      return path0 + path1;
2207
0
    }
2208
14.0k
  }
2209
28.1k
}
2210
2211
static std::string FindFile(const std::vector<std::string> &paths,
2212
42.1k
                            const std::string &filepath, FsCallbacks *fs) {
2213
42.1k
  if (fs == nullptr || fs->ExpandFilePath == nullptr ||
2214
42.1k
      fs->FileExists == nullptr) {
2215
    // Error, fs callback[s] missing
2216
0
    return std::string();
2217
0
  }
2218
2219
  // https://github.com/syoyo/tinygltf/issues/416
2220
  // Use strlen() since std::string's size/length reports the number of elements
2221
  // in the buffer, not the length of string(null-terminated) strip
2222
  // null-character in the middle of string.
2223
42.1k
  size_t slength = strlen(filepath.c_str());
2224
42.1k
  if (slength == 0) {
2225
28.0k
    return std::string();
2226
28.0k
  }
2227
2228
14.0k
  std::string cleaned_filepath = std::string(filepath.c_str());
2229
2230
42.2k
  for (size_t i = 0; i < paths.size(); i++) {
2231
28.1k
    std::string absPath =
2232
28.1k
        fs->ExpandFilePath(JoinPath(paths[i], cleaned_filepath), fs->user_data);
2233
28.1k
    if (fs->FileExists(absPath, fs->user_data)) {
2234
0
      return absPath;
2235
0
    }
2236
28.1k
  }
2237
2238
14.0k
  return std::string();
2239
14.0k
}
2240
2241
0
static std::string GetFilePathExtension(const std::string &FileName) {
2242
0
  if (FileName.find_last_of(".") != std::string::npos)
2243
0
    return FileName.substr(FileName.find_last_of(".") + 1);
2244
0
  return "";
2245
0
}
2246
2247
0
static std::string GetBaseDir(const std::string &filepath) {
2248
0
  if (filepath.find_last_of("/\\") != std::string::npos)
2249
0
    return filepath.substr(0, filepath.find_last_of("/\\"));
2250
0
  return "";
2251
0
}
2252
2253
0
static std::string GetBaseFilename(const std::string &filepath) {
2254
0
  auto idx = filepath.find_last_of("/\\");
2255
0
  if (idx != std::string::npos) return filepath.substr(idx + 1);
2256
0
  return filepath;
2257
0
}
2258
2259
std::string base64_encode(unsigned char const *, unsigned int len);
2260
std::string base64_decode(std::string const &s);
2261
2262
/*
2263
   base64.cpp and base64.h
2264
2265
   Copyright (C) 2004-2008 René Nyffenegger
2266
2267
   This source code is provided 'as-is', without any express or implied
2268
   warranty. In no event will the author be held liable for any damages
2269
   arising from the use of this software.
2270
2271
   Permission is granted to anyone to use this software for any purpose,
2272
   including commercial applications, and to alter it and redistribute it
2273
   freely, subject to the following restrictions:
2274
2275
   1. The origin of this source code must not be misrepresented; you must not
2276
      claim that you wrote the original source code. If you use this source code
2277
      in a product, an acknowledgment in the product documentation would be
2278
      appreciated but is not required.
2279
2280
   2. Altered source versions must be plainly marked as such, and must not be
2281
      misrepresented as being the original source code.
2282
2283
   3. This notice may not be removed or altered from any source distribution.
2284
2285
   René Nyffenegger rene.nyffenegger@adp-gmbh.ch
2286
2287
*/
2288
2289
#ifdef __clang__
2290
#pragma clang diagnostic push
2291
#pragma clang diagnostic ignored "-Wsign-conversion"
2292
#pragma clang diagnostic ignored "-Wconversion"
2293
#endif
2294
2295
3.84M
static inline bool is_base64(unsigned char c) {
2296
3.84M
  return (isalnum(c) || (c == '+') || (c == '/'));
2297
3.84M
}
2298
2299
std::string base64_encode(unsigned char const *bytes_to_encode,
2300
0
                          unsigned int in_len) {
2301
0
  std::string ret;
2302
0
  int i = 0;
2303
0
  int j = 0;
2304
0
  unsigned char char_array_3[3];
2305
0
  unsigned char char_array_4[4];
2306
2307
0
  const char *base64_chars =
2308
0
      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2309
0
      "abcdefghijklmnopqrstuvwxyz"
2310
0
      "0123456789+/";
2311
2312
0
  while (in_len--) {
2313
0
    char_array_3[i++] = *(bytes_to_encode++);
2314
0
    if (i == 3) {
2315
0
      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
2316
0
      char_array_4[1] =
2317
0
          ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
2318
0
      char_array_4[2] =
2319
0
          ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
2320
0
      char_array_4[3] = char_array_3[2] & 0x3f;
2321
2322
0
      for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]];
2323
0
      i = 0;
2324
0
    }
2325
0
  }
2326
2327
0
  if (i) {
2328
0
    for (j = i; j < 3; j++) char_array_3[j] = '\0';
2329
2330
0
    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
2331
0
    char_array_4[1] =
2332
0
        ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
2333
0
    char_array_4[2] =
2334
0
        ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
2335
2336
0
    for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]];
2337
2338
0
    while ((i++ < 3)) ret += '=';
2339
0
  }
2340
2341
0
  return ret;
2342
0
}
2343
2344
19.0k
std::string base64_decode(std::string const &encoded_string) {
2345
19.0k
  int in_len = static_cast<int>(encoded_string.size());
2346
19.0k
  int i = 0;
2347
19.0k
  int j = 0;
2348
19.0k
  int in_ = 0;
2349
19.0k
  unsigned char char_array_4[4], char_array_3[3];
2350
19.0k
  std::string ret;
2351
2352
19.0k
  const std::string base64_chars =
2353
19.0k
      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
2354
19.0k
      "abcdefghijklmnopqrstuvwxyz"
2355
19.0k
      "0123456789+/";
2356
2357
3.85M
  while (in_len-- && (encoded_string[in_] != '=') &&
2358
3.85M
         is_base64(encoded_string[in_])) {
2359
3.83M
    char_array_4[i++] = encoded_string[in_];
2360
3.83M
    in_++;
2361
3.83M
    if (i == 4) {
2362
4.75M
      for (i = 0; i < 4; i++)
2363
3.80M
        char_array_4[i] =
2364
3.80M
            static_cast<unsigned char>(base64_chars.find(char_array_4[i]));
2365
2366
951k
      char_array_3[0] =
2367
951k
          (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
2368
951k
      char_array_3[1] =
2369
951k
          ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
2370
951k
      char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
2371
2372
3.80M
      for (i = 0; (i < 3); i++) ret += char_array_3[i];
2373
951k
      i = 0;
2374
951k
    }
2375
3.83M
  }
2376
2377
19.0k
  if (i) {
2378
39.0k
    for (j = i; j < 4; j++) char_array_4[j] = 0;
2379
2380
69.5k
    for (j = 0; j < 4; j++)
2381
55.6k
      char_array_4[j] =
2382
55.6k
          static_cast<unsigned char>(base64_chars.find(char_array_4[j]));
2383
2384
13.9k
    char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
2385
13.9k
    char_array_3[1] =
2386
13.9k
        ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
2387
13.9k
    char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
2388
2389
30.4k
    for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
2390
13.9k
  }
2391
2392
19.0k
  return ret;
2393
19.0k
}
2394
#ifdef __clang__
2395
#pragma clang diagnostic pop
2396
#endif
2397
2398
// https://github.com/syoyo/tinygltf/issues/228
2399
// TODO(syoyo): Use uriparser https://uriparser.github.io/ for stricter Uri
2400
// decoding?
2401
//
2402
// Uri Decoding from DLIB
2403
// http://dlib.net/dlib/server/server_http.cpp.html
2404
// --- dlib begin ------------------------------------------------------------
2405
// Copyright (C) 2003  Davis E. King (davis@dlib.net)
2406
// License: Boost Software License
2407
// Boost Software License - Version 1.0 - August 17th, 2003
2408
2409
// Permission is hereby granted, free of charge, to any person or organization
2410
// obtaining a copy of the software and accompanying documentation covered by
2411
// this license (the "Software") to use, reproduce, display, distribute,
2412
// execute, and transmit the Software, and to prepare derivative works of the
2413
// Software, and to permit third-parties to whom the Software is furnished to
2414
// do so, all subject to the following:
2415
// The copyright notices in the Software and this entire statement, including
2416
// the above license grant, this restriction and the following disclaimer,
2417
// must be included in all copies of the Software, in whole or in part, and
2418
// all derivative works of the Software, unless such copies or derivative
2419
// works are solely in the form of machine-executable object code generated by
2420
// a source language processor.
2421
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2422
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2423
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
2424
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
2425
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
2426
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2427
// DEALINGS IN THE SOFTWARE.
2428
//
2429
namespace dlib {
2430
2431
350k
inline unsigned char from_hex(unsigned char ch) {
2432
350k
  if (ch <= '9' && ch >= '0')
2433
14.6k
    ch -= '0';
2434
335k
  else if (ch <= 'f' && ch >= 'a')
2435
16.2k
    ch -= 'a' - 10;
2436
319k
  else if (ch <= 'F' && ch >= 'A')
2437
28.5k
    ch -= 'A' - 10;
2438
290k
  else
2439
290k
    ch = 0;
2440
350k
  return ch;
2441
350k
}
2442
2443
42.1k
static const std::string urldecode(const std::string &str) {
2444
42.1k
  using namespace std;
2445
42.1k
  string result;
2446
42.1k
  string::size_type i;
2447
6.33M
  for (i = 0; i < str.size(); ++i) {
2448
6.29M
    if (str[i] == '+') {
2449
14.7k
      result += ' ';
2450
6.27M
    } else if (str[i] == '%' && str.size() > i + 2) {
2451
175k
      const unsigned char ch1 =
2452
175k
          from_hex(static_cast<unsigned char>(str[i + 1]));
2453
175k
      const unsigned char ch2 =
2454
175k
          from_hex(static_cast<unsigned char>(str[i + 2]));
2455
175k
      const unsigned char ch = static_cast<unsigned char>((ch1 << 4) | ch2);
2456
175k
      result += static_cast<char>(ch);
2457
175k
      i += 2;
2458
6.10M
    } else {
2459
6.10M
      result += str[i];
2460
6.10M
    }
2461
6.29M
  }
2462
42.1k
  return result;
2463
42.1k
}
2464
2465
}  // namespace dlib
2466
// --- dlib end --------------------------------------------------------------
2467
2468
bool URIDecode(const std::string &in_uri, std::string *out_uri,
2469
42.1k
               void *user_data) {
2470
42.1k
  (void)user_data;
2471
42.1k
  *out_uri = dlib::urldecode(in_uri);
2472
42.1k
  return true;
2473
42.1k
}
2474
2475
static bool LoadExternalFile(std::vector<unsigned char> *out, std::string *err,
2476
                             std::string *warn, const std::string &filename,
2477
                             const std::string &basedir, bool required,
2478
                             size_t reqBytes, bool checkSize,
2479
42.1k
                             size_t maxFileSize, FsCallbacks *fs) {
2480
42.1k
  if (fs == nullptr || fs->FileExists == nullptr ||
2481
42.1k
      fs->ExpandFilePath == nullptr || fs->ReadWholeFile == nullptr) {
2482
    // This is a developer error, assert() ?
2483
0
    if (err) {
2484
0
      (*err) += "FS callback[s] not set\n";
2485
0
    }
2486
0
    return false;
2487
0
  }
2488
2489
42.1k
  std::string *failMsgOut = required ? err : warn;
2490
2491
42.1k
  out->clear();
2492
2493
42.1k
  std::vector<std::string> paths;
2494
42.1k
  paths.push_back(basedir);
2495
42.1k
  paths.push_back(".");
2496
2497
42.1k
  std::string filepath = FindFile(paths, filename, fs);
2498
42.1k
  if (filepath.empty() || filename.empty()) {
2499
42.1k
    if (failMsgOut) {
2500
42.1k
      (*failMsgOut) += "File not found : " + filename + "\n";
2501
42.1k
    }
2502
42.1k
    return false;
2503
42.1k
  }
2504
2505
  // Check file size
2506
0
  if (fs->GetFileSizeInBytes) {
2507
0
    size_t file_size{0};
2508
0
    std::string _err;
2509
0
    bool ok =
2510
0
        fs->GetFileSizeInBytes(&file_size, &_err, filepath, fs->user_data);
2511
0
    if (!ok) {
2512
0
      if (_err.size()) {
2513
0
        if (failMsgOut) {
2514
0
          (*failMsgOut) += "Getting file size failed : " + filename +
2515
0
                           ", err = " + _err + "\n";
2516
0
        }
2517
0
      }
2518
0
      return false;
2519
0
    }
2520
2521
0
    if (file_size > maxFileSize) {
2522
0
      if (failMsgOut) {
2523
0
        (*failMsgOut) += "File size " + std::to_string(file_size) +
2524
0
                         " exceeds maximum allowed file size " +
2525
0
                         std::to_string(maxFileSize) + " : " + filepath + "\n";
2526
0
      }
2527
0
      return false;
2528
0
    }
2529
0
  }
2530
2531
0
  std::vector<unsigned char> buf;
2532
0
  std::string fileReadErr;
2533
0
  bool fileRead =
2534
0
      fs->ReadWholeFile(&buf, &fileReadErr, filepath, fs->user_data);
2535
0
  if (!fileRead) {
2536
0
    if (failMsgOut) {
2537
0
      (*failMsgOut) +=
2538
0
          "File read error : " + filepath + " : " + fileReadErr + "\n";
2539
0
    }
2540
0
    return false;
2541
0
  }
2542
2543
0
  size_t sz = buf.size();
2544
0
  if (sz == 0) {
2545
0
    if (failMsgOut) {
2546
0
      (*failMsgOut) += "File is empty : " + filepath + "\n";
2547
0
    }
2548
0
    return false;
2549
0
  }
2550
2551
0
  if (checkSize) {
2552
0
    if (reqBytes == sz) {
2553
0
      out->swap(buf);
2554
0
      return true;
2555
0
    } else {
2556
0
      std::stringstream ss;
2557
0
      ss << "File size mismatch : " << filepath << ", requestedBytes "
2558
0
         << reqBytes << ", but got " << sz << std::endl;
2559
0
      if (failMsgOut) {
2560
0
        (*failMsgOut) += ss.str();
2561
0
      }
2562
0
      return false;
2563
0
    }
2564
0
  }
2565
2566
0
  out->swap(buf);
2567
0
  return true;
2568
0
}
2569
2570
0
void TinyGLTF::SetParseStrictness(ParseStrictness strictness) {
2571
0
  strictness_ = strictness;
2572
0
}
2573
2574
0
void TinyGLTF::SetImageLoader(LoadImageDataFunction func, void *user_data) {
2575
0
  LoadImageData = func;
2576
0
  load_image_user_data_ = user_data;
2577
0
  user_image_loader_ = true;
2578
0
}
2579
2580
0
void TinyGLTF::RemoveImageLoader() {
2581
0
  LoadImageData =
2582
0
#ifndef TINYGLTF_NO_STB_IMAGE
2583
0
      &tinygltf::LoadImageData;
2584
#else
2585
      nullptr;
2586
#endif
2587
2588
0
  load_image_user_data_ = nullptr;
2589
0
  user_image_loader_ = false;
2590
0
}
2591
2592
#ifndef TINYGLTF_NO_STB_IMAGE
2593
bool LoadImageData(Image *image, const int image_idx, std::string *err,
2594
                   std::string *warn, int req_width, int req_height,
2595
19.0k
                   const unsigned char *bytes, int size, void *user_data) {
2596
19.0k
  (void)warn;
2597
2598
19.0k
  LoadImageDataOption option;
2599
19.0k
  if (user_data) {
2600
19.0k
    option = *reinterpret_cast<LoadImageDataOption *>(user_data);
2601
19.0k
  }
2602
2603
19.0k
  int w = 0, h = 0, comp = 0, req_comp = 0;
2604
2605
19.0k
  unsigned char *data = nullptr;
2606
2607
  // preserve_channels true: Use channels stored in the image file.
2608
  // false: force 32-bit textures for common Vulkan compatibility. It appears
2609
  // that some GPU drivers do not support 24-bit images for Vulkan
2610
19.0k
  req_comp = option.preserve_channels ? 0 : 4;
2611
19.0k
  int bits = 8;
2612
19.0k
  int pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
2613
2614
  // It is possible that the image we want to load is a 16bit per channel image
2615
  // We are going to attempt to load it as 16bit per channel, and if it worked,
2616
  // set the image data accordingly. We are casting the returned pointer into
2617
  // unsigned char, because we are representing "bytes". But we are updating
2618
  // the Image metadata to signal that this image uses 2 bytes (16bits) per
2619
  // channel:
2620
19.0k
  if (stbi_is_16_bit_from_memory(bytes, size)) {
2621
1.40k
    data = reinterpret_cast<unsigned char *>(
2622
1.40k
        stbi_load_16_from_memory(bytes, size, &w, &h, &comp, req_comp));
2623
1.40k
    if (data) {
2624
1.37k
      bits = 16;
2625
1.37k
      pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT;
2626
1.37k
    }
2627
1.40k
  }
2628
2629
  // at this point, if data is still NULL, it means that the image wasn't
2630
  // 16bit per channel, we are going to load it as a normal 8bit per channel
2631
  // image as we used to do:
2632
  // if image cannot be decoded, ignore parsing and keep it by its path
2633
  // don't break in this case
2634
  // FIXME we should only enter this function if the image is embedded. If
2635
  // image->uri references
2636
  // an image file, it should be left as it is. Image loading should not be
2637
  // mandatory (to support other formats)
2638
19.0k
  if (!data) data = stbi_load_from_memory(bytes, size, &w, &h, &comp, req_comp);
2639
19.0k
  if (!data) {
2640
    // NOTE: you can use `warn` instead of `err`
2641
319
    if (err) {
2642
319
      (*err) +=
2643
319
          "Unknown image format. STB cannot decode image data for image[" +
2644
319
          std::to_string(image_idx) + "] name = \"" + image->name + "\".\n";
2645
319
    }
2646
319
    return false;
2647
319
  }
2648
2649
18.6k
  if ((w < 1) || (h < 1)) {
2650
0
    stbi_image_free(data);
2651
0
    if (err) {
2652
0
      (*err) += "Invalid image data for image[" + std::to_string(image_idx) +
2653
0
                "] name = \"" + image->name + "\"\n";
2654
0
    }
2655
0
    return false;
2656
0
  }
2657
2658
18.6k
  if (req_width > 0) {
2659
0
    if (req_width != w) {
2660
0
      stbi_image_free(data);
2661
0
      if (err) {
2662
0
        (*err) += "Image width mismatch for image[" +
2663
0
                  std::to_string(image_idx) + "] name = \"" + image->name +
2664
0
                  "\"\n";
2665
0
      }
2666
0
      return false;
2667
0
    }
2668
0
  }
2669
2670
18.6k
  if (req_height > 0) {
2671
0
    if (req_height != h) {
2672
0
      stbi_image_free(data);
2673
0
      if (err) {
2674
0
        (*err) += "Image height mismatch. for image[" +
2675
0
                  std::to_string(image_idx) + "] name = \"" + image->name +
2676
0
                  "\"\n";
2677
0
      }
2678
0
      return false;
2679
0
    }
2680
0
  }
2681
2682
18.6k
  if (req_comp != 0) {
2683
    // loaded data has `req_comp` channels(components)
2684
18.6k
    comp = req_comp;
2685
18.6k
  }
2686
2687
18.6k
  image->width = w;
2688
18.6k
  image->height = h;
2689
18.6k
  image->component = comp;
2690
18.6k
  image->bits = bits;
2691
18.6k
  image->pixel_type = pixel_type;
2692
18.6k
  image->image.resize(static_cast<size_t>(w * h * comp) * size_t(bits / 8));
2693
18.6k
  std::copy(data, data + w * h * comp * (bits / 8), image->image.begin());
2694
18.6k
  stbi_image_free(data);
2695
2696
18.6k
  return true;
2697
18.6k
}
2698
#endif
2699
2700
0
void TinyGLTF::SetImageWriter(WriteImageDataFunction func, void *user_data) {
2701
0
  WriteImageData = func;
2702
0
  write_image_user_data_ = user_data;
2703
0
}
2704
2705
#ifndef TINYGLTF_NO_STB_IMAGE_WRITE
2706
0
static void WriteToMemory_stbi(void *context, void *data, int size) {
2707
0
  std::vector<unsigned char> *buffer =
2708
0
      reinterpret_cast<std::vector<unsigned char> *>(context);
2709
2710
0
  unsigned char *pData = reinterpret_cast<unsigned char *>(data);
2711
2712
0
  buffer->insert(buffer->end(), pData, pData + size);
2713
0
}
2714
2715
bool WriteImageData(const std::string *basepath, const std::string *filename,
2716
                    const Image *image, bool embedImages,
2717
                    const URICallbacks *uri_cb, std::string *out_uri,
2718
0
                    void *fsPtr) {
2719
0
  const std::string ext = GetFilePathExtension(*filename);
2720
2721
  // Write image to temporary buffer
2722
0
  std::string header;
2723
0
  std::vector<unsigned char> data;
2724
2725
0
  if (ext == "png") {
2726
0
    if ((image->bits != 8) ||
2727
0
        (image->pixel_type != TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)) {
2728
      // Unsupported pixel format
2729
0
      return false;
2730
0
    }
2731
2732
0
    if (!stbi_write_png_to_func(WriteToMemory_stbi, &data, image->width,
2733
0
                                image->height, image->component,
2734
0
                                &image->image[0], 0)) {
2735
0
      return false;
2736
0
    }
2737
0
    header = "data:image/png;base64,";
2738
0
  } else if (ext == "jpg") {
2739
0
    if (!stbi_write_jpg_to_func(WriteToMemory_stbi, &data, image->width,
2740
0
                                image->height, image->component,
2741
0
                                &image->image[0], 100)) {
2742
0
      return false;
2743
0
    }
2744
0
    header = "data:image/jpeg;base64,";
2745
0
  } else if (ext == "bmp") {
2746
0
    if (!stbi_write_bmp_to_func(WriteToMemory_stbi, &data, image->width,
2747
0
                                image->height, image->component,
2748
0
                                &image->image[0])) {
2749
0
      return false;
2750
0
    }
2751
0
    header = "data:image/bmp;base64,";
2752
0
  } else if (!embedImages) {
2753
    // Error: can't output requested format to file
2754
0
    return false;
2755
0
  }
2756
2757
0
  if (embedImages) {
2758
    // Embed base64-encoded image into URI
2759
0
    if (data.size()) {
2760
0
      *out_uri = header + base64_encode(&data[0],
2761
0
                                        static_cast<unsigned int>(data.size()));
2762
0
    } else {
2763
      // Throw error?
2764
0
    }
2765
0
  } else {
2766
    // Write image to disc
2767
0
    FsCallbacks *fs = reinterpret_cast<FsCallbacks *>(fsPtr);
2768
0
    if ((fs != nullptr) && (fs->WriteWholeFile != nullptr)) {
2769
0
      const std::string imagefilepath = JoinPath(*basepath, *filename);
2770
0
      std::string writeError;
2771
0
      if (!fs->WriteWholeFile(&writeError, imagefilepath, data,
2772
0
                              fs->user_data)) {
2773
        // Could not write image file to disc; Throw error ?
2774
0
        return false;
2775
0
      }
2776
0
    } else {
2777
      // Throw error?
2778
0
    }
2779
0
    if (uri_cb->encode) {
2780
0
      if (!uri_cb->encode(*filename, "image", out_uri, uri_cb->user_data)) {
2781
0
        return false;
2782
0
      }
2783
0
    } else {
2784
0
      *out_uri = *filename;
2785
0
    }
2786
0
  }
2787
2788
0
  return true;
2789
0
}
2790
#endif
2791
2792
0
void TinyGLTF::SetURICallbacks(URICallbacks callbacks) {
2793
0
  assert(callbacks.decode);
2794
0
  if (callbacks.decode) {
2795
0
    uri_cb = callbacks;
2796
0
  }
2797
0
}
2798
2799
0
void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; }
2800
2801
#ifdef _WIN32
2802
static inline std::wstring UTF8ToWchar(const std::string &str) {
2803
  int wstr_size =
2804
      MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0);
2805
  std::wstring wstr((size_t)wstr_size, 0);
2806
  MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstr[0],
2807
                      (int)wstr.size());
2808
  return wstr;
2809
}
2810
2811
static inline std::string WcharToUTF8(const std::wstring &wstr) {
2812
  int str_size = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(),
2813
                                     nullptr, 0, nullptr, nullptr);
2814
  std::string str((size_t)str_size, 0);
2815
  WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), &str[0],
2816
                      (int)str.size(), nullptr, nullptr);
2817
  return str;
2818
}
2819
#endif
2820
2821
#ifndef TINYGLTF_NO_FS
2822
// Default implementations of filesystem functions
2823
2824
28.1k
bool FileExists(const std::string &abs_filename, void *) {
2825
28.1k
  bool ret;
2826
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
2827
  if (asset_manager) {
2828
    AAsset *asset = AAssetManager_open(asset_manager, abs_filename.c_str(),
2829
                                       AASSET_MODE_STREAMING);
2830
    if (!asset) {
2831
      return false;
2832
    }
2833
    AAsset_close(asset);
2834
    ret = true;
2835
  } else {
2836
    return false;
2837
  }
2838
#else
2839
#ifdef _WIN32
2840
#if defined(_MSC_VER) || defined(_LIBCPP_VERSION)
2841
2842
  // First check if a file is a directory.
2843
  DWORD result = GetFileAttributesW(UTF8ToWchar(abs_filename).c_str());
2844
  if (result == INVALID_FILE_ATTRIBUTES) {
2845
    return false;
2846
  }
2847
  if (result & FILE_ATTRIBUTE_DIRECTORY) {
2848
    return false;
2849
  }
2850
2851
  FILE *fp = nullptr;
2852
  errno_t err = _wfopen_s(&fp, UTF8ToWchar(abs_filename).c_str(), L"rb");
2853
  if (err != 0) {
2854
    return false;
2855
  }
2856
#elif defined(__GLIBCXX__)
2857
  FILE *fp = fopen(abs_filename.c_str(), "rb");
2858
  if (!fp) {
2859
    return false;
2860
  }
2861
#else
2862
  // TODO: is_directory check
2863
  FILE *fp = nullptr;
2864
  errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb");
2865
  if (err != 0) {
2866
    return false;
2867
  }
2868
#endif
2869
2870
#else
2871
28.1k
  struct stat sb;
2872
28.1k
  if (stat(abs_filename.c_str(), &sb)) {
2873
27.7k
    return false;
2874
27.7k
  }
2875
382
  if (S_ISDIR(sb.st_mode)) {
2876
382
    return false;
2877
382
  }
2878
2879
0
  FILE *fp = fopen(abs_filename.c_str(), "rb");
2880
0
#endif
2881
0
  if (fp) {
2882
0
    ret = true;
2883
0
    fclose(fp);
2884
0
  } else {
2885
0
    ret = false;
2886
0
  }
2887
0
#endif
2888
2889
0
  return ret;
2890
382
}
2891
2892
28.1k
std::string ExpandFilePath(const std::string &filepath, void *) {
2893
  // https://github.com/syoyo/tinygltf/issues/368
2894
  //
2895
  // No file path expansion in built-in FS function anymore, since glTF URI
2896
  // should not contain tilde('~') and environment variables, and for security
2897
  // reason(`wordexp`).
2898
  //
2899
  // Users need to supply `base_dir`(in `LoadASCIIFromString`,
2900
  // `LoadBinaryFromMemory`) in expanded absolute path.
2901
2902
28.1k
  return filepath;
2903
2904
#if 0
2905
#ifdef _WIN32
2906
  // Assume input `filepath` is encoded in UTF-8
2907
  std::wstring wfilepath = UTF8ToWchar(filepath);
2908
  DWORD wlen = ExpandEnvironmentStringsW(wfilepath.c_str(), nullptr, 0);
2909
  wchar_t *wstr = new wchar_t[wlen];
2910
  ExpandEnvironmentStringsW(wfilepath.c_str(), wstr, wlen);
2911
2912
  std::wstring ws(wstr);
2913
  delete[] wstr;
2914
  return WcharToUTF8(ws);
2915
2916
#else
2917
2918
#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \
2919
    defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__OpenBSD__)
2920
  // no expansion
2921
  std::string s = filepath;
2922
#else
2923
  std::string s;
2924
  wordexp_t p;
2925
2926
  if (filepath.empty()) {
2927
    return "";
2928
  }
2929
2930
  // Quote the string to keep any spaces in filepath intact.
2931
  std::string quoted_path = "\"" + filepath + "\"";
2932
  // char** w;
2933
  int ret = wordexp(quoted_path.c_str(), &p, 0);
2934
  if (ret) {
2935
    // err
2936
    s = filepath;
2937
    return s;
2938
  }
2939
2940
  // Use first element only.
2941
  if (p.we_wordv) {
2942
    s = std::string(p.we_wordv[0]);
2943
    wordfree(&p);
2944
  } else {
2945
    s = filepath;
2946
  }
2947
2948
#endif
2949
2950
  return s;
2951
#endif
2952
#endif
2953
28.1k
}
2954
2955
bool GetFileSizeInBytes(size_t *filesize_out, std::string *err,
2956
0
                        const std::string &filepath, void *userdata) {
2957
0
  (void)userdata;
2958
2959
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
2960
  if (asset_manager) {
2961
    AAsset *asset = AAssetManager_open(asset_manager, filepath.c_str(),
2962
                                       AASSET_MODE_STREAMING);
2963
    if (!asset) {
2964
      if (err) {
2965
        (*err) += "File open error : " + filepath + "\n";
2966
      }
2967
      return false;
2968
    }
2969
    size_t size = AAsset_getLength(asset);
2970
2971
    if (size == 0) {
2972
      if (err) {
2973
        (*err) += "Invalid file size : " + filepath +
2974
                  " (does the path point to a directory?)";
2975
      }
2976
      return false;
2977
    }
2978
2979
    return true;
2980
  } else {
2981
    if (err) {
2982
      (*err) += "No asset manager specified : " + filepath + "\n";
2983
    }
2984
    return false;
2985
  }
2986
#else
2987
#ifdef _WIN32
2988
#if defined(__GLIBCXX__)  // mingw
2989
  int file_descriptor =
2990
      _wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY);
2991
  __gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
2992
  std::istream f(&wfile_buf);
2993
#elif defined(_MSC_VER) || defined(_LIBCPP_VERSION)
2994
  // For libcxx, assume _LIBCPP_HAS_OPEN_WITH_WCHAR is defined to accept
2995
  // `wchar_t *`
2996
  std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary);
2997
#else
2998
  // Unknown compiler/runtime
2999
  std::ifstream f(filepath.c_str(), std::ifstream::binary);
3000
#endif
3001
#else
3002
0
  std::ifstream f(filepath.c_str(), std::ifstream::binary);
3003
0
#endif
3004
0
  if (!f) {
3005
0
    if (err) {
3006
0
      (*err) += "File open error : " + filepath + "\n";
3007
0
    }
3008
0
    return false;
3009
0
  }
3010
3011
  // For directory(and pipe?), peek() will fail(Posix gnustl/libc++ only)
3012
0
  f.peek();
3013
0
  if (!f) {
3014
0
    if (err) {
3015
0
      (*err) +=
3016
0
          "File read error. Maybe empty file or invalid file : " + filepath +
3017
0
          "\n";
3018
0
    }
3019
0
    return false;
3020
0
  }
3021
3022
0
  f.seekg(0, f.end);
3023
0
  size_t sz = static_cast<size_t>(f.tellg());
3024
3025
  // std::cout << "sz = " << sz << "\n";
3026
0
  f.seekg(0, f.beg);
3027
3028
0
  if (int64_t(sz) < 0) {
3029
0
    if (err) {
3030
0
      (*err) += "Invalid file size : " + filepath +
3031
0
                " (does the path point to a directory?)";
3032
0
    }
3033
0
    return false;
3034
0
  } else if (sz == 0) {
3035
0
    if (err) {
3036
0
      (*err) += "File is empty : " + filepath + "\n";
3037
0
    }
3038
0
    return false;
3039
0
  } else if (sz >= (std::numeric_limits<std::streamoff>::max)()) {
3040
0
    if (err) {
3041
0
      (*err) += "Invalid file size : " + filepath + "\n";
3042
0
    }
3043
0
    return false;
3044
0
  }
3045
3046
0
  (*filesize_out) = sz;
3047
0
  return true;
3048
0
#endif
3049
0
}
3050
3051
bool ReadWholeFile(std::vector<unsigned char> *out, std::string *err,
3052
0
                   const std::string &filepath, void *) {
3053
#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS
3054
  if (asset_manager) {
3055
    AAsset *asset = AAssetManager_open(asset_manager, filepath.c_str(),
3056
                                       AASSET_MODE_STREAMING);
3057
    if (!asset) {
3058
      if (err) {
3059
        (*err) += "File open error : " + filepath + "\n";
3060
      }
3061
      return false;
3062
    }
3063
    size_t size = AAsset_getLength(asset);
3064
    if (size == 0) {
3065
      if (err) {
3066
        (*err) += "Invalid file size : " + filepath +
3067
                  " (does the path point to a directory?)";
3068
      }
3069
      return false;
3070
    }
3071
    out->resize(size);
3072
    AAsset_read(asset, reinterpret_cast<char *>(&out->at(0)), size);
3073
    AAsset_close(asset);
3074
    return true;
3075
  } else {
3076
    if (err) {
3077
      (*err) += "No asset manager specified : " + filepath + "\n";
3078
    }
3079
    return false;
3080
  }
3081
#else
3082
#ifdef _WIN32
3083
#if defined(__GLIBCXX__)  // mingw
3084
  int file_descriptor =
3085
      _wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY);
3086
  __gnu_cxx::stdio_filebuf<char> wfile_buf(file_descriptor, std::ios_base::in);
3087
  std::istream f(&wfile_buf);
3088
#elif defined(_MSC_VER) || defined(_LIBCPP_VERSION)
3089
  // For libcxx, assume _LIBCPP_HAS_OPEN_WITH_WCHAR is defined to accept
3090
  // `wchar_t *`
3091
  std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary);
3092
#else
3093
  // Unknown compiler/runtime
3094
  std::ifstream f(filepath.c_str(), std::ifstream::binary);
3095
#endif
3096
#else
3097
0
  std::ifstream f(filepath.c_str(), std::ifstream::binary);
3098
0
#endif
3099
0
  if (!f) {
3100
0
    if (err) {
3101
0
      (*err) += "File open error : " + filepath + "\n";
3102
0
    }
3103
0
    return false;
3104
0
  }
3105
3106
  // For directory(and pipe?), peek() will fail(Posix gnustl/libc++ only)
3107
0
  f.peek();
3108
0
  if (!f) {
3109
0
    if (err) {
3110
0
      (*err) +=
3111
0
          "File read error. Maybe empty file or invalid file : " + filepath +
3112
0
          "\n";
3113
0
    }
3114
0
    return false;
3115
0
  }
3116
3117
0
  f.seekg(0, f.end);
3118
0
  size_t sz = static_cast<size_t>(f.tellg());
3119
3120
  // std::cout << "sz = " << sz << "\n";
3121
0
  f.seekg(0, f.beg);
3122
3123
0
  if (int64_t(sz) < 0) {
3124
0
    if (err) {
3125
0
      (*err) += "Invalid file size : " + filepath +
3126
0
                " (does the path point to a directory?)";
3127
0
    }
3128
0
    return false;
3129
0
  } else if (sz == 0) {
3130
0
    if (err) {
3131
0
      (*err) += "File is empty : " + filepath + "\n";
3132
0
    }
3133
0
    return false;
3134
0
  } else if (sz >= (std::numeric_limits<std::streamoff>::max)()) {
3135
0
    if (err) {
3136
0
      (*err) += "Invalid file size : " + filepath + "\n";
3137
0
    }
3138
0
    return false;
3139
0
  }
3140
3141
0
  out->resize(sz);
3142
0
  f.read(reinterpret_cast<char *>(&out->at(0)),
3143
0
         static_cast<std::streamsize>(sz));
3144
3145
0
  return true;
3146
0
#endif
3147
0
}
3148
3149
bool WriteWholeFile(std::string *err, const std::string &filepath,
3150
0
                    const std::vector<unsigned char> &contents, void *) {
3151
#ifdef _WIN32
3152
#if defined(__GLIBCXX__)  // mingw
3153
  int file_descriptor = _wopen(UTF8ToWchar(filepath).c_str(),
3154
                               _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY);
3155
  __gnu_cxx::stdio_filebuf<char> wfile_buf(
3156
      file_descriptor, std::ios_base::out | std::ios_base::binary);
3157
  std::ostream f(&wfile_buf);
3158
#elif defined(_MSC_VER)
3159
  std::ofstream f(UTF8ToWchar(filepath).c_str(), std::ofstream::binary);
3160
#else  // clang?
3161
  std::ofstream f(filepath.c_str(), std::ofstream::binary);
3162
#endif
3163
#else
3164
0
  std::ofstream f(filepath.c_str(), std::ofstream::binary);
3165
0
#endif
3166
0
  if (!f) {
3167
0
    if (err) {
3168
0
      (*err) += "File open error for writing : " + filepath + "\n";
3169
0
    }
3170
0
    return false;
3171
0
  }
3172
3173
0
  f.write(reinterpret_cast<const char *>(&contents.at(0)),
3174
0
          static_cast<std::streamsize>(contents.size()));
3175
0
  if (!f) {
3176
0
    if (err) {
3177
0
      (*err) += "File write error: " + filepath + "\n";
3178
0
    }
3179
0
    return false;
3180
0
  }
3181
3182
0
  return true;
3183
0
}
3184
3185
#endif  // TINYGLTF_NO_FS
3186
3187
0
static std::string MimeToExt(const std::string &mimeType) {
3188
0
  if (mimeType == "image/jpeg") {
3189
0
    return "jpg";
3190
0
  } else if (mimeType == "image/png") {
3191
0
    return "png";
3192
0
  } else if (mimeType == "image/bmp") {
3193
0
    return "bmp";
3194
0
  } else if (mimeType == "image/gif") {
3195
0
    return "gif";
3196
0
  }
3197
3198
0
  return "";
3199
0
}
3200
3201
static bool UpdateImageObject(const Image &image, std::string &baseDir,
3202
                              int index, bool embedImages,
3203
                              const URICallbacks *uri_cb,
3204
                              WriteImageDataFunction *WriteImageData,
3205
0
                              void *user_data, std::string *out_uri) {
3206
0
  std::string filename;
3207
0
  std::string ext;
3208
  // If image has uri, use it as a filename
3209
0
  if (image.uri.size()) {
3210
0
    std::string decoded_uri;
3211
0
    if (!uri_cb->decode(image.uri, &decoded_uri, uri_cb->user_data)) {
3212
      // A decode failure results in a failure to write the gltf.
3213
0
      return false;
3214
0
    }
3215
0
    filename = GetBaseFilename(decoded_uri);
3216
0
    ext = GetFilePathExtension(filename);
3217
0
  } else if (image.bufferView != -1) {
3218
    // If there's no URI and the data exists in a buffer,
3219
    // don't change properties or write images
3220
0
  } else if (image.name.size()) {
3221
0
    ext = MimeToExt(image.mimeType);
3222
    // Otherwise use name as filename
3223
0
    filename = image.name + "." + ext;
3224
0
  } else {
3225
0
    ext = MimeToExt(image.mimeType);
3226
    // Fallback to index of image as filename
3227
0
    filename = std::to_string(index) + "." + ext;
3228
0
  }
3229
3230
  // If callback is set and image data exists, modify image data object. If
3231
  // image data does not exist, this is not considered a failure and the
3232
  // original uri should be maintained.
3233
0
  bool imageWritten = false;
3234
0
  if (*WriteImageData != nullptr && !filename.empty() && !image.image.empty()) {
3235
0
    imageWritten = (*WriteImageData)(&baseDir, &filename, &image, embedImages,
3236
0
                                     uri_cb, out_uri, user_data);
3237
0
    if (!imageWritten) {
3238
0
      return false;
3239
0
    }
3240
0
  }
3241
3242
  // Use the original uri if the image was not written.
3243
0
  if (!imageWritten) {
3244
0
    *out_uri = image.uri;
3245
0
  }
3246
3247
0
  return true;
3248
0
}
3249
3250
61.1k
bool IsDataURI(const std::string &in) {
3251
61.1k
  std::string header = "data:application/octet-stream;base64,";
3252
61.1k
  if (in.find(header) == 0) {
3253
506
    return true;
3254
506
  }
3255
3256
60.6k
  header = "data:image/jpeg;base64,";
3257
60.6k
  if (in.find(header) == 0) {
3258
11.0k
    return true;
3259
11.0k
  }
3260
3261
49.6k
  header = "data:image/png;base64,";
3262
49.6k
  if (in.find(header) == 0) {
3263
2.09k
    return true;
3264
2.09k
  }
3265
3266
47.5k
  header = "data:image/bmp;base64,";
3267
47.5k
  if (in.find(header) == 0) {
3268
2.32k
    return true;
3269
2.32k
  }
3270
3271
45.2k
  header = "data:image/gif;base64,";
3272
45.2k
  if (in.find(header) == 0) {
3273
498
    return true;
3274
498
  }
3275
3276
44.7k
  header = "data:text/plain;base64,";
3277
44.7k
  if (in.find(header) == 0) {
3278
1.78k
    return true;
3279
1.78k
  }
3280
3281
42.9k
  header = "data:application/gltf-buffer;base64,";
3282
42.9k
  if (in.find(header) == 0) {
3283
790
    return true;
3284
790
  }
3285
3286
42.1k
  return false;
3287
42.9k
}
3288
3289
bool DecodeDataURI(std::vector<unsigned char> *out, std::string &mime_type,
3290
19.0k
                   const std::string &in, size_t reqBytes, bool checkSize) {
3291
19.0k
  std::string header = "data:application/octet-stream;base64,";
3292
19.0k
  std::string data;
3293
19.0k
  if (in.find(header) == 0) {
3294
506
    data = base64_decode(in.substr(header.size()));  // cut mime string.
3295
506
  }
3296
3297
19.0k
  if (data.empty()) {
3298
18.5k
    header = "data:image/jpeg;base64,";
3299
18.5k
    if (in.find(header) == 0) {
3300
11.0k
      mime_type = "image/jpeg";
3301
11.0k
      data = base64_decode(in.substr(header.size()));  // cut mime string.
3302
11.0k
    }
3303
18.5k
  }
3304
3305
19.0k
  if (data.empty()) {
3306
7.49k
    header = "data:image/png;base64,";
3307
7.49k
    if (in.find(header) == 0) {
3308
2.09k
      mime_type = "image/png";
3309
2.09k
      data = base64_decode(in.substr(header.size()));  // cut mime string.
3310
2.09k
    }
3311
7.49k
  }
3312
3313
19.0k
  if (data.empty()) {
3314
5.41k
    header = "data:image/bmp;base64,";
3315
5.41k
    if (in.find(header) == 0) {
3316
2.32k
      mime_type = "image/bmp";
3317
2.32k
      data = base64_decode(in.substr(header.size()));  // cut mime string.
3318
2.32k
    }
3319
5.41k
  }
3320
3321
19.0k
  if (data.empty()) {
3322
3.09k
    header = "data:image/gif;base64,";
3323
3.09k
    if (in.find(header) == 0) {
3324
498
      mime_type = "image/gif";
3325
498
      data = base64_decode(in.substr(header.size()));  // cut mime string.
3326
498
    }
3327
3.09k
  }
3328
3329
19.0k
  if (data.empty()) {
3330
2.61k
    header = "data:text/plain;base64,";
3331
2.61k
    if (in.find(header) == 0) {
3332
1.78k
      mime_type = "text/plain";
3333
1.78k
      data = base64_decode(in.substr(header.size()));
3334
1.78k
    }
3335
2.61k
  }
3336
3337
19.0k
  if (data.empty()) {
3338
832
    header = "data:application/gltf-buffer;base64,";
3339
832
    if (in.find(header) == 0) {
3340
790
      data = base64_decode(in.substr(header.size()));
3341
790
    }
3342
832
  }
3343
3344
  // TODO(syoyo): Allow empty buffer? #229
3345
19.0k
  if (data.empty()) {
3346
47
    return false;
3347
47
  }
3348
3349
19.0k
  if (checkSize) {
3350
0
    if (data.size() != reqBytes) {
3351
0
      return false;
3352
0
    }
3353
0
    out->resize(reqBytes);
3354
19.0k
  } else {
3355
19.0k
    out->resize(data.size());
3356
19.0k
  }
3357
19.0k
  std::copy(data.begin(), data.end(), out->begin());
3358
19.0k
  return true;
3359
19.0k
}
3360
3361
namespace detail {
3362
589k
bool GetInt(const detail::json &o, int &val) {
3363
#ifdef TINYGLTF_USE_RAPIDJSON
3364
  if (!o.IsDouble()) {
3365
    if (o.IsInt()) {
3366
      val = o.GetInt();
3367
      return true;
3368
    } else if (o.IsUint()) {
3369
      val = static_cast<int>(o.GetUint());
3370
      return true;
3371
    } else if (o.IsInt64()) {
3372
      val = static_cast<int>(o.GetInt64());
3373
      return true;
3374
    } else if (o.IsUint64()) {
3375
      val = static_cast<int>(o.GetUint64());
3376
      return true;
3377
    }
3378
  }
3379
3380
  return false;
3381
#else
3382
589k
  auto type = o.type();
3383
3384
589k
  if ((type == detail::json::value_t::number_integer) ||
3385
589k
      (type == detail::json::value_t::number_unsigned)) {
3386
587k
    val = static_cast<int>(o.get<int64_t>());
3387
587k
    return true;
3388
587k
  }
3389
3390
2.44k
  return false;
3391
589k
#endif
3392
589k
}
3393
3394
#ifdef TINYGLTF_USE_RAPIDJSON
3395
bool GetDouble(const detail::json &o, double &val) {
3396
  if (o.IsDouble()) {
3397
    val = o.GetDouble();
3398
    return true;
3399
  }
3400
3401
  return false;
3402
}
3403
#endif
3404
3405
747k
bool GetNumber(const detail::json &o, double &val) {
3406
#ifdef TINYGLTF_USE_RAPIDJSON
3407
  if (o.IsNumber()) {
3408
    val = o.GetDouble();
3409
    return true;
3410
  }
3411
3412
  return false;
3413
#else
3414
747k
  if (o.is_number()) {
3415
739k
    val = o.get<double>();
3416
739k
    return true;
3417
739k
  }
3418
3419
7.85k
  return false;
3420
747k
#endif
3421
747k
}
3422
3423
365k
bool GetString(const detail::json &o, std::string &val) {
3424
#ifdef TINYGLTF_USE_RAPIDJSON
3425
  if (o.IsString()) {
3426
    val = o.GetString();
3427
    return true;
3428
  }
3429
3430
  return false;
3431
#else
3432
365k
  if (o.type() == detail::json::value_t::string) {
3433
70.1k
    val = o.get<std::string>();
3434
70.1k
    return true;
3435
70.1k
  }
3436
3437
295k
  return false;
3438
365k
#endif
3439
365k
}
3440
3441
29.2k
bool IsArray(const detail::json &o) {
3442
#ifdef TINYGLTF_USE_RAPIDJSON
3443
  return o.IsArray();
3444
#else
3445
29.2k
  return o.is_array();
3446
29.2k
#endif
3447
29.2k
}
3448
3449
14.9k
detail::json_const_array_iterator ArrayBegin(const detail::json &o) {
3450
#ifdef TINYGLTF_USE_RAPIDJSON
3451
  return o.Begin();
3452
#else
3453
14.9k
  return o.begin();
3454
14.9k
#endif
3455
14.9k
}
3456
3457
14.9k
detail::json_const_array_iterator ArrayEnd(const detail::json &o) {
3458
#ifdef TINYGLTF_USE_RAPIDJSON
3459
  return o.End();
3460
#else
3461
14.9k
  return o.end();
3462
14.9k
#endif
3463
14.9k
}
3464
3465
1.30M
bool IsObject(const detail::json &o) {
3466
#ifdef TINYGLTF_USE_RAPIDJSON
3467
  return o.IsObject();
3468
#else
3469
1.30M
  return o.is_object();
3470
1.30M
#endif
3471
1.30M
}
3472
3473
363k
detail::json_const_iterator ObjectBegin(const detail::json &o) {
3474
#ifdef TINYGLTF_USE_RAPIDJSON
3475
  return o.MemberBegin();
3476
#else
3477
363k
  return o.begin();
3478
363k
#endif
3479
363k
}
3480
3481
363k
detail::json_const_iterator ObjectEnd(const detail::json &o) {
3482
#ifdef TINYGLTF_USE_RAPIDJSON
3483
  return o.MemberEnd();
3484
#else
3485
363k
  return o.end();
3486
363k
#endif
3487
363k
}
3488
3489
// Making this a const char* results in a pointer to a temporary when
3490
// TINYGLTF_USE_RAPIDJSON is off.
3491
89.7k
std::string GetKey(detail::json_const_iterator &it) {
3492
#ifdef TINYGLTF_USE_RAPIDJSON
3493
  return it->name.GetString();
3494
#else
3495
89.7k
  return it.key().c_str();
3496
89.7k
#endif
3497
89.7k
}
3498
3499
bool FindMember(const detail::json &o, const char *member,
3500
14.1M
                detail::json_const_iterator &it) {
3501
#ifdef TINYGLTF_USE_RAPIDJSON
3502
  if (!o.IsObject()) {
3503
    return false;
3504
  }
3505
  it = o.FindMember(member);
3506
  return it != o.MemberEnd();
3507
#else
3508
14.1M
  it = o.find(member);
3509
14.1M
  return it != o.end();
3510
14.1M
#endif
3511
14.1M
}
3512
3513
bool FindMember(detail::json &o, const char *member,
3514
0
                detail::json_iterator &it) {
3515
#ifdef TINYGLTF_USE_RAPIDJSON
3516
  if (!o.IsObject()) {
3517
    return false;
3518
  }
3519
  it = o.FindMember(member);
3520
  return it != o.MemberEnd();
3521
#else
3522
0
  it = o.find(member);
3523
0
  return it != o.end();
3524
0
#endif
3525
0
}
3526
3527
0
void Erase(detail::json &o, detail::json_iterator &it) {
3528
#ifdef TINYGLTF_USE_RAPIDJSON
3529
  o.EraseMember(it);
3530
#else
3531
0
  o.erase(it);
3532
0
#endif
3533
0
}
3534
3535
0
bool IsEmpty(const detail::json &o) {
3536
#ifdef TINYGLTF_USE_RAPIDJSON
3537
  return o.ObjectEmpty();
3538
#else
3539
0
  return o.empty();
3540
0
#endif
3541
0
}
3542
3543
255k
const detail::json &GetValue(detail::json_const_iterator &it) {
3544
#ifdef TINYGLTF_USE_RAPIDJSON
3545
  return it->value;
3546
#else
3547
255k
  return it.value();
3548
255k
#endif
3549
255k
}
3550
3551
0
detail::json &GetValue(detail::json_iterator &it) {
3552
#ifdef TINYGLTF_USE_RAPIDJSON
3553
  return it->value;
3554
#else
3555
0
  return it.value();
3556
0
#endif
3557
0
}
3558
3559
0
std::string JsonToString(const detail::json &o, int spacing = -1) {
3560
#ifdef TINYGLTF_USE_RAPIDJSON
3561
  using namespace rapidjson;
3562
  StringBuffer buffer;
3563
  if (spacing == -1) {
3564
    Writer<StringBuffer> writer(buffer);
3565
    // TODO: Better error handling.
3566
    // https://github.com/syoyo/tinygltf/issues/332
3567
    if (!o.Accept(writer)) {
3568
      return "tiny_gltf::JsonToString() failed rapidjson conversion";
3569
    }
3570
  } else {
3571
    PrettyWriter<StringBuffer> writer(buffer);
3572
    writer.SetIndent(' ', uint32_t(spacing));
3573
    if (!o.Accept(writer)) {
3574
      return "tiny_gltf::JsonToString() failed rapidjson conversion";
3575
    }
3576
  }
3577
  return buffer.GetString();
3578
#else
3579
0
  return o.dump(spacing);
3580
0
#endif
3581
0
}
3582
3583
}  // namespace detail
3584
3585
842k
static bool ParseJsonAsValue(Value *ret, const detail::json &o) {
3586
842k
  Value val{};
3587
#ifdef TINYGLTF_USE_RAPIDJSON
3588
  using rapidjson::Type;
3589
  switch (o.GetType()) {
3590
    case Type::kObjectType: {
3591
      Value::Object value_object;
3592
      for (auto it = o.MemberBegin(); it != o.MemberEnd(); ++it) {
3593
        Value entry;
3594
        ParseJsonAsValue(&entry, it->value);
3595
        if (entry.Type() != NULL_TYPE)
3596
          value_object.emplace(detail::GetKey(it), std::move(entry));
3597
      }
3598
      if (value_object.size() > 0) val = Value(std::move(value_object));
3599
    } break;
3600
    case Type::kArrayType: {
3601
      Value::Array value_array;
3602
      value_array.reserve(o.Size());
3603
      for (auto it = o.Begin(); it != o.End(); ++it) {
3604
        Value entry;
3605
        ParseJsonAsValue(&entry, *it);
3606
        if (entry.Type() != NULL_TYPE)
3607
          value_array.emplace_back(std::move(entry));
3608
      }
3609
      if (value_array.size() > 0) val = Value(std::move(value_array));
3610
    } break;
3611
    case Type::kStringType:
3612
      val = Value(std::string(o.GetString()));
3613
      break;
3614
    case Type::kFalseType:
3615
    case Type::kTrueType:
3616
      val = Value(o.GetBool());
3617
      break;
3618
    case Type::kNumberType:
3619
      if (!o.IsDouble()) {
3620
        int i = 0;
3621
        detail::GetInt(o, i);
3622
        val = Value(i);
3623
      } else {
3624
        double d = 0.0;
3625
        detail::GetDouble(o, d);
3626
        val = Value(d);
3627
      }
3628
      break;
3629
    case Type::kNullType:
3630
      break;
3631
      // all types are covered, so no `case default`
3632
  }
3633
#else
3634
842k
  switch (o.type()) {
3635
22.4k
    case detail::json::value_t::object: {
3636
22.4k
      Value::Object value_object;
3637
40.7k
      for (auto it = o.begin(); it != o.end(); it++) {
3638
18.2k
        Value entry;
3639
18.2k
        ParseJsonAsValue(&entry, it.value());
3640
18.2k
        if (entry.Type() != NULL_TYPE)
3641
13.2k
          value_object.emplace(it.key(), std::move(entry));
3642
18.2k
      }
3643
22.4k
      if (value_object.size() > 0) val = Value(std::move(value_object));
3644
22.4k
    } break;
3645
36.8k
    case detail::json::value_t::array: {
3646
36.8k
      Value::Array value_array;
3647
36.8k
      value_array.reserve(o.size());
3648
846k
      for (auto it = o.begin(); it != o.end(); it++) {
3649
809k
        Value entry;
3650
809k
        ParseJsonAsValue(&entry, it.value());
3651
809k
        if (entry.Type() != NULL_TYPE)
3652
773k
          value_array.emplace_back(std::move(entry));
3653
809k
      }
3654
36.8k
      if (value_array.size() > 0) val = Value(std::move(value_array));
3655
36.8k
    } break;
3656
2.90k
    case detail::json::value_t::string:
3657
2.90k
      val = Value(o.get<std::string>());
3658
2.90k
      break;
3659
198
    case detail::json::value_t::boolean:
3660
198
      val = Value(o.get<bool>());
3661
198
      break;
3662
2.83k
    case detail::json::value_t::number_integer:
3663
775k
    case detail::json::value_t::number_unsigned:
3664
775k
      val = Value(static_cast<int>(o.get<int64_t>()));
3665
775k
      break;
3666
4.56k
    case detail::json::value_t::number_float:
3667
4.56k
      val = Value(o.get<double>());
3668
4.56k
      break;
3669
167
    case detail::json::value_t::null:
3670
167
    case detail::json::value_t::discarded:
3671
167
    case detail::json::value_t::binary:
3672
      // default:
3673
167
      break;
3674
842k
  }
3675
842k
#endif
3676
842k
  const bool isNotNull = val.Type() != NULL_TYPE;
3677
3678
842k
  if (ret) *ret = std::move(val);
3679
3680
842k
  return isNotNull;
3681
842k
}
3682
3683
2.00M
static bool ParseExtrasProperty(Value *ret, const detail::json &o) {
3684
2.00M
  detail::json_const_iterator it;
3685
2.00M
  if (!detail::FindMember(o, "extras", it)) {
3686
2.00M
    return false;
3687
2.00M
  }
3688
3689
2.22k
  return ParseJsonAsValue(ret, detail::GetValue(it));
3690
2.00M
}
3691
3692
static bool ParseBooleanProperty(bool *ret, std::string *err,
3693
                                 const detail::json &o,
3694
                                 const std::string &property,
3695
                                 const bool required,
3696
313k
                                 const std::string &parent_node = "") {
3697
313k
  detail::json_const_iterator it;
3698
313k
  if (!detail::FindMember(o, property.c_str(), it)) {
3699
312k
    if (required) {
3700
0
      if (err) {
3701
0
        (*err) += "'" + property + "' property is missing";
3702
0
        if (!parent_node.empty()) {
3703
0
          (*err) += " in " + parent_node;
3704
0
        }
3705
0
        (*err) += ".\n";
3706
0
      }
3707
0
    }
3708
312k
    return false;
3709
312k
  }
3710
3711
917
  auto &value = detail::GetValue(it);
3712
3713
917
  bool isBoolean;
3714
917
  bool boolValue = false;
3715
#ifdef TINYGLTF_USE_RAPIDJSON
3716
  isBoolean = value.IsBool();
3717
  if (isBoolean) {
3718
    boolValue = value.GetBool();
3719
  }
3720
#else
3721
917
  isBoolean = value.is_boolean();
3722
917
  if (isBoolean) {
3723
287
    boolValue = value.get<bool>();
3724
287
  }
3725
917
#endif
3726
917
  if (!isBoolean) {
3727
630
    if (required) {
3728
0
      if (err) {
3729
0
        (*err) += "'" + property + "' property is not a bool type.\n";
3730
0
      }
3731
0
    }
3732
630
    return false;
3733
630
  }
3734
3735
287
  if (ret) {
3736
287
    (*ret) = boolValue;
3737
287
  }
3738
3739
287
  return true;
3740
917
}
3741
3742
static bool ParseIntegerProperty(int *ret, std::string *err,
3743
                                 const detail::json &o,
3744
                                 const std::string &property,
3745
                                 const bool required,
3746
2.46M
                                 const std::string &parent_node = "") {
3747
2.46M
  detail::json_const_iterator it;
3748
2.46M
  if (!detail::FindMember(o, property.c_str(), it)) {
3749
2.45M
    if (required) {
3750
774k
      if (err) {
3751
774k
        (*err) += "'" + property + "' property is missing";
3752
774k
        if (!parent_node.empty()) {
3753
5.68k
          (*err) += " in " + parent_node;
3754
5.68k
        }
3755
774k
        (*err) += ".\n";
3756
774k
      }
3757
774k
    }
3758
2.45M
    return false;
3759
2.45M
  }
3760
3761
3.22k
  int intValue;
3762
3.22k
  bool isInt = detail::GetInt(detail::GetValue(it), intValue);
3763
3.22k
  if (!isInt) {
3764
171
    if (required) {
3765
171
      if (err) {
3766
171
        (*err) += "'" + property + "' property is not an integer type.\n";
3767
171
      }
3768
171
    }
3769
171
    return false;
3770
171
  }
3771
3772
3.04k
  if (ret) {
3773
3.04k
    (*ret) = intValue;
3774
3.04k
  }
3775
3776
3.04k
  return true;
3777
3.22k
}
3778
3779
static bool ParseUnsignedProperty(size_t *ret, std::string *err,
3780
                                  const detail::json &o,
3781
                                  const std::string &property,
3782
                                  const bool required,
3783
0
                                  const std::string &parent_node = "") {
3784
0
  detail::json_const_iterator it;
3785
0
  if (!detail::FindMember(o, property.c_str(), it)) {
3786
0
    if (required) {
3787
0
      if (err) {
3788
0
        (*err) += "'" + property + "' property is missing";
3789
0
        if (!parent_node.empty()) {
3790
0
          (*err) += " in " + parent_node;
3791
0
        }
3792
0
        (*err) += ".\n";
3793
0
      }
3794
0
    }
3795
0
    return false;
3796
0
  }
3797
3798
0
  auto &value = detail::GetValue(it);
3799
3800
0
  size_t uValue = 0;
3801
0
  bool isUValue;
3802
#ifdef TINYGLTF_USE_RAPIDJSON
3803
  isUValue = false;
3804
  if (value.IsUint()) {
3805
    uValue = value.GetUint();
3806
    isUValue = true;
3807
  } else if (value.IsUint64()) {
3808
    uValue = value.GetUint64();
3809
    isUValue = true;
3810
  }
3811
#else
3812
0
  isUValue = value.is_number_unsigned();
3813
0
  if (isUValue) {
3814
0
    uValue = value.get<size_t>();
3815
0
  }
3816
0
#endif
3817
0
  if (!isUValue) {
3818
0
    if (required) {
3819
0
      if (err) {
3820
0
        (*err) += "'" + property + "' property is not a positive integer.\n";
3821
0
      }
3822
0
    }
3823
0
    return false;
3824
0
  }
3825
3826
0
  if (ret) {
3827
0
    (*ret) = uValue;
3828
0
  }
3829
3830
0
  return true;
3831
0
}
3832
3833
static bool ParseNumberProperty(double *ret, std::string *err,
3834
                                const detail::json &o,
3835
                                const std::string &property,
3836
                                const bool required,
3837
330k
                                const std::string &parent_node = "") {
3838
330k
  detail::json_const_iterator it;
3839
3840
330k
  if (!detail::FindMember(o, property.c_str(), it)) {
3841
316k
    if (required) {
3842
0
      if (err) {
3843
0
        (*err) += "'" + property + "' property is missing";
3844
0
        if (!parent_node.empty()) {
3845
0
          (*err) += " in " + parent_node;
3846
0
        }
3847
0
        (*err) += ".\n";
3848
0
      }
3849
0
    }
3850
316k
    return false;
3851
316k
  }
3852
3853
14.0k
  double numberValue;
3854
14.0k
  bool isNumber = detail::GetNumber(detail::GetValue(it), numberValue);
3855
3856
14.0k
  if (!isNumber) {
3857
6.08k
    if (required) {
3858
0
      if (err) {
3859
0
        (*err) += "'" + property + "' property is not a number type.\n";
3860
0
      }
3861
0
    }
3862
6.08k
    return false;
3863
6.08k
  }
3864
3865
7.94k
  if (ret) {
3866
7.94k
    (*ret) = numberValue;
3867
7.94k
  }
3868
3869
7.94k
  return true;
3870
14.0k
}
3871
3872
static bool ParseNumberArrayProperty(std::vector<double> *ret, std::string *err,
3873
                                     const detail::json &o,
3874
                                     const std::string &property, bool required,
3875
969k
                                     const std::string &parent_node = "") {
3876
969k
  detail::json_const_iterator it;
3877
969k
  if (!detail::FindMember(o, property.c_str(), it)) {
3878
952k
    if (required) {
3879
0
      if (err) {
3880
0
        (*err) += "'" + property + "' property is missing";
3881
0
        if (!parent_node.empty()) {
3882
0
          (*err) += " in " + parent_node;
3883
0
        }
3884
0
        (*err) += ".\n";
3885
0
      }
3886
0
    }
3887
952k
    return false;
3888
952k
  }
3889
3890
16.7k
  if (!detail::IsArray(detail::GetValue(it))) {
3891
13.4k
    if (required) {
3892
0
      if (err) {
3893
0
        (*err) += "'" + property + "' property is not an array";
3894
0
        if (!parent_node.empty()) {
3895
0
          (*err) += " in " + parent_node;
3896
0
        }
3897
0
        (*err) += ".\n";
3898
0
      }
3899
0
    }
3900
13.4k
    return false;
3901
13.4k
  }
3902
3903
3.39k
  ret->clear();
3904
3.39k
  auto end = detail::ArrayEnd(detail::GetValue(it));
3905
731k
  for (auto i = detail::ArrayBegin(detail::GetValue(it)); i != end; ++i) {
3906
729k
    double numberValue;
3907
729k
    const bool isNumber = detail::GetNumber(*i, numberValue);
3908
729k
    if (!isNumber) {
3909
1.01k
      if (required) {
3910
0
        if (err) {
3911
0
          (*err) += "'" + property + "' property is not a number.\n";
3912
0
          if (!parent_node.empty()) {
3913
0
            (*err) += " in " + parent_node;
3914
0
          }
3915
0
          (*err) += ".\n";
3916
0
        }
3917
0
      }
3918
1.01k
      return false;
3919
1.01k
    }
3920
728k
    ret->push_back(numberValue);
3921
728k
  }
3922
3923
2.38k
  return true;
3924
3.39k
}
3925
3926
static bool ParseIntegerArrayProperty(std::vector<int> *ret, std::string *err,
3927
                                      const detail::json &o,
3928
                                      const std::string &property,
3929
                                      bool required,
3930
141k
                                      const std::string &parent_node = "") {
3931
141k
  detail::json_const_iterator it;
3932
141k
  if (!detail::FindMember(o, property.c_str(), it)) {
3933
139k
    if (required) {
3934
0
      if (err) {
3935
0
        (*err) += "'" + property + "' property is missing";
3936
0
        if (!parent_node.empty()) {
3937
0
          (*err) += " in " + parent_node;
3938
0
        }
3939
0
        (*err) += ".\n";
3940
0
      }
3941
0
    }
3942
139k
    return false;
3943
139k
  }
3944
3945
1.85k
  if (!detail::IsArray(detail::GetValue(it))) {
3946
164
    if (required) {
3947
0
      if (err) {
3948
0
        (*err) += "'" + property + "' property is not an array";
3949
0
        if (!parent_node.empty()) {
3950
0
          (*err) += " in " + parent_node;
3951
0
        }
3952
0
        (*err) += ".\n";
3953
0
      }
3954
0
    }
3955
164
    return false;
3956
164
  }
3957
3958
1.69k
  ret->clear();
3959
1.69k
  auto end = detail::ArrayEnd(detail::GetValue(it));
3960
542k
  for (auto i = detail::ArrayBegin(detail::GetValue(it)); i != end; ++i) {
3961
541k
    int numberValue;
3962
541k
    bool isNumber = detail::GetInt(*i, numberValue);
3963
541k
    if (!isNumber) {
3964
1.25k
      if (required) {
3965
0
        if (err) {
3966
0
          (*err) += "'" + property + "' property is not an integer type.\n";
3967
0
          if (!parent_node.empty()) {
3968
0
            (*err) += " in " + parent_node;
3969
0
          }
3970
0
          (*err) += ".\n";
3971
0
        }
3972
0
      }
3973
1.25k
      return false;
3974
1.25k
    }
3975
540k
    ret->push_back(numberValue);
3976
540k
  }
3977
3978
436
  return true;
3979
1.69k
}
3980
3981
static bool ParseStringProperty(
3982
    std::string *ret, std::string *err, const detail::json &o,
3983
    const std::string &property, bool required,
3984
4.24M
    const std::string &parent_node = std::string()) {
3985
4.24M
  detail::json_const_iterator it;
3986
4.24M
  if (!detail::FindMember(o, property.c_str(), it)) {
3987
4.15M
    if (required) {
3988
768k
      if (err) {
3989
768k
        (*err) += "'" + property + "' property is missing";
3990
768k
        if (parent_node.empty()) {
3991
768k
          (*err) += ".\n";
3992
768k
        } else {
3993
0
          (*err) += " in `" + parent_node + "'.\n";
3994
0
        }
3995
768k
      }
3996
768k
    }
3997
4.15M
    return false;
3998
4.15M
  }
3999
4000
84.0k
  std::string strValue;
4001
84.0k
  if (!detail::GetString(detail::GetValue(it), strValue)) {
4002
15.8k
    if (required) {
4003
169
      if (err) {
4004
169
        (*err) += "'" + property + "' property is not a string type.\n";
4005
169
      }
4006
169
    }
4007
15.8k
    return false;
4008
15.8k
  }
4009
4010
68.1k
  if (ret) {
4011
68.1k
    (*ret) = std::move(strValue);
4012
68.1k
  }
4013
4014
68.1k
  return true;
4015
84.0k
}
4016
4017
static bool ParseStringIntegerProperty(std::map<std::string, int> *ret,
4018
                                       std::string *err, const detail::json &o,
4019
                                       const std::string &property,
4020
                                       bool required,
4021
4.09k
                                       const std::string &parent = "") {
4022
4.09k
  detail::json_const_iterator it;
4023
4.09k
  if (!detail::FindMember(o, property.c_str(), it)) {
4024
390
    if (required) {
4025
390
      if (err) {
4026
390
        if (!parent.empty()) {
4027
390
          (*err) +=
4028
390
              "'" + property + "' property is missing in " + parent + ".\n";
4029
390
        } else {
4030
0
          (*err) += "'" + property + "' property is missing.\n";
4031
0
        }
4032
390
      }
4033
390
    }
4034
390
    return false;
4035
390
  }
4036
4037
3.70k
  const detail::json &dict = detail::GetValue(it);
4038
4039
  // Make sure we are dealing with an object / dictionary.
4040
3.70k
  if (!detail::IsObject(dict)) {
4041
134
    if (required) {
4042
134
      if (err) {
4043
134
        (*err) += "'" + property + "' property is not an object.\n";
4044
134
      }
4045
134
    }
4046
134
    return false;
4047
134
  }
4048
4049
3.56k
  ret->clear();
4050
4051
3.56k
  detail::json_const_iterator dictIt(detail::ObjectBegin(dict));
4052
3.56k
  detail::json_const_iterator dictItEnd(detail::ObjectEnd(dict));
4053
4054
8.39k
  for (; dictIt != dictItEnd; ++dictIt) {
4055
5.04k
    int intVal;
4056
5.04k
    if (!detail::GetInt(detail::GetValue(dictIt), intVal)) {
4057
218
      if (required) {
4058
218
        if (err) {
4059
218
          (*err) += "'" + property + "' value is not an integer type.\n";
4060
218
        }
4061
218
      }
4062
218
      return false;
4063
218
    }
4064
4065
    // Insert into the list.
4066
4.82k
    (*ret)[detail::GetKey(dictIt)] = intVal;
4067
4.82k
  }
4068
3.34k
  return true;
4069
3.56k
}
4070
4071
static bool ParseJSONProperty(std::map<std::string, double> *ret,
4072
                              std::string *err, const detail::json &o,
4073
6.41k
                              const std::string &property, bool required) {
4074
6.41k
  detail::json_const_iterator it;
4075
6.41k
  if (!detail::FindMember(o, property.c_str(), it)) {
4076
329
    if (required) {
4077
0
      if (err) {
4078
0
        (*err) += "'" + property + "' property is missing. \n'";
4079
0
      }
4080
0
    }
4081
329
    return false;
4082
329
  }
4083
4084
6.08k
  const detail::json &obj = detail::GetValue(it);
4085
4086
6.08k
  if (!detail::IsObject(obj)) {
4087
894
    if (required) {
4088
0
      if (err) {
4089
0
        (*err) += "'" + property + "' property is not a JSON object.\n";
4090
0
      }
4091
0
    }
4092
894
    return false;
4093
894
  }
4094
4095
5.19k
  ret->clear();
4096
4097
5.19k
  detail::json_const_iterator it2(detail::ObjectBegin(obj));
4098
5.19k
  detail::json_const_iterator itEnd(detail::ObjectEnd(obj));
4099
8.93k
  for (; it2 != itEnd; ++it2) {
4100
3.74k
    double numVal;
4101
3.74k
    if (detail::GetNumber(detail::GetValue(it2), numVal))
4102
2.99k
      ret->emplace(std::string(detail::GetKey(it2)), numVal);
4103
3.74k
  }
4104
4105
5.19k
  return true;
4106
6.08k
}
4107
4108
static bool ParseParameterProperty(Parameter *param, std::string *err,
4109
                                   const detail::json &o,
4110
17.5k
                                   const std::string &prop, bool required) {
4111
  // A parameter value can either be a string or an array of either a boolean or
4112
  // a number. Booleans of any kind aren't supported here. Granted, it
4113
  // complicates the Parameter structure and breaks it semantically in the sense
4114
  // that the client probably works off the assumption that if the string is
4115
  // empty the vector is used, etc. Would a tagged union work?
4116
17.5k
  if (ParseStringProperty(&param->string_value, err, o, prop, false)) {
4117
    // Found string property.
4118
1.46k
    return true;
4119
16.0k
  } else if (ParseNumberArrayProperty(&param->number_array, err, o, prop,
4120
16.0k
                                      false)) {
4121
    // Found a number array.
4122
1.69k
    return true;
4123
14.3k
  } else if (ParseNumberProperty(&param->number_value, err, o, prop, false)) {
4124
7.94k
    param->has_number_value = true;
4125
7.94k
    return true;
4126
7.94k
  } else if (ParseJSONProperty(&param->json_double_value, err, o, prop,
4127
6.41k
                               false)) {
4128
5.19k
    return true;
4129
5.19k
  } else if (ParseBooleanProperty(&param->bool_value, err, o, prop, false)) {
4130
264
    return true;
4131
959
  } else {
4132
959
    if (required) {
4133
0
      if (err) {
4134
0
        (*err) += "parameter must be a string or number / number array.\n";
4135
0
      }
4136
0
    }
4137
959
    return false;
4138
959
  }
4139
17.5k
}
4140
4141
static bool ParseExtensionsProperty(ExtensionMap *ret, std::string *err,
4142
2.00M
                                    const detail::json &o) {
4143
2.00M
  (void)err;
4144
4145
2.00M
  detail::json_const_iterator it;
4146
2.00M
  if (!detail::FindMember(o, "extensions", it)) {
4147
2.00M
    return false;
4148
2.00M
  }
4149
4150
5.77k
  auto &obj = detail::GetValue(it);
4151
5.77k
  if (!detail::IsObject(obj)) {
4152
264
    return false;
4153
264
  }
4154
5.50k
  ExtensionMap extensions;
4155
5.50k
  detail::json_const_iterator extIt =
4156
5.50k
      detail::ObjectBegin(obj);  // it.value().begin();
4157
5.50k
  detail::json_const_iterator extEnd = detail::ObjectEnd(obj);
4158
19.6k
  for (; extIt != extEnd; ++extIt) {
4159
14.1k
    auto &itObj = detail::GetValue(extIt);
4160
14.1k
    if (!detail::IsObject(itObj)) continue;
4161
12.2k
    std::string key(detail::GetKey(extIt));
4162
12.2k
    if (!ParseJsonAsValue(&extensions[key], itObj)) {
4163
9.56k
      if (!key.empty()) {
4164
        // create empty object so that an extension object is still of type
4165
        // object
4166
7.69k
        extensions[key] = Value{Value::Object{}};
4167
7.69k
      }
4168
9.56k
    }
4169
12.2k
  }
4170
5.50k
  if (ret) {
4171
5.50k
    (*ret) = std::move(extensions);
4172
5.50k
  }
4173
5.50k
  return true;
4174
5.77k
}
4175
4176
template <typename GltfType>
4177
static bool ParseExtrasAndExtensions(GltfType *target, std::string *err,
4178
                                     const detail::json &o,
4179
2.00M
                                     bool store_json_strings) {
4180
2.00M
  ParseExtensionsProperty(&target->extensions, err, o);
4181
2.00M
  ParseExtrasProperty(&target->extras, o);
4182
4183
2.00M
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
2.00M
  return true;
4199
2.00M
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Asset>(tinygltf::Asset*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
1.59k
                                     bool store_json_strings) {
4180
1.59k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
1.59k
  ParseExtrasProperty(&target->extras, o);
4182
4183
1.59k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
1.59k
  return true;
4199
1.59k
}
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::SpotLight>(tinygltf::SpotLight*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Light>(tinygltf::Light*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::PositionalEmitter>(tinygltf::PositionalEmitter*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::AudioEmitter>(tinygltf::AudioEmitter*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::AudioSource>(tinygltf::AudioSource*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
769k
                                     bool store_json_strings) {
4180
769k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
769k
  ParseExtrasProperty(&target->extras, o);
4182
4183
769k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
769k
  return true;
4199
769k
}
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Buffer>(tinygltf::Buffer*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::BufferView>(tinygltf::BufferView*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Accessor>(tinygltf::Accessor*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Accessor::Sparse>(tinygltf::Accessor::Sparse*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Accessor::Sparse::{unnamed type#1}>(tinygltf::Accessor::Sparse::{unnamed type#1}*, std::__1::basic_string<char, tinygltf::Accessor::Sparse::{unnamed type#1}*::char_traits<char>, tinygltf::Accessor::Sparse::{unnamed type#1}*::allocator<char> >*, nlohmann::basic_json<tinygltf::Accessor::Sparse::{unnamed type#1}*::map, tinygltf::Accessor::Sparse::{unnamed type#1}*::vector, tinygltf::Accessor::Sparse::{unnamed type#1}*::allocator<char>, bool, long, unsigned long, double, tinygltf::Accessor::Sparse::{unnamed type#1}*::char_traits<char>, std::__1::basic_string<char, tinygltf::Accessor::Sparse::{unnamed type#1}*::char_traits<char>, tinygltf::Accessor::Sparse::{unnamed type#1}*::allocator<char> >*::adl_serializer, tinygltf::Accessor::Sparse::{unnamed type#1}*::map<unsigned char, tinygltf::Accessor::Sparse::{unnamed type#1}*::char_traits<char><unsigned char> > > const&, bool)
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Accessor::Sparse::{unnamed type#2}>(tinygltf::Accessor::Sparse::{unnamed type#2}*, std::__1::basic_string<char, tinygltf::Accessor::Sparse::{unnamed type#2}*::char_traits<char>, tinygltf::Accessor::Sparse::{unnamed type#2}*::allocator<char> >*, nlohmann::basic_json<tinygltf::Accessor::Sparse::{unnamed type#2}*::map, tinygltf::Accessor::Sparse::{unnamed type#2}*::vector, tinygltf::Accessor::Sparse::{unnamed type#2}*::allocator<char>, bool, long, unsigned long, double, tinygltf::Accessor::Sparse::{unnamed type#2}*::char_traits<char>, std::__1::basic_string<char, tinygltf::Accessor::Sparse::{unnamed type#2}*::char_traits<char>, tinygltf::Accessor::Sparse::{unnamed type#2}*::allocator<char> >*::adl_serializer, tinygltf::Accessor::Sparse::{unnamed type#2}*::map<unsigned char, tinygltf::Accessor::Sparse::{unnamed type#2}*::char_traits<char><unsigned char> > > const&, bool)
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Primitive>(tinygltf::Primitive*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
3.34k
                                     bool store_json_strings) {
4180
3.34k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
3.34k
  ParseExtrasProperty(&target->extras, o);
4182
4183
3.34k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
3.34k
  return true;
4199
3.34k
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Mesh>(tinygltf::Mesh*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
272k
                                     bool store_json_strings) {
4180
272k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
272k
  ParseExtrasProperty(&target->extras, o);
4182
4183
272k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
272k
  return true;
4199
272k
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Node>(tinygltf::Node*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
73.4k
                                     bool store_json_strings) {
4180
73.4k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
73.4k
  ParseExtrasProperty(&target->extras, o);
4182
4183
73.4k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
73.4k
  return true;
4199
73.4k
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Scene>(tinygltf::Scene*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
67.7k
                                     bool store_json_strings) {
4180
67.7k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
67.7k
  ParseExtrasProperty(&target->extras, o);
4182
4183
67.7k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
67.7k
  return true;
4199
67.7k
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::PbrMetallicRoughness>(tinygltf::PbrMetallicRoughness*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
1.72k
                                     bool store_json_strings) {
4180
1.72k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
1.72k
  ParseExtrasProperty(&target->extras, o);
4182
4183
1.72k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
1.72k
  return true;
4199
1.72k
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::NormalTextureInfo>(tinygltf::NormalTextureInfo*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
347
                                     bool store_json_strings) {
4180
347
  ParseExtensionsProperty(&target->extensions, err, o);
4181
347
  ParseExtrasProperty(&target->extras, o);
4182
4183
347
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
347
  return true;
4199
347
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::OcclusionTextureInfo>(tinygltf::OcclusionTextureInfo*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
308
                                     bool store_json_strings) {
4180
308
  ParseExtensionsProperty(&target->extensions, err, o);
4181
308
  ParseExtrasProperty(&target->extras, o);
4182
4183
308
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
308
  return true;
4199
308
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::TextureInfo>(tinygltf::TextureInfo*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
161
                                     bool store_json_strings) {
4180
161
  ParseExtensionsProperty(&target->extensions, err, o);
4181
161
  ParseExtrasProperty(&target->extras, o);
4182
4183
161
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
161
  return true;
4199
161
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Material>(tinygltf::Material*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
311k
                                     bool store_json_strings) {
4180
311k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
311k
  ParseExtrasProperty(&target->extras, o);
4182
4183
311k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
311k
  return true;
4199
311k
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Image>(tinygltf::Image*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
61.1k
                                     bool store_json_strings) {
4180
61.1k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
61.1k
  ParseExtrasProperty(&target->extras, o);
4182
4183
61.1k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
61.1k
  return true;
4199
61.1k
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Texture>(tinygltf::Texture*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
135k
                                     bool store_json_strings) {
4180
135k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
135k
  ParseExtrasProperty(&target->extras, o);
4182
4183
135k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
135k
  return true;
4199
135k
}
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::AnimationChannel>(tinygltf::AnimationChannel*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
2.07k
                                     bool store_json_strings) {
4180
2.07k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
2.07k
  ParseExtrasProperty(&target->extras, o);
4182
4183
2.07k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
2.07k
  return true;
4199
2.07k
}
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::AnimationSampler>(tinygltf::AnimationSampler*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Animation>(tinygltf::Animation*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
11.1k
                                     bool store_json_strings) {
4180
11.1k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
11.1k
  ParseExtrasProperty(&target->extras, o);
4182
4183
11.1k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
11.1k
  return true;
4199
11.1k
}
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Skin>(tinygltf::Skin*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Sampler>(tinygltf::Sampler*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
294k
                                     bool store_json_strings) {
4180
294k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
294k
  ParseExtrasProperty(&target->extras, o);
4182
4183
294k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
294k
  return true;
4199
294k
}
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::OrthographicCamera>(tinygltf::OrthographicCamera*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::PerspectiveCamera>(tinygltf::PerspectiveCamera*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Unexecuted instantiation: fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Camera>(tinygltf::Camera*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
fuzz_gltf.cc:bool tinygltf::ParseExtrasAndExtensions<tinygltf::Model>(tinygltf::Model*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*, nlohmann::basic_json<std::__1::map, std::__1::vector, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool, long, unsigned long, double, std::__1::allocator, nlohmann::adl_serializer, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > > const&, bool)
Line
Count
Source
4179
1.14k
                                     bool store_json_strings) {
4180
1.14k
  ParseExtensionsProperty(&target->extensions, err, o);
4181
1.14k
  ParseExtrasProperty(&target->extras, o);
4182
4183
1.14k
  if (store_json_strings) {
4184
0
    {
4185
0
      detail::json_const_iterator it;
4186
0
      if (detail::FindMember(o, "extensions", it)) {
4187
0
        target->extensions_json_string =
4188
0
            detail::JsonToString(detail::GetValue(it));
4189
0
      }
4190
0
    }
4191
0
    {
4192
0
      detail::json_const_iterator it;
4193
0
      if (detail::FindMember(o, "extras", it)) {
4194
0
        target->extras_json_string = detail::JsonToString(detail::GetValue(it));
4195
0
      }
4196
0
    }
4197
0
  }
4198
1.14k
  return true;
4199
1.14k
}
4200
4201
static bool ParseAsset(Asset *asset, std::string *err, const detail::json &o,
4202
1.59k
                       bool store_original_json_for_extras_and_extensions) {
4203
1.59k
  ParseStringProperty(&asset->version, err, o, "version", true, "Asset");
4204
1.59k
  ParseStringProperty(&asset->generator, err, o, "generator", false, "Asset");
4205
1.59k
  ParseStringProperty(&asset->minVersion, err, o, "minVersion", false, "Asset");
4206
1.59k
  ParseStringProperty(&asset->copyright, err, o, "copyright", false, "Asset");
4207
4208
1.59k
  ParseExtrasAndExtensions(asset, err, o,
4209
1.59k
                           store_original_json_for_extras_and_extensions);
4210
1.59k
  return true;
4211
1.59k
}
4212
4213
static bool ParseImage(Image *image, const int image_idx, std::string *err,
4214
                       std::string *warn, const detail::json &o,
4215
                       bool store_original_json_for_extras_and_extensions,
4216
                       const std::string &basedir, const size_t max_file_size,
4217
                       FsCallbacks *fs, const URICallbacks *uri_cb,
4218
                       LoadImageDataFunction *LoadImageData = nullptr,
4219
61.2k
                       void *load_image_user_data = nullptr) {
4220
  // A glTF image must either reference a bufferView or an image uri
4221
4222
  // schema says oneOf [`bufferView`, `uri`]
4223
  // TODO(syoyo): Check the type of each parameters.
4224
61.2k
  detail::json_const_iterator it;
4225
61.2k
  bool hasBufferView = detail::FindMember(o, "bufferView", it);
4226
61.2k
  bool hasURI = detail::FindMember(o, "uri", it);
4227
4228
61.2k
  ParseStringProperty(&image->name, err, o, "name", false);
4229
4230
61.2k
  if (hasBufferView && hasURI) {
4231
    // Should not both defined.
4232
0
    if (err) {
4233
0
      (*err) +=
4234
0
          "Only one of `bufferView` or `uri` should be defined, but both are "
4235
0
          "defined for image[" +
4236
0
          std::to_string(image_idx) + "] name = \"" + image->name + "\"\n";
4237
0
    }
4238
0
    return false;
4239
0
  }
4240
4241
61.2k
  if (!hasBufferView && !hasURI) {
4242
12
    if (err) {
4243
12
      (*err) += "Neither required `bufferView` nor `uri` defined for image[" +
4244
12
                std::to_string(image_idx) + "] name = \"" + image->name +
4245
12
                "\"\n";
4246
12
    }
4247
12
    return false;
4248
12
  }
4249
4250
61.1k
  ParseExtrasAndExtensions(image, err, o,
4251
61.1k
                           store_original_json_for_extras_and_extensions);
4252
4253
61.1k
  if (hasBufferView) {
4254
0
    int bufferView = -1;
4255
0
    if (!ParseIntegerProperty(&bufferView, err, o, "bufferView", true)) {
4256
0
      if (err) {
4257
0
        (*err) += "Failed to parse `bufferView` for image[" +
4258
0
                  std::to_string(image_idx) + "] name = \"" + image->name +
4259
0
                  "\"\n";
4260
0
      }
4261
0
      return false;
4262
0
    }
4263
4264
0
    std::string mime_type;
4265
0
    ParseStringProperty(&mime_type, err, o, "mimeType", false);
4266
4267
0
    int width = 0;
4268
0
    ParseIntegerProperty(&width, err, o, "width", false);
4269
4270
0
    int height = 0;
4271
0
    ParseIntegerProperty(&height, err, o, "height", false);
4272
4273
    // Just only save some information here. Loading actual image data from
4274
    // bufferView is done after this `ParseImage` function.
4275
0
    image->bufferView = bufferView;
4276
0
    image->mimeType = mime_type;
4277
0
    image->width = width;
4278
0
    image->height = height;
4279
4280
0
    return true;
4281
0
  }
4282
4283
  // Parse URI & Load image data.
4284
4285
61.1k
  std::string uri;
4286
61.1k
  std::string tmp_err;
4287
61.1k
  if (!ParseStringProperty(&uri, &tmp_err, o, "uri", true)) {
4288
1
    if (err) {
4289
1
      (*err) += "Failed to parse `uri` for image[" + std::to_string(image_idx) +
4290
1
                "] name = \"" + image->name + "\".\n";
4291
1
    }
4292
1
    return false;
4293
1
  }
4294
4295
61.1k
  std::vector<unsigned char> img;
4296
4297
61.1k
  if (IsDataURI(uri)) {
4298
19.0k
    if (!DecodeDataURI(&img, image->mimeType, uri, 0, false)) {
4299
47
      if (err) {
4300
47
        (*err) += "Failed to decode 'uri' for image[" +
4301
47
                  std::to_string(image_idx) + "] name = \"" + image->name +
4302
47
                  "\"\n";
4303
47
      }
4304
47
      return false;
4305
47
    }
4306
42.1k
  } else {
4307
    // Assume external file
4308
    // Keep texture path (for textures that cannot be decoded)
4309
42.1k
    image->uri = uri;
4310
#ifdef TINYGLTF_NO_EXTERNAL_IMAGE
4311
    return true;
4312
#else
4313
42.1k
    std::string decoded_uri;
4314
42.1k
    if (!uri_cb->decode(uri, &decoded_uri, uri_cb->user_data)) {
4315
0
      if (warn) {
4316
0
        (*warn) += "Failed to decode 'uri' for image[" +
4317
0
                   std::to_string(image_idx) + "] name = \"" + image->name +
4318
0
                   "\"\n";
4319
0
      }
4320
4321
      // Image loading failure is not critical to overall gltf loading.
4322
0
      return true;
4323
0
    }
4324
4325
42.1k
    if (!LoadExternalFile(&img, err, warn, decoded_uri, basedir,
4326
42.1k
                          /* required */ false, /* required bytes */ 0,
4327
42.1k
                          /* checksize */ false,
4328
42.1k
                          /* max file size */ max_file_size, fs)) {
4329
42.1k
      if (warn) {
4330
42.1k
        (*warn) += "Failed to load external 'uri' for image[" +
4331
42.1k
                   std::to_string(image_idx) + "] name = \"" + decoded_uri +
4332
42.1k
                   "\"\n";
4333
42.1k
      }
4334
      // If the image cannot be loaded, keep uri as image->uri.
4335
42.1k
      return true;
4336
42.1k
    }
4337
4338
0
    if (img.empty()) {
4339
0
      if (warn) {
4340
0
        (*warn) += "Image data is empty for image[" +
4341
0
                   std::to_string(image_idx) + "] name = \"" + image->name +
4342
0
                   "\" \n";
4343
0
      }
4344
0
      return false;
4345
0
    }
4346
0
#endif
4347
0
  }
4348
4349
19.0k
  if (*LoadImageData == nullptr) {
4350
0
    if (err) {
4351
0
      (*err) += "No LoadImageData callback specified.\n";
4352
0
    }
4353
0
    return false;
4354
0
  }
4355
19.0k
  return (*LoadImageData)(image, image_idx, err, warn, 0, 0, &img.at(0),
4356
19.0k
                          static_cast<int>(img.size()), load_image_user_data);
4357
19.0k
}
4358
4359
static bool ParseTexture(Texture *texture, std::string *err,
4360
                         const detail::json &o,
4361
                         bool store_original_json_for_extras_and_extensions,
4362
135k
                         const std::string &basedir) {
4363
135k
  (void)basedir;
4364
135k
  int sampler = -1;
4365
135k
  int source = -1;
4366
135k
  ParseIntegerProperty(&sampler, err, o, "sampler", false);
4367
4368
135k
  ParseIntegerProperty(&source, err, o, "source", false);
4369
4370
135k
  texture->sampler = sampler;
4371
135k
  texture->source = source;
4372
4373
135k
  ParseExtrasAndExtensions(texture, err, o,
4374
135k
                           store_original_json_for_extras_and_extensions);
4375
4376
135k
  ParseStringProperty(&texture->name, err, o, "name", false);
4377
4378
135k
  return true;
4379
135k
}
4380
4381
static bool ParseTextureInfo(
4382
    TextureInfo *texinfo, std::string *err, const detail::json &o,
4383
733
    bool store_original_json_for_extras_and_extensions) {
4384
733
  if (texinfo == nullptr) {
4385
0
    return false;
4386
0
  }
4387
4388
733
  if (!ParseIntegerProperty(&texinfo->index, err, o, "index",
4389
733
                            /* required */ true, "TextureInfo")) {
4390
572
    return false;
4391
572
  }
4392
4393
161
  ParseIntegerProperty(&texinfo->texCoord, err, o, "texCoord", false);
4394
4395
161
  ParseExtrasAndExtensions(texinfo, err, o,
4396
161
                           store_original_json_for_extras_and_extensions);
4397
4398
161
  return true;
4399
733
}
4400
4401
static bool ParseNormalTextureInfo(
4402
    NormalTextureInfo *texinfo, std::string *err, const detail::json &o,
4403
555
    bool store_original_json_for_extras_and_extensions) {
4404
555
  if (texinfo == nullptr) {
4405
0
    return false;
4406
0
  }
4407
4408
555
  if (!ParseIntegerProperty(&texinfo->index, err, o, "index",
4409
555
                            /* required */ true, "NormalTextureInfo")) {
4410
208
    return false;
4411
208
  }
4412
4413
347
  ParseIntegerProperty(&texinfo->texCoord, err, o, "texCoord", false);
4414
347
  ParseNumberProperty(&texinfo->scale, err, o, "scale", false);
4415
4416
347
  ParseExtrasAndExtensions(texinfo, err, o,
4417
347
                           store_original_json_for_extras_and_extensions);
4418
4419
347
  return true;
4420
555
}
4421
4422
static bool ParseOcclusionTextureInfo(
4423
    OcclusionTextureInfo *texinfo, std::string *err, const detail::json &o,
4424
494
    bool store_original_json_for_extras_and_extensions) {
4425
494
  if (texinfo == nullptr) {
4426
0
    return false;
4427
0
  }
4428
4429
494
  if (!ParseIntegerProperty(&texinfo->index, err, o, "index",
4430
494
                            /* required */ true, "NormalTextureInfo")) {
4431
186
    return false;
4432
186
  }
4433
4434
308
  ParseIntegerProperty(&texinfo->texCoord, err, o, "texCoord", false);
4435
308
  ParseNumberProperty(&texinfo->strength, err, o, "strength", false);
4436
4437
308
  ParseExtrasAndExtensions(texinfo, err, o,
4438
308
                           store_original_json_for_extras_and_extensions);
4439
4440
308
  return true;
4441
494
}
4442
4443
static bool ParseBuffer(Buffer *buffer, std::string *err, const detail::json &o,
4444
                        bool store_original_json_for_extras_and_extensions,
4445
                        FsCallbacks *fs, const URICallbacks *uri_cb,
4446
                        const std::string &basedir,
4447
                        const size_t max_buffer_size, bool is_binary = false,
4448
                        const unsigned char *bin_data = nullptr,
4449
0
                        size_t bin_size = 0) {
4450
0
  size_t byteLength;
4451
0
  if (!ParseUnsignedProperty(&byteLength, err, o, "byteLength", true,
4452
0
                             "Buffer")) {
4453
0
    return false;
4454
0
  }
4455
4456
  // In glTF 2.0, uri is not mandatory anymore
4457
0
  buffer->uri.clear();
4458
0
  ParseStringProperty(&buffer->uri, err, o, "uri", false, "Buffer");
4459
4460
  // having an empty uri for a non embedded image should not be valid
4461
0
  if (!is_binary && buffer->uri.empty()) {
4462
0
    if (err) {
4463
0
      (*err) += "'uri' is missing from non binary glTF file buffer.\n";
4464
0
    }
4465
0
  }
4466
4467
0
  detail::json_const_iterator type;
4468
0
  if (detail::FindMember(o, "type", type)) {
4469
0
    std::string typeStr;
4470
0
    if (detail::GetString(detail::GetValue(type), typeStr)) {
4471
0
      if (typeStr.compare("arraybuffer") == 0) {
4472
        // buffer.type = "arraybuffer";
4473
0
      }
4474
0
    }
4475
0
  }
4476
4477
0
  if (is_binary) {
4478
    // Still binary glTF accepts external dataURI.
4479
0
    if (!buffer->uri.empty()) {
4480
      // First try embedded data URI.
4481
0
      if (IsDataURI(buffer->uri)) {
4482
0
        std::string mime_type;
4483
0
        if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, byteLength,
4484
0
                           true)) {
4485
0
          if (err) {
4486
0
            (*err) +=
4487
0
                "Failed to decode 'uri' : " + buffer->uri + " in Buffer\n";
4488
0
          }
4489
0
          return false;
4490
0
        }
4491
0
      } else {
4492
        // External .bin file.
4493
0
        std::string decoded_uri;
4494
0
        if (!uri_cb->decode(buffer->uri, &decoded_uri, uri_cb->user_data)) {
4495
0
          return false;
4496
0
        }
4497
0
        if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr,
4498
0
                              decoded_uri, basedir, /* required */ true,
4499
0
                              byteLength, /* checkSize */ true,
4500
0
                              /* max_file_size */ max_buffer_size, fs)) {
4501
0
          return false;
4502
0
        }
4503
0
      }
4504
0
    } else {
4505
      // load data from (embedded) binary data
4506
4507
0
      if ((bin_size == 0) || (bin_data == nullptr)) {
4508
0
        if (err) {
4509
0
          (*err) +=
4510
0
              "Invalid binary data in `Buffer', or GLB with empty BIN chunk.\n";
4511
0
        }
4512
0
        return false;
4513
0
      }
4514
4515
0
      if (byteLength > bin_size) {
4516
0
        if (err) {
4517
0
          std::stringstream ss;
4518
0
          ss << "Invalid `byteLength'. Must be equal or less than binary size: "
4519
0
                "`byteLength' = "
4520
0
             << byteLength << ", binary size = " << bin_size << std::endl;
4521
0
          (*err) += ss.str();
4522
0
        }
4523
0
        return false;
4524
0
      }
4525
4526
      // Read buffer data
4527
0
      buffer->data.resize(static_cast<size_t>(byteLength));
4528
0
      memcpy(&(buffer->data.at(0)), bin_data, static_cast<size_t>(byteLength));
4529
0
    }
4530
4531
0
  } else {
4532
0
    if (IsDataURI(buffer->uri)) {
4533
0
      std::string mime_type;
4534
0
      if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, byteLength,
4535
0
                         true)) {
4536
0
        if (err) {
4537
0
          (*err) += "Failed to decode 'uri' : " + buffer->uri + " in Buffer\n";
4538
0
        }
4539
0
        return false;
4540
0
      }
4541
0
    } else {
4542
      // Assume external .bin file.
4543
0
      std::string decoded_uri;
4544
0
      if (!uri_cb->decode(buffer->uri, &decoded_uri, uri_cb->user_data)) {
4545
0
        return false;
4546
0
      }
4547
0
      if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, decoded_uri,
4548
0
                            basedir, /* required */ true, byteLength,