oj 3.13.17 → 3.16.3
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 +77 -0
- data/README.md +4 -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 +44 -96
- data/ext/oj/debug.c +3 -9
- data/ext/oj/dump.c +69 -39
- 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 -6
- data/ext/oj/fast.c +76 -106
- data/ext/oj/intern.c +63 -51
- 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 +43 -30
- data/ext/oj/object.c +61 -70
- data/ext/oj/odd.c +8 -6
- data/ext/oj/odd.h +4 -4
- data/ext/oj/oj.c +243 -205
- data/ext/oj/oj.h +82 -78
- data/ext/oj/parse.c +123 -188
- data/ext/oj/parse.h +23 -24
- data/ext/oj/parser.c +103 -63
- data/ext/oj/parser.h +19 -9
- data/ext/oj/rails.c +68 -92
- data/ext/oj/reader.c +10 -15
- 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 +74 -92
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +3 -14
- data/ext/oj/sparse.c +22 -70
- data/ext/oj/stream_writer.c +43 -35
- data/ext/oj/strict.c +20 -52
- data/ext/oj/string_writer.c +60 -34
- data/ext/oj/trace.h +31 -4
- data/ext/oj/usual.c +125 -150
- data/ext/oj/usual.h +69 -0
- data/ext/oj/util.h +1 -1
- data/ext/oj/val_stack.c +14 -3
- 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 +6 -2
- data/lib/oj/state.rb +9 -6
- data/lib/oj/version.rb +1 -2
- data/lib/oj.rb +2 -0
- data/pages/Compatibility.md +1 -1
- data/pages/InstallOptions.md +20 -0
- data/pages/Options.md +10 -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/files.rb +15 -15
- data/test/foo.rb +9 -72
- data/test/helper.rb +11 -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 +53 -37
- data/test/json_gem/json_generic_object_test.rb +11 -11
- data/test/json_gem/json_parser_test.rb +47 -47
- data/test/json_gem/json_string_matching_test.rb +9 -9
- data/test/json_gem/test_helper.rb +7 -3
- 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 +80 -53
- data/test/test_custom.rb +73 -51
- data/test/test_debian.rb +7 -10
- data/test/test_fast.rb +86 -90
- data/test/test_file.rb +28 -35
- data/test/test_gc.rb +16 -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 +94 -96
- data/test/test_parser.rb +6 -22
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +61 -22
- data/test/test_parser_usual.rb +16 -6
- data/test/test_rails.rb +2 -2
- data/test/test_saj.rb +10 -8
- data/test/test_scp.rb +37 -39
- data/test/test_strict.rb +40 -32
- data/test/test_various.rb +148 -100
- data/test/test_wab.rb +48 -44
- data/test/test_writer.rb +47 -47
- data/test/tests.rb +13 -4
- data/test/tests_mimic.rb +12 -3
- data/test/tests_mimic_addition.rb +12 -3
- metadata +36 -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/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;
|
@@ -192,19 +192,21 @@ static inline const char *scan_string_noSIMD(const char *str, const char *end) {
|
|
192
192
|
return str;
|
193
193
|
}
|
194
194
|
|
195
|
-
#
|
196
|
-
#include <nmmintrin.h>
|
197
|
-
|
195
|
+
#ifdef OJ_USE_SSE4_2
|
198
196
|
static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
199
197
|
static const char chars[16] = "\x00\\\"";
|
200
|
-
const __m128i
|
201
|
-
const char
|
198
|
+
const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
|
199
|
+
const char *_end = (const char *)(end - 16);
|
202
200
|
|
203
201
|
for (; str <= _end; str += 16) {
|
204
202
|
const __m128i string = _mm_loadu_si128((const __m128i *)str);
|
205
|
-
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);
|
206
208
|
if (r != 16) {
|
207
|
-
str = (char*)(str + r);
|
209
|
+
str = (char *)(str + r);
|
208
210
|
return str;
|
209
211
|
}
|
210
212
|
}
|
@@ -213,6 +215,14 @@ static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
|
213
215
|
}
|
214
216
|
#endif
|
215
217
|
|
218
|
+
static const char *(*scan_func)(const char *str, const char *end) = scan_string_noSIMD;
|
219
|
+
|
220
|
+
void oj_scanner_init(void) {
|
221
|
+
#ifdef OJ_USE_SSE4_2
|
222
|
+
scan_func = scan_string_SIMD;
|
223
|
+
#endif
|
224
|
+
}
|
225
|
+
|
216
226
|
// entered at /
|
217
227
|
static void read_escaped_str(ParseInfo pi, const char *start) {
|
218
228
|
struct _buf buf;
|
@@ -225,21 +235,13 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
225
235
|
buf_append_string(&buf, start, cnt);
|
226
236
|
|
227
237
|
for (s = pi->cur; '"' != *s;) {
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
#endif
|
233
|
-
if (scanned >= pi->end) {
|
234
|
-
oj_set_error_at(pi,
|
235
|
-
oj_parse_error_class,
|
236
|
-
__FILE__,
|
237
|
-
__LINE__,
|
238
|
-
"quoted string not terminated");
|
238
|
+
const char *scanned = scan_func(s, pi->end);
|
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");
|
239
242
|
buf_cleanup(&buf);
|
240
243
|
return;
|
241
244
|
}
|
242
|
-
|
243
245
|
buf_append_string(&buf, s, (size_t)(scanned - s));
|
244
246
|
s = scanned;
|
245
247
|
|
@@ -273,11 +275,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
273
275
|
break;
|
274
276
|
}
|
275
277
|
pi->cur = s;
|
276
|
-
oj_set_error_at(pi,
|
277
|
-
oj_parse_error_class,
|
278
|
-
__FILE__,
|
279
|
-
__LINE__,
|
280
|
-
"invalid escaped character");
|
278
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
281
279
|
buf_cleanup(&buf);
|
282
280
|
return;
|
283
281
|
}
|
@@ -304,11 +302,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
304
302
|
break;
|
305
303
|
}
|
306
304
|
pi->cur = s;
|
307
|
-
oj_set_error_at(pi,
|
308
|
-
oj_parse_error_class,
|
309
|
-
__FILE__,
|
310
|
-
__LINE__,
|
311
|
-
"invalid escaped character");
|
305
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
312
306
|
buf_cleanup(&buf);
|
313
307
|
return;
|
314
308
|
}
|
@@ -328,7 +322,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
328
322
|
case NEXT_HASH_KEY:
|
329
323
|
if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
|
330
324
|
parent->klen = buf_len(&buf);
|
331
|
-
parent->key =
|
325
|
+
parent->key = OJ_MALLOC(parent->klen + 1);
|
332
326
|
memcpy((char *)parent->key, buf.head, parent->klen);
|
333
327
|
*(char *)(parent->key + parent->klen) = '\0';
|
334
328
|
} else {
|
@@ -340,9 +334,8 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
340
334
|
break;
|
341
335
|
case NEXT_HASH_VALUE:
|
342
336
|
pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start);
|
343
|
-
if (0 != parent->key && 0 < parent->klen &&
|
344
|
-
(
|
345
|
-
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);
|
346
339
|
parent->key = 0;
|
347
340
|
}
|
348
341
|
parent->next = NEXT_HASH_COMMA;
|
@@ -369,17 +362,9 @@ static void read_str(ParseInfo pi) {
|
|
369
362
|
const char *str = pi->cur;
|
370
363
|
Val parent = stack_peek(&pi->stack);
|
371
364
|
|
372
|
-
|
373
|
-
pi->cur = scan_string_SIMD(pi->cur, pi->end);
|
374
|
-
#else
|
375
|
-
pi->cur = scan_string_noSIMD(pi->cur, pi->end);
|
376
|
-
#endif
|
365
|
+
pi->cur = scan_func(pi->cur, pi->end);
|
377
366
|
if (RB_UNLIKELY(pi->end <= pi->cur)) {
|
378
|
-
oj_set_error_at(pi,
|
379
|
-
oj_parse_error_class,
|
380
|
-
__FILE__,
|
381
|
-
__LINE__,
|
382
|
-
"quoted string not terminated");
|
367
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
|
383
368
|
return;
|
384
369
|
}
|
385
370
|
if (RB_UNLIKELY('\0' == *pi->cur)) {
|
@@ -414,9 +399,8 @@ static void read_str(ParseInfo pi) {
|
|
414
399
|
break;
|
415
400
|
case NEXT_HASH_VALUE:
|
416
401
|
pi->hash_set_cstr(pi, parent, str, pi->cur - str, str);
|
417
|
-
if (0 != parent->key && 0 < parent->klen &&
|
418
|
-
(
|
419
|
-
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);
|
420
404
|
parent->key = 0;
|
421
405
|
}
|
422
406
|
parent->next = NEXT_HASH_COMMA;
|
@@ -442,6 +426,7 @@ static void read_num(ParseInfo pi) {
|
|
442
426
|
struct _numInfo ni;
|
443
427
|
Val parent = stack_peek(&pi->stack);
|
444
428
|
|
429
|
+
ni.pi = pi;
|
445
430
|
ni.str = pi->cur;
|
446
431
|
ni.i = 0;
|
447
432
|
ni.num = 0;
|
@@ -458,7 +443,7 @@ static void read_num(ParseInfo pi) {
|
|
458
443
|
ni.no_big = !pi->options.compat_bigdec;
|
459
444
|
ni.bigdec_load = pi->options.compat_bigdec;
|
460
445
|
} else {
|
461
|
-
ni.no_big
|
446
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
|
462
447
|
RubyDec == pi->options.bigdec_load);
|
463
448
|
ni.bigdec_load = pi->options.bigdec_load;
|
464
449
|
}
|
@@ -468,33 +453,21 @@ static void read_num(ParseInfo pi) {
|
|
468
453
|
ni.neg = 1;
|
469
454
|
} else if ('+' == *pi->cur) {
|
470
455
|
if (StrictMode == pi->options.mode) {
|
471
|
-
oj_set_error_at(pi,
|
472
|
-
oj_parse_error_class,
|
473
|
-
__FILE__,
|
474
|
-
__LINE__,
|
475
|
-
"not a number or other value");
|
456
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
476
457
|
return;
|
477
458
|
}
|
478
459
|
pi->cur++;
|
479
460
|
}
|
480
461
|
if ('I' == *pi->cur) {
|
481
462
|
if (No == pi->options.allow_nan || 0 != strncmp("Infinity", pi->cur, 8)) {
|
482
|
-
oj_set_error_at(pi,
|
483
|
-
oj_parse_error_class,
|
484
|
-
__FILE__,
|
485
|
-
__LINE__,
|
486
|
-
"not a number or other value");
|
463
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
487
464
|
return;
|
488
465
|
}
|
489
466
|
pi->cur += 8;
|
490
467
|
ni.infinity = 1;
|
491
468
|
} else if ('N' == *pi->cur || 'n' == *pi->cur) {
|
492
469
|
if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) {
|
493
|
-
oj_set_error_at(pi,
|
494
|
-
oj_parse_error_class,
|
495
|
-
__FILE__,
|
496
|
-
__LINE__,
|
497
|
-
"not a number or other value");
|
470
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
498
471
|
return;
|
499
472
|
}
|
500
473
|
pi->cur += 3;
|
@@ -503,33 +476,27 @@ static void read_num(ParseInfo pi) {
|
|
503
476
|
int dec_cnt = 0;
|
504
477
|
bool zero1 = false;
|
505
478
|
|
479
|
+
// Skip leading zeros.
|
480
|
+
for (; '0' == *pi->cur; pi->cur++) {
|
481
|
+
zero1 = true;
|
482
|
+
}
|
483
|
+
|
506
484
|
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
507
|
-
|
508
|
-
zero1 = true;
|
509
|
-
}
|
510
|
-
if (0 < ni.i) {
|
511
|
-
dec_cnt++;
|
512
|
-
}
|
513
|
-
if (!ni.big) {
|
514
|
-
int d = (*pi->cur - '0');
|
485
|
+
int d = (*pi->cur - '0');
|
515
486
|
|
516
|
-
|
517
|
-
|
518
|
-
oj_set_error_at(pi,
|
519
|
-
oj_parse_error_class,
|
520
|
-
__FILE__,
|
521
|
-
__LINE__,
|
522
|
-
"not a number");
|
523
|
-
return;
|
524
|
-
}
|
525
|
-
zero1 = false;
|
526
|
-
}
|
527
|
-
ni.i = ni.i * 10 + d;
|
528
|
-
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
529
|
-
ni.big = 1;
|
530
|
-
}
|
487
|
+
if (RB_LIKELY(0 != ni.i)) {
|
488
|
+
dec_cnt++;
|
531
489
|
}
|
490
|
+
ni.i = ni.i * 10 + d;
|
491
|
+
}
|
492
|
+
if (RB_UNLIKELY(0 != ni.i && zero1 && CompatMode == pi->options.mode)) {
|
493
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
494
|
+
return;
|
495
|
+
}
|
496
|
+
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
497
|
+
ni.big = true;
|
532
498
|
}
|
499
|
+
|
533
500
|
if ('.' == *pi->cur) {
|
534
501
|
pi->cur++;
|
535
502
|
// A trailing . is not a valid decimal but if encountered allow it
|
@@ -549,25 +516,20 @@ static void read_num(ParseInfo pi) {
|
|
549
516
|
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
550
517
|
int d = (*pi->cur - '0');
|
551
518
|
|
552
|
-
if (0
|
519
|
+
if (RB_LIKELY(0 != ni.num || 0 != ni.i)) {
|
553
520
|
dec_cnt++;
|
554
521
|
}
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
}
|
559
|
-
} else {
|
560
|
-
ni.num = ni.num * 10 + d;
|
561
|
-
ni.div *= 10;
|
562
|
-
ni.di++;
|
563
|
-
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
564
|
-
if (!ni.no_big) {
|
565
|
-
ni.big = true;
|
566
|
-
}
|
567
|
-
}
|
568
|
-
}
|
522
|
+
ni.num = ni.num * 10 + d;
|
523
|
+
ni.div *= 10;
|
524
|
+
ni.di++;
|
569
525
|
}
|
570
526
|
}
|
527
|
+
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
528
|
+
if (!ni.no_big) {
|
529
|
+
ni.big = true;
|
530
|
+
}
|
531
|
+
}
|
532
|
+
|
571
533
|
if ('e' == *pi->cur || 'E' == *pi->cur) {
|
572
534
|
int eneg = 0;
|
573
535
|
|
@@ -620,9 +582,8 @@ static void read_num(ParseInfo pi) {
|
|
620
582
|
break;
|
621
583
|
case NEXT_HASH_VALUE:
|
622
584
|
pi->hash_set_num(pi, parent, &ni);
|
623
|
-
if (0 != parent->key && 0 < parent->klen &&
|
624
|
-
(
|
625
|
-
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);
|
626
587
|
parent->key = 0;
|
627
588
|
}
|
628
589
|
parent->next = NEXT_HASH_COMMA;
|
@@ -640,7 +601,7 @@ static void read_num(ParseInfo pi) {
|
|
640
601
|
}
|
641
602
|
|
642
603
|
static void array_start(ParseInfo pi) {
|
643
|
-
|
604
|
+
VALUE v = pi->start_array(pi);
|
644
605
|
|
645
606
|
stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
|
646
607
|
}
|
@@ -664,13 +625,13 @@ static void array_end(ParseInfo pi) {
|
|
664
625
|
}
|
665
626
|
|
666
627
|
static void hash_start(ParseInfo pi) {
|
667
|
-
|
628
|
+
VALUE v = pi->start_hash(pi);
|
668
629
|
|
669
630
|
stack_push(&pi->stack, v, NEXT_HASH_NEW);
|
670
631
|
}
|
671
632
|
|
672
633
|
static void hash_end(ParseInfo pi) {
|
673
|
-
|
634
|
+
Val hash = stack_peek(&pi->stack);
|
674
635
|
|
675
636
|
// leave hash on stack until just before
|
676
637
|
if (0 == hash) {
|
@@ -749,17 +710,10 @@ void oj_parse2(ParseInfo pi) {
|
|
749
710
|
case '[': array_start(pi); break;
|
750
711
|
case ']': array_end(pi); break;
|
751
712
|
case ',': comma(pi); break;
|
752
|
-
case '"':
|
753
|
-
read_str(pi);
|
754
|
-
break;
|
755
|
-
// case '+':
|
713
|
+
case '"': read_str(pi); break;
|
756
714
|
case '+':
|
757
715
|
if (CompatMode == pi->options.mode) {
|
758
|
-
oj_set_error_at(pi,
|
759
|
-
oj_parse_error_class,
|
760
|
-
__FILE__,
|
761
|
-
__LINE__,
|
762
|
-
"unexpected character");
|
716
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
763
717
|
return;
|
764
718
|
}
|
765
719
|
pi->cur--;
|
@@ -785,11 +739,7 @@ void oj_parse2(ParseInfo pi) {
|
|
785
739
|
pi->cur--;
|
786
740
|
read_num(pi);
|
787
741
|
} else {
|
788
|
-
oj_set_error_at(pi,
|
789
|
-
oj_parse_error_class,
|
790
|
-
__FILE__,
|
791
|
-
__LINE__,
|
792
|
-
"unexpected character");
|
742
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
793
743
|
}
|
794
744
|
break;
|
795
745
|
case 't': read_true(pi); break;
|
@@ -809,9 +759,7 @@ void oj_parse2(ParseInfo pi) {
|
|
809
759
|
}
|
810
760
|
break;
|
811
761
|
case '\0': pi->cur--; return;
|
812
|
-
default:
|
813
|
-
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
814
|
-
return;
|
762
|
+
default: oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); return;
|
815
763
|
}
|
816
764
|
if (err_has(&pi->err)) {
|
817
765
|
return;
|
@@ -848,16 +796,15 @@ static VALUE parse_big_decimal(VALUE str) {
|
|
848
796
|
}
|
849
797
|
|
850
798
|
static long double exp_plus[] = {
|
851
|
-
1.0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
|
852
|
-
1.
|
853
|
-
1.
|
854
|
-
1.
|
855
|
-
1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49,
|
799
|
+
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,
|
800
|
+
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,
|
801
|
+
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,
|
802
|
+
1.0e39, 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49,
|
856
803
|
};
|
857
804
|
|
858
805
|
VALUE
|
859
806
|
oj_num_as_value(NumInfo ni) {
|
860
|
-
|
807
|
+
VALUE rnum = Qnil;
|
861
808
|
|
862
809
|
if (ni->infinity) {
|
863
810
|
if (ni->neg) {
|
@@ -876,12 +823,12 @@ oj_num_as_value(NumInfo ni) {
|
|
876
823
|
buf[ni->len] = '\0';
|
877
824
|
rnum = rb_cstr_to_inum(buf, 10, 0);
|
878
825
|
} else {
|
879
|
-
char *buf =
|
826
|
+
char *buf = OJ_R_ALLOC_N(char, ni->len + 1);
|
880
827
|
|
881
828
|
memcpy(buf, ni->str, ni->len);
|
882
829
|
buf[ni->len] = '\0';
|
883
830
|
rnum = rb_cstr_to_inum(buf, 10, 0);
|
884
|
-
|
831
|
+
OJ_R_FREE(buf);
|
885
832
|
}
|
886
833
|
} else {
|
887
834
|
if (ni->neg) {
|
@@ -892,7 +839,7 @@ oj_num_as_value(NumInfo ni) {
|
|
892
839
|
}
|
893
840
|
} else { // decimal
|
894
841
|
if (ni->big) {
|
895
|
-
|
842
|
+
VALUE bd = rb_str_new(ni->str, ni->len);
|
896
843
|
|
897
844
|
rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
|
898
845
|
if (ni->no_big) {
|
@@ -920,15 +867,19 @@ oj_num_as_value(NumInfo ni) {
|
|
920
867
|
}
|
921
868
|
rnum = rb_float_new((double)ld);
|
922
869
|
} else if (RubyDec == ni->bigdec_load) {
|
923
|
-
|
870
|
+
VALUE sv = rb_str_new(ni->str, ni->len);
|
924
871
|
|
925
872
|
rnum = rb_funcall(sv, rb_intern("to_f"), 0);
|
926
873
|
} else {
|
927
|
-
char
|
874
|
+
char *end;
|
928
875
|
double d = strtod(ni->str, &end);
|
929
876
|
|
930
877
|
if ((long)ni->len != (long)(end - ni->str)) {
|
931
|
-
|
878
|
+
if (Qnil == ni->pi->err_class) {
|
879
|
+
rb_raise(oj_parse_error_class, "Invalid float");
|
880
|
+
} else {
|
881
|
+
rb_raise(ni->pi->err_class, "Invalid float");
|
882
|
+
}
|
932
883
|
}
|
933
884
|
rnum = rb_float_new(d);
|
934
885
|
}
|
@@ -936,28 +887,23 @@ oj_num_as_value(NumInfo ni) {
|
|
936
887
|
return rnum;
|
937
888
|
}
|
938
889
|
|
939
|
-
void oj_set_error_at(ParseInfo
|
940
|
-
VALUE err_clas,
|
941
|
-
const char *file,
|
942
|
-
int line,
|
943
|
-
const char *format,
|
944
|
-
...) {
|
890
|
+
void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...) {
|
945
891
|
va_list ap;
|
946
892
|
char msg[256];
|
947
|
-
char
|
948
|
-
char
|
949
|
-
char
|
893
|
+
char *p = msg;
|
894
|
+
char *end = p + sizeof(msg) - 2;
|
895
|
+
char *start;
|
950
896
|
Val vp;
|
951
|
-
int
|
897
|
+
int mlen;
|
952
898
|
|
953
899
|
va_start(ap, format);
|
954
900
|
mlen = vsnprintf(msg, sizeof(msg) - 1, format, ap);
|
955
901
|
if (0 < mlen) {
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
902
|
+
if (sizeof(msg) - 2 < (size_t)mlen) {
|
903
|
+
p = end - 2;
|
904
|
+
} else {
|
905
|
+
p += mlen;
|
906
|
+
}
|
961
907
|
}
|
962
908
|
va_end(ap);
|
963
909
|
pi->err.clas = err_clas;
|
@@ -994,14 +940,7 @@ void oj_set_error_at(ParseInfo pi,
|
|
994
940
|
}
|
995
941
|
*p = '\0';
|
996
942
|
if (0 == pi->json) {
|
997
|
-
oj_err_set(&pi->err,
|
998
|
-
err_clas,
|
999
|
-
"%s at line %d, column %d [%s:%d]",
|
1000
|
-
msg,
|
1001
|
-
pi->rd.line,
|
1002
|
-
pi->rd.col,
|
1003
|
-
file,
|
1004
|
-
line);
|
943
|
+
oj_err_set(&pi->err, err_clas, "%s at line %d, column %d [%s:%d]", msg, pi->rd.line, pi->rd.col, file, line);
|
1005
944
|
} else {
|
1006
945
|
_oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
|
1007
946
|
}
|
@@ -1015,12 +954,12 @@ static VALUE protect_parse(VALUE pip) {
|
|
1015
954
|
|
1016
955
|
extern int oj_utf8_index;
|
1017
956
|
|
1018
|
-
static void oj_pi_set_input_str(ParseInfo pi,
|
957
|
+
static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
|
1019
958
|
int idx = RB_ENCODING_GET(*inputp);
|
1020
959
|
|
1021
960
|
if (oj_utf8_encoding_index != idx) {
|
1022
961
|
rb_encoding *enc = rb_enc_from_index(idx);
|
1023
|
-
*inputp
|
962
|
+
*inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
|
1024
963
|
}
|
1025
964
|
pi->json = RSTRING_PTR(*inputp);
|
1026
965
|
pi->end = pi->json + RSTRING_LEN(*inputp);
|
@@ -1028,12 +967,12 @@ static void oj_pi_set_input_str(ParseInfo pi, volatile VALUE *inputp) {
|
|
1028
967
|
|
1029
968
|
VALUE
|
1030
969
|
oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
|
1031
|
-
char *
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
int
|
1036
|
-
int
|
970
|
+
char *buf = 0;
|
971
|
+
VALUE input;
|
972
|
+
VALUE wrapped_stack;
|
973
|
+
VALUE result = Qnil;
|
974
|
+
int line = 0;
|
975
|
+
int free_json = 0;
|
1037
976
|
|
1038
977
|
if (argc < 1) {
|
1039
978
|
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
@@ -1069,8 +1008,8 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1069
1008
|
rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
|
1070
1009
|
}
|
1071
1010
|
} else {
|
1072
|
-
VALUE
|
1073
|
-
|
1011
|
+
VALUE clas = rb_obj_class(input);
|
1012
|
+
VALUE s;
|
1074
1013
|
|
1075
1014
|
if (oj_stringio_class == clas) {
|
1076
1015
|
s = rb_funcall2(input, oj_string_id, 0, 0);
|
@@ -1082,19 +1021,18 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1082
1021
|
size_t len = lseek(fd, 0, SEEK_END);
|
1083
1022
|
|
1084
1023
|
lseek(fd, 0, SEEK_SET);
|
1085
|
-
buf =
|
1024
|
+
buf = OJ_R_ALLOC_N(char, len + 1);
|
1086
1025
|
pi->json = buf;
|
1087
1026
|
pi->end = buf + len;
|
1088
1027
|
if (0 >= (cnt = read(fd, (char *)pi->json, len)) || cnt != (ssize_t)len) {
|
1089
1028
|
if (0 != buf) {
|
1090
|
-
|
1029
|
+
OJ_R_FREE(buf);
|
1091
1030
|
}
|
1092
1031
|
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
1093
1032
|
}
|
1094
1033
|
((char *)pi->json)[len] = '\0';
|
1095
1034
|
/* skip UTF-8 BOM if present */
|
1096
|
-
if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] &&
|
1097
|
-
0xBF == (uint8_t)pi->json[2]) {
|
1035
|
+
if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) {
|
1098
1036
|
pi->cur += 3;
|
1099
1037
|
}
|
1100
1038
|
#endif
|
@@ -1120,8 +1058,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1120
1058
|
wrapped_stack = oj_stack_init(&pi->stack);
|
1121
1059
|
rb_protect(protect_parse, (VALUE)pi, &line);
|
1122
1060
|
if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
|
1123
|
-
if (No == pi->options.nilnil ||
|
1124
|
-
(CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
|
1061
|
+
if (No == pi->options.nilnil || (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
|
1125
1062
|
oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input");
|
1126
1063
|
}
|
1127
1064
|
}
|
@@ -1149,9 +1086,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1149
1086
|
switch (v->next) {
|
1150
1087
|
case NEXT_ARRAY_NEW:
|
1151
1088
|
case NEXT_ARRAY_ELEMENT:
|
1152
|
-
case NEXT_ARRAY_COMMA:
|
1153
|
-
oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
|
1154
|
-
break;
|
1089
|
+
case NEXT_ARRAY_COMMA: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); break;
|
1155
1090
|
case NEXT_HASH_NEW:
|
1156
1091
|
case NEXT_HASH_KEY:
|
1157
1092
|
case NEXT_HASH_COLON:
|
@@ -1169,9 +1104,9 @@ CLEANUP:
|
|
1169
1104
|
oj_circ_array_free(pi->circ_array);
|
1170
1105
|
}
|
1171
1106
|
if (0 != buf) {
|
1172
|
-
|
1107
|
+
OJ_R_FREE(buf);
|
1173
1108
|
} else if (free_json) {
|
1174
|
-
|
1109
|
+
OJ_R_FREE(json);
|
1175
1110
|
}
|
1176
1111
|
stack_cleanup(&pi->stack);
|
1177
1112
|
if (pi->str_rx.head != oj_default_options.str_rx.head) {
|