oj 3.13.23 → 3.16.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +81 -0
- data/README.md +2 -2
- data/ext/oj/buf.h +7 -6
- data/ext/oj/cache.c +29 -26
- data/ext/oj/cache.h +3 -2
- data/ext/oj/cache8.c +10 -9
- data/ext/oj/circarray.c +7 -5
- data/ext/oj/circarray.h +2 -2
- data/ext/oj/code.c +5 -12
- data/ext/oj/code.h +2 -2
- data/ext/oj/compat.c +20 -60
- data/ext/oj/custom.c +26 -59
- data/ext/oj/debug.c +3 -9
- data/ext/oj/dump.c +103 -53
- data/ext/oj/dump.h +1 -4
- data/ext/oj/dump_compat.c +557 -592
- data/ext/oj/dump_leaf.c +3 -5
- data/ext/oj/dump_object.c +42 -48
- data/ext/oj/dump_strict.c +10 -22
- data/ext/oj/encoder.c +1 -1
- data/ext/oj/err.c +2 -13
- data/ext/oj/err.h +9 -12
- data/ext/oj/extconf.rb +16 -7
- data/ext/oj/fast.c +60 -92
- data/ext/oj/intern.c +62 -47
- data/ext/oj/intern.h +3 -7
- data/ext/oj/mem.c +318 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +51 -32
- data/ext/oj/object.c +33 -43
- data/ext/oj/odd.c +8 -6
- data/ext/oj/odd.h +4 -4
- data/ext/oj/oj.c +243 -212
- data/ext/oj/oj.h +83 -81
- data/ext/oj/parse.c +94 -148
- data/ext/oj/parse.h +21 -24
- data/ext/oj/parser.c +80 -67
- data/ext/oj/parser.h +7 -8
- data/ext/oj/rails.c +70 -92
- data/ext/oj/reader.c +9 -14
- data/ext/oj/reader.h +4 -2
- data/ext/oj/resolve.c +3 -4
- data/ext/oj/rxclass.c +6 -5
- data/ext/oj/rxclass.h +1 -1
- data/ext/oj/saj.c +10 -9
- data/ext/oj/saj2.c +37 -49
- data/ext/oj/saj2.h +1 -1
- data/ext/oj/scp.c +3 -14
- data/ext/oj/sparse.c +22 -70
- data/ext/oj/stream_writer.c +45 -41
- data/ext/oj/strict.c +20 -52
- data/ext/oj/string_writer.c +64 -38
- data/ext/oj/trace.h +31 -4
- data/ext/oj/usual.c +125 -114
- data/ext/oj/usual.h +7 -6
- data/ext/oj/util.h +1 -1
- data/ext/oj/val_stack.c +13 -2
- data/ext/oj/val_stack.h +8 -7
- data/ext/oj/wab.c +25 -57
- data/lib/oj/active_support_helper.rb +1 -3
- data/lib/oj/bag.rb +7 -1
- data/lib/oj/easy_hash.rb +4 -5
- data/lib/oj/error.rb +0 -1
- data/lib/oj/json.rb +162 -150
- data/lib/oj/mimic.rb +7 -7
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/state.rb +8 -5
- data/lib/oj/version.rb +1 -2
- data/lib/oj.rb +2 -0
- data/pages/InstallOptions.md +20 -0
- data/pages/Options.md +4 -0
- data/test/_test_active.rb +8 -9
- data/test/_test_active_mimic.rb +7 -8
- data/test/_test_mimic_rails.rb +17 -20
- data/test/activerecord/result_test.rb +5 -6
- data/test/activesupport6/encoding_test.rb +63 -28
- data/test/activesupport7/abstract_unit.rb +4 -1
- data/test/activesupport7/encoding_test.rb +72 -22
- data/test/files.rb +15 -15
- data/test/foo.rb +18 -69
- data/test/helper.rb +5 -8
- data/test/isolated/shared.rb +3 -2
- data/test/json_gem/json_addition_test.rb +2 -2
- data/test/json_gem/json_common_interface_test.rb +8 -6
- data/test/json_gem/json_encoding_test.rb +0 -0
- data/test/json_gem/json_ext_parser_test.rb +1 -0
- data/test/json_gem/json_fixtures_test.rb +3 -2
- data/test/json_gem/json_generator_test.rb +50 -33
- data/test/json_gem/json_generic_object_test.rb +11 -11
- data/test/json_gem/json_parser_test.rb +46 -46
- data/test/json_gem/json_string_matching_test.rb +9 -9
- data/test/mem.rb +13 -12
- data/test/perf.rb +21 -26
- data/test/perf_compat.rb +31 -33
- data/test/perf_dump.rb +28 -28
- data/test/perf_fast.rb +80 -82
- data/test/perf_file.rb +27 -29
- data/test/perf_object.rb +65 -69
- data/test/perf_once.rb +12 -11
- data/test/perf_parser.rb +42 -48
- data/test/perf_saj.rb +46 -54
- data/test/perf_scp.rb +57 -69
- data/test/perf_simple.rb +41 -39
- data/test/perf_strict.rb +68 -70
- data/test/perf_wab.rb +67 -69
- data/test/prec.rb +5 -5
- data/test/sample/change.rb +0 -1
- data/test/sample/dir.rb +0 -1
- data/test/sample/doc.rb +0 -1
- data/test/sample/file.rb +0 -1
- data/test/sample/group.rb +0 -1
- data/test/sample/hasprops.rb +0 -1
- data/test/sample/layer.rb +0 -1
- data/test/sample/rect.rb +0 -1
- data/test/sample/shape.rb +0 -1
- data/test/sample/text.rb +0 -1
- data/test/sample.rb +16 -16
- data/test/sample_json.rb +8 -8
- data/test/test_compat.rb +81 -54
- data/test/test_custom.rb +63 -52
- data/test/test_debian.rb +7 -10
- data/test/test_fast.rb +86 -90
- data/test/test_file.rb +24 -29
- data/test/test_gc.rb +5 -5
- data/test/test_generate.rb +5 -5
- data/test/test_hash.rb +4 -4
- data/test/test_integer_range.rb +9 -9
- data/test/test_null.rb +20 -20
- data/test/test_object.rb +92 -87
- data/test/test_parser.rb +4 -4
- data/test/test_parser_debug.rb +5 -5
- data/test/test_parser_saj.rb +27 -25
- data/test/test_parser_usual.rb +44 -6
- data/test/test_rails.rb +2 -2
- data/test/test_saj.rb +10 -8
- data/test/test_scp.rb +35 -35
- data/test/test_strict.rb +38 -32
- data/test/test_various.rb +146 -97
- data/test/test_wab.rb +46 -44
- data/test/test_writer.rb +63 -47
- data/test/tests.rb +7 -7
- data/test/tests_mimic.rb +6 -6
- data/test/tests_mimic_addition.rb +6 -6
- metadata +46 -26
- data/test/activesupport4/decoding_test.rb +0 -108
- data/test/activesupport4/encoding_test.rb +0 -531
- data/test/activesupport4/test_helper.rb +0 -41
- data/test/activesupport5/abstract_unit.rb +0 -45
- data/test/activesupport5/decoding_test.rb +0 -133
- data/test/activesupport5/encoding_test.rb +0 -500
- data/test/activesupport5/encoding_test_cases.rb +0 -98
- data/test/activesupport5/test_helper.rb +0 -72
- data/test/activesupport5/time_zone_test_helpers.rb +0 -39
- data/test/bar.rb +0 -11
- data/test/baz.rb +0 -16
- data/test/bug.rb +0 -16
- data/test/zoo.rb +0 -13
data/ext/oj/parse.c
CHANGED
@@ -12,14 +12,19 @@
|
|
12
12
|
|
13
13
|
#include "buf.h"
|
14
14
|
#include "encode.h"
|
15
|
+
#include "mem.h"
|
15
16
|
#include "oj.h"
|
16
17
|
#include "rxclass.h"
|
17
18
|
#include "val_stack.h"
|
18
19
|
|
20
|
+
#ifdef OJ_USE_SSE4_2
|
21
|
+
#include <nmmintrin.h>
|
22
|
+
#endif
|
23
|
+
|
19
24
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
20
25
|
#define OJ_INFINITY (1.0 / 0.0)
|
21
26
|
|
22
|
-
|
27
|
+
// #define EXP_MAX 1023
|
23
28
|
#define EXP_MAX 100000
|
24
29
|
#define DEC_MAX 15
|
25
30
|
|
@@ -44,11 +49,7 @@ static void skip_comment(ParseInfo pi) {
|
|
44
49
|
pi->cur += 2;
|
45
50
|
return;
|
46
51
|
} else if (pi->end <= pi->cur) {
|
47
|
-
oj_set_error_at(pi,
|
48
|
-
oj_parse_error_class,
|
49
|
-
__FILE__,
|
50
|
-
__LINE__,
|
51
|
-
"comment not terminated");
|
52
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
|
52
53
|
return;
|
53
54
|
}
|
54
55
|
}
|
@@ -81,9 +82,8 @@ static void add_value(ParseInfo pi, VALUE rval) {
|
|
81
82
|
break;
|
82
83
|
case NEXT_HASH_VALUE:
|
83
84
|
pi->hash_set_value(pi, parent, rval);
|
84
|
-
if (0 != parent->key && 0 < parent->klen &&
|
85
|
-
(
|
86
|
-
xfree((char *)parent->key);
|
85
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
86
|
+
OJ_R_FREE((char *)parent->key);
|
87
87
|
parent->key = 0;
|
88
88
|
}
|
89
89
|
parent->next = NEXT_HASH_COMMA;
|
@@ -195,14 +195,18 @@ static inline const char *scan_string_noSIMD(const char *str, const char *end) {
|
|
195
195
|
#ifdef OJ_USE_SSE4_2
|
196
196
|
static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
197
197
|
static const char chars[16] = "\x00\\\"";
|
198
|
-
const __m128i
|
199
|
-
const char
|
198
|
+
const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
|
199
|
+
const char *_end = (const char *)(end - 16);
|
200
200
|
|
201
201
|
for (; str <= _end; str += 16) {
|
202
202
|
const __m128i string = _mm_loadu_si128((const __m128i *)str);
|
203
|
-
const int
|
203
|
+
const int r = _mm_cmpestri(terminate,
|
204
|
+
3,
|
205
|
+
string,
|
206
|
+
16,
|
207
|
+
_SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
|
204
208
|
if (r != 16) {
|
205
|
-
str = (char*)(str + r);
|
209
|
+
str = (char *)(str + r);
|
206
210
|
return str;
|
207
211
|
}
|
208
212
|
}
|
@@ -211,7 +215,7 @@ static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
|
211
215
|
}
|
212
216
|
#endif
|
213
217
|
|
214
|
-
static const char *(*scan_func)
|
218
|
+
static const char *(*scan_func)(const char *str, const char *end) = scan_string_noSIMD;
|
215
219
|
|
216
220
|
void oj_scanner_init(void) {
|
217
221
|
#ifdef OJ_USE_SSE4_2
|
@@ -232,16 +236,12 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
232
236
|
|
233
237
|
for (s = pi->cur; '"' != *s;) {
|
234
238
|
const char *scanned = scan_func(s, pi->end);
|
235
|
-
if (scanned >= pi->end) {
|
236
|
-
|
237
|
-
|
238
|
-
__FILE__,
|
239
|
-
__LINE__,
|
240
|
-
"quoted string not terminated");
|
239
|
+
if (scanned >= pi->end || '\0' == *scanned) {
|
240
|
+
// if (scanned >= pi->end) {
|
241
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
|
241
242
|
buf_cleanup(&buf);
|
242
243
|
return;
|
243
244
|
}
|
244
|
-
|
245
245
|
buf_append_string(&buf, s, (size_t)(scanned - s));
|
246
246
|
s = scanned;
|
247
247
|
|
@@ -275,11 +275,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
275
275
|
break;
|
276
276
|
}
|
277
277
|
pi->cur = s;
|
278
|
-
oj_set_error_at(pi,
|
279
|
-
oj_parse_error_class,
|
280
|
-
__FILE__,
|
281
|
-
__LINE__,
|
282
|
-
"invalid escaped character");
|
278
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
283
279
|
buf_cleanup(&buf);
|
284
280
|
return;
|
285
281
|
}
|
@@ -306,11 +302,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
306
302
|
break;
|
307
303
|
}
|
308
304
|
pi->cur = s;
|
309
|
-
oj_set_error_at(pi,
|
310
|
-
oj_parse_error_class,
|
311
|
-
__FILE__,
|
312
|
-
__LINE__,
|
313
|
-
"invalid escaped character");
|
305
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
314
306
|
buf_cleanup(&buf);
|
315
307
|
return;
|
316
308
|
}
|
@@ -330,7 +322,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
330
322
|
case NEXT_HASH_KEY:
|
331
323
|
if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
|
332
324
|
parent->klen = buf_len(&buf);
|
333
|
-
parent->key =
|
325
|
+
parent->key = OJ_MALLOC(parent->klen + 1);
|
334
326
|
memcpy((char *)parent->key, buf.head, parent->klen);
|
335
327
|
*(char *)(parent->key + parent->klen) = '\0';
|
336
328
|
} else {
|
@@ -342,9 +334,8 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
342
334
|
break;
|
343
335
|
case NEXT_HASH_VALUE:
|
344
336
|
pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start);
|
345
|
-
if (0 != parent->key && 0 < parent->klen &&
|
346
|
-
(
|
347
|
-
xfree((char *)parent->key);
|
337
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
338
|
+
OJ_R_FREE((char *)parent->key);
|
348
339
|
parent->key = 0;
|
349
340
|
}
|
350
341
|
parent->next = NEXT_HASH_COMMA;
|
@@ -373,11 +364,7 @@ static void read_str(ParseInfo pi) {
|
|
373
364
|
|
374
365
|
pi->cur = scan_func(pi->cur, pi->end);
|
375
366
|
if (RB_UNLIKELY(pi->end <= pi->cur)) {
|
376
|
-
oj_set_error_at(pi,
|
377
|
-
oj_parse_error_class,
|
378
|
-
__FILE__,
|
379
|
-
__LINE__,
|
380
|
-
"quoted string not terminated");
|
367
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
|
381
368
|
return;
|
382
369
|
}
|
383
370
|
if (RB_UNLIKELY('\0' == *pi->cur)) {
|
@@ -412,9 +399,8 @@ static void read_str(ParseInfo pi) {
|
|
412
399
|
break;
|
413
400
|
case NEXT_HASH_VALUE:
|
414
401
|
pi->hash_set_cstr(pi, parent, str, pi->cur - str, str);
|
415
|
-
if (0 != parent->key && 0 < parent->klen &&
|
416
|
-
(
|
417
|
-
xfree((char *)parent->key);
|
402
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
403
|
+
OJ_R_FREE((char *)parent->key);
|
418
404
|
parent->key = 0;
|
419
405
|
}
|
420
406
|
parent->next = NEXT_HASH_COMMA;
|
@@ -440,6 +426,7 @@ static void read_num(ParseInfo pi) {
|
|
440
426
|
struct _numInfo ni;
|
441
427
|
Val parent = stack_peek(&pi->stack);
|
442
428
|
|
429
|
+
ni.pi = pi;
|
443
430
|
ni.str = pi->cur;
|
444
431
|
ni.i = 0;
|
445
432
|
ni.num = 0;
|
@@ -456,7 +443,7 @@ static void read_num(ParseInfo pi) {
|
|
456
443
|
ni.no_big = !pi->options.compat_bigdec;
|
457
444
|
ni.bigdec_load = pi->options.compat_bigdec;
|
458
445
|
} else {
|
459
|
-
ni.no_big
|
446
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
|
460
447
|
RubyDec == pi->options.bigdec_load);
|
461
448
|
ni.bigdec_load = pi->options.bigdec_load;
|
462
449
|
}
|
@@ -466,33 +453,21 @@ static void read_num(ParseInfo pi) {
|
|
466
453
|
ni.neg = 1;
|
467
454
|
} else if ('+' == *pi->cur) {
|
468
455
|
if (StrictMode == pi->options.mode) {
|
469
|
-
oj_set_error_at(pi,
|
470
|
-
oj_parse_error_class,
|
471
|
-
__FILE__,
|
472
|
-
__LINE__,
|
473
|
-
"not a number or other value");
|
456
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
474
457
|
return;
|
475
458
|
}
|
476
459
|
pi->cur++;
|
477
460
|
}
|
478
461
|
if ('I' == *pi->cur) {
|
479
462
|
if (No == pi->options.allow_nan || 0 != strncmp("Infinity", pi->cur, 8)) {
|
480
|
-
oj_set_error_at(pi,
|
481
|
-
oj_parse_error_class,
|
482
|
-
__FILE__,
|
483
|
-
__LINE__,
|
484
|
-
"not a number or other value");
|
463
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
485
464
|
return;
|
486
465
|
}
|
487
466
|
pi->cur += 8;
|
488
467
|
ni.infinity = 1;
|
489
468
|
} else if ('N' == *pi->cur || 'n' == *pi->cur) {
|
490
469
|
if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) {
|
491
|
-
oj_set_error_at(pi,
|
492
|
-
oj_parse_error_class,
|
493
|
-
__FILE__,
|
494
|
-
__LINE__,
|
495
|
-
"not a number or other value");
|
470
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
496
471
|
return;
|
497
472
|
}
|
498
473
|
pi->cur += 3;
|
@@ -515,11 +490,7 @@ static void read_num(ParseInfo pi) {
|
|
515
490
|
ni.i = ni.i * 10 + d;
|
516
491
|
}
|
517
492
|
if (RB_UNLIKELY(0 != ni.i && zero1 && CompatMode == pi->options.mode)) {
|
518
|
-
oj_set_error_at(pi,
|
519
|
-
oj_parse_error_class,
|
520
|
-
__FILE__,
|
521
|
-
__LINE__,
|
522
|
-
"not a number");
|
493
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
523
494
|
return;
|
524
495
|
}
|
525
496
|
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
@@ -611,9 +582,8 @@ static void read_num(ParseInfo pi) {
|
|
611
582
|
break;
|
612
583
|
case NEXT_HASH_VALUE:
|
613
584
|
pi->hash_set_num(pi, parent, &ni);
|
614
|
-
if (0 != parent->key && 0 < parent->klen &&
|
615
|
-
(
|
616
|
-
xfree((char *)parent->key);
|
585
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
586
|
+
OJ_R_FREE((char *)parent->key);
|
617
587
|
parent->key = 0;
|
618
588
|
}
|
619
589
|
parent->next = NEXT_HASH_COMMA;
|
@@ -711,7 +681,7 @@ void oj_parse2(ParseInfo pi) {
|
|
711
681
|
pi->cur = pi->json;
|
712
682
|
err_init(&pi->err);
|
713
683
|
while (1) {
|
714
|
-
if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
|
684
|
+
if (RB_UNLIKELY(0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1)) {
|
715
685
|
VALUE err_clas = oj_get_json_err_class("NestingError");
|
716
686
|
|
717
687
|
oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
|
@@ -719,18 +689,20 @@ void oj_parse2(ParseInfo pi) {
|
|
719
689
|
return;
|
720
690
|
}
|
721
691
|
next_non_white(pi);
|
722
|
-
if (
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
}
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
692
|
+
if (first) {
|
693
|
+
// If no tokens are consumed (i.e. empty string), throw a parse error
|
694
|
+
// this is the behavior of JSON.parse in both Ruby and JS.
|
695
|
+
if (RB_UNLIKELY('\0' == *pi->cur && No == pi->options.empty_string)) {
|
696
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
697
|
+
}
|
698
|
+
} else {
|
699
|
+
if (RB_UNLIKELY('\0' != *pi->cur)) {
|
700
|
+
oj_set_error_at(pi,
|
701
|
+
oj_parse_error_class,
|
702
|
+
__FILE__,
|
703
|
+
__LINE__,
|
704
|
+
"unexpected characters after the JSON document");
|
705
|
+
}
|
734
706
|
}
|
735
707
|
|
736
708
|
switch (*pi->cur++) {
|
@@ -740,17 +712,10 @@ void oj_parse2(ParseInfo pi) {
|
|
740
712
|
case '[': array_start(pi); break;
|
741
713
|
case ']': array_end(pi); break;
|
742
714
|
case ',': comma(pi); break;
|
743
|
-
case '"':
|
744
|
-
read_str(pi);
|
745
|
-
break;
|
746
|
-
// case '+':
|
715
|
+
case '"': read_str(pi); break;
|
747
716
|
case '+':
|
748
717
|
if (CompatMode == pi->options.mode) {
|
749
|
-
oj_set_error_at(pi,
|
750
|
-
oj_parse_error_class,
|
751
|
-
__FILE__,
|
752
|
-
__LINE__,
|
753
|
-
"unexpected character");
|
718
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
754
719
|
return;
|
755
720
|
}
|
756
721
|
pi->cur--;
|
@@ -776,11 +741,7 @@ void oj_parse2(ParseInfo pi) {
|
|
776
741
|
pi->cur--;
|
777
742
|
read_num(pi);
|
778
743
|
} else {
|
779
|
-
oj_set_error_at(pi,
|
780
|
-
oj_parse_error_class,
|
781
|
-
__FILE__,
|
782
|
-
__LINE__,
|
783
|
-
"unexpected character");
|
744
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
784
745
|
}
|
785
746
|
break;
|
786
747
|
case 't': read_true(pi); break;
|
@@ -800,11 +761,9 @@ void oj_parse2(ParseInfo pi) {
|
|
800
761
|
}
|
801
762
|
break;
|
802
763
|
case '\0': pi->cur--; return;
|
803
|
-
default:
|
804
|
-
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
805
|
-
return;
|
764
|
+
default: oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); return;
|
806
765
|
}
|
807
|
-
if (err_has(&pi->err)) {
|
766
|
+
if (RB_UNLIKELY(err_has(&pi->err))) {
|
808
767
|
return;
|
809
768
|
}
|
810
769
|
if (stack_empty(&pi->stack)) {
|
@@ -839,11 +798,10 @@ static VALUE parse_big_decimal(VALUE str) {
|
|
839
798
|
}
|
840
799
|
|
841
800
|
static long double exp_plus[] = {
|
842
|
-
1.0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
|
843
|
-
1.
|
844
|
-
1.
|
845
|
-
1.
|
846
|
-
1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49,
|
801
|
+
1.0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, 1.0e11, 1.0e12,
|
802
|
+
1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25,
|
803
|
+
1.0e26, 1.0e27, 1.0e28, 1.0e29, 1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38,
|
804
|
+
1.0e39, 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49,
|
847
805
|
};
|
848
806
|
|
849
807
|
VALUE
|
@@ -867,12 +825,12 @@ oj_num_as_value(NumInfo ni) {
|
|
867
825
|
buf[ni->len] = '\0';
|
868
826
|
rnum = rb_cstr_to_inum(buf, 10, 0);
|
869
827
|
} else {
|
870
|
-
char *buf =
|
828
|
+
char *buf = OJ_R_ALLOC_N(char, ni->len + 1);
|
871
829
|
|
872
830
|
memcpy(buf, ni->str, ni->len);
|
873
831
|
buf[ni->len] = '\0';
|
874
832
|
rnum = rb_cstr_to_inum(buf, 10, 0);
|
875
|
-
|
833
|
+
OJ_R_FREE(buf);
|
876
834
|
}
|
877
835
|
} else {
|
878
836
|
if (ni->neg) {
|
@@ -915,11 +873,15 @@ oj_num_as_value(NumInfo ni) {
|
|
915
873
|
|
916
874
|
rnum = rb_funcall(sv, rb_intern("to_f"), 0);
|
917
875
|
} else {
|
918
|
-
char
|
876
|
+
char *end;
|
919
877
|
double d = strtod(ni->str, &end);
|
920
878
|
|
921
879
|
if ((long)ni->len != (long)(end - ni->str)) {
|
922
|
-
|
880
|
+
if (Qnil == ni->pi->err_class) {
|
881
|
+
rb_raise(oj_parse_error_class, "Invalid float");
|
882
|
+
} else {
|
883
|
+
rb_raise(ni->pi->err_class, "Invalid float");
|
884
|
+
}
|
923
885
|
}
|
924
886
|
rnum = rb_float_new(d);
|
925
887
|
}
|
@@ -927,28 +889,23 @@ oj_num_as_value(NumInfo ni) {
|
|
927
889
|
return rnum;
|
928
890
|
}
|
929
891
|
|
930
|
-
void oj_set_error_at(ParseInfo
|
931
|
-
VALUE err_clas,
|
932
|
-
const char *file,
|
933
|
-
int line,
|
934
|
-
const char *format,
|
935
|
-
...) {
|
892
|
+
void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...) {
|
936
893
|
va_list ap;
|
937
894
|
char msg[256];
|
938
|
-
char
|
939
|
-
char
|
940
|
-
char
|
895
|
+
char *p = msg;
|
896
|
+
char *end = p + sizeof(msg) - 2;
|
897
|
+
char *start;
|
941
898
|
Val vp;
|
942
|
-
int
|
899
|
+
int mlen;
|
943
900
|
|
944
901
|
va_start(ap, format);
|
945
902
|
mlen = vsnprintf(msg, sizeof(msg) - 1, format, ap);
|
946
903
|
if (0 < mlen) {
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
904
|
+
if (sizeof(msg) - 2 < (size_t)mlen) {
|
905
|
+
p = end - 2;
|
906
|
+
} else {
|
907
|
+
p += mlen;
|
908
|
+
}
|
952
909
|
}
|
953
910
|
va_end(ap);
|
954
911
|
pi->err.clas = err_clas;
|
@@ -985,14 +942,7 @@ void oj_set_error_at(ParseInfo pi,
|
|
985
942
|
}
|
986
943
|
*p = '\0';
|
987
944
|
if (0 == pi->json) {
|
988
|
-
oj_err_set(&pi->err,
|
989
|
-
err_clas,
|
990
|
-
"%s at line %d, column %d [%s:%d]",
|
991
|
-
msg,
|
992
|
-
pi->rd.line,
|
993
|
-
pi->rd.col,
|
994
|
-
file,
|
995
|
-
line);
|
945
|
+
oj_err_set(&pi->err, err_clas, "%s at line %d, column %d [%s:%d]", msg, pi->rd.line, pi->rd.col, file, line);
|
996
946
|
} else {
|
997
947
|
_oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
|
998
948
|
}
|
@@ -1011,7 +961,7 @@ static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
|
|
1011
961
|
|
1012
962
|
if (oj_utf8_encoding_index != idx) {
|
1013
963
|
rb_encoding *enc = rb_enc_from_index(idx);
|
1014
|
-
*inputp
|
964
|
+
*inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
|
1015
965
|
}
|
1016
966
|
pi->json = RSTRING_PTR(*inputp);
|
1017
967
|
pi->end = pi->json + RSTRING_LEN(*inputp);
|
@@ -1019,12 +969,12 @@ static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
|
|
1019
969
|
|
1020
970
|
VALUE
|
1021
971
|
oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
|
1022
|
-
char *
|
1023
|
-
VALUE
|
1024
|
-
VALUE
|
1025
|
-
VALUE
|
1026
|
-
int
|
1027
|
-
int
|
972
|
+
char *buf = 0;
|
973
|
+
VALUE input;
|
974
|
+
VALUE wrapped_stack;
|
975
|
+
VALUE result = Qnil;
|
976
|
+
int line = 0;
|
977
|
+
int free_json = 0;
|
1028
978
|
|
1029
979
|
if (argc < 1) {
|
1030
980
|
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
@@ -1073,19 +1023,18 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1073
1023
|
size_t len = lseek(fd, 0, SEEK_END);
|
1074
1024
|
|
1075
1025
|
lseek(fd, 0, SEEK_SET);
|
1076
|
-
buf =
|
1026
|
+
buf = OJ_R_ALLOC_N(char, len + 1);
|
1077
1027
|
pi->json = buf;
|
1078
1028
|
pi->end = buf + len;
|
1079
1029
|
if (0 >= (cnt = read(fd, (char *)pi->json, len)) || cnt != (ssize_t)len) {
|
1080
1030
|
if (0 != buf) {
|
1081
|
-
|
1031
|
+
OJ_R_FREE(buf);
|
1082
1032
|
}
|
1083
1033
|
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
1084
1034
|
}
|
1085
1035
|
((char *)pi->json)[len] = '\0';
|
1086
1036
|
/* skip UTF-8 BOM if present */
|
1087
|
-
if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] &&
|
1088
|
-
0xBF == (uint8_t)pi->json[2]) {
|
1037
|
+
if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) {
|
1089
1038
|
pi->cur += 3;
|
1090
1039
|
}
|
1091
1040
|
#endif
|
@@ -1111,8 +1060,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1111
1060
|
wrapped_stack = oj_stack_init(&pi->stack);
|
1112
1061
|
rb_protect(protect_parse, (VALUE)pi, &line);
|
1113
1062
|
if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
|
1114
|
-
if (No == pi->options.nilnil ||
|
1115
|
-
(CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
|
1063
|
+
if (No == pi->options.nilnil || (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
|
1116
1064
|
oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input");
|
1117
1065
|
}
|
1118
1066
|
}
|
@@ -1140,9 +1088,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1140
1088
|
switch (v->next) {
|
1141
1089
|
case NEXT_ARRAY_NEW:
|
1142
1090
|
case NEXT_ARRAY_ELEMENT:
|
1143
|
-
case NEXT_ARRAY_COMMA:
|
1144
|
-
oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
|
1145
|
-
break;
|
1091
|
+
case NEXT_ARRAY_COMMA: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); break;
|
1146
1092
|
case NEXT_HASH_NEW:
|
1147
1093
|
case NEXT_HASH_KEY:
|
1148
1094
|
case NEXT_HASH_COLON:
|
@@ -1160,9 +1106,9 @@ CLEANUP:
|
|
1160
1106
|
oj_circ_array_free(pi->circ_array);
|
1161
1107
|
}
|
1162
1108
|
if (0 != buf) {
|
1163
|
-
|
1109
|
+
OJ_R_FREE(buf);
|
1164
1110
|
} else if (free_json) {
|
1165
|
-
|
1111
|
+
OJ_R_FREE(json);
|
1166
1112
|
}
|
1167
1113
|
stack_cleanup(&pi->stack);
|
1168
1114
|
if (pi->str_rx.head != oj_default_options.str_rx.head) {
|
data/ext/oj/parse.h
CHANGED
@@ -16,23 +16,25 @@
|
|
16
16
|
#include "val_stack.h"
|
17
17
|
|
18
18
|
struct _rxClass;
|
19
|
+
struct _parseInfo;
|
19
20
|
|
20
21
|
typedef struct _numInfo {
|
21
|
-
int64_t
|
22
|
-
int64_t
|
23
|
-
int64_t
|
24
|
-
int64_t
|
25
|
-
const char
|
26
|
-
size_t
|
27
|
-
long
|
28
|
-
|
29
|
-
int
|
30
|
-
int
|
31
|
-
int
|
32
|
-
int
|
33
|
-
int
|
34
|
-
int
|
35
|
-
|
22
|
+
int64_t i;
|
23
|
+
int64_t num;
|
24
|
+
int64_t div;
|
25
|
+
int64_t di;
|
26
|
+
const char *str;
|
27
|
+
size_t len;
|
28
|
+
long exp;
|
29
|
+
struct _parseInfo *pi;
|
30
|
+
int big;
|
31
|
+
int infinity;
|
32
|
+
int nan;
|
33
|
+
int neg;
|
34
|
+
int has_exp;
|
35
|
+
int no_big;
|
36
|
+
int bigdec_load;
|
37
|
+
} *NumInfo;
|
36
38
|
|
37
39
|
typedef struct _parseInfo {
|
38
40
|
// used for the string parser
|
@@ -54,11 +56,7 @@ typedef struct _parseInfo {
|
|
54
56
|
VALUE (*start_hash)(struct _parseInfo *pi);
|
55
57
|
void (*end_hash)(struct _parseInfo *pi);
|
56
58
|
VALUE (*hash_key)(struct _parseInfo *pi, const char *key, size_t klen);
|
57
|
-
void (*hash_set_cstr)(struct _parseInfo *pi,
|
58
|
-
Val kval,
|
59
|
-
const char * str,
|
60
|
-
size_t len,
|
61
|
-
const char * orig);
|
59
|
+
void (*hash_set_cstr)(struct _parseInfo *pi, Val kval, const char *str, size_t len, const char *orig);
|
62
60
|
void (*hash_set_num)(struct _parseInfo *pi, Val kval, NumInfo ni);
|
63
61
|
void (*hash_set_value)(struct _parseInfo *pi, Val kval, VALUE value);
|
64
62
|
|
@@ -73,11 +71,10 @@ typedef struct _parseInfo {
|
|
73
71
|
void (*add_value)(struct _parseInfo *pi, VALUE val);
|
74
72
|
VALUE err_class;
|
75
73
|
bool has_callbacks;
|
76
|
-
} *
|
74
|
+
} *ParseInfo;
|
77
75
|
|
78
|
-
extern void
|
79
|
-
extern void
|
80
|
-
oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...);
|
76
|
+
extern void oj_parse2(ParseInfo pi);
|
77
|
+
extern void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...);
|
81
78
|
extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk);
|
82
79
|
extern VALUE oj_num_as_value(NumInfo ni);
|
83
80
|
|