Coverage Report

Created: 2023-11-19 06:39

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