mirror of
https://github.com/syoyo/tinygltf.git
synced 2026-06-08 11:13:50 +00:00
Replace recursive parser with iterative loop using CJ_MAX_ITER explicit frame stack
Co-authored-by: syoyo <18676+syoyo@users.noreply.github.com>
This commit is contained in:
368
tinygltf_json.h
368
tinygltf_json.h
@@ -1112,17 +1112,28 @@ template<> inline std::string tinygltf_json::get<std::string>() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ======================================================================
|
/* ======================================================================
|
||||||
* PARSER (C-style recursive descent)
|
* PARSER (C-style iterative, explicit frame stack)
|
||||||
|
*
|
||||||
|
* Uses an explicit cj_frame stack instead of C recursion so that deeply
|
||||||
|
* nested JSON cannot overflow the call stack. CJ_MAX_ITER limits both
|
||||||
|
* the container nesting depth (stack size) and serves as the iteration
|
||||||
|
* safety budget: a malformed input that keeps pushing containers without
|
||||||
|
* consuming content is rejected once the stack is full.
|
||||||
* ====================================================================== */
|
* ====================================================================== */
|
||||||
|
|
||||||
/* Maximum nesting depth (arrays/objects) to prevent stack overflow */
|
/* Maximum container nesting depth (size of the explicit frame stack) */
|
||||||
#define CJ_MAX_DEPTH 512
|
#define CJ_MAX_ITER 512
|
||||||
|
|
||||||
|
/* One entry per open container (array or object) on the explicit stack */
|
||||||
|
struct cj_frame {
|
||||||
|
tinygltf_json *container; /* The array or object being populated */
|
||||||
|
int is_object; /* 0 = array, 1 = object */
|
||||||
|
};
|
||||||
|
|
||||||
struct cj_parse_ctx {
|
struct cj_parse_ctx {
|
||||||
const char *cur;
|
const char *cur;
|
||||||
const char *end;
|
const char *end;
|
||||||
int err;
|
int err;
|
||||||
int depth; /* current nesting depth */
|
|
||||||
char errmsg[256];
|
char errmsg[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1134,9 +1145,6 @@ static void cj_ctx_error(cj_parse_ctx *ctx, const char *msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Forward declaration */
|
|
||||||
static void cj_parse_value(cj_parse_ctx *ctx, tinygltf_json *out);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a JSON string from the current position.
|
* Parse a JSON string from the current position.
|
||||||
* cur must point to the opening '"'.
|
* cur must point to the opening '"'.
|
||||||
@@ -1196,168 +1204,229 @@ static void cj_parse_string_to(cj_parse_ctx *ctx, char **out_str,
|
|||||||
*out_str = NULL; *out_len = 0;
|
*out_str = NULL; *out_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cj_parse_array(cj_parse_ctx *ctx, tinygltf_json *out) {
|
/*
|
||||||
assert(*ctx->cur == '[');
|
* Parse a scalar JSON value (string, number, bool, null) into *slot.
|
||||||
if (ctx->depth >= CJ_MAX_DEPTH) {
|
* ctx->cur must point to the first character of the value (whitespace
|
||||||
cj_ctx_error(ctx, "nesting depth exceeded");
|
* already consumed).
|
||||||
return;
|
*/
|
||||||
}
|
static void cj_parse_scalar(cj_parse_ctx *ctx, tinygltf_json *slot) {
|
||||||
++ctx->cur;
|
|
||||||
++ctx->depth;
|
|
||||||
out->make_array_();
|
|
||||||
|
|
||||||
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
|
||||||
if (ctx->cur < ctx->end && *ctx->cur == ']') {
|
|
||||||
++ctx->cur;
|
|
||||||
--ctx->depth;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
if (ctx->err || ctx->cur >= ctx->end) break;
|
|
||||||
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
|
||||||
if (ctx->cur >= ctx->end) { cj_ctx_error(ctx, "EOF in array"); break; }
|
|
||||||
if (*ctx->cur == ']') { ++ctx->cur; break; }
|
|
||||||
|
|
||||||
tinygltf_json elem;
|
|
||||||
cj_parse_value(ctx, &elem);
|
|
||||||
if (ctx->err) break;
|
|
||||||
out->push_back(static_cast<tinygltf_json &&>(elem));
|
|
||||||
|
|
||||||
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
|
||||||
if (ctx->cur >= ctx->end) { cj_ctx_error(ctx, "EOF after array element"); break; }
|
|
||||||
if (*ctx->cur == ',') ++ctx->cur;
|
|
||||||
else if (*ctx->cur == ']') { ++ctx->cur; break; }
|
|
||||||
else { cj_ctx_error(ctx, "expected ',' or ']'"); break; }
|
|
||||||
}
|
|
||||||
--ctx->depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cj_parse_object(cj_parse_ctx *ctx, tinygltf_json *out) {
|
|
||||||
assert(*ctx->cur == '{');
|
|
||||||
if (ctx->depth >= CJ_MAX_DEPTH) {
|
|
||||||
cj_ctx_error(ctx, "nesting depth exceeded");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
++ctx->cur;
|
|
||||||
++ctx->depth;
|
|
||||||
out->make_object_();
|
|
||||||
|
|
||||||
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
|
||||||
if (ctx->cur < ctx->end && *ctx->cur == '}') { ++ctx->cur; --ctx->depth; return; }
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
if (ctx->err || ctx->cur >= ctx->end) break;
|
|
||||||
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
|
||||||
if (ctx->cur >= ctx->end) { cj_ctx_error(ctx, "EOF in object"); break; }
|
|
||||||
if (*ctx->cur == '}') { ++ctx->cur; break; }
|
|
||||||
|
|
||||||
/* Parse key */
|
|
||||||
if (*ctx->cur != '"') { cj_ctx_error(ctx, "expected key string"); break; }
|
|
||||||
char *key_str = NULL;
|
|
||||||
size_t key_len = 0;
|
|
||||||
cj_parse_string_to(ctx, &key_str, &key_len);
|
|
||||||
if (ctx->err || !key_str) { free(key_str); break; }
|
|
||||||
|
|
||||||
/* Parse colon */
|
|
||||||
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
|
||||||
if (ctx->cur >= ctx->end || *ctx->cur != ':') {
|
|
||||||
free(key_str);
|
|
||||||
cj_ctx_error(ctx, "expected ':'");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
++ctx->cur;
|
|
||||||
|
|
||||||
/* Allocate member slot */
|
|
||||||
if (!out->obj_reserve_()) { free(key_str); cj_ctx_error(ctx, "OOM"); break; }
|
|
||||||
tinygltf_json_member *m = &out->obj_data_[out->obj_size_];
|
|
||||||
new (m) tinygltf_json_member();
|
|
||||||
m->key = key_str;
|
|
||||||
m->key_len = key_len;
|
|
||||||
++out->obj_size_;
|
|
||||||
|
|
||||||
/* Parse value directly into m->val */
|
|
||||||
cj_parse_value(ctx, &m->val);
|
|
||||||
if (ctx->err) break;
|
|
||||||
|
|
||||||
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
|
||||||
if (ctx->cur >= ctx->end) { cj_ctx_error(ctx, "EOF after value"); break; }
|
|
||||||
if (*ctx->cur == ',') ++ctx->cur;
|
|
||||||
else if (*ctx->cur == '}') { ++ctx->cur; break; }
|
|
||||||
else { cj_ctx_error(ctx, "expected ',' or '}'"); break; }
|
|
||||||
}
|
|
||||||
--ctx->depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cj_parse_value(cj_parse_ctx *ctx, tinygltf_json *out) {
|
|
||||||
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
|
||||||
if (ctx->cur >= ctx->end) {
|
|
||||||
cj_ctx_error(ctx, "unexpected EOF");
|
|
||||||
out->destroy_();
|
|
||||||
out->init_null_();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char c = *ctx->cur;
|
char c = *ctx->cur;
|
||||||
|
|
||||||
if (c == '"') {
|
if (c == '"') {
|
||||||
char *s = NULL;
|
char *s = NULL; size_t slen = 0;
|
||||||
size_t len = 0;
|
cj_parse_string_to(ctx, &s, &slen);
|
||||||
cj_parse_string_to(ctx, &s, &len);
|
if (ctx->err || !s) { free(s); slot->destroy_(); slot->init_null_(); return; }
|
||||||
if (ctx->err || !s) { free(s); out->destroy_(); out->init_null_(); return; }
|
slot->destroy_(); slot->init_null_();
|
||||||
out->destroy_();
|
slot->type_ = CJ_STRING; slot->str_ = s; slot->str_len_ = slen;
|
||||||
out->init_null_();
|
|
||||||
out->type_ = CJ_STRING;
|
|
||||||
out->str_ = s;
|
|
||||||
out->str_len_ = len;
|
|
||||||
} else if (c == '{') {
|
|
||||||
cj_parse_object(ctx, out);
|
|
||||||
} else if (c == '[') {
|
|
||||||
cj_parse_array(ctx, out);
|
|
||||||
} else if (c == 't') {
|
} else if (c == 't') {
|
||||||
if (ctx->end - ctx->cur >= 4 && memcmp(ctx->cur, "true", 4) == 0) {
|
if (ctx->end - ctx->cur >= 4 && memcmp(ctx->cur, "true", 4) == 0) {
|
||||||
ctx->cur += 4;
|
ctx->cur += 4;
|
||||||
*out = tinygltf_json(true);
|
slot->destroy_(); slot->init_null_();
|
||||||
|
slot->type_ = CJ_BOOL; slot->b_ = 1;
|
||||||
} else { cj_ctx_error(ctx, "invalid literal 'true'"); }
|
} else { cj_ctx_error(ctx, "invalid literal 'true'"); }
|
||||||
} else if (c == 'f') {
|
} else if (c == 'f') {
|
||||||
if (ctx->end - ctx->cur >= 5 && memcmp(ctx->cur, "false", 5) == 0) {
|
if (ctx->end - ctx->cur >= 5 && memcmp(ctx->cur, "false", 5) == 0) {
|
||||||
ctx->cur += 5;
|
ctx->cur += 5;
|
||||||
*out = tinygltf_json(false);
|
slot->destroy_(); slot->init_null_();
|
||||||
|
slot->type_ = CJ_BOOL; slot->b_ = 0;
|
||||||
} else { cj_ctx_error(ctx, "invalid literal 'false'"); }
|
} else { cj_ctx_error(ctx, "invalid literal 'false'"); }
|
||||||
} else if (c == 'n') {
|
} else if (c == 'n') {
|
||||||
if (ctx->end - ctx->cur >= 4 && memcmp(ctx->cur, "null", 4) == 0) {
|
if (ctx->end - ctx->cur >= 4 && memcmp(ctx->cur, "null", 4) == 0) {
|
||||||
ctx->cur += 4;
|
ctx->cur += 4;
|
||||||
out->destroy_();
|
slot->destroy_(); slot->init_null_();
|
||||||
out->init_null_();
|
|
||||||
} else { cj_ctx_error(ctx, "invalid literal 'null'"); }
|
} else { cj_ctx_error(ctx, "invalid literal 'null'"); }
|
||||||
} else if (c == '-' || (c >= '0' && c <= '9')) {
|
} else if (c == '-' || (c >= '0' && c <= '9')) {
|
||||||
int is_int = 0;
|
int is_int = 0; int64_t ival = 0; double dval = 0.0;
|
||||||
int64_t ival = 0;
|
const char *next = cj_parse_number(ctx->cur, ctx->end, &is_int, &ival, &dval);
|
||||||
double dval = 0.0;
|
|
||||||
const char *next = cj_parse_number(ctx->cur, ctx->end,
|
|
||||||
&is_int, &ival, &dval);
|
|
||||||
if (!next) { cj_ctx_error(ctx, "invalid number"); return; }
|
if (!next) { cj_ctx_error(ctx, "invalid number"); return; }
|
||||||
ctx->cur = next;
|
ctx->cur = next;
|
||||||
if (is_int) {
|
slot->destroy_(); slot->init_null_();
|
||||||
out->destroy_();
|
if (is_int) { slot->type_ = CJ_INT; slot->i_ = ival; }
|
||||||
out->init_null_();
|
else { slot->type_ = CJ_REAL; slot->d_ = dval; }
|
||||||
out->type_ = CJ_INT;
|
|
||||||
out->i_ = ival;
|
|
||||||
} else {
|
|
||||||
out->destroy_();
|
|
||||||
out->init_null_();
|
|
||||||
out->type_ = CJ_REAL;
|
|
||||||
out->d_ = dval;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
char errbuf[64];
|
char errbuf[64];
|
||||||
snprintf(errbuf, sizeof(errbuf),
|
snprintf(errbuf, sizeof(errbuf), "unexpected character '%c' (0x%02X)",
|
||||||
"unexpected character '%c' (0x%02X)",
|
(unsigned char)c >= 0x20u ? c : '?', (unsigned char)c);
|
||||||
(unsigned char)c >= 0x20u ? c : '?',
|
|
||||||
(unsigned char)c);
|
|
||||||
cj_ctx_error(ctx, errbuf);
|
cj_ctx_error(ctx, errbuf);
|
||||||
out->destroy_();
|
slot->destroy_(); slot->init_null_();
|
||||||
out->init_null_();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cj_parse_json -- iterative JSON parser.
|
||||||
|
*
|
||||||
|
* Parses one complete JSON value from ctx into *root using an explicit
|
||||||
|
* cj_frame[CJ_MAX_ITER] stack instead of C recursion. No C stack frames
|
||||||
|
* are consumed for nesting; the only stack growth comes from the fixed-size
|
||||||
|
* cj_frame array declared as a local variable here.
|
||||||
|
*
|
||||||
|
* Loop structure:
|
||||||
|
* after_val == 0 -> parse the next JSON value into *slot
|
||||||
|
* after_val == 1 -> a value was just completed; handle ',' / ']' / '}'
|
||||||
|
*
|
||||||
|
* CJ_MAX_ITER caps the container nesting depth. Each '{' or '[' increments
|
||||||
|
* depth; reaching the cap produces an error rather than an out-of-bounds
|
||||||
|
* write.
|
||||||
|
*/
|
||||||
|
static void cj_parse_json(cj_parse_ctx *ctx, tinygltf_json *root) {
|
||||||
|
cj_frame stack[CJ_MAX_ITER];
|
||||||
|
int depth = 0; /* frames in use */
|
||||||
|
int after_val = 0; /* 0 = need value, 1 = value just finished */
|
||||||
|
|
||||||
|
/* Where to write the next parsed value */
|
||||||
|
tinygltf_json *slot = root;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (ctx->err) break;
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------
|
||||||
|
* POST-VALUE: handle separator / closing bracket
|
||||||
|
* ------------------------------------------------------------- */
|
||||||
|
if (after_val) {
|
||||||
|
after_val = 0;
|
||||||
|
|
||||||
|
if (depth == 0) break; /* root value complete */
|
||||||
|
|
||||||
|
cj_frame *f = &stack[depth - 1];
|
||||||
|
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
||||||
|
if (ctx->cur >= ctx->end) {
|
||||||
|
cj_ctx_error(ctx, "unexpected EOF after value"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!f->is_object) {
|
||||||
|
/* ---- Array: expect ',' or ']' ---- */
|
||||||
|
if (*ctx->cur == ',') {
|
||||||
|
++ctx->cur;
|
||||||
|
/* Allocate next element slot */
|
||||||
|
tinygltf_json *cont = f->container;
|
||||||
|
if (!cont->arr_reserve_()) { cj_ctx_error(ctx, "OOM"); break; }
|
||||||
|
new (&cont->arr_data_[cont->arr_size_]) tinygltf_json();
|
||||||
|
slot = &cont->arr_data_[cont->arr_size_];
|
||||||
|
++cont->arr_size_;
|
||||||
|
/* Loop back to parse the element value */
|
||||||
|
} else if (*ctx->cur == ']') {
|
||||||
|
++ctx->cur;
|
||||||
|
--depth;
|
||||||
|
after_val = 1; /* the array itself is now the completed value */
|
||||||
|
} else {
|
||||||
|
cj_ctx_error(ctx, "expected ',' or ']' in array"); break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* ---- Object: expect ',' or '}' ---- */
|
||||||
|
if (*ctx->cur == ',') {
|
||||||
|
++ctx->cur;
|
||||||
|
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
||||||
|
if (ctx->cur >= ctx->end) {
|
||||||
|
cj_ctx_error(ctx, "unexpected EOF in object"); break;
|
||||||
|
}
|
||||||
|
if (*ctx->cur != '"') {
|
||||||
|
cj_ctx_error(ctx, "expected object key after ','"); break;
|
||||||
|
}
|
||||||
|
/* Parse key and allocate member slot */
|
||||||
|
char *k = NULL; size_t kl = 0;
|
||||||
|
cj_parse_string_to(ctx, &k, &kl);
|
||||||
|
if (ctx->err || !k) { free(k); break; }
|
||||||
|
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
||||||
|
if (ctx->cur >= ctx->end || *ctx->cur != ':') {
|
||||||
|
free(k); cj_ctx_error(ctx, "expected ':' in object"); break;
|
||||||
|
}
|
||||||
|
++ctx->cur;
|
||||||
|
tinygltf_json *cont = f->container;
|
||||||
|
if (!cont->obj_reserve_()) { free(k); cj_ctx_error(ctx, "OOM"); break; }
|
||||||
|
tinygltf_json_member *m = &cont->obj_data_[cont->obj_size_];
|
||||||
|
new (m) tinygltf_json_member();
|
||||||
|
m->key = k; m->key_len = kl;
|
||||||
|
++cont->obj_size_;
|
||||||
|
slot = &m->val;
|
||||||
|
/* Loop back to parse the member value */
|
||||||
|
} else if (*ctx->cur == '}') {
|
||||||
|
++ctx->cur;
|
||||||
|
--depth;
|
||||||
|
after_val = 1; /* the object itself is now the completed value */
|
||||||
|
} else {
|
||||||
|
cj_ctx_error(ctx, "expected ',' or '}' in object"); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------
|
||||||
|
* PARSE VALUE: read *slot from ctx->cur
|
||||||
|
* ------------------------------------------------------------- */
|
||||||
|
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
||||||
|
if (ctx->cur >= ctx->end) {
|
||||||
|
if (depth == 0) break; /* trailing whitespace on root value is ok */
|
||||||
|
cj_ctx_error(ctx, "unexpected EOF"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char c = *ctx->cur;
|
||||||
|
|
||||||
|
if (c == '{') {
|
||||||
|
/* ---- Begin object ---- */
|
||||||
|
if (depth >= CJ_MAX_ITER) {
|
||||||
|
cj_ctx_error(ctx, "nesting limit exceeded"); break;
|
||||||
|
}
|
||||||
|
++ctx->cur;
|
||||||
|
slot->destroy_(); slot->init_null_(); slot->type_ = CJ_OBJECT;
|
||||||
|
|
||||||
|
stack[depth].container = slot;
|
||||||
|
stack[depth].is_object = 1;
|
||||||
|
++depth;
|
||||||
|
|
||||||
|
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
||||||
|
if (ctx->cur >= ctx->end) { cj_ctx_error(ctx, "EOF in object"); break; }
|
||||||
|
if (*ctx->cur == '}') { ++ctx->cur; --depth; after_val = 1; continue; }
|
||||||
|
|
||||||
|
/* Parse first key */
|
||||||
|
if (*ctx->cur != '"') { cj_ctx_error(ctx, "expected key in object"); break; }
|
||||||
|
{
|
||||||
|
char *k = NULL; size_t kl = 0;
|
||||||
|
cj_parse_string_to(ctx, &k, &kl);
|
||||||
|
if (ctx->err || !k) { free(k); break; }
|
||||||
|
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
||||||
|
if (ctx->cur >= ctx->end || *ctx->cur != ':') {
|
||||||
|
free(k); cj_ctx_error(ctx, "expected ':' in object"); break;
|
||||||
|
}
|
||||||
|
++ctx->cur;
|
||||||
|
if (!slot->obj_reserve_()) { free(k); cj_ctx_error(ctx, "OOM"); break; }
|
||||||
|
tinygltf_json_member *m = &slot->obj_data_[slot->obj_size_];
|
||||||
|
new (m) tinygltf_json_member();
|
||||||
|
m->key = k; m->key_len = kl;
|
||||||
|
++slot->obj_size_;
|
||||||
|
slot = &m->val; /* next iteration parses the first value */
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (c == '[') {
|
||||||
|
/* ---- Begin array ---- */
|
||||||
|
if (depth >= CJ_MAX_ITER) {
|
||||||
|
cj_ctx_error(ctx, "nesting limit exceeded"); break;
|
||||||
|
}
|
||||||
|
++ctx->cur;
|
||||||
|
slot->destroy_(); slot->init_null_(); slot->type_ = CJ_ARRAY;
|
||||||
|
|
||||||
|
stack[depth].container = slot;
|
||||||
|
stack[depth].is_object = 0;
|
||||||
|
++depth;
|
||||||
|
|
||||||
|
ctx->cur = cj_skip_ws(ctx->cur, ctx->end);
|
||||||
|
if (ctx->cur >= ctx->end) { cj_ctx_error(ctx, "EOF in array"); break; }
|
||||||
|
if (*ctx->cur == ']') { ++ctx->cur; --depth; after_val = 1; continue; }
|
||||||
|
|
||||||
|
/* Allocate first element slot */
|
||||||
|
{
|
||||||
|
tinygltf_json *cont = stack[depth - 1].container;
|
||||||
|
if (!cont->arr_reserve_()) { cj_ctx_error(ctx, "OOM"); break; }
|
||||||
|
new (&cont->arr_data_[cont->arr_size_]) tinygltf_json();
|
||||||
|
slot = &cont->arr_data_[cont->arr_size_];
|
||||||
|
++cont->arr_size_;
|
||||||
|
}
|
||||||
|
/* next iteration parses the first element */
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* ---- Scalar value ---- */
|
||||||
|
cj_parse_scalar(ctx, slot);
|
||||||
|
after_val = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1529,11 +1598,10 @@ inline tinygltf_json tinygltf_json::parse(const char *first, const char *last,
|
|||||||
ctx.cur = first;
|
ctx.cur = first;
|
||||||
ctx.end = last;
|
ctx.end = last;
|
||||||
ctx.err = 0;
|
ctx.err = 0;
|
||||||
ctx.depth = 0;
|
|
||||||
ctx.errmsg[0] = '\0';
|
ctx.errmsg[0] = '\0';
|
||||||
|
|
||||||
tinygltf_json result;
|
tinygltf_json result;
|
||||||
cj_parse_value(&ctx, &result);
|
cj_parse_json(&ctx, &result);
|
||||||
|
|
||||||
if (ctx.err) {
|
if (ctx.err) {
|
||||||
if (allow_exceptions) {
|
if (allow_exceptions) {
|
||||||
|
|||||||
Reference in New Issue
Block a user