oj 3.13.23 → 3.16.10
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 +86 -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 +63 -98
- 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 +54 -38
- 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 +245 -216
- data/ext/oj/oj.h +83 -81
- data/ext/oj/parse.c +109 -153
- data/ext/oj/parse.h +21 -24
- data/ext/oj/parser.c +80 -67
- data/ext/oj/parser.h +9 -8
- data/ext/oj/rails.c +71 -94
- 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 +13 -15
- data/ext/oj/saj2.c +37 -49
- data/ext/oj/saj2.h +1 -1
- data/ext/oj/scp.c +6 -20
- data/ext/oj/sparse.c +22 -70
- data/ext/oj/stream_writer.c +46 -48
- data/ext/oj/strict.c +22 -56
- data/ext/oj/string_writer.c +64 -40
- 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
- metadata +46 -121
- data/test/_test_active.rb +0 -76
- data/test/_test_active_mimic.rb +0 -96
- data/test/_test_mimic_rails.rb +0 -126
- data/test/activerecord/result_test.rb +0 -32
- 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/activesupport6/abstract_unit.rb +0 -44
- data/test/activesupport6/decoding_test.rb +0 -133
- data/test/activesupport6/encoding_test.rb +0 -507
- data/test/activesupport6/encoding_test_cases.rb +0 -98
- data/test/activesupport6/test_common.rb +0 -17
- data/test/activesupport6/test_helper.rb +0 -163
- data/test/activesupport6/time_zone_test_helpers.rb +0 -39
- data/test/activesupport7/abstract_unit.rb +0 -49
- data/test/activesupport7/decoding_test.rb +0 -125
- data/test/activesupport7/encoding_test.rb +0 -486
- data/test/activesupport7/encoding_test_cases.rb +0 -104
- data/test/activesupport7/time_zone_test_helpers.rb +0 -47
- data/test/bar.rb +0 -11
- data/test/baz.rb +0 -16
- data/test/bug.rb +0 -16
- data/test/files.rb +0 -29
- data/test/foo.rb +0 -77
- data/test/helper.rb +0 -42
- data/test/isolated/shared.rb +0 -308
- data/test/isolated/test_mimic_after.rb +0 -13
- data/test/isolated/test_mimic_alone.rb +0 -12
- data/test/isolated/test_mimic_as_json.rb +0 -45
- data/test/isolated/test_mimic_before.rb +0 -13
- data/test/isolated/test_mimic_define.rb +0 -28
- data/test/isolated/test_mimic_rails_after.rb +0 -22
- data/test/isolated/test_mimic_rails_before.rb +0 -21
- data/test/isolated/test_mimic_redefine.rb +0 -15
- data/test/json_gem/json_addition_test.rb +0 -216
- data/test/json_gem/json_common_interface_test.rb +0 -153
- data/test/json_gem/json_encoding_test.rb +0 -107
- data/test/json_gem/json_ext_parser_test.rb +0 -20
- data/test/json_gem/json_fixtures_test.rb +0 -35
- data/test/json_gem/json_generator_test.rb +0 -396
- data/test/json_gem/json_generic_object_test.rb +0 -90
- data/test/json_gem/json_parser_test.rb +0 -477
- data/test/json_gem/json_string_matching_test.rb +0 -42
- data/test/json_gem/test_helper.rb +0 -30
- data/test/mem.rb +0 -33
- data/test/perf.rb +0 -107
- data/test/perf_compat.rb +0 -130
- data/test/perf_dump.rb +0 -50
- data/test/perf_fast.rb +0 -164
- data/test/perf_file.rb +0 -64
- data/test/perf_object.rb +0 -138
- data/test/perf_once.rb +0 -58
- data/test/perf_parser.rb +0 -189
- data/test/perf_saj.rb +0 -109
- data/test/perf_scp.rb +0 -152
- data/test/perf_simple.rb +0 -287
- data/test/perf_strict.rb +0 -139
- data/test/perf_wab.rb +0 -131
- data/test/prec.rb +0 -23
- data/test/sample/change.rb +0 -14
- data/test/sample/dir.rb +0 -19
- data/test/sample/doc.rb +0 -36
- data/test/sample/file.rb +0 -48
- data/test/sample/group.rb +0 -16
- data/test/sample/hasprops.rb +0 -16
- data/test/sample/layer.rb +0 -12
- data/test/sample/line.rb +0 -20
- data/test/sample/oval.rb +0 -10
- data/test/sample/rect.rb +0 -10
- data/test/sample/shape.rb +0 -35
- data/test/sample/text.rb +0 -20
- data/test/sample.rb +0 -54
- data/test/sample_json.rb +0 -37
- data/test/test_compat.rb +0 -540
- data/test/test_custom.rb +0 -544
- data/test/test_debian.rb +0 -53
- data/test/test_fast.rb +0 -530
- data/test/test_file.rb +0 -255
- data/test/test_gc.rb +0 -60
- data/test/test_generate.rb +0 -21
- data/test/test_hash.rb +0 -39
- data/test/test_integer_range.rb +0 -72
- data/test/test_null.rb +0 -376
- data/test/test_object.rb +0 -1025
- data/test/test_parser.rb +0 -11
- data/test/test_parser_debug.rb +0 -27
- data/test/test_parser_saj.rb +0 -335
- data/test/test_parser_usual.rb +0 -217
- data/test/test_rails.rb +0 -35
- data/test/test_saj.rb +0 -186
- data/test/test_scp.rb +0 -431
- data/test/test_strict.rb +0 -435
- data/test/test_various.rb +0 -752
- data/test/test_wab.rb +0 -309
- data/test/test_writer.rb +0 -380
- data/test/tests.rb +0 -33
- data/test/tests_mimic.rb +0 -23
- data/test/tests_mimic_addition.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;
|
@@ -183,9 +183,19 @@ static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
|
183
183
|
}
|
184
184
|
}
|
185
185
|
|
186
|
+
static const unsigned char end_of_scan_string[] = {
|
187
|
+
// Filled 1 at the positions of '\0', '\\', and '"'
|
188
|
+
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
|
189
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
190
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
191
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
192
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
193
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
194
|
+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
195
|
+
};
|
186
196
|
static inline const char *scan_string_noSIMD(const char *str, const char *end) {
|
187
|
-
for (;
|
188
|
-
if (
|
197
|
+
for (; str < end; str++) {
|
198
|
+
if (end_of_scan_string[(unsigned char)*str]) {
|
189
199
|
break;
|
190
200
|
}
|
191
201
|
}
|
@@ -195,14 +205,18 @@ static inline const char *scan_string_noSIMD(const char *str, const char *end) {
|
|
195
205
|
#ifdef OJ_USE_SSE4_2
|
196
206
|
static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
197
207
|
static const char chars[16] = "\x00\\\"";
|
198
|
-
const __m128i
|
199
|
-
const char
|
208
|
+
const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
|
209
|
+
const char *_end = (const char *)(end - 16);
|
200
210
|
|
201
211
|
for (; str <= _end; str += 16) {
|
202
212
|
const __m128i string = _mm_loadu_si128((const __m128i *)str);
|
203
|
-
const int
|
213
|
+
const int r = _mm_cmpestri(terminate,
|
214
|
+
3,
|
215
|
+
string,
|
216
|
+
16,
|
217
|
+
_SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
|
204
218
|
if (r != 16) {
|
205
|
-
str = (char*)(str + r);
|
219
|
+
str = (char *)(str + r);
|
206
220
|
return str;
|
207
221
|
}
|
208
222
|
}
|
@@ -211,7 +225,7 @@ static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
|
211
225
|
}
|
212
226
|
#endif
|
213
227
|
|
214
|
-
static const char *(*scan_func)
|
228
|
+
static const char *(*scan_func)(const char *str, const char *end) = scan_string_noSIMD;
|
215
229
|
|
216
230
|
void oj_scanner_init(void) {
|
217
231
|
#ifdef OJ_USE_SSE4_2
|
@@ -232,16 +246,12 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
232
246
|
|
233
247
|
for (s = pi->cur; '"' != *s;) {
|
234
248
|
const char *scanned = scan_func(s, pi->end);
|
235
|
-
if (scanned >= pi->end) {
|
236
|
-
|
237
|
-
|
238
|
-
__FILE__,
|
239
|
-
__LINE__,
|
240
|
-
"quoted string not terminated");
|
249
|
+
if (scanned >= pi->end || '\0' == *scanned) {
|
250
|
+
// if (scanned >= pi->end) {
|
251
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
|
241
252
|
buf_cleanup(&buf);
|
242
253
|
return;
|
243
254
|
}
|
244
|
-
|
245
255
|
buf_append_string(&buf, s, (size_t)(scanned - s));
|
246
256
|
s = scanned;
|
247
257
|
|
@@ -275,11 +285,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
275
285
|
break;
|
276
286
|
}
|
277
287
|
pi->cur = s;
|
278
|
-
oj_set_error_at(pi,
|
279
|
-
oj_parse_error_class,
|
280
|
-
__FILE__,
|
281
|
-
__LINE__,
|
282
|
-
"invalid escaped character");
|
288
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
283
289
|
buf_cleanup(&buf);
|
284
290
|
return;
|
285
291
|
}
|
@@ -306,11 +312,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
306
312
|
break;
|
307
313
|
}
|
308
314
|
pi->cur = s;
|
309
|
-
oj_set_error_at(pi,
|
310
|
-
oj_parse_error_class,
|
311
|
-
__FILE__,
|
312
|
-
__LINE__,
|
313
|
-
"invalid escaped character");
|
315
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
314
316
|
buf_cleanup(&buf);
|
315
317
|
return;
|
316
318
|
}
|
@@ -330,7 +332,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
330
332
|
case NEXT_HASH_KEY:
|
331
333
|
if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
|
332
334
|
parent->klen = buf_len(&buf);
|
333
|
-
parent->key =
|
335
|
+
parent->key = OJ_MALLOC(parent->klen + 1);
|
334
336
|
memcpy((char *)parent->key, buf.head, parent->klen);
|
335
337
|
*(char *)(parent->key + parent->klen) = '\0';
|
336
338
|
} else {
|
@@ -342,9 +344,8 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
342
344
|
break;
|
343
345
|
case NEXT_HASH_VALUE:
|
344
346
|
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);
|
347
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
348
|
+
OJ_R_FREE((char *)parent->key);
|
348
349
|
parent->key = 0;
|
349
350
|
}
|
350
351
|
parent->next = NEXT_HASH_COMMA;
|
@@ -373,11 +374,7 @@ static void read_str(ParseInfo pi) {
|
|
373
374
|
|
374
375
|
pi->cur = scan_func(pi->cur, pi->end);
|
375
376
|
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");
|
377
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
|
381
378
|
return;
|
382
379
|
}
|
383
380
|
if (RB_UNLIKELY('\0' == *pi->cur)) {
|
@@ -412,9 +409,8 @@ static void read_str(ParseInfo pi) {
|
|
412
409
|
break;
|
413
410
|
case NEXT_HASH_VALUE:
|
414
411
|
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);
|
412
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
413
|
+
OJ_R_FREE((char *)parent->key);
|
418
414
|
parent->key = 0;
|
419
415
|
}
|
420
416
|
parent->next = NEXT_HASH_COMMA;
|
@@ -440,6 +436,7 @@ static void read_num(ParseInfo pi) {
|
|
440
436
|
struct _numInfo ni;
|
441
437
|
Val parent = stack_peek(&pi->stack);
|
442
438
|
|
439
|
+
ni.pi = pi;
|
443
440
|
ni.str = pi->cur;
|
444
441
|
ni.i = 0;
|
445
442
|
ni.num = 0;
|
@@ -456,7 +453,7 @@ static void read_num(ParseInfo pi) {
|
|
456
453
|
ni.no_big = !pi->options.compat_bigdec;
|
457
454
|
ni.bigdec_load = pi->options.compat_bigdec;
|
458
455
|
} else {
|
459
|
-
ni.no_big
|
456
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
|
460
457
|
RubyDec == pi->options.bigdec_load);
|
461
458
|
ni.bigdec_load = pi->options.bigdec_load;
|
462
459
|
}
|
@@ -466,33 +463,21 @@ static void read_num(ParseInfo pi) {
|
|
466
463
|
ni.neg = 1;
|
467
464
|
} else if ('+' == *pi->cur) {
|
468
465
|
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");
|
466
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
474
467
|
return;
|
475
468
|
}
|
476
469
|
pi->cur++;
|
477
470
|
}
|
478
471
|
if ('I' == *pi->cur) {
|
479
472
|
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");
|
473
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
485
474
|
return;
|
486
475
|
}
|
487
476
|
pi->cur += 8;
|
488
477
|
ni.infinity = 1;
|
489
478
|
} else if ('N' == *pi->cur || 'n' == *pi->cur) {
|
490
479
|
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");
|
480
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
496
481
|
return;
|
497
482
|
}
|
498
483
|
pi->cur += 3;
|
@@ -515,11 +500,7 @@ static void read_num(ParseInfo pi) {
|
|
515
500
|
ni.i = ni.i * 10 + d;
|
516
501
|
}
|
517
502
|
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");
|
503
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
523
504
|
return;
|
524
505
|
}
|
525
506
|
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
@@ -611,9 +592,8 @@ static void read_num(ParseInfo pi) {
|
|
611
592
|
break;
|
612
593
|
case NEXT_HASH_VALUE:
|
613
594
|
pi->hash_set_num(pi, parent, &ni);
|
614
|
-
if (0 != parent->key && 0 < parent->klen &&
|
615
|
-
(
|
616
|
-
xfree((char *)parent->key);
|
595
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
596
|
+
OJ_R_FREE((char *)parent->key);
|
617
597
|
parent->key = 0;
|
618
598
|
}
|
619
599
|
parent->next = NEXT_HASH_COMMA;
|
@@ -711,7 +691,7 @@ void oj_parse2(ParseInfo pi) {
|
|
711
691
|
pi->cur = pi->json;
|
712
692
|
err_init(&pi->err);
|
713
693
|
while (1) {
|
714
|
-
if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
|
694
|
+
if (RB_UNLIKELY(0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1)) {
|
715
695
|
VALUE err_clas = oj_get_json_err_class("NestingError");
|
716
696
|
|
717
697
|
oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
|
@@ -719,18 +699,20 @@ void oj_parse2(ParseInfo pi) {
|
|
719
699
|
return;
|
720
700
|
}
|
721
701
|
next_non_white(pi);
|
722
|
-
if (
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
}
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
702
|
+
if (first) {
|
703
|
+
// If no tokens are consumed (i.e. empty string), throw a parse error
|
704
|
+
// this is the behavior of JSON.parse in both Ruby and JS.
|
705
|
+
if (RB_UNLIKELY('\0' == *pi->cur && No == pi->options.empty_string)) {
|
706
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
707
|
+
}
|
708
|
+
} else {
|
709
|
+
if (RB_UNLIKELY('\0' != *pi->cur)) {
|
710
|
+
oj_set_error_at(pi,
|
711
|
+
oj_parse_error_class,
|
712
|
+
__FILE__,
|
713
|
+
__LINE__,
|
714
|
+
"unexpected characters after the JSON document");
|
715
|
+
}
|
734
716
|
}
|
735
717
|
|
736
718
|
switch (*pi->cur++) {
|
@@ -740,17 +722,10 @@ void oj_parse2(ParseInfo pi) {
|
|
740
722
|
case '[': array_start(pi); break;
|
741
723
|
case ']': array_end(pi); break;
|
742
724
|
case ',': comma(pi); break;
|
743
|
-
case '"':
|
744
|
-
read_str(pi);
|
745
|
-
break;
|
746
|
-
// case '+':
|
725
|
+
case '"': read_str(pi); break;
|
747
726
|
case '+':
|
748
727
|
if (CompatMode == pi->options.mode) {
|
749
|
-
oj_set_error_at(pi,
|
750
|
-
oj_parse_error_class,
|
751
|
-
__FILE__,
|
752
|
-
__LINE__,
|
753
|
-
"unexpected character");
|
728
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
754
729
|
return;
|
755
730
|
}
|
756
731
|
pi->cur--;
|
@@ -776,11 +751,7 @@ void oj_parse2(ParseInfo pi) {
|
|
776
751
|
pi->cur--;
|
777
752
|
read_num(pi);
|
778
753
|
} else {
|
779
|
-
oj_set_error_at(pi,
|
780
|
-
oj_parse_error_class,
|
781
|
-
__FILE__,
|
782
|
-
__LINE__,
|
783
|
-
"unexpected character");
|
754
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
784
755
|
}
|
785
756
|
break;
|
786
757
|
case 't': read_true(pi); break;
|
@@ -800,11 +771,9 @@ void oj_parse2(ParseInfo pi) {
|
|
800
771
|
}
|
801
772
|
break;
|
802
773
|
case '\0': pi->cur--; return;
|
803
|
-
default:
|
804
|
-
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
805
|
-
return;
|
774
|
+
default: oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); return;
|
806
775
|
}
|
807
|
-
if (err_has(&pi->err)) {
|
776
|
+
if (RB_UNLIKELY(err_has(&pi->err))) {
|
808
777
|
return;
|
809
778
|
}
|
810
779
|
if (stack_empty(&pi->stack)) {
|
@@ -839,11 +808,10 @@ static VALUE parse_big_decimal(VALUE str) {
|
|
839
808
|
}
|
840
809
|
|
841
810
|
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,
|
811
|
+
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,
|
812
|
+
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,
|
813
|
+
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,
|
814
|
+
1.0e39, 1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49,
|
847
815
|
};
|
848
816
|
|
849
817
|
VALUE
|
@@ -867,12 +835,12 @@ oj_num_as_value(NumInfo ni) {
|
|
867
835
|
buf[ni->len] = '\0';
|
868
836
|
rnum = rb_cstr_to_inum(buf, 10, 0);
|
869
837
|
} else {
|
870
|
-
char *buf =
|
838
|
+
char *buf = OJ_R_ALLOC_N(char, ni->len + 1);
|
871
839
|
|
872
840
|
memcpy(buf, ni->str, ni->len);
|
873
841
|
buf[ni->len] = '\0';
|
874
842
|
rnum = rb_cstr_to_inum(buf, 10, 0);
|
875
|
-
|
843
|
+
OJ_R_FREE(buf);
|
876
844
|
}
|
877
845
|
} else {
|
878
846
|
if (ni->neg) {
|
@@ -915,11 +883,15 @@ oj_num_as_value(NumInfo ni) {
|
|
915
883
|
|
916
884
|
rnum = rb_funcall(sv, rb_intern("to_f"), 0);
|
917
885
|
} else {
|
918
|
-
char
|
886
|
+
char *end;
|
919
887
|
double d = strtod(ni->str, &end);
|
920
888
|
|
921
889
|
if ((long)ni->len != (long)(end - ni->str)) {
|
922
|
-
|
890
|
+
if (Qnil == ni->pi->err_class) {
|
891
|
+
rb_raise(oj_parse_error_class, "Invalid float");
|
892
|
+
} else {
|
893
|
+
rb_raise(ni->pi->err_class, "Invalid float");
|
894
|
+
}
|
923
895
|
}
|
924
896
|
rnum = rb_float_new(d);
|
925
897
|
}
|
@@ -927,28 +899,23 @@ oj_num_as_value(NumInfo ni) {
|
|
927
899
|
return rnum;
|
928
900
|
}
|
929
901
|
|
930
|
-
void oj_set_error_at(ParseInfo
|
931
|
-
VALUE err_clas,
|
932
|
-
const char *file,
|
933
|
-
int line,
|
934
|
-
const char *format,
|
935
|
-
...) {
|
902
|
+
void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...) {
|
936
903
|
va_list ap;
|
937
904
|
char msg[256];
|
938
|
-
char
|
939
|
-
char
|
940
|
-
char
|
905
|
+
char *p = msg;
|
906
|
+
char *end = p + sizeof(msg) - 2;
|
907
|
+
char *start;
|
941
908
|
Val vp;
|
942
|
-
int
|
909
|
+
int mlen;
|
943
910
|
|
944
911
|
va_start(ap, format);
|
945
912
|
mlen = vsnprintf(msg, sizeof(msg) - 1, format, ap);
|
946
913
|
if (0 < mlen) {
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
914
|
+
if (sizeof(msg) - 2 < (size_t)mlen) {
|
915
|
+
p = end - 2;
|
916
|
+
} else {
|
917
|
+
p += mlen;
|
918
|
+
}
|
952
919
|
}
|
953
920
|
va_end(ap);
|
954
921
|
pi->err.clas = err_clas;
|
@@ -985,14 +952,7 @@ void oj_set_error_at(ParseInfo pi,
|
|
985
952
|
}
|
986
953
|
*p = '\0';
|
987
954
|
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);
|
955
|
+
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
956
|
} else {
|
997
957
|
_oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
|
998
958
|
}
|
@@ -1011,7 +971,7 @@ static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
|
|
1011
971
|
|
1012
972
|
if (oj_utf8_encoding_index != idx) {
|
1013
973
|
rb_encoding *enc = rb_enc_from_index(idx);
|
1014
|
-
*inputp
|
974
|
+
*inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
|
1015
975
|
}
|
1016
976
|
pi->json = RSTRING_PTR(*inputp);
|
1017
977
|
pi->end = pi->json + RSTRING_LEN(*inputp);
|
@@ -1019,12 +979,12 @@ static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
|
|
1019
979
|
|
1020
980
|
VALUE
|
1021
981
|
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
|
982
|
+
char *buf = 0;
|
983
|
+
VALUE input;
|
984
|
+
VALUE wrapped_stack;
|
985
|
+
VALUE result = Qnil;
|
986
|
+
int line = 0;
|
987
|
+
int free_json = 0;
|
1028
988
|
|
1029
989
|
if (argc < 1) {
|
1030
990
|
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
@@ -1073,19 +1033,18 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1073
1033
|
size_t len = lseek(fd, 0, SEEK_END);
|
1074
1034
|
|
1075
1035
|
lseek(fd, 0, SEEK_SET);
|
1076
|
-
buf =
|
1036
|
+
buf = OJ_R_ALLOC_N(char, len + 1);
|
1077
1037
|
pi->json = buf;
|
1078
1038
|
pi->end = buf + len;
|
1079
1039
|
if (0 >= (cnt = read(fd, (char *)pi->json, len)) || cnt != (ssize_t)len) {
|
1080
1040
|
if (0 != buf) {
|
1081
|
-
|
1041
|
+
OJ_R_FREE(buf);
|
1082
1042
|
}
|
1083
1043
|
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
1084
1044
|
}
|
1085
1045
|
((char *)pi->json)[len] = '\0';
|
1086
1046
|
/* 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]) {
|
1047
|
+
if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) {
|
1089
1048
|
pi->cur += 3;
|
1090
1049
|
}
|
1091
1050
|
#endif
|
@@ -1111,8 +1070,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1111
1070
|
wrapped_stack = oj_stack_init(&pi->stack);
|
1112
1071
|
rb_protect(protect_parse, (VALUE)pi, &line);
|
1113
1072
|
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)) {
|
1073
|
+
if (No == pi->options.nilnil || (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
|
1116
1074
|
oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input");
|
1117
1075
|
}
|
1118
1076
|
}
|
@@ -1140,9 +1098,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1140
1098
|
switch (v->next) {
|
1141
1099
|
case NEXT_ARRAY_NEW:
|
1142
1100
|
case NEXT_ARRAY_ELEMENT:
|
1143
|
-
case NEXT_ARRAY_COMMA:
|
1144
|
-
oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
|
1145
|
-
break;
|
1101
|
+
case NEXT_ARRAY_COMMA: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); break;
|
1146
1102
|
case NEXT_HASH_NEW:
|
1147
1103
|
case NEXT_HASH_KEY:
|
1148
1104
|
case NEXT_HASH_COLON:
|
@@ -1160,9 +1116,9 @@ CLEANUP:
|
|
1160
1116
|
oj_circ_array_free(pi->circ_array);
|
1161
1117
|
}
|
1162
1118
|
if (0 != buf) {
|
1163
|
-
|
1119
|
+
OJ_R_FREE(buf);
|
1164
1120
|
} else if (free_json) {
|
1165
|
-
|
1121
|
+
OJ_R_FREE(json);
|
1166
1122
|
}
|
1167
1123
|
stack_cleanup(&pi->stack);
|
1168
1124
|
if (pi->str_rx.head != oj_default_options.str_rx.head) {
|
@@ -1177,12 +1133,12 @@ CLEANUP:
|
|
1177
1133
|
// The json gem requires the error message be UTF-8 encoded. In
|
1178
1134
|
// additional the complete JSON source must be returned. There
|
1179
1135
|
// does not seem to be a size limit.
|
1180
|
-
VALUE msg =
|
1136
|
+
VALUE msg = rb_utf8_str_new_cstr(pi->err.msg);
|
1181
1137
|
VALUE args[1];
|
1182
1138
|
|
1183
1139
|
if (NULL != pi->json) {
|
1184
|
-
msg = rb_str_append(msg,
|
1185
|
-
msg = rb_str_append(msg,
|
1140
|
+
msg = rb_str_append(msg, rb_utf8_str_new_cstr(" in '"));
|
1141
|
+
msg = rb_str_append(msg, rb_utf8_str_new_cstr(pi->json));
|
1186
1142
|
}
|
1187
1143
|
args[0] = msg;
|
1188
1144
|
if (pi->err.clas == oj_parse_error_class) {
|
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
|
|