oj 3.13.14 → 3.13.22
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 +32 -0
- data/README.md +2 -0
- data/ext/oj/buf.h +4 -0
- data/ext/oj/compat.c +10 -10
- data/ext/oj/custom.c +34 -53
- data/ext/oj/dump.c +24 -13
- data/ext/oj/dump_compat.c +5 -10
- data/ext/oj/dump_object.c +5 -60
- data/ext/oj/dump_strict.c +5 -5
- data/ext/oj/extconf.rb +5 -4
- data/ext/oj/fast.c +15 -13
- data/ext/oj/intern.c +6 -9
- data/ext/oj/introspect.c +96 -0
- data/ext/oj/mimic_json.c +18 -8
- data/ext/oj/object.c +42 -41
- data/ext/oj/oj.c +27 -4
- data/ext/oj/oj.h +4 -1
- data/ext/oj/parse.c +111 -76
- data/ext/oj/parse.h +2 -0
- data/ext/oj/parser.c +61 -4
- data/ext/oj/parser.h +12 -0
- data/ext/oj/rails.c +5 -10
- data/ext/oj/saj2.c +333 -85
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/sparse.c +4 -0
- data/ext/oj/strict.c +13 -13
- data/ext/oj/usual.c +82 -129
- data/ext/oj/usual.h +68 -0
- data/ext/oj/val_stack.c +1 -1
- data/ext/oj/validate.c +21 -26
- data/ext/oj/wab.c +15 -20
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/state.rb +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/test/bar.rb +3 -1
- data/test/helper.rb +8 -2
- data/test/json_gem/json_generator_test.rb +3 -4
- data/test/json_gem/json_parser_test.rb +8 -1
- data/test/json_gem/test_helper.rb +7 -3
- data/test/test_compat.rb +25 -0
- data/test/test_custom.rb +13 -2
- data/test/test_file.rb +23 -7
- data/test/test_gc.rb +11 -0
- data/test/test_object.rb +3 -10
- data/test/test_parser.rb +3 -19
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +92 -2
- data/test/test_scp.rb +2 -4
- data/test/test_strict.rb +2 -0
- data/test/test_various.rb +8 -3
- data/test/test_wab.rb +2 -0
- data/test/tests.rb +9 -0
- data/test/tests_mimic.rb +9 -0
- data/test/tests_mimic_addition.rb +9 -0
- metadata +7 -107
data/ext/oj/oj.c
CHANGED
@@ -32,6 +32,7 @@ ID oj_array_append_id;
|
|
32
32
|
ID oj_array_end_id;
|
33
33
|
ID oj_array_start_id;
|
34
34
|
ID oj_as_json_id;
|
35
|
+
ID oj_at_id;
|
35
36
|
ID oj_begin_id;
|
36
37
|
ID oj_bigdecimal_id;
|
37
38
|
ID oj_end_id;
|
@@ -45,7 +46,6 @@ ID oj_hash_key_id;
|
|
45
46
|
ID oj_hash_set_id;
|
46
47
|
ID oj_hash_start_id;
|
47
48
|
ID oj_iconv_id;
|
48
|
-
ID oj_instance_variables_id;
|
49
49
|
ID oj_json_create_id;
|
50
50
|
ID oj_length_id;
|
51
51
|
ID oj_new_id;
|
@@ -90,7 +90,9 @@ VALUE oj_array_class_sym;
|
|
90
90
|
VALUE oj_create_additions_sym;
|
91
91
|
VALUE oj_decimal_class_sym;
|
92
92
|
VALUE oj_hash_class_sym;
|
93
|
+
VALUE oj_in_sym;
|
93
94
|
VALUE oj_indent_sym;
|
95
|
+
VALUE oj_nanosecond_sym;
|
94
96
|
VALUE oj_object_class_sym;
|
95
97
|
VALUE oj_quirks_mode_sym;
|
96
98
|
VALUE oj_safe_sym;
|
@@ -137,6 +139,7 @@ static VALUE rails_sym;
|
|
137
139
|
static VALUE raise_sym;
|
138
140
|
static VALUE ruby_sym;
|
139
141
|
static VALUE sec_prec_sym;
|
142
|
+
static VALUE slash_sym;
|
140
143
|
static VALUE strict_sym;
|
141
144
|
static VALUE symbol_keys_sym;
|
142
145
|
static VALUE time_format_sym;
|
@@ -405,6 +408,7 @@ static VALUE get_def_opts(VALUE self) {
|
|
405
408
|
switch (oj_default_options.escape_mode) {
|
406
409
|
case NLEsc: rb_hash_aset(opts, escape_mode_sym, newline_sym); break;
|
407
410
|
case JSONEsc: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
|
411
|
+
case SlashEsc: rb_hash_aset(opts, escape_mode_sym, slash_sym); break;
|
408
412
|
case XSSEsc: rb_hash_aset(opts, escape_mode_sym, xss_safe_sym); break;
|
409
413
|
case ASCIIEsc: rb_hash_aset(opts, escape_mode_sym, ascii_sym); break;
|
410
414
|
case JXEsc: rb_hash_aset(opts, escape_mode_sym, unicode_xss_sym); break;
|
@@ -734,6 +738,8 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
734
738
|
copts->escape_mode = NLEsc;
|
735
739
|
} else if (json_sym == v) {
|
736
740
|
copts->escape_mode = JSONEsc;
|
741
|
+
} else if (slash_sym == v) {
|
742
|
+
copts->escape_mode = SlashEsc;
|
737
743
|
} else if (xss_safe_sym == v) {
|
738
744
|
copts->escape_mode = XSSEsc;
|
739
745
|
} else if (ascii_sym == v) {
|
@@ -926,7 +932,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
926
932
|
if (Qnil == v) {
|
927
933
|
return ST_CONTINUE;
|
928
934
|
}
|
929
|
-
if (
|
935
|
+
if (rb_obj_class(v) == rb_cRange) {
|
930
936
|
VALUE min = rb_funcall(v, oj_begin_id, 0);
|
931
937
|
VALUE max = rb_funcall(v, oj_end_id, 0);
|
932
938
|
|
@@ -1148,7 +1154,17 @@ static VALUE load_file(int argc, VALUE *argv, VALUE self) {
|
|
1148
1154
|
}
|
1149
1155
|
}
|
1150
1156
|
path = StringValuePtr(*argv);
|
1151
|
-
|
1157
|
+
#ifdef _WIN32
|
1158
|
+
{
|
1159
|
+
WCHAR *wide_path;
|
1160
|
+
wide_path = rb_w32_mbstr_to_wstr(CP_UTF8, path, -1, NULL);
|
1161
|
+
fd = rb_w32_wopen(wide_path, O_RDONLY);
|
1162
|
+
free(wide_path);
|
1163
|
+
}
|
1164
|
+
#else
|
1165
|
+
fd = open(path, O_RDONLY);
|
1166
|
+
#endif
|
1167
|
+
if (0 == fd) {
|
1152
1168
|
rb_raise(rb_eIOError, "%s", strerror(errno));
|
1153
1169
|
}
|
1154
1170
|
switch (mode) {
|
@@ -1801,6 +1817,7 @@ void Init_oj(void) {
|
|
1801
1817
|
oj_array_end_id = rb_intern("array_end");
|
1802
1818
|
oj_array_start_id = rb_intern("array_start");
|
1803
1819
|
oj_as_json_id = rb_intern("as_json");
|
1820
|
+
oj_at_id = rb_intern("at");
|
1804
1821
|
oj_begin_id = rb_intern("begin");
|
1805
1822
|
oj_bigdecimal_id = rb_intern("BigDecimal");
|
1806
1823
|
oj_end_id = rb_intern("end");
|
@@ -1814,7 +1831,6 @@ void Init_oj(void) {
|
|
1814
1831
|
oj_hash_set_id = rb_intern("hash_set");
|
1815
1832
|
oj_hash_start_id = rb_intern("hash_start");
|
1816
1833
|
oj_iconv_id = rb_intern("iconv");
|
1817
|
-
oj_instance_variables_id = rb_intern("instance_variables");
|
1818
1834
|
oj_json_create_id = rb_intern("json_create");
|
1819
1835
|
oj_length_id = rb_intern("length");
|
1820
1836
|
oj_new_id = rb_intern("new");
|
@@ -1949,10 +1965,14 @@ void Init_oj(void) {
|
|
1949
1965
|
rb_gc_register_address(&oj_decimal_class_sym);
|
1950
1966
|
oj_hash_class_sym = ID2SYM(rb_intern("hash_class"));
|
1951
1967
|
rb_gc_register_address(&oj_hash_class_sym);
|
1968
|
+
oj_in_sym = ID2SYM(rb_intern("in"));
|
1969
|
+
rb_gc_register_address(&oj_in_sym);
|
1952
1970
|
oj_indent_sym = ID2SYM(rb_intern("indent"));
|
1953
1971
|
rb_gc_register_address(&oj_indent_sym);
|
1954
1972
|
oj_max_nesting_sym = ID2SYM(rb_intern("max_nesting"));
|
1955
1973
|
rb_gc_register_address(&oj_max_nesting_sym);
|
1974
|
+
oj_nanosecond_sym = ID2SYM(rb_intern("nanosecond"));
|
1975
|
+
rb_gc_register_address(&oj_nanosecond_sym);
|
1956
1976
|
oj_object_class_sym = ID2SYM(rb_intern("object_class"));
|
1957
1977
|
rb_gc_register_address(&oj_object_class_sym);
|
1958
1978
|
oj_object_nl_sym = ID2SYM(rb_intern("object_nl"));
|
@@ -1977,6 +1997,8 @@ void Init_oj(void) {
|
|
1977
1997
|
rb_gc_register_address(&ruby_sym);
|
1978
1998
|
sec_prec_sym = ID2SYM(rb_intern("second_precision"));
|
1979
1999
|
rb_gc_register_address(&sec_prec_sym);
|
2000
|
+
slash_sym = ID2SYM(rb_intern("slash"));
|
2001
|
+
rb_gc_register_address(&slash_sym);
|
1980
2002
|
strict_sym = ID2SYM(rb_intern("strict"));
|
1981
2003
|
rb_gc_register_address(&strict_sym);
|
1982
2004
|
symbol_keys_sym = ID2SYM(rb_intern("symbol_keys"));
|
@@ -2029,4 +2051,5 @@ void Init_oj(void) {
|
|
2029
2051
|
oj_init_doc();
|
2030
2052
|
|
2031
2053
|
oj_parser_init();
|
2054
|
+
oj_scanner_init();
|
2032
2055
|
}
|
data/ext/oj/oj.h
CHANGED
@@ -66,6 +66,7 @@ typedef enum { UnixTime = 'u', UnixZTime = 'z', XmlTime = 'x', RubyTime = 'r' }
|
|
66
66
|
typedef enum {
|
67
67
|
NLEsc = 'n',
|
68
68
|
JSONEsc = 'j',
|
69
|
+
SlashEsc = 's',
|
69
70
|
XSSEsc = 'x',
|
70
71
|
ASCIIEsc = 'a',
|
71
72
|
JXEsc = 'g', // json gem
|
@@ -316,7 +317,9 @@ extern VALUE oj_ascii_only_sym;
|
|
316
317
|
extern VALUE oj_create_additions_sym;
|
317
318
|
extern VALUE oj_decimal_class_sym;
|
318
319
|
extern VALUE oj_hash_class_sym;
|
320
|
+
extern VALUE oj_in_sym;
|
319
321
|
extern VALUE oj_indent_sym;
|
322
|
+
extern VALUE oj_nanosecond_sym;
|
320
323
|
extern VALUE oj_max_nesting_sym;
|
321
324
|
extern VALUE oj_object_class_sym;
|
322
325
|
extern VALUE oj_object_nl_sym;
|
@@ -333,6 +336,7 @@ extern ID oj_array_append_id;
|
|
333
336
|
extern ID oj_array_end_id;
|
334
337
|
extern ID oj_array_start_id;
|
335
338
|
extern ID oj_as_json_id;
|
339
|
+
extern ID oj_at_id;
|
336
340
|
extern ID oj_begin_id;
|
337
341
|
extern ID oj_bigdecimal_id;
|
338
342
|
extern ID oj_end_id;
|
@@ -346,7 +350,6 @@ extern ID oj_hash_key_id;
|
|
346
350
|
extern ID oj_hash_set_id;
|
347
351
|
extern ID oj_hash_start_id;
|
348
352
|
extern ID oj_iconv_id;
|
349
|
-
extern ID oj_instance_variables_id;
|
350
353
|
extern ID oj_json_create_id;
|
351
354
|
extern ID oj_length_id;
|
352
355
|
extern ID oj_new_id;
|
data/ext/oj/parse.c
CHANGED
@@ -183,6 +183,42 @@ static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
|
183
183
|
}
|
184
184
|
}
|
185
185
|
|
186
|
+
static inline const char *scan_string_noSIMD(const char *str, const char *end) {
|
187
|
+
for (; '"' != *str; str++) {
|
188
|
+
if (end <= str || '\0' == *str || '\\' == *str) {
|
189
|
+
break;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
return str;
|
193
|
+
}
|
194
|
+
|
195
|
+
#ifdef OJ_USE_SSE4_2
|
196
|
+
static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
197
|
+
static const char chars[16] = "\x00\\\"";
|
198
|
+
const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
|
199
|
+
const char *_end = (const char *)(end - 16);
|
200
|
+
|
201
|
+
for (; str <= _end; str += 16) {
|
202
|
+
const __m128i string = _mm_loadu_si128((const __m128i *)str);
|
203
|
+
const int r = _mm_cmpestri(terminate, 3, string, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
|
204
|
+
if (r != 16) {
|
205
|
+
str = (char*)(str + r);
|
206
|
+
return str;
|
207
|
+
}
|
208
|
+
}
|
209
|
+
|
210
|
+
return scan_string_noSIMD(str, end);
|
211
|
+
}
|
212
|
+
#endif
|
213
|
+
|
214
|
+
static const char *(*scan_func) (const char *str, const char *end) = scan_string_noSIMD;
|
215
|
+
|
216
|
+
void oj_scanner_init(void) {
|
217
|
+
#ifdef OJ_USE_SSE4_2
|
218
|
+
scan_func = scan_string_SIMD;
|
219
|
+
#endif
|
220
|
+
}
|
221
|
+
|
186
222
|
// entered at /
|
187
223
|
static void read_escaped_str(ParseInfo pi, const char *start) {
|
188
224
|
struct _buf buf;
|
@@ -192,11 +228,11 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
192
228
|
Val parent = stack_peek(&pi->stack);
|
193
229
|
|
194
230
|
buf_init(&buf);
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
if (
|
231
|
+
buf_append_string(&buf, start, cnt);
|
232
|
+
|
233
|
+
for (s = pi->cur; '"' != *s;) {
|
234
|
+
const char *scanned = scan_func(s, pi->end);
|
235
|
+
if (scanned >= pi->end) {
|
200
236
|
oj_set_error_at(pi,
|
201
237
|
oj_parse_error_class,
|
202
238
|
__FILE__,
|
@@ -204,7 +240,12 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
204
240
|
"quoted string not terminated");
|
205
241
|
buf_cleanup(&buf);
|
206
242
|
return;
|
207
|
-
}
|
243
|
+
}
|
244
|
+
|
245
|
+
buf_append_string(&buf, s, (size_t)(scanned - s));
|
246
|
+
s = scanned;
|
247
|
+
|
248
|
+
if ('\\' == *s) {
|
208
249
|
s++;
|
209
250
|
switch (*s) {
|
210
251
|
case 'n': buf_append(&buf, '\n'); break;
|
@@ -273,8 +314,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
273
314
|
buf_cleanup(&buf);
|
274
315
|
return;
|
275
316
|
}
|
276
|
-
|
277
|
-
buf_append(&buf, *s);
|
317
|
+
s++;
|
278
318
|
}
|
279
319
|
}
|
280
320
|
if (0 == parent) {
|
@@ -331,22 +371,24 @@ static void read_str(ParseInfo pi) {
|
|
331
371
|
const char *str = pi->cur;
|
332
372
|
Val parent = stack_peek(&pi->stack);
|
333
373
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
} else if ('\0' == *pi->cur) {
|
343
|
-
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string");
|
344
|
-
return;
|
345
|
-
} else if ('\\' == *pi->cur) {
|
346
|
-
read_escaped_str(pi, str);
|
347
|
-
return;
|
348
|
-
}
|
374
|
+
pi->cur = scan_func(pi->cur, pi->end);
|
375
|
+
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");
|
381
|
+
return;
|
349
382
|
}
|
383
|
+
if (RB_UNLIKELY('\0' == *pi->cur)) {
|
384
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string");
|
385
|
+
return;
|
386
|
+
}
|
387
|
+
if ('\\' == *pi->cur) {
|
388
|
+
read_escaped_str(pi, str);
|
389
|
+
return;
|
390
|
+
}
|
391
|
+
|
350
392
|
if (0 == parent) { // simple add
|
351
393
|
pi->add_cstr(pi, str, pi->cur - str, str);
|
352
394
|
} else {
|
@@ -459,33 +501,31 @@ static void read_num(ParseInfo pi) {
|
|
459
501
|
int dec_cnt = 0;
|
460
502
|
bool zero1 = false;
|
461
503
|
|
504
|
+
// Skip leading zeros.
|
505
|
+
for (; '0' == *pi->cur; pi->cur++) {
|
506
|
+
zero1 = true;
|
507
|
+
}
|
508
|
+
|
462
509
|
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
463
|
-
|
464
|
-
zero1 = true;
|
465
|
-
}
|
466
|
-
if (0 < ni.i) {
|
467
|
-
dec_cnt++;
|
468
|
-
}
|
469
|
-
if (!ni.big) {
|
470
|
-
int d = (*pi->cur - '0');
|
510
|
+
int d = (*pi->cur - '0');
|
471
511
|
|
472
|
-
|
473
|
-
|
474
|
-
oj_set_error_at(pi,
|
475
|
-
oj_parse_error_class,
|
476
|
-
__FILE__,
|
477
|
-
__LINE__,
|
478
|
-
"not a number");
|
479
|
-
return;
|
480
|
-
}
|
481
|
-
zero1 = false;
|
482
|
-
}
|
483
|
-
ni.i = ni.i * 10 + d;
|
484
|
-
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
485
|
-
ni.big = 1;
|
486
|
-
}
|
512
|
+
if (RB_LIKELY(0 != ni.i)) {
|
513
|
+
dec_cnt++;
|
487
514
|
}
|
515
|
+
ni.i = ni.i * 10 + d;
|
488
516
|
}
|
517
|
+
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");
|
523
|
+
return;
|
524
|
+
}
|
525
|
+
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
526
|
+
ni.big = true;
|
527
|
+
}
|
528
|
+
|
489
529
|
if ('.' == *pi->cur) {
|
490
530
|
pi->cur++;
|
491
531
|
// A trailing . is not a valid decimal but if encountered allow it
|
@@ -505,25 +545,20 @@ static void read_num(ParseInfo pi) {
|
|
505
545
|
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
506
546
|
int d = (*pi->cur - '0');
|
507
547
|
|
508
|
-
if (0
|
548
|
+
if (RB_LIKELY(0 != ni.num || 0 != ni.i)) {
|
509
549
|
dec_cnt++;
|
510
550
|
}
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
520
|
-
if (!ni.no_big) {
|
521
|
-
ni.big = true;
|
522
|
-
}
|
523
|
-
}
|
524
|
-
}
|
551
|
+
ni.num = ni.num * 10 + d;
|
552
|
+
ni.div *= 10;
|
553
|
+
ni.di++;
|
554
|
+
}
|
555
|
+
}
|
556
|
+
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
557
|
+
if (!ni.no_big) {
|
558
|
+
ni.big = true;
|
525
559
|
}
|
526
560
|
}
|
561
|
+
|
527
562
|
if ('e' == *pi->cur || 'E' == *pi->cur) {
|
528
563
|
int eneg = 0;
|
529
564
|
|
@@ -596,7 +631,7 @@ static void read_num(ParseInfo pi) {
|
|
596
631
|
}
|
597
632
|
|
598
633
|
static void array_start(ParseInfo pi) {
|
599
|
-
|
634
|
+
VALUE v = pi->start_array(pi);
|
600
635
|
|
601
636
|
stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
|
602
637
|
}
|
@@ -620,13 +655,13 @@ static void array_end(ParseInfo pi) {
|
|
620
655
|
}
|
621
656
|
|
622
657
|
static void hash_start(ParseInfo pi) {
|
623
|
-
|
658
|
+
VALUE v = pi->start_hash(pi);
|
624
659
|
|
625
660
|
stack_push(&pi->stack, v, NEXT_HASH_NEW);
|
626
661
|
}
|
627
662
|
|
628
663
|
static void hash_end(ParseInfo pi) {
|
629
|
-
|
664
|
+
Val hash = stack_peek(&pi->stack);
|
630
665
|
|
631
666
|
// leave hash on stack until just before
|
632
667
|
if (0 == hash) {
|
@@ -813,7 +848,7 @@ static long double exp_plus[] = {
|
|
813
848
|
|
814
849
|
VALUE
|
815
850
|
oj_num_as_value(NumInfo ni) {
|
816
|
-
|
851
|
+
VALUE rnum = Qnil;
|
817
852
|
|
818
853
|
if (ni->infinity) {
|
819
854
|
if (ni->neg) {
|
@@ -848,7 +883,7 @@ oj_num_as_value(NumInfo ni) {
|
|
848
883
|
}
|
849
884
|
} else { // decimal
|
850
885
|
if (ni->big) {
|
851
|
-
|
886
|
+
VALUE bd = rb_str_new(ni->str, ni->len);
|
852
887
|
|
853
888
|
rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
|
854
889
|
if (ni->no_big) {
|
@@ -876,7 +911,7 @@ oj_num_as_value(NumInfo ni) {
|
|
876
911
|
}
|
877
912
|
rnum = rb_float_new((double)ld);
|
878
913
|
} else if (RubyDec == ni->bigdec_load) {
|
879
|
-
|
914
|
+
VALUE sv = rb_str_new(ni->str, ni->len);
|
880
915
|
|
881
916
|
rnum = rb_funcall(sv, rb_intern("to_f"), 0);
|
882
917
|
} else {
|
@@ -971,7 +1006,7 @@ static VALUE protect_parse(VALUE pip) {
|
|
971
1006
|
|
972
1007
|
extern int oj_utf8_index;
|
973
1008
|
|
974
|
-
static void oj_pi_set_input_str(ParseInfo pi,
|
1009
|
+
static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
|
975
1010
|
int idx = RB_ENCODING_GET(*inputp);
|
976
1011
|
|
977
1012
|
if (oj_utf8_encoding_index != idx) {
|
@@ -984,12 +1019,12 @@ static void oj_pi_set_input_str(ParseInfo pi, volatile VALUE *inputp) {
|
|
984
1019
|
|
985
1020
|
VALUE
|
986
1021
|
oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
|
987
|
-
char *
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
int
|
992
|
-
int
|
1022
|
+
char * buf = 0;
|
1023
|
+
VALUE input;
|
1024
|
+
VALUE wrapped_stack;
|
1025
|
+
VALUE result = Qnil;
|
1026
|
+
int line = 0;
|
1027
|
+
int free_json = 0;
|
993
1028
|
|
994
1029
|
if (argc < 1) {
|
995
1030
|
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
@@ -1025,8 +1060,8 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1025
1060
|
rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
|
1026
1061
|
}
|
1027
1062
|
} else {
|
1028
|
-
VALUE
|
1029
|
-
|
1063
|
+
VALUE clas = rb_obj_class(input);
|
1064
|
+
VALUE s;
|
1030
1065
|
|
1031
1066
|
if (oj_stringio_class == clas) {
|
1032
1067
|
s = rb_funcall2(input, oj_string_id, 0, 0);
|
data/ext/oj/parse.h
CHANGED
data/ext/oj/parser.c
CHANGED
@@ -533,6 +533,7 @@ static void calc_num(ojParser p) {
|
|
533
533
|
// nothing to do
|
534
534
|
break;
|
535
535
|
}
|
536
|
+
p->type = OJ_NONE;
|
536
537
|
}
|
537
538
|
|
538
539
|
static void big_change(ojParser p) {
|
@@ -598,6 +599,8 @@ static void parse(ojParser p, const byte *json) {
|
|
598
599
|
const byte *b = json;
|
599
600
|
int i;
|
600
601
|
|
602
|
+
p->line = 1;
|
603
|
+
p->col = -1;
|
601
604
|
#if DEBUG
|
602
605
|
printf("*** parse - mode: %c %s\n", p->map[256], (const char *)json);
|
603
606
|
#endif
|
@@ -652,6 +655,7 @@ static void parse(ojParser p, const byte *json) {
|
|
652
655
|
}
|
653
656
|
buf_append_string(&p->buf, (const char *)start, b - start);
|
654
657
|
if ('"' == *b) {
|
658
|
+
p->cur = b - json;
|
655
659
|
p->funcs[p->stack[p->depth]].add_str(p);
|
656
660
|
p->map = (0 == p->depth) ? value_map : after_map;
|
657
661
|
break;
|
@@ -661,12 +665,14 @@ static void parse(ojParser p, const byte *json) {
|
|
661
665
|
p->next_map = (0 == p->depth) ? value_map : after_map;
|
662
666
|
break;
|
663
667
|
case OPEN_OBJECT:
|
668
|
+
p->cur = b - json;
|
664
669
|
p->funcs[p->stack[p->depth]].open_object(p);
|
665
670
|
p->depth++;
|
666
671
|
p->stack[p->depth] = OBJECT_FUN;
|
667
672
|
p->map = key1_map;
|
668
673
|
break;
|
669
674
|
case NUM_CLOSE_OBJECT:
|
675
|
+
p->cur = b - json;
|
670
676
|
calc_num(p);
|
671
677
|
// flow through
|
672
678
|
case CLOSE_OBJECT:
|
@@ -677,15 +683,18 @@ static void parse(ojParser p, const byte *json) {
|
|
677
683
|
return;
|
678
684
|
}
|
679
685
|
p->depth--;
|
686
|
+
p->cur = b - json;
|
680
687
|
p->funcs[p->stack[p->depth]].close_object(p);
|
681
688
|
break;
|
682
689
|
case OPEN_ARRAY:
|
690
|
+
p->cur = b - json;
|
683
691
|
p->funcs[p->stack[p->depth]].open_array(p);
|
684
692
|
p->depth++;
|
685
693
|
p->stack[p->depth] = ARRAY_FUN;
|
686
694
|
p->map = value_map;
|
687
695
|
break;
|
688
696
|
case NUM_CLOSE_ARRAY:
|
697
|
+
p->cur = b - json;
|
689
698
|
calc_num(p);
|
690
699
|
// flow through
|
691
700
|
case CLOSE_ARRAY:
|
@@ -696,9 +705,11 @@ static void parse(ojParser p, const byte *json) {
|
|
696
705
|
return;
|
697
706
|
}
|
698
707
|
p->depth--;
|
708
|
+
p->cur = b - json;
|
699
709
|
p->funcs[p->stack[p->depth]].close_array(p);
|
700
710
|
break;
|
701
711
|
case NUM_COMMA:
|
712
|
+
p->cur = b - json;
|
702
713
|
calc_num(p);
|
703
714
|
if (0 < p->depth && OBJECT_FUN == p->stack[p->depth]) {
|
704
715
|
p->map = key_map;
|
@@ -860,8 +871,14 @@ static void parse(ojParser p, const byte *json) {
|
|
860
871
|
b--;
|
861
872
|
p->map = big_exp_map;
|
862
873
|
break;
|
863
|
-
case NUM_SPC:
|
864
|
-
|
874
|
+
case NUM_SPC:
|
875
|
+
p->cur = b - json;
|
876
|
+
calc_num(p);
|
877
|
+
break;
|
878
|
+
case NUM_NEWLINE:
|
879
|
+
p->cur = b - json;
|
880
|
+
calc_num(p);
|
881
|
+
b++;
|
865
882
|
#ifdef SPACE_JUMP
|
866
883
|
// for (uint32_t *sj = (uint32_t*)b; 0x20202020 == *sj; sj++) { b += 4; }
|
867
884
|
for (uint16_t *sj = (uint16_t *)b; 0x2020 == *sj; sj++) {
|
@@ -882,6 +899,7 @@ static void parse(ojParser p, const byte *json) {
|
|
882
899
|
buf_append_string(&p->buf, (const char *)start, b - start);
|
883
900
|
}
|
884
901
|
if ('"' == *b) {
|
902
|
+
p->cur = b - json;
|
885
903
|
p->funcs[p->stack[p->depth]].add_str(p);
|
886
904
|
p->map = p->next_map;
|
887
905
|
break;
|
@@ -890,6 +908,7 @@ static void parse(ojParser p, const byte *json) {
|
|
890
908
|
break;
|
891
909
|
case STR_SLASH: p->map = esc_map; break;
|
892
910
|
case STR_QUOTE:
|
911
|
+
p->cur = b - json;
|
893
912
|
p->funcs[p->stack[p->depth]].add_str(p);
|
894
913
|
p->map = p->next_map;
|
895
914
|
break;
|
@@ -967,6 +986,7 @@ static void parse(ojParser p, const byte *json) {
|
|
967
986
|
case VAL_NULL:
|
968
987
|
if ('u' == b[1] && 'l' == b[2] && 'l' == b[3]) {
|
969
988
|
b += 3;
|
989
|
+
p->cur = b - json;
|
970
990
|
p->funcs[p->stack[p->depth]].add_null(p);
|
971
991
|
p->map = (0 == p->depth) ? value_map : after_map;
|
972
992
|
break;
|
@@ -992,6 +1012,7 @@ static void parse(ojParser p, const byte *json) {
|
|
992
1012
|
case VAL_TRUE:
|
993
1013
|
if ('r' == b[1] && 'u' == b[2] && 'e' == b[3]) {
|
994
1014
|
b += 3;
|
1015
|
+
p->cur = b - json;
|
995
1016
|
p->funcs[p->stack[p->depth]].add_true(p);
|
996
1017
|
p->map = (0 == p->depth) ? value_map : after_map;
|
997
1018
|
break;
|
@@ -1017,6 +1038,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1017
1038
|
case VAL_FALSE:
|
1018
1039
|
if ('a' == b[1] && 'l' == b[2] && 's' == b[3] && 'e' == b[4]) {
|
1019
1040
|
b += 4;
|
1041
|
+
p->cur = b - json;
|
1020
1042
|
p->funcs[p->stack[p->depth]].add_false(p);
|
1021
1043
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1022
1044
|
break;
|
@@ -1050,6 +1072,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1050
1072
|
parse_error(p, "expected null");
|
1051
1073
|
return;
|
1052
1074
|
}
|
1075
|
+
p->cur = b - json;
|
1053
1076
|
p->funcs[p->stack[p->depth]].add_null(p);
|
1054
1077
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1055
1078
|
}
|
@@ -1061,6 +1084,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1061
1084
|
parse_error(p, "expected false");
|
1062
1085
|
return;
|
1063
1086
|
}
|
1087
|
+
p->cur = b - json;
|
1064
1088
|
p->funcs[p->stack[p->depth]].add_false(p);
|
1065
1089
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1066
1090
|
}
|
@@ -1072,6 +1096,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1072
1096
|
parse_error(p, "expected true");
|
1073
1097
|
return;
|
1074
1098
|
}
|
1099
|
+
p->cur = b - json;
|
1075
1100
|
p->funcs[p->stack[p->depth]].add_true(p);
|
1076
1101
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1077
1102
|
}
|
@@ -1089,6 +1114,9 @@ static void parse(ojParser p, const byte *json) {
|
|
1089
1114
|
p->map = trail_map;
|
1090
1115
|
}
|
1091
1116
|
}
|
1117
|
+
if (0 < p->depth) {
|
1118
|
+
parse_error(p, "parse error, not closed");
|
1119
|
+
}
|
1092
1120
|
if (0 == p->depth) {
|
1093
1121
|
switch (p->map[256]) {
|
1094
1122
|
case '0':
|
@@ -1099,7 +1127,10 @@ static void parse(ojParser p, const byte *json) {
|
|
1099
1127
|
case 'D':
|
1100
1128
|
case 'g':
|
1101
1129
|
case 'B':
|
1102
|
-
case 'Y':
|
1130
|
+
case 'Y':
|
1131
|
+
p->cur = b - json;
|
1132
|
+
calc_num(p);
|
1133
|
+
break;
|
1103
1134
|
}
|
1104
1135
|
}
|
1105
1136
|
return;
|
@@ -1223,6 +1254,32 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
1223
1254
|
return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
|
1224
1255
|
}
|
1225
1256
|
|
1257
|
+
// Create a new parser without setting the delegate. The parser is
|
1258
|
+
// wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
|
1259
|
+
// from this function. A delegate must be added before the parser can be
|
1260
|
+
// used. Optionally oj_parser_set_options can be called if the options are not
|
1261
|
+
// set directly.
|
1262
|
+
VALUE oj_parser_new() {
|
1263
|
+
ojParser p = ALLOC(struct _ojParser);
|
1264
|
+
|
1265
|
+
#if HAVE_RB_EXT_RACTOR_SAFE
|
1266
|
+
// This doesn't seem to do anything.
|
1267
|
+
rb_ext_ractor_safe(true);
|
1268
|
+
#endif
|
1269
|
+
memset(p, 0, sizeof(struct _ojParser));
|
1270
|
+
buf_init(&p->key);
|
1271
|
+
buf_init(&p->buf);
|
1272
|
+
p->map = value_map;
|
1273
|
+
|
1274
|
+
return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
// Set set the options from a hash (ropts).
|
1278
|
+
void oj_parser_set_option(ojParser p, VALUE ropts) {
|
1279
|
+
Check_Type(ropts, T_HASH);
|
1280
|
+
rb_hash_foreach(ropts, opt_cb, (VALUE)p);
|
1281
|
+
}
|
1282
|
+
|
1226
1283
|
/* Document-method: method_missing(value)
|
1227
1284
|
* call-seq: method_missing(value)
|
1228
1285
|
*
|
@@ -1456,7 +1513,7 @@ static VALUE saj_parser = Qundef;
|
|
1456
1513
|
/* Document-method: saj
|
1457
1514
|
* call-seq: saj
|
1458
1515
|
*
|
1459
|
-
* Returns the default
|
1516
|
+
* Returns the default SAJ parser. Note the default SAJ parser can not be used
|
1460
1517
|
* concurrently in more than one thread.
|
1461
1518
|
*/
|
1462
1519
|
static VALUE parser_saj(VALUE self) {
|