oj 3.14.1 → 3.14.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +0 -1
- data/ext/oj/buf.h +7 -6
- data/ext/oj/cache.c +25 -24
- 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 +2 -2
- data/ext/oj/code.h +2 -2
- data/ext/oj/compat.c +7 -14
- data/ext/oj/custom.c +3 -2
- data/ext/oj/debug.c +3 -9
- data/ext/oj/dump.c +18 -17
- data/ext/oj/dump_compat.c +551 -576
- data/ext/oj/dump_leaf.c +3 -5
- data/ext/oj/dump_object.c +37 -37
- data/ext/oj/dump_strict.c +2 -4
- 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 +1 -1
- data/ext/oj/fast.c +33 -46
- data/ext/oj/intern.c +44 -46
- 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 +20 -25
- data/ext/oj/object.c +7 -7
- data/ext/oj/odd.c +8 -6
- data/ext/oj/odd.h +4 -4
- data/ext/oj/oj.c +71 -85
- data/ext/oj/oj.h +53 -54
- data/ext/oj/parse.c +67 -128
- data/ext/oj/parse.h +5 -10
- data/ext/oj/parser.c +13 -14
- data/ext/oj/parser.h +7 -8
- data/ext/oj/rails.c +36 -66
- data/ext/oj/reader.c +8 -11
- 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 +9 -8
- data/ext/oj/saj2.c +36 -52
- 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 +9 -21
- data/ext/oj/strict.c +7 -13
- data/ext/oj/string_writer.c +11 -18
- data/ext/oj/trace.h +27 -16
- data/ext/oj/usual.c +89 -87
- data/ext/oj/usual.h +6 -6
- data/ext/oj/util.h +1 -1
- data/ext/oj/val_stack.h +8 -7
- data/ext/oj/wab.c +7 -9
- data/lib/oj/active_support_helper.rb +0 -1
- 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 +4 -2
- data/lib/oj/mimic.rb +4 -2
- data/lib/oj/state.rb +8 -5
- data/lib/oj/version.rb +1 -2
- data/lib/oj.rb +0 -1
- data/test/_test_active.rb +0 -1
- data/test/_test_active_mimic.rb +0 -1
- data/test/_test_mimic_rails.rb +0 -1
- data/test/activerecord/result_test.rb +5 -6
- data/test/bar.rb +3 -3
- data/test/files.rb +1 -1
- data/test/foo.rb +5 -3
- data/test/helper.rb +1 -4
- 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 +4 -4
- 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 +43 -32
- 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 +7 -7
- data/test/perf.rb +2 -2
- data/test/perf_compat.rb +1 -1
- data/test/perf_fast.rb +1 -1
- data/test/perf_file.rb +2 -2
- data/test/perf_object.rb +1 -2
- data/test/perf_once.rb +4 -4
- data/test/perf_parser.rb +2 -2
- data/test/perf_saj.rb +1 -2
- data/test/perf_scp.rb +1 -1
- data/test/perf_simple.rb +3 -3
- data/test/perf_strict.rb +1 -1
- data/test/perf_wab.rb +1 -1
- 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 +2 -3
- data/test/sample_json.rb +0 -1
- data/test/test_compat.rb +11 -9
- data/test/test_custom.rb +5 -9
- data/test/test_debian.rb +1 -1
- data/test/test_fast.rb +10 -20
- data/test/test_file.rb +8 -8
- data/test/test_integer_range.rb +2 -2
- data/test/test_null.rb +5 -3
- data/test/test_object.rb +6 -5
- data/test/test_parser_saj.rb +23 -21
- data/test/test_parser_usual.rb +3 -3
- data/test/test_saj.rb +2 -0
- data/test/test_scp.rb +6 -6
- data/test/test_strict.rb +6 -4
- data/test/test_various.rb +21 -24
- data/test/test_wab.rb +6 -5
- data/test/test_writer.rb +1 -1
- metadata +20 -27
- 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/ext/oj/parse.c
CHANGED
@@ -12,6 +12,7 @@
|
|
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"
|
@@ -23,7 +24,7 @@
|
|
23
24
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
24
25
|
#define OJ_INFINITY (1.0 / 0.0)
|
25
26
|
|
26
|
-
|
27
|
+
// #define EXP_MAX 1023
|
27
28
|
#define EXP_MAX 100000
|
28
29
|
#define DEC_MAX 15
|
29
30
|
|
@@ -48,11 +49,7 @@ static void skip_comment(ParseInfo pi) {
|
|
48
49
|
pi->cur += 2;
|
49
50
|
return;
|
50
51
|
} else if (pi->end <= pi->cur) {
|
51
|
-
oj_set_error_at(pi,
|
52
|
-
oj_parse_error_class,
|
53
|
-
__FILE__,
|
54
|
-
__LINE__,
|
55
|
-
"comment not terminated");
|
52
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
|
56
53
|
return;
|
57
54
|
}
|
58
55
|
}
|
@@ -85,9 +82,8 @@ static void add_value(ParseInfo pi, VALUE rval) {
|
|
85
82
|
break;
|
86
83
|
case NEXT_HASH_VALUE:
|
87
84
|
pi->hash_set_value(pi, parent, rval);
|
88
|
-
if (0 != parent->key && 0 < parent->klen &&
|
89
|
-
(
|
90
|
-
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);
|
91
87
|
parent->key = 0;
|
92
88
|
}
|
93
89
|
parent->next = NEXT_HASH_COMMA;
|
@@ -199,14 +195,18 @@ static inline const char *scan_string_noSIMD(const char *str, const char *end) {
|
|
199
195
|
#ifdef OJ_USE_SSE4_2
|
200
196
|
static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
201
197
|
static const char chars[16] = "\x00\\\"";
|
202
|
-
const __m128i
|
203
|
-
const char
|
198
|
+
const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
|
199
|
+
const char *_end = (const char *)(end - 16);
|
204
200
|
|
205
201
|
for (; str <= _end; str += 16) {
|
206
202
|
const __m128i string = _mm_loadu_si128((const __m128i *)str);
|
207
|
-
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);
|
208
208
|
if (r != 16) {
|
209
|
-
str = (char*)(str + r);
|
209
|
+
str = (char *)(str + r);
|
210
210
|
return str;
|
211
211
|
}
|
212
212
|
}
|
@@ -215,7 +215,7 @@ static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
|
215
215
|
}
|
216
216
|
#endif
|
217
217
|
|
218
|
-
static const char *(*scan_func)
|
218
|
+
static const char *(*scan_func)(const char *str, const char *end) = scan_string_noSIMD;
|
219
219
|
|
220
220
|
void oj_scanner_init(void) {
|
221
221
|
#ifdef OJ_USE_SSE4_2
|
@@ -236,12 +236,9 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
236
236
|
|
237
237
|
for (s = pi->cur; '"' != *s;) {
|
238
238
|
const char *scanned = scan_func(s, pi->end);
|
239
|
-
if (scanned >= pi->end || '\0' == *
|
240
|
-
|
241
|
-
|
242
|
-
__FILE__,
|
243
|
-
__LINE__,
|
244
|
-
"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");
|
245
242
|
buf_cleanup(&buf);
|
246
243
|
return;
|
247
244
|
}
|
@@ -278,11 +275,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
278
275
|
break;
|
279
276
|
}
|
280
277
|
pi->cur = s;
|
281
|
-
oj_set_error_at(pi,
|
282
|
-
oj_parse_error_class,
|
283
|
-
__FILE__,
|
284
|
-
__LINE__,
|
285
|
-
"invalid escaped character");
|
278
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
286
279
|
buf_cleanup(&buf);
|
287
280
|
return;
|
288
281
|
}
|
@@ -309,11 +302,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
309
302
|
break;
|
310
303
|
}
|
311
304
|
pi->cur = s;
|
312
|
-
oj_set_error_at(pi,
|
313
|
-
oj_parse_error_class,
|
314
|
-
__FILE__,
|
315
|
-
__LINE__,
|
316
|
-
"invalid escaped character");
|
305
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
317
306
|
buf_cleanup(&buf);
|
318
307
|
return;
|
319
308
|
}
|
@@ -333,7 +322,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
333
322
|
case NEXT_HASH_KEY:
|
334
323
|
if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
|
335
324
|
parent->klen = buf_len(&buf);
|
336
|
-
parent->key =
|
325
|
+
parent->key = OJ_MALLOC(parent->klen + 1);
|
337
326
|
memcpy((char *)parent->key, buf.head, parent->klen);
|
338
327
|
*(char *)(parent->key + parent->klen) = '\0';
|
339
328
|
} else {
|
@@ -345,9 +334,8 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
345
334
|
break;
|
346
335
|
case NEXT_HASH_VALUE:
|
347
336
|
pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start);
|
348
|
-
if (0 != parent->key && 0 < parent->klen &&
|
349
|
-
(
|
350
|
-
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);
|
351
339
|
parent->key = 0;
|
352
340
|
}
|
353
341
|
parent->next = NEXT_HASH_COMMA;
|
@@ -376,11 +364,7 @@ static void read_str(ParseInfo pi) {
|
|
376
364
|
|
377
365
|
pi->cur = scan_func(pi->cur, pi->end);
|
378
366
|
if (RB_UNLIKELY(pi->end <= pi->cur)) {
|
379
|
-
oj_set_error_at(pi,
|
380
|
-
oj_parse_error_class,
|
381
|
-
__FILE__,
|
382
|
-
__LINE__,
|
383
|
-
"quoted string not terminated");
|
367
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
|
384
368
|
return;
|
385
369
|
}
|
386
370
|
if (RB_UNLIKELY('\0' == *pi->cur)) {
|
@@ -415,9 +399,8 @@ static void read_str(ParseInfo pi) {
|
|
415
399
|
break;
|
416
400
|
case NEXT_HASH_VALUE:
|
417
401
|
pi->hash_set_cstr(pi, parent, str, pi->cur - str, str);
|
418
|
-
if (0 != parent->key && 0 < parent->klen &&
|
419
|
-
(
|
420
|
-
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);
|
421
404
|
parent->key = 0;
|
422
405
|
}
|
423
406
|
parent->next = NEXT_HASH_COMMA;
|
@@ -459,7 +442,7 @@ static void read_num(ParseInfo pi) {
|
|
459
442
|
ni.no_big = !pi->options.compat_bigdec;
|
460
443
|
ni.bigdec_load = pi->options.compat_bigdec;
|
461
444
|
} else {
|
462
|
-
ni.no_big
|
445
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
|
463
446
|
RubyDec == pi->options.bigdec_load);
|
464
447
|
ni.bigdec_load = pi->options.bigdec_load;
|
465
448
|
}
|
@@ -469,33 +452,21 @@ static void read_num(ParseInfo pi) {
|
|
469
452
|
ni.neg = 1;
|
470
453
|
} else if ('+' == *pi->cur) {
|
471
454
|
if (StrictMode == pi->options.mode) {
|
472
|
-
oj_set_error_at(pi,
|
473
|
-
oj_parse_error_class,
|
474
|
-
__FILE__,
|
475
|
-
__LINE__,
|
476
|
-
"not a number or other value");
|
455
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
477
456
|
return;
|
478
457
|
}
|
479
458
|
pi->cur++;
|
480
459
|
}
|
481
460
|
if ('I' == *pi->cur) {
|
482
461
|
if (No == pi->options.allow_nan || 0 != strncmp("Infinity", pi->cur, 8)) {
|
483
|
-
oj_set_error_at(pi,
|
484
|
-
oj_parse_error_class,
|
485
|
-
__FILE__,
|
486
|
-
__LINE__,
|
487
|
-
"not a number or other value");
|
462
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
488
463
|
return;
|
489
464
|
}
|
490
465
|
pi->cur += 8;
|
491
466
|
ni.infinity = 1;
|
492
467
|
} else if ('N' == *pi->cur || 'n' == *pi->cur) {
|
493
468
|
if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) {
|
494
|
-
oj_set_error_at(pi,
|
495
|
-
oj_parse_error_class,
|
496
|
-
__FILE__,
|
497
|
-
__LINE__,
|
498
|
-
"not a number or other value");
|
469
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
499
470
|
return;
|
500
471
|
}
|
501
472
|
pi->cur += 3;
|
@@ -518,11 +489,7 @@ static void read_num(ParseInfo pi) {
|
|
518
489
|
ni.i = ni.i * 10 + d;
|
519
490
|
}
|
520
491
|
if (RB_UNLIKELY(0 != ni.i && zero1 && CompatMode == pi->options.mode)) {
|
521
|
-
oj_set_error_at(pi,
|
522
|
-
oj_parse_error_class,
|
523
|
-
__FILE__,
|
524
|
-
__LINE__,
|
525
|
-
"not a number");
|
492
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
526
493
|
return;
|
527
494
|
}
|
528
495
|
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
@@ -614,9 +581,8 @@ static void read_num(ParseInfo pi) {
|
|
614
581
|
break;
|
615
582
|
case NEXT_HASH_VALUE:
|
616
583
|
pi->hash_set_num(pi, parent, &ni);
|
617
|
-
if (0 != parent->key && 0 < parent->klen &&
|
618
|
-
(
|
619
|
-
xfree((char *)parent->key);
|
584
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
585
|
+
OJ_R_FREE((char *)parent->key);
|
620
586
|
parent->key = 0;
|
621
587
|
}
|
622
588
|
parent->next = NEXT_HASH_COMMA;
|
@@ -749,11 +715,7 @@ void oj_parse2(ParseInfo pi) {
|
|
749
715
|
// case '+':
|
750
716
|
case '+':
|
751
717
|
if (CompatMode == pi->options.mode) {
|
752
|
-
oj_set_error_at(pi,
|
753
|
-
oj_parse_error_class,
|
754
|
-
__FILE__,
|
755
|
-
__LINE__,
|
756
|
-
"unexpected character");
|
718
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
757
719
|
return;
|
758
720
|
}
|
759
721
|
pi->cur--;
|
@@ -779,11 +741,7 @@ void oj_parse2(ParseInfo pi) {
|
|
779
741
|
pi->cur--;
|
780
742
|
read_num(pi);
|
781
743
|
} else {
|
782
|
-
oj_set_error_at(pi,
|
783
|
-
oj_parse_error_class,
|
784
|
-
__FILE__,
|
785
|
-
__LINE__,
|
786
|
-
"unexpected character");
|
744
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
787
745
|
}
|
788
746
|
break;
|
789
747
|
case 't': read_true(pi); break;
|
@@ -803,9 +761,7 @@ void oj_parse2(ParseInfo pi) {
|
|
803
761
|
}
|
804
762
|
break;
|
805
763
|
case '\0': pi->cur--; return;
|
806
|
-
default:
|
807
|
-
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
808
|
-
return;
|
764
|
+
default: oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); return;
|
809
765
|
}
|
810
766
|
if (err_has(&pi->err)) {
|
811
767
|
return;
|
@@ -842,11 +798,10 @@ static VALUE parse_big_decimal(VALUE str) {
|
|
842
798
|
}
|
843
799
|
|
844
800
|
static long double exp_plus[] = {
|
845
|
-
1.0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
|
846
|
-
1.
|
847
|
-
1.
|
848
|
-
1.
|
849
|
-
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,
|
850
805
|
};
|
851
806
|
|
852
807
|
VALUE
|
@@ -870,12 +825,12 @@ oj_num_as_value(NumInfo ni) {
|
|
870
825
|
buf[ni->len] = '\0';
|
871
826
|
rnum = rb_cstr_to_inum(buf, 10, 0);
|
872
827
|
} else {
|
873
|
-
char *buf =
|
828
|
+
char *buf = OJ_R_ALLOC_N(char, ni->len + 1);
|
874
829
|
|
875
830
|
memcpy(buf, ni->str, ni->len);
|
876
831
|
buf[ni->len] = '\0';
|
877
832
|
rnum = rb_cstr_to_inum(buf, 10, 0);
|
878
|
-
|
833
|
+
OJ_R_FREE(buf);
|
879
834
|
}
|
880
835
|
} else {
|
881
836
|
if (ni->neg) {
|
@@ -918,7 +873,7 @@ oj_num_as_value(NumInfo ni) {
|
|
918
873
|
|
919
874
|
rnum = rb_funcall(sv, rb_intern("to_f"), 0);
|
920
875
|
} else {
|
921
|
-
char
|
876
|
+
char *end;
|
922
877
|
double d = strtod(ni->str, &end);
|
923
878
|
|
924
879
|
if ((long)ni->len != (long)(end - ni->str)) {
|
@@ -930,28 +885,23 @@ oj_num_as_value(NumInfo ni) {
|
|
930
885
|
return rnum;
|
931
886
|
}
|
932
887
|
|
933
|
-
void oj_set_error_at(ParseInfo
|
934
|
-
VALUE err_clas,
|
935
|
-
const char *file,
|
936
|
-
int line,
|
937
|
-
const char *format,
|
938
|
-
...) {
|
888
|
+
void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...) {
|
939
889
|
va_list ap;
|
940
890
|
char msg[256];
|
941
|
-
char
|
942
|
-
char
|
943
|
-
char
|
891
|
+
char *p = msg;
|
892
|
+
char *end = p + sizeof(msg) - 2;
|
893
|
+
char *start;
|
944
894
|
Val vp;
|
945
|
-
int
|
895
|
+
int mlen;
|
946
896
|
|
947
897
|
va_start(ap, format);
|
948
898
|
mlen = vsnprintf(msg, sizeof(msg) - 1, format, ap);
|
949
899
|
if (0 < mlen) {
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
900
|
+
if (sizeof(msg) - 2 < (size_t)mlen) {
|
901
|
+
p = end - 2;
|
902
|
+
} else {
|
903
|
+
p += mlen;
|
904
|
+
}
|
955
905
|
}
|
956
906
|
va_end(ap);
|
957
907
|
pi->err.clas = err_clas;
|
@@ -988,14 +938,7 @@ void oj_set_error_at(ParseInfo pi,
|
|
988
938
|
}
|
989
939
|
*p = '\0';
|
990
940
|
if (0 == pi->json) {
|
991
|
-
oj_err_set(&pi->err,
|
992
|
-
err_clas,
|
993
|
-
"%s at line %d, column %d [%s:%d]",
|
994
|
-
msg,
|
995
|
-
pi->rd.line,
|
996
|
-
pi->rd.col,
|
997
|
-
file,
|
998
|
-
line);
|
941
|
+
oj_err_set(&pi->err, err_clas, "%s at line %d, column %d [%s:%d]", msg, pi->rd.line, pi->rd.col, file, line);
|
999
942
|
} else {
|
1000
943
|
_oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
|
1001
944
|
}
|
@@ -1014,7 +957,7 @@ static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
|
|
1014
957
|
|
1015
958
|
if (oj_utf8_encoding_index != idx) {
|
1016
959
|
rb_encoding *enc = rb_enc_from_index(idx);
|
1017
|
-
*inputp
|
960
|
+
*inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
|
1018
961
|
}
|
1019
962
|
pi->json = RSTRING_PTR(*inputp);
|
1020
963
|
pi->end = pi->json + RSTRING_LEN(*inputp);
|
@@ -1022,12 +965,12 @@ static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
|
|
1022
965
|
|
1023
966
|
VALUE
|
1024
967
|
oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
|
1025
|
-
char *
|
1026
|
-
VALUE
|
1027
|
-
VALUE
|
1028
|
-
VALUE
|
1029
|
-
int
|
1030
|
-
int
|
968
|
+
char *buf = 0;
|
969
|
+
VALUE input;
|
970
|
+
VALUE wrapped_stack;
|
971
|
+
VALUE result = Qnil;
|
972
|
+
int line = 0;
|
973
|
+
int free_json = 0;
|
1031
974
|
|
1032
975
|
if (argc < 1) {
|
1033
976
|
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
@@ -1076,19 +1019,18 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1076
1019
|
size_t len = lseek(fd, 0, SEEK_END);
|
1077
1020
|
|
1078
1021
|
lseek(fd, 0, SEEK_SET);
|
1079
|
-
buf =
|
1022
|
+
buf = OJ_R_ALLOC_N(char, len + 1);
|
1080
1023
|
pi->json = buf;
|
1081
1024
|
pi->end = buf + len;
|
1082
1025
|
if (0 >= (cnt = read(fd, (char *)pi->json, len)) || cnt != (ssize_t)len) {
|
1083
1026
|
if (0 != buf) {
|
1084
|
-
|
1027
|
+
OJ_R_FREE(buf);
|
1085
1028
|
}
|
1086
1029
|
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
1087
1030
|
}
|
1088
1031
|
((char *)pi->json)[len] = '\0';
|
1089
1032
|
/* skip UTF-8 BOM if present */
|
1090
|
-
if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] &&
|
1091
|
-
0xBF == (uint8_t)pi->json[2]) {
|
1033
|
+
if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) {
|
1092
1034
|
pi->cur += 3;
|
1093
1035
|
}
|
1094
1036
|
#endif
|
@@ -1114,8 +1056,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1114
1056
|
wrapped_stack = oj_stack_init(&pi->stack);
|
1115
1057
|
rb_protect(protect_parse, (VALUE)pi, &line);
|
1116
1058
|
if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
|
1117
|
-
if (No == pi->options.nilnil ||
|
1118
|
-
(CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
|
1059
|
+
if (No == pi->options.nilnil || (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
|
1119
1060
|
oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input");
|
1120
1061
|
}
|
1121
1062
|
}
|
@@ -1143,9 +1084,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1143
1084
|
switch (v->next) {
|
1144
1085
|
case NEXT_ARRAY_NEW:
|
1145
1086
|
case NEXT_ARRAY_ELEMENT:
|
1146
|
-
case NEXT_ARRAY_COMMA:
|
1147
|
-
oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
|
1148
|
-
break;
|
1087
|
+
case NEXT_ARRAY_COMMA: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); break;
|
1149
1088
|
case NEXT_HASH_NEW:
|
1150
1089
|
case NEXT_HASH_KEY:
|
1151
1090
|
case NEXT_HASH_COLON:
|
@@ -1163,9 +1102,9 @@ CLEANUP:
|
|
1163
1102
|
oj_circ_array_free(pi->circ_array);
|
1164
1103
|
}
|
1165
1104
|
if (0 != buf) {
|
1166
|
-
|
1105
|
+
OJ_R_FREE(buf);
|
1167
1106
|
} else if (free_json) {
|
1168
|
-
|
1107
|
+
OJ_R_FREE(json);
|
1169
1108
|
}
|
1170
1109
|
stack_cleanup(&pi->stack);
|
1171
1110
|
if (pi->str_rx.head != oj_default_options.str_rx.head) {
|
data/ext/oj/parse.h
CHANGED
@@ -32,7 +32,7 @@ typedef struct _numInfo {
|
|
32
32
|
int has_exp;
|
33
33
|
int no_big;
|
34
34
|
int bigdec_load;
|
35
|
-
} *
|
35
|
+
} *NumInfo;
|
36
36
|
|
37
37
|
typedef struct _parseInfo {
|
38
38
|
// used for the string parser
|
@@ -54,11 +54,7 @@ typedef struct _parseInfo {
|
|
54
54
|
VALUE (*start_hash)(struct _parseInfo *pi);
|
55
55
|
void (*end_hash)(struct _parseInfo *pi);
|
56
56
|
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);
|
57
|
+
void (*hash_set_cstr)(struct _parseInfo *pi, Val kval, const char *str, size_t len, const char *orig);
|
62
58
|
void (*hash_set_num)(struct _parseInfo *pi, Val kval, NumInfo ni);
|
63
59
|
void (*hash_set_value)(struct _parseInfo *pi, Val kval, VALUE value);
|
64
60
|
|
@@ -73,11 +69,10 @@ typedef struct _parseInfo {
|
|
73
69
|
void (*add_value)(struct _parseInfo *pi, VALUE val);
|
74
70
|
VALUE err_class;
|
75
71
|
bool has_callbacks;
|
76
|
-
} *
|
72
|
+
} *ParseInfo;
|
77
73
|
|
78
|
-
extern void
|
79
|
-
extern void
|
80
|
-
oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...);
|
74
|
+
extern void oj_parse2(ParseInfo pi);
|
75
|
+
extern void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...);
|
81
76
|
extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk);
|
82
77
|
extern VALUE oj_num_as_value(NumInfo ni);
|
83
78
|
|
data/ext/oj/parser.c
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
#define FRAC_LIMIT 10000000000000000ULL
|
21
21
|
|
22
22
|
// Give better performance with indented JSON but worse with unindented.
|
23
|
-
|
23
|
+
// #define SPACE_JUMP
|
24
24
|
|
25
25
|
enum {
|
26
26
|
SKIP_CHAR = 'a',
|
@@ -1148,7 +1148,7 @@ static void parser_free(void *ptr) {
|
|
1148
1148
|
if (NULL != p->free) {
|
1149
1149
|
p->free(p);
|
1150
1150
|
}
|
1151
|
-
|
1151
|
+
OJ_R_FREE(ptr);
|
1152
1152
|
}
|
1153
1153
|
|
1154
1154
|
static void parser_mark(void *ptr) {
|
@@ -1180,7 +1180,7 @@ static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
|
|
1180
1180
|
rkey = rb_sym2str(rkey);
|
1181
1181
|
// fall through
|
1182
1182
|
case RUBY_T_STRING:
|
1183
|
-
key =
|
1183
|
+
key = StringValuePtr(rkey);
|
1184
1184
|
klen = RSTRING_LEN(rkey);
|
1185
1185
|
break;
|
1186
1186
|
default: rb_raise(rb_eArgError, "option keys must be a symbol or string");
|
@@ -1205,7 +1205,7 @@ static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
|
|
1205
1205
|
* Oj::Parser.new(:usual, cache_keys: true).
|
1206
1206
|
*/
|
1207
1207
|
static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
1208
|
-
ojParser p =
|
1208
|
+
ojParser p = OJ_R_ALLOC(struct _ojParser);
|
1209
1209
|
|
1210
1210
|
#if HAVE_RB_EXT_RACTOR_SAFE
|
1211
1211
|
// This doesn't seem to do anything.
|
@@ -1264,7 +1264,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
1264
1264
|
// used. Optionally oj_parser_set_options can be called if the options are not
|
1265
1265
|
// set directly.
|
1266
1266
|
VALUE oj_parser_new(void) {
|
1267
|
-
ojParser p =
|
1267
|
+
ojParser p = OJ_R_ALLOC(struct _ojParser);
|
1268
1268
|
|
1269
1269
|
#if HAVE_RB_EXT_RACTOR_SAFE
|
1270
1270
|
// This doesn't seem to do anything.
|
@@ -1349,7 +1349,7 @@ static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
|
|
1349
1349
|
case RUBY_T_SYMBOL:
|
1350
1350
|
rkey = rb_sym2str(rkey);
|
1351
1351
|
// fall through
|
1352
|
-
case RUBY_T_STRING: key =
|
1352
|
+
case RUBY_T_STRING: key = StringValuePtr(rkey); break;
|
1353
1353
|
default: rb_raise(rb_eArgError, "option method must be a symbol or string");
|
1354
1354
|
}
|
1355
1355
|
if (1 < argc) {
|
@@ -1366,12 +1366,12 @@ static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
|
|
1366
1366
|
* Returns the result according to the delegate of the parser.
|
1367
1367
|
*/
|
1368
1368
|
static VALUE parser_parse(VALUE self, VALUE json) {
|
1369
|
-
ojParser
|
1369
|
+
ojParser p = (ojParser)DATA_PTR(self);
|
1370
|
+
const byte *ptr = (const byte *)StringValuePtr(json);
|
1370
1371
|
|
1371
|
-
Check_Type(json, T_STRING);
|
1372
1372
|
parser_reset(p);
|
1373
1373
|
p->start(p);
|
1374
|
-
parse(p,
|
1374
|
+
parse(p, ptr);
|
1375
1375
|
|
1376
1376
|
return p->result(p);
|
1377
1377
|
}
|
@@ -1424,8 +1424,7 @@ static VALUE parser_file(VALUE self, VALUE filename) {
|
|
1424
1424
|
const char *path;
|
1425
1425
|
int fd;
|
1426
1426
|
|
1427
|
-
|
1428
|
-
path = rb_string_value_ptr(&filename);
|
1427
|
+
path = StringValuePtr(filename);
|
1429
1428
|
|
1430
1429
|
parser_reset(p);
|
1431
1430
|
p->start(p);
|
@@ -1499,7 +1498,7 @@ static VALUE usual_parser = Qundef;
|
|
1499
1498
|
*/
|
1500
1499
|
static VALUE parser_usual(VALUE self) {
|
1501
1500
|
if (Qundef == usual_parser) {
|
1502
|
-
ojParser p =
|
1501
|
+
ojParser p = OJ_R_ALLOC(struct _ojParser);
|
1503
1502
|
|
1504
1503
|
memset(p, 0, sizeof(struct _ojParser));
|
1505
1504
|
buf_init(&p->key);
|
@@ -1522,7 +1521,7 @@ static VALUE saj_parser = Qundef;
|
|
1522
1521
|
*/
|
1523
1522
|
static VALUE parser_saj(VALUE self) {
|
1524
1523
|
if (Qundef == saj_parser) {
|
1525
|
-
ojParser p =
|
1524
|
+
ojParser p = OJ_R_ALLOC(struct _ojParser);
|
1526
1525
|
|
1527
1526
|
memset(p, 0, sizeof(struct _ojParser));
|
1528
1527
|
buf_init(&p->key);
|
@@ -1544,7 +1543,7 @@ static VALUE validate_parser = Qundef;
|
|
1544
1543
|
*/
|
1545
1544
|
static VALUE parser_validate(VALUE self) {
|
1546
1545
|
if (Qundef == validate_parser) {
|
1547
|
-
ojParser p =
|
1546
|
+
ojParser p = OJ_R_ALLOC(struct _ojParser);
|
1548
1547
|
|
1549
1548
|
memset(p, 0, sizeof(struct _ojParser));
|
1550
1549
|
buf_init(&p->key);
|
data/ext/oj/parser.h
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
#ifndef OJ_PARSER_H
|
5
5
|
#define OJ_PARSER_H
|
6
6
|
|
7
|
-
#include <stdbool.h>
|
8
7
|
#include <ruby.h>
|
8
|
+
#include <stdbool.h>
|
9
9
|
|
10
10
|
#include "buf.h"
|
11
11
|
|
@@ -38,7 +38,7 @@ typedef struct _num {
|
|
38
38
|
bool neg;
|
39
39
|
bool exp_neg;
|
40
40
|
// for numbers as strings, reuse buf
|
41
|
-
} *
|
41
|
+
} *Num;
|
42
42
|
|
43
43
|
struct _ojParser;
|
44
44
|
|
@@ -54,11 +54,11 @@ typedef struct _funcs {
|
|
54
54
|
void (*close_array)(struct _ojParser *p);
|
55
55
|
void (*open_object)(struct _ojParser *p);
|
56
56
|
void (*close_object)(struct _ojParser *p);
|
57
|
-
} *
|
57
|
+
} *Funcs;
|
58
58
|
|
59
59
|
typedef struct _ojParser {
|
60
|
-
const char
|
61
|
-
const char
|
60
|
+
const char *map;
|
61
|
+
const char *next_map;
|
62
62
|
int depth;
|
63
63
|
unsigned char stack[1024];
|
64
64
|
|
@@ -67,7 +67,7 @@ typedef struct _ojParser {
|
|
67
67
|
struct _buf key;
|
68
68
|
struct _buf buf;
|
69
69
|
|
70
|
-
struct _funcs funcs[3];
|
70
|
+
struct _funcs funcs[3]; // indexed by XXX_FUN defines
|
71
71
|
|
72
72
|
void (*start)(struct _ojParser *p);
|
73
73
|
VALUE (*option)(struct _ojParser *p, const char *key, VALUE value);
|
@@ -86,7 +86,7 @@ typedef struct _ojParser {
|
|
86
86
|
uint32_t ucode;
|
87
87
|
ojType type; // valType
|
88
88
|
bool just_one;
|
89
|
-
} *
|
89
|
+
} *ojParser;
|
90
90
|
|
91
91
|
// Create a new parser without setting the delegate. The parser is
|
92
92
|
// wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
|
@@ -98,5 +98,4 @@ extern VALUE oj_parser_new();
|
|
98
98
|
// Set set the options from a hash (ropts).
|
99
99
|
extern void oj_parser_set_option(ojParser p, VALUE ropts);
|
100
100
|
|
101
|
-
|
102
101
|
#endif /* OJ_PARSER_H */
|