oj 3.11.0 → 3.16.5
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 +1421 -0
- data/README.md +20 -5
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +48 -38
- data/ext/oj/cache.c +329 -0
- data/ext/oj/cache.h +22 -0
- data/ext/oj/cache8.c +60 -62
- data/ext/oj/cache8.h +8 -7
- data/ext/oj/circarray.c +35 -35
- data/ext/oj/circarray.h +11 -9
- data/ext/oj/code.c +156 -174
- data/ext/oj/code.h +19 -18
- data/ext/oj/compat.c +140 -197
- data/ext/oj/custom.c +737 -879
- data/ext/oj/debug.c +126 -0
- data/ext/oj/dump.c +830 -835
- data/ext/oj/dump.h +65 -53
- data/ext/oj/dump_compat.c +566 -642
- data/ext/oj/dump_leaf.c +95 -182
- data/ext/oj/dump_object.c +518 -659
- data/ext/oj/dump_strict.c +301 -334
- data/ext/oj/encode.h +3 -4
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +27 -24
- data/ext/oj/err.h +38 -13
- data/ext/oj/extconf.rb +23 -7
- data/ext/oj/fast.c +1043 -1073
- data/ext/oj/intern.c +313 -0
- data/ext/oj/intern.h +22 -0
- data/ext/oj/mem.c +318 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +449 -423
- data/ext/oj/object.c +530 -576
- data/ext/oj/odd.c +155 -138
- data/ext/oj/odd.h +24 -22
- data/ext/oj/oj.c +1331 -993
- data/ext/oj/oj.h +306 -292
- data/ext/oj/parse.c +934 -938
- data/ext/oj/parse.h +73 -70
- data/ext/oj/parser.c +1600 -0
- data/ext/oj/parser.h +101 -0
- data/ext/oj/rails.c +795 -845
- data/ext/oj/rails.h +7 -7
- data/ext/oj/reader.c +132 -140
- data/ext/oj/reader.h +67 -78
- data/ext/oj/resolve.c +40 -59
- data/ext/oj/resolve.h +3 -2
- data/ext/oj/rxclass.c +67 -67
- data/ext/oj/rxclass.h +11 -9
- data/ext/oj/saj.c +441 -480
- data/ext/oj/saj2.c +584 -0
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +78 -111
- data/ext/oj/sparse.c +726 -730
- data/ext/oj/stream_writer.c +146 -165
- data/ext/oj/strict.c +103 -123
- data/ext/oj/string_writer.c +241 -253
- data/ext/oj/trace.c +29 -33
- data/ext/oj/trace.h +41 -11
- data/ext/oj/usual.c +1218 -0
- data/ext/oj/usual.h +69 -0
- data/ext/oj/util.c +103 -103
- data/ext/oj/util.h +3 -2
- data/ext/oj/val_stack.c +60 -49
- data/ext/oj/val_stack.h +79 -85
- data/ext/oj/validate.c +46 -0
- data/ext/oj/wab.c +307 -350
- data/lib/oj/active_support_helper.rb +1 -3
- data/lib/oj/bag.rb +8 -1
- data/lib/oj/easy_hash.rb +9 -9
- data/lib/oj/error.rb +1 -2
- data/lib/oj/json.rb +162 -150
- data/lib/oj/mimic.rb +9 -19
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/state.rb +12 -8
- 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/JsonGem.md +15 -0
- data/pages/Modes.md +8 -3
- data/pages/Options.md +43 -5
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +14 -2
- 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 +12 -8
- data/test/activesupport6/encoding_test.rb +63 -28
- data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
- data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
- data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
- data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
- data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
- data/test/files.rb +15 -15
- data/test/foo.rb +17 -43
- data/test/helper.rb +16 -3
- 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 +71 -41
- data/test/json_gem/json_generic_object_test.rb +11 -11
- data/test/json_gem/json_parser_test.rb +54 -47
- data/test/json_gem/json_string_matching_test.rb +9 -9
- data/test/json_gem/test_helper.rb +12 -0
- data/test/mem.rb +34 -0
- data/test/perf.rb +22 -27
- data/test/perf_compat.rb +31 -33
- data/test/perf_dump.rb +50 -0
- 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 +59 -0
- data/test/perf_parser.rb +183 -0
- data/test/perf_saj.rb +46 -54
- data/test/perf_scp.rb +58 -69
- data/test/perf_simple.rb +41 -39
- data/test/perf_strict.rb +74 -82
- 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 +97 -45
- data/test/test_custom.rb +73 -51
- data/test/test_debian.rb +7 -10
- data/test/test_fast.rb +135 -79
- data/test/test_file.rb +41 -30
- data/test/test_gc.rb +16 -5
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +15 -5
- data/test/test_integer_range.rb +9 -9
- data/test/test_null.rb +20 -20
- data/test/test_object.rb +99 -96
- data/test/test_parser.rb +11 -0
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +337 -0
- data/test/test_parser_usual.rb +251 -0
- data/test/test_rails.rb +2 -2
- data/test/test_saj.rb +10 -8
- data/test/test_scp.rb +38 -40
- data/test/test_strict.rb +40 -32
- data/test/test_various.rb +165 -84
- data/test/test_wab.rb +48 -44
- data/test/test_writer.rb +47 -47
- data/test/tests.rb +13 -5
- data/test/tests_mimic.rb +12 -3
- data/test/tests_mimic_addition.rb +12 -3
- metadata +75 -127
- data/ext/oj/hash.c +0 -135
- data/ext/oj/hash.h +0 -18
- data/ext/oj/hash_test.c +0 -484
- 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/test_helper.rb +0 -72
- data/test/bar.rb +0 -35
- data/test/baz.rb +0 -16
- data/test/zoo.rb +0 -13
data/ext/oj/parse.c
CHANGED
@@ -1,953 +1,952 @@
|
|
1
1
|
// Copyright (c) 2013 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
2
3
|
|
3
|
-
#include
|
4
|
+
#include "parse.h"
|
5
|
+
|
6
|
+
#include <math.h>
|
7
|
+
#include <ruby/util.h>
|
4
8
|
#include <stdio.h>
|
9
|
+
#include <stdlib.h>
|
5
10
|
#include <string.h>
|
6
11
|
#include <unistd.h>
|
7
|
-
#include <math.h>
|
8
|
-
#include <ruby/util.h>
|
9
12
|
|
10
|
-
#include "oj.h"
|
11
|
-
#include "encode.h"
|
12
|
-
#include "parse.h"
|
13
13
|
#include "buf.h"
|
14
|
-
#include "
|
14
|
+
#include "encode.h"
|
15
|
+
#include "mem.h"
|
16
|
+
#include "oj.h"
|
15
17
|
#include "rxclass.h"
|
18
|
+
#include "val_stack.h"
|
19
|
+
|
20
|
+
#ifdef OJ_USE_SSE4_2
|
21
|
+
#include <nmmintrin.h>
|
22
|
+
#endif
|
16
23
|
|
17
24
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
18
|
-
#define OJ_INFINITY
|
25
|
+
#define OJ_INFINITY (1.0 / 0.0)
|
19
26
|
|
20
|
-
|
21
|
-
#define EXP_MAX
|
22
|
-
#define DEC_MAX
|
27
|
+
// #define EXP_MAX 1023
|
28
|
+
#define EXP_MAX 100000
|
29
|
+
#define DEC_MAX 15
|
23
30
|
|
24
|
-
static void
|
25
|
-
next_non_white(ParseInfo pi) {
|
31
|
+
static void next_non_white(ParseInfo pi) {
|
26
32
|
for (; 1; pi->cur++) {
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
return;
|
36
|
-
}
|
33
|
+
switch (*pi->cur) {
|
34
|
+
case ' ':
|
35
|
+
case '\t':
|
36
|
+
case '\f':
|
37
|
+
case '\n':
|
38
|
+
case '\r': break;
|
39
|
+
default: return;
|
40
|
+
}
|
37
41
|
}
|
38
42
|
}
|
39
43
|
|
40
|
-
static void
|
41
|
-
skip_comment(ParseInfo pi) {
|
44
|
+
static void skip_comment(ParseInfo pi) {
|
42
45
|
if ('*' == *pi->cur) {
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
pi->cur++;
|
47
|
+
for (; pi->cur < pi->end; pi->cur++) {
|
48
|
+
if ('*' == *pi->cur && '/' == *(pi->cur + 1)) {
|
49
|
+
pi->cur += 2;
|
50
|
+
return;
|
51
|
+
} else if (pi->end <= pi->cur) {
|
52
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
|
53
|
+
return;
|
54
|
+
}
|
55
|
+
}
|
53
56
|
} else if ('/' == *pi->cur) {
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
}
|
64
|
-
}
|
57
|
+
for (; 1; pi->cur++) {
|
58
|
+
switch (*pi->cur) {
|
59
|
+
case '\n':
|
60
|
+
case '\r':
|
61
|
+
case '\f':
|
62
|
+
case '\0': return;
|
63
|
+
default: break;
|
64
|
+
}
|
65
|
+
}
|
65
66
|
} else {
|
66
|
-
|
67
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
|
67
68
|
}
|
68
69
|
}
|
69
70
|
|
70
|
-
static void
|
71
|
-
|
72
|
-
Val parent = stack_peek(&pi->stack);
|
71
|
+
static void add_value(ParseInfo pi, VALUE rval) {
|
72
|
+
Val parent = stack_peek(&pi->stack);
|
73
73
|
|
74
|
-
if (0 == parent) {
|
75
|
-
|
74
|
+
if (0 == parent) { // simple add
|
75
|
+
pi->add_value(pi, rval);
|
76
76
|
} else {
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
77
|
+
switch (parent->next) {
|
78
|
+
case NEXT_ARRAY_NEW:
|
79
|
+
case NEXT_ARRAY_ELEMENT:
|
80
|
+
pi->array_append_value(pi, rval);
|
81
|
+
parent->next = NEXT_ARRAY_COMMA;
|
82
|
+
break;
|
83
|
+
case NEXT_HASH_VALUE:
|
84
|
+
pi->hash_set_value(pi, parent, rval);
|
85
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
86
|
+
OJ_R_FREE((char *)parent->key);
|
87
|
+
parent->key = 0;
|
88
|
+
}
|
89
|
+
parent->next = NEXT_HASH_COMMA;
|
90
|
+
break;
|
91
|
+
case NEXT_HASH_NEW:
|
92
|
+
case NEXT_HASH_KEY:
|
93
|
+
case NEXT_HASH_COMMA:
|
94
|
+
case NEXT_NONE:
|
95
|
+
case NEXT_ARRAY_COMMA:
|
96
|
+
case NEXT_HASH_COLON:
|
97
|
+
default:
|
98
|
+
oj_set_error_at(pi,
|
99
|
+
oj_parse_error_class,
|
100
|
+
__FILE__,
|
101
|
+
__LINE__,
|
102
|
+
"expected %s",
|
103
|
+
oj_stack_next_string(parent->next));
|
104
|
+
break;
|
105
|
+
}
|
101
106
|
}
|
102
107
|
}
|
103
108
|
|
104
|
-
static void
|
105
|
-
read_null(ParseInfo pi) {
|
109
|
+
static void read_null(ParseInfo pi) {
|
106
110
|
if ('u' == *pi->cur++ && 'l' == *pi->cur++ && 'l' == *pi->cur++) {
|
107
|
-
|
111
|
+
add_value(pi, Qnil);
|
108
112
|
} else {
|
109
|
-
|
113
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null");
|
110
114
|
}
|
111
115
|
}
|
112
116
|
|
113
|
-
static void
|
114
|
-
read_true(ParseInfo pi) {
|
117
|
+
static void read_true(ParseInfo pi) {
|
115
118
|
if ('r' == *pi->cur++ && 'u' == *pi->cur++ && 'e' == *pi->cur++) {
|
116
|
-
|
119
|
+
add_value(pi, Qtrue);
|
117
120
|
} else {
|
118
|
-
|
121
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
|
119
122
|
}
|
120
123
|
}
|
121
124
|
|
122
|
-
static void
|
123
|
-
read_false(ParseInfo pi) {
|
125
|
+
static void read_false(ParseInfo pi) {
|
124
126
|
if ('a' == *pi->cur++ && 'l' == *pi->cur++ && 's' == *pi->cur++ && 'e' == *pi->cur++) {
|
125
|
-
|
127
|
+
add_value(pi, Qfalse);
|
126
128
|
} else {
|
127
|
-
|
129
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
|
128
130
|
}
|
129
131
|
}
|
130
132
|
|
131
|
-
static uint32_t
|
132
|
-
|
133
|
-
|
134
|
-
int i;
|
133
|
+
static uint32_t read_hex(ParseInfo pi, const char *h) {
|
134
|
+
uint32_t b = 0;
|
135
|
+
int i;
|
135
136
|
|
136
137
|
for (i = 0; i < 4; i++, h++) {
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
138
|
+
b = b << 4;
|
139
|
+
if ('0' <= *h && *h <= '9') {
|
140
|
+
b += *h - '0';
|
141
|
+
} else if ('A' <= *h && *h <= 'F') {
|
142
|
+
b += *h - 'A' + 10;
|
143
|
+
} else if ('a' <= *h && *h <= 'f') {
|
144
|
+
b += *h - 'a' + 10;
|
145
|
+
} else {
|
146
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character");
|
147
|
+
return 0;
|
148
|
+
}
|
148
149
|
}
|
149
150
|
return b;
|
150
151
|
}
|
151
152
|
|
152
|
-
static void
|
153
|
-
unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
153
|
+
static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
154
154
|
if (0x0000007F >= code) {
|
155
|
-
|
155
|
+
buf_append(buf, (char)code);
|
156
156
|
} else if (0x000007FF >= code) {
|
157
|
-
|
158
|
-
|
157
|
+
buf_append(buf, 0xC0 | (code >> 6));
|
158
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
159
159
|
} else if (0x0000FFFF >= code) {
|
160
|
-
|
161
|
-
|
162
|
-
|
160
|
+
buf_append(buf, 0xE0 | (code >> 12));
|
161
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
162
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
163
163
|
} else if (0x001FFFFF >= code) {
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
164
|
+
buf_append(buf, 0xF0 | (code >> 18));
|
165
|
+
buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
|
166
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
167
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
168
168
|
} else if (0x03FFFFFF >= code) {
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
169
|
+
buf_append(buf, 0xF8 | (code >> 24));
|
170
|
+
buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
|
171
|
+
buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
|
172
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
173
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
174
174
|
} else if (0x7FFFFFFF >= code) {
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
175
|
+
buf_append(buf, 0xFC | (code >> 30));
|
176
|
+
buf_append(buf, 0x80 | ((code >> 24) & 0x3F));
|
177
|
+
buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
|
178
|
+
buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
|
179
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
180
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
181
181
|
} else {
|
182
|
-
|
182
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
|
183
|
+
}
|
184
|
+
}
|
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,
|
204
|
+
3,
|
205
|
+
string,
|
206
|
+
16,
|
207
|
+
_SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
|
208
|
+
if (r != 16) {
|
209
|
+
str = (char *)(str + r);
|
210
|
+
return str;
|
211
|
+
}
|
183
212
|
}
|
213
|
+
|
214
|
+
return scan_string_noSIMD(str, end);
|
215
|
+
}
|
216
|
+
#endif
|
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
|
184
224
|
}
|
185
225
|
|
186
226
|
// entered at /
|
187
|
-
static void
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
Val parent = stack_peek(&pi->stack);
|
227
|
+
static void read_escaped_str(ParseInfo pi, const char *start) {
|
228
|
+
struct _buf buf;
|
229
|
+
const char *s;
|
230
|
+
int cnt = (int)(pi->cur - start);
|
231
|
+
uint32_t code;
|
232
|
+
Val parent = stack_peek(&pi->stack);
|
194
233
|
|
195
234
|
buf_init(&buf);
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
235
|
+
buf_append_string(&buf, start, cnt);
|
236
|
+
|
237
|
+
for (s = pi->cur; '"' != *s;) {
|
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");
|
242
|
+
buf_cleanup(&buf);
|
243
|
+
return;
|
244
|
+
}
|
245
|
+
buf_append_string(&buf, s, (size_t)(scanned - s));
|
246
|
+
s = scanned;
|
247
|
+
|
248
|
+
if ('\\' == *s) {
|
249
|
+
s++;
|
250
|
+
switch (*s) {
|
251
|
+
case 'n': buf_append(&buf, '\n'); break;
|
252
|
+
case 'r': buf_append(&buf, '\r'); break;
|
253
|
+
case 't': buf_append(&buf, '\t'); break;
|
254
|
+
case 'f': buf_append(&buf, '\f'); break;
|
255
|
+
case 'b': buf_append(&buf, '\b'); break;
|
256
|
+
case '"': buf_append(&buf, '"'); break;
|
257
|
+
case '/': buf_append(&buf, '/'); break;
|
258
|
+
case '\\': buf_append(&buf, '\\'); break;
|
259
|
+
case 'u':
|
260
|
+
s++;
|
261
|
+
if (0 == (code = read_hex(pi, s)) && err_has(&pi->err)) {
|
262
|
+
buf_cleanup(&buf);
|
263
|
+
return;
|
264
|
+
}
|
265
|
+
s += 3;
|
266
|
+
if (0x0000D800 <= code && code <= 0x0000DFFF) {
|
267
|
+
uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
|
268
|
+
uint32_t c2;
|
269
|
+
|
270
|
+
s++;
|
271
|
+
if ('\\' != *s || 'u' != *(s + 1)) {
|
272
|
+
if (Yes == pi->options.allow_invalid) {
|
273
|
+
s--;
|
274
|
+
unicode_to_chars(pi, &buf, code);
|
275
|
+
break;
|
276
|
+
}
|
277
|
+
pi->cur = s;
|
278
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
279
|
+
buf_cleanup(&buf);
|
280
|
+
return;
|
281
|
+
}
|
282
|
+
s += 2;
|
283
|
+
if (0 == (c2 = read_hex(pi, s)) && err_has(&pi->err)) {
|
284
|
+
buf_cleanup(&buf);
|
285
|
+
return;
|
286
|
+
}
|
287
|
+
s += 3;
|
288
|
+
c2 = (c2 - 0x0000DC00) & 0x000003FF;
|
289
|
+
code = ((c1 << 10) | c2) + 0x00010000;
|
290
|
+
}
|
291
|
+
unicode_to_chars(pi, &buf, code);
|
292
|
+
if (err_has(&pi->err)) {
|
293
|
+
buf_cleanup(&buf);
|
294
|
+
return;
|
295
|
+
}
|
296
|
+
break;
|
297
|
+
default:
|
298
|
+
// The json gem claims this is not an error despite the
|
299
|
+
// ECMA-404 indicating it is not valid.
|
300
|
+
if (CompatMode == pi->options.mode) {
|
301
|
+
buf_append(&buf, *s);
|
302
|
+
break;
|
303
|
+
}
|
304
|
+
pi->cur = s;
|
305
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
|
306
|
+
buf_cleanup(&buf);
|
307
|
+
return;
|
308
|
+
}
|
309
|
+
s++;
|
310
|
+
}
|
268
311
|
}
|
269
312
|
if (0 == parent) {
|
270
|
-
|
313
|
+
pi->add_cstr(pi, buf.head, buf_len(&buf), start);
|
271
314
|
} else {
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
315
|
+
switch (parent->next) {
|
316
|
+
case NEXT_ARRAY_NEW:
|
317
|
+
case NEXT_ARRAY_ELEMENT:
|
318
|
+
pi->array_append_cstr(pi, buf.head, buf_len(&buf), start);
|
319
|
+
parent->next = NEXT_ARRAY_COMMA;
|
320
|
+
break;
|
321
|
+
case NEXT_HASH_NEW:
|
322
|
+
case NEXT_HASH_KEY:
|
323
|
+
if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
|
324
|
+
parent->klen = buf_len(&buf);
|
325
|
+
parent->key = OJ_MALLOC(parent->klen + 1);
|
326
|
+
memcpy((char *)parent->key, buf.head, parent->klen);
|
327
|
+
*(char *)(parent->key + parent->klen) = '\0';
|
328
|
+
} else {
|
329
|
+
parent->key = "";
|
330
|
+
parent->klen = 0;
|
331
|
+
}
|
332
|
+
parent->k1 = *start;
|
333
|
+
parent->next = NEXT_HASH_COLON;
|
334
|
+
break;
|
335
|
+
case NEXT_HASH_VALUE:
|
336
|
+
pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start);
|
337
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
338
|
+
OJ_R_FREE((char *)parent->key);
|
339
|
+
parent->key = 0;
|
340
|
+
}
|
341
|
+
parent->next = NEXT_HASH_COMMA;
|
342
|
+
break;
|
343
|
+
case NEXT_HASH_COMMA:
|
344
|
+
case NEXT_NONE:
|
345
|
+
case NEXT_ARRAY_COMMA:
|
346
|
+
case NEXT_HASH_COLON:
|
347
|
+
default:
|
348
|
+
oj_set_error_at(pi,
|
349
|
+
oj_parse_error_class,
|
350
|
+
__FILE__,
|
351
|
+
__LINE__,
|
352
|
+
"expected %s, not a string",
|
353
|
+
oj_stack_next_string(parent->next));
|
354
|
+
break;
|
355
|
+
}
|
308
356
|
}
|
309
357
|
pi->cur = s + 1;
|
310
358
|
buf_cleanup(&buf);
|
311
359
|
}
|
312
360
|
|
313
|
-
static void
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
} else if ('\\' == *pi->cur) {
|
326
|
-
read_escaped_str(pi, str);
|
327
|
-
return;
|
328
|
-
}
|
361
|
+
static void read_str(ParseInfo pi) {
|
362
|
+
const char *str = pi->cur;
|
363
|
+
Val parent = stack_peek(&pi->stack);
|
364
|
+
|
365
|
+
pi->cur = scan_func(pi->cur, pi->end);
|
366
|
+
if (RB_UNLIKELY(pi->end <= pi->cur)) {
|
367
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
|
368
|
+
return;
|
369
|
+
}
|
370
|
+
if (RB_UNLIKELY('\0' == *pi->cur)) {
|
371
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string");
|
372
|
+
return;
|
329
373
|
}
|
330
|
-
if (
|
331
|
-
|
374
|
+
if ('\\' == *pi->cur) {
|
375
|
+
read_escaped_str(pi, str);
|
376
|
+
return;
|
377
|
+
}
|
378
|
+
|
379
|
+
if (0 == parent) { // simple add
|
380
|
+
pi->add_cstr(pi, str, pi->cur - str, str);
|
332
381
|
} else {
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
382
|
+
switch (parent->next) {
|
383
|
+
case NEXT_ARRAY_NEW:
|
384
|
+
case NEXT_ARRAY_ELEMENT:
|
385
|
+
pi->array_append_cstr(pi, str, pi->cur - str, str);
|
386
|
+
parent->next = NEXT_ARRAY_COMMA;
|
387
|
+
break;
|
388
|
+
case NEXT_HASH_NEW:
|
389
|
+
case NEXT_HASH_KEY:
|
390
|
+
if (Qundef == (parent->key_val = pi->hash_key(pi, str, pi->cur - str))) {
|
391
|
+
parent->key = str;
|
392
|
+
parent->klen = pi->cur - str;
|
393
|
+
} else {
|
394
|
+
parent->key = "";
|
395
|
+
parent->klen = 0;
|
396
|
+
}
|
397
|
+
parent->k1 = *str;
|
398
|
+
parent->next = NEXT_HASH_COLON;
|
399
|
+
break;
|
400
|
+
case NEXT_HASH_VALUE:
|
401
|
+
pi->hash_set_cstr(pi, parent, str, pi->cur - str, str);
|
402
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
403
|
+
OJ_R_FREE((char *)parent->key);
|
404
|
+
parent->key = 0;
|
405
|
+
}
|
406
|
+
parent->next = NEXT_HASH_COMMA;
|
407
|
+
break;
|
408
|
+
case NEXT_HASH_COMMA:
|
409
|
+
case NEXT_NONE:
|
410
|
+
case NEXT_ARRAY_COMMA:
|
411
|
+
case NEXT_HASH_COLON:
|
412
|
+
default:
|
413
|
+
oj_set_error_at(pi,
|
414
|
+
oj_parse_error_class,
|
415
|
+
__FILE__,
|
416
|
+
__LINE__,
|
417
|
+
"expected %s, not a string",
|
418
|
+
oj_stack_next_string(parent->next));
|
419
|
+
break;
|
420
|
+
}
|
367
421
|
}
|
368
|
-
pi->cur++;
|
422
|
+
pi->cur++; // move past "
|
369
423
|
}
|
370
424
|
|
371
|
-
static void
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
ni.str
|
377
|
-
ni.i
|
378
|
-
ni.num
|
379
|
-
ni.div
|
380
|
-
ni.di
|
381
|
-
ni.len
|
382
|
-
ni.exp
|
383
|
-
ni.big
|
425
|
+
static void read_num(ParseInfo pi) {
|
426
|
+
struct _numInfo ni;
|
427
|
+
Val parent = stack_peek(&pi->stack);
|
428
|
+
|
429
|
+
ni.pi = pi;
|
430
|
+
ni.str = pi->cur;
|
431
|
+
ni.i = 0;
|
432
|
+
ni.num = 0;
|
433
|
+
ni.div = 1;
|
434
|
+
ni.di = 0;
|
435
|
+
ni.len = 0;
|
436
|
+
ni.exp = 0;
|
437
|
+
ni.big = 0;
|
384
438
|
ni.infinity = 0;
|
385
|
-
ni.nan
|
386
|
-
ni.neg
|
387
|
-
ni.has_exp
|
439
|
+
ni.nan = 0;
|
440
|
+
ni.neg = 0;
|
441
|
+
ni.has_exp = 0;
|
388
442
|
if (CompatMode == pi->options.mode) {
|
389
|
-
|
390
|
-
|
443
|
+
ni.no_big = !pi->options.compat_bigdec;
|
444
|
+
ni.bigdec_load = pi->options.compat_bigdec;
|
391
445
|
} else {
|
392
|
-
|
393
|
-
|
446
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
|
447
|
+
RubyDec == pi->options.bigdec_load);
|
448
|
+
ni.bigdec_load = pi->options.bigdec_load;
|
394
449
|
}
|
395
450
|
|
396
451
|
if ('-' == *pi->cur) {
|
397
|
-
|
398
|
-
|
452
|
+
pi->cur++;
|
453
|
+
ni.neg = 1;
|
399
454
|
} else if ('+' == *pi->cur) {
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
455
|
+
if (StrictMode == pi->options.mode) {
|
456
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
457
|
+
return;
|
458
|
+
}
|
459
|
+
pi->cur++;
|
405
460
|
}
|
406
461
|
if ('I' == *pi->cur) {
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
462
|
+
if (No == pi->options.allow_nan || 0 != strncmp("Infinity", pi->cur, 8)) {
|
463
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
464
|
+
return;
|
465
|
+
}
|
466
|
+
pi->cur += 8;
|
467
|
+
ni.infinity = 1;
|
413
468
|
} else if ('N' == *pi->cur || 'n' == *pi->cur) {
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
469
|
+
if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) {
|
470
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
471
|
+
return;
|
472
|
+
}
|
473
|
+
pi->cur += 3;
|
474
|
+
ni.nan = 1;
|
420
475
|
} else {
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
}
|
501
|
-
}
|
502
|
-
if (eneg) {
|
503
|
-
ni.exp = -ni.exp;
|
504
|
-
}
|
505
|
-
}
|
506
|
-
ni.len = pi->cur - ni.str;
|
476
|
+
int dec_cnt = 0;
|
477
|
+
bool zero1 = false;
|
478
|
+
|
479
|
+
// Skip leading zeros.
|
480
|
+
for (; '0' == *pi->cur; pi->cur++) {
|
481
|
+
zero1 = true;
|
482
|
+
}
|
483
|
+
|
484
|
+
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
485
|
+
int d = (*pi->cur - '0');
|
486
|
+
|
487
|
+
if (RB_LIKELY(0 != ni.i)) {
|
488
|
+
dec_cnt++;
|
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;
|
498
|
+
}
|
499
|
+
|
500
|
+
if ('.' == *pi->cur) {
|
501
|
+
pi->cur++;
|
502
|
+
// A trailing . is not a valid decimal but if encountered allow it
|
503
|
+
// except when mimicking the JSON gem or in strict mode.
|
504
|
+
if (StrictMode == pi->options.mode || CompatMode == pi->options.mode) {
|
505
|
+
int pos = (int)(pi->cur - ni.str);
|
506
|
+
|
507
|
+
if (1 == pos || (2 == pos && ni.neg)) {
|
508
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
509
|
+
return;
|
510
|
+
}
|
511
|
+
if (*pi->cur < '0' || '9' < *pi->cur) {
|
512
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
513
|
+
return;
|
514
|
+
}
|
515
|
+
}
|
516
|
+
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
517
|
+
int d = (*pi->cur - '0');
|
518
|
+
|
519
|
+
if (RB_LIKELY(0 != ni.num || 0 != ni.i)) {
|
520
|
+
dec_cnt++;
|
521
|
+
}
|
522
|
+
ni.num = ni.num * 10 + d;
|
523
|
+
ni.div *= 10;
|
524
|
+
ni.di++;
|
525
|
+
}
|
526
|
+
}
|
527
|
+
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
528
|
+
if (!ni.no_big) {
|
529
|
+
ni.big = true;
|
530
|
+
}
|
531
|
+
}
|
532
|
+
|
533
|
+
if ('e' == *pi->cur || 'E' == *pi->cur) {
|
534
|
+
int eneg = 0;
|
535
|
+
|
536
|
+
ni.has_exp = 1;
|
537
|
+
pi->cur++;
|
538
|
+
if ('-' == *pi->cur) {
|
539
|
+
pi->cur++;
|
540
|
+
eneg = 1;
|
541
|
+
} else if ('+' == *pi->cur) {
|
542
|
+
pi->cur++;
|
543
|
+
}
|
544
|
+
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
545
|
+
ni.exp = ni.exp * 10 + (*pi->cur - '0');
|
546
|
+
if (EXP_MAX <= ni.exp) {
|
547
|
+
ni.big = true;
|
548
|
+
}
|
549
|
+
}
|
550
|
+
if (eneg) {
|
551
|
+
ni.exp = -ni.exp;
|
552
|
+
}
|
553
|
+
}
|
554
|
+
ni.len = pi->cur - ni.str;
|
507
555
|
}
|
508
556
|
// Check for special reserved values for Infinity and NaN.
|
509
557
|
if (ni.big) {
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
558
|
+
if (0 == strcasecmp(INF_VAL, ni.str)) {
|
559
|
+
ni.infinity = 1;
|
560
|
+
} else if (0 == strcasecmp(NINF_VAL, ni.str)) {
|
561
|
+
ni.infinity = 1;
|
562
|
+
ni.neg = 1;
|
563
|
+
} else if (0 == strcasecmp(NAN_VAL, ni.str)) {
|
564
|
+
ni.nan = 1;
|
565
|
+
}
|
518
566
|
}
|
519
567
|
if (CompatMode == pi->options.mode) {
|
520
|
-
|
521
|
-
|
522
|
-
|
568
|
+
if (pi->options.compat_bigdec) {
|
569
|
+
ni.big = 1;
|
570
|
+
}
|
523
571
|
} else if (BigDec == pi->options.bigdec_load) {
|
524
|
-
|
572
|
+
ni.big = 1;
|
525
573
|
}
|
526
574
|
if (0 == parent) {
|
527
|
-
|
575
|
+
pi->add_num(pi, &ni);
|
528
576
|
} else {
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
577
|
+
switch (parent->next) {
|
578
|
+
case NEXT_ARRAY_NEW:
|
579
|
+
case NEXT_ARRAY_ELEMENT:
|
580
|
+
pi->array_append_num(pi, &ni);
|
581
|
+
parent->next = NEXT_ARRAY_COMMA;
|
582
|
+
break;
|
583
|
+
case NEXT_HASH_VALUE:
|
584
|
+
pi->hash_set_num(pi, parent, &ni);
|
585
|
+
if (0 != parent->key && 0 < parent->klen && (parent->key < pi->json || pi->cur < parent->key)) {
|
586
|
+
OJ_R_FREE((char *)parent->key);
|
587
|
+
parent->key = 0;
|
588
|
+
}
|
589
|
+
parent->next = NEXT_HASH_COMMA;
|
590
|
+
break;
|
591
|
+
default:
|
592
|
+
oj_set_error_at(pi,
|
593
|
+
oj_parse_error_class,
|
594
|
+
__FILE__,
|
595
|
+
__LINE__,
|
596
|
+
"expected %s",
|
597
|
+
oj_stack_next_string(parent->next));
|
598
|
+
break;
|
599
|
+
}
|
547
600
|
}
|
548
601
|
}
|
549
602
|
|
550
|
-
static void
|
551
|
-
|
552
|
-
volatile VALUE v = pi->start_array(pi);
|
603
|
+
static void array_start(ParseInfo pi) {
|
604
|
+
VALUE v = pi->start_array(pi);
|
553
605
|
|
554
606
|
stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
|
555
607
|
}
|
556
608
|
|
557
|
-
static void
|
558
|
-
|
559
|
-
Val array = stack_pop(&pi->stack);
|
609
|
+
static void array_end(ParseInfo pi) {
|
610
|
+
Val array = stack_pop(&pi->stack);
|
560
611
|
|
561
612
|
if (0 == array) {
|
562
|
-
|
613
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
|
563
614
|
} else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
|
564
|
-
|
615
|
+
oj_set_error_at(pi,
|
616
|
+
oj_parse_error_class,
|
617
|
+
__FILE__,
|
618
|
+
__LINE__,
|
619
|
+
"expected %s, not an array close",
|
620
|
+
oj_stack_next_string(array->next));
|
565
621
|
} else {
|
566
|
-
|
567
|
-
|
622
|
+
pi->end_array(pi);
|
623
|
+
add_value(pi, array->val);
|
568
624
|
}
|
569
625
|
}
|
570
626
|
|
571
|
-
static void
|
572
|
-
|
573
|
-
volatile VALUE v = pi->start_hash(pi);
|
627
|
+
static void hash_start(ParseInfo pi) {
|
628
|
+
VALUE v = pi->start_hash(pi);
|
574
629
|
|
575
630
|
stack_push(&pi->stack, v, NEXT_HASH_NEW);
|
576
631
|
}
|
577
632
|
|
578
|
-
static void
|
579
|
-
|
580
|
-
volatile Val hash = stack_peek(&pi->stack);
|
633
|
+
static void hash_end(ParseInfo pi) {
|
634
|
+
Val hash = stack_peek(&pi->stack);
|
581
635
|
|
582
636
|
// leave hash on stack until just before
|
583
637
|
if (0 == hash) {
|
584
|
-
|
638
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
|
585
639
|
} else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
|
586
|
-
|
640
|
+
oj_set_error_at(pi,
|
641
|
+
oj_parse_error_class,
|
642
|
+
__FILE__,
|
643
|
+
__LINE__,
|
644
|
+
"expected %s, not a hash close",
|
645
|
+
oj_stack_next_string(hash->next));
|
587
646
|
} else {
|
588
|
-
|
589
|
-
|
590
|
-
|
647
|
+
pi->end_hash(pi);
|
648
|
+
stack_pop(&pi->stack);
|
649
|
+
add_value(pi, hash->val);
|
591
650
|
}
|
592
651
|
}
|
593
652
|
|
594
|
-
static void
|
595
|
-
|
596
|
-
Val parent = stack_peek(&pi->stack);
|
653
|
+
static void comma(ParseInfo pi) {
|
654
|
+
Val parent = stack_peek(&pi->stack);
|
597
655
|
|
598
656
|
if (0 == parent) {
|
599
|
-
|
657
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
600
658
|
} else if (NEXT_ARRAY_COMMA == parent->next) {
|
601
|
-
|
659
|
+
parent->next = NEXT_ARRAY_ELEMENT;
|
602
660
|
} else if (NEXT_HASH_COMMA == parent->next) {
|
603
|
-
|
661
|
+
parent->next = NEXT_HASH_KEY;
|
604
662
|
} else {
|
605
|
-
|
663
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
606
664
|
}
|
607
665
|
}
|
608
666
|
|
609
|
-
static void
|
610
|
-
|
611
|
-
Val parent = stack_peek(&pi->stack);
|
667
|
+
static void colon(ParseInfo pi) {
|
668
|
+
Val parent = stack_peek(&pi->stack);
|
612
669
|
|
613
670
|
if (0 != parent && NEXT_HASH_COLON == parent->next) {
|
614
|
-
|
671
|
+
parent->next = NEXT_HASH_VALUE;
|
615
672
|
} else {
|
616
|
-
|
673
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
|
617
674
|
}
|
618
675
|
}
|
619
676
|
|
620
|
-
void
|
621
|
-
|
622
|
-
|
623
|
-
long start = 0;
|
677
|
+
void oj_parse2(ParseInfo pi) {
|
678
|
+
int first = 1;
|
679
|
+
long start = 0;
|
624
680
|
|
625
681
|
pi->cur = pi->json;
|
626
682
|
err_init(&pi->err);
|
627
683
|
while (1) {
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
if (stack_empty(&pi->stack)) {
|
731
|
-
if (Qundef != pi->proc) {
|
732
|
-
VALUE args[3];
|
733
|
-
long len = (pi->cur - pi->json) - start;
|
734
|
-
|
735
|
-
*args = stack_head_val(&pi->stack);
|
736
|
-
args[1] = LONG2NUM(start);
|
737
|
-
args[2] = LONG2NUM(len);
|
738
|
-
|
739
|
-
if (Qnil == pi->proc) {
|
740
|
-
rb_yield_values2(3, args);
|
741
|
-
} else {
|
742
|
-
rb_proc_call_with_block(pi->proc, 3, args, Qnil);
|
743
|
-
}
|
744
|
-
} else if (!pi->has_callbacks) {
|
745
|
-
first = 0;
|
746
|
-
}
|
747
|
-
start = pi->cur - pi->json;
|
748
|
-
}
|
684
|
+
if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
|
685
|
+
VALUE err_clas = oj_get_json_err_class("NestingError");
|
686
|
+
|
687
|
+
oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
|
688
|
+
pi->err_class = err_clas;
|
689
|
+
return;
|
690
|
+
}
|
691
|
+
next_non_white(pi);
|
692
|
+
if (!first && '\0' != *pi->cur) {
|
693
|
+
oj_set_error_at(pi,
|
694
|
+
oj_parse_error_class,
|
695
|
+
__FILE__,
|
696
|
+
__LINE__,
|
697
|
+
"unexpected characters after the JSON document");
|
698
|
+
}
|
699
|
+
|
700
|
+
// If no tokens are consumed (i.e. empty string), throw a parse error
|
701
|
+
// this is the behavior of JSON.parse in both Ruby and JS.
|
702
|
+
if (No == pi->options.empty_string && 1 == first && '\0' == *pi->cur) {
|
703
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
704
|
+
}
|
705
|
+
|
706
|
+
switch (*pi->cur++) {
|
707
|
+
case '{': hash_start(pi); break;
|
708
|
+
case '}': hash_end(pi); break;
|
709
|
+
case ':': colon(pi); break;
|
710
|
+
case '[': array_start(pi); break;
|
711
|
+
case ']': array_end(pi); break;
|
712
|
+
case ',': comma(pi); break;
|
713
|
+
case '"': read_str(pi); break;
|
714
|
+
case '+':
|
715
|
+
if (CompatMode == pi->options.mode) {
|
716
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
717
|
+
return;
|
718
|
+
}
|
719
|
+
pi->cur--;
|
720
|
+
read_num(pi);
|
721
|
+
break;
|
722
|
+
case '-':
|
723
|
+
case '0':
|
724
|
+
case '1':
|
725
|
+
case '2':
|
726
|
+
case '3':
|
727
|
+
case '4':
|
728
|
+
case '5':
|
729
|
+
case '6':
|
730
|
+
case '7':
|
731
|
+
case '8':
|
732
|
+
case '9':
|
733
|
+
pi->cur--;
|
734
|
+
read_num(pi);
|
735
|
+
break;
|
736
|
+
case 'I':
|
737
|
+
case 'N':
|
738
|
+
if (Yes == pi->options.allow_nan) {
|
739
|
+
pi->cur--;
|
740
|
+
read_num(pi);
|
741
|
+
} else {
|
742
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
743
|
+
}
|
744
|
+
break;
|
745
|
+
case 't': read_true(pi); break;
|
746
|
+
case 'f': read_false(pi); break;
|
747
|
+
case 'n':
|
748
|
+
if ('u' == *pi->cur) {
|
749
|
+
read_null(pi);
|
750
|
+
} else {
|
751
|
+
pi->cur--;
|
752
|
+
read_num(pi);
|
753
|
+
}
|
754
|
+
break;
|
755
|
+
case '/':
|
756
|
+
skip_comment(pi);
|
757
|
+
if (first) {
|
758
|
+
continue;
|
759
|
+
}
|
760
|
+
break;
|
761
|
+
case '\0': pi->cur--; return;
|
762
|
+
default: oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character"); return;
|
763
|
+
}
|
764
|
+
if (err_has(&pi->err)) {
|
765
|
+
return;
|
766
|
+
}
|
767
|
+
if (stack_empty(&pi->stack)) {
|
768
|
+
if (Qundef != pi->proc) {
|
769
|
+
VALUE args[3];
|
770
|
+
long len = (pi->cur - pi->json) - start;
|
771
|
+
|
772
|
+
*args = stack_head_val(&pi->stack);
|
773
|
+
args[1] = LONG2NUM(start);
|
774
|
+
args[2] = LONG2NUM(len);
|
775
|
+
|
776
|
+
if (Qnil == pi->proc) {
|
777
|
+
rb_yield_values2(3, args);
|
778
|
+
} else {
|
779
|
+
rb_proc_call_with_block(pi->proc, 3, args, Qnil);
|
780
|
+
}
|
781
|
+
} else if (!pi->has_callbacks) {
|
782
|
+
first = 0;
|
783
|
+
}
|
784
|
+
start = pi->cur - pi->json;
|
785
|
+
}
|
749
786
|
}
|
750
787
|
}
|
751
788
|
|
752
|
-
static VALUE
|
753
|
-
rescue_big_decimal(VALUE str, VALUE ignore) {
|
789
|
+
static VALUE rescue_big_decimal(VALUE str, VALUE ignore) {
|
754
790
|
rb_raise(oj_parse_error_class, "Invalid value for BigDecimal()");
|
755
791
|
return Qnil;
|
756
792
|
}
|
757
793
|
|
758
|
-
static VALUE
|
759
|
-
parse_big_decimal(VALUE str) {
|
794
|
+
static VALUE parse_big_decimal(VALUE str) {
|
760
795
|
return rb_funcall(rb_cObject, oj_bigdecimal_id, 1, str);
|
761
796
|
}
|
762
797
|
|
763
|
-
static long double
|
764
|
-
1.0,
|
765
|
-
1.
|
766
|
-
1.
|
767
|
-
1.
|
768
|
-
1.0e4,
|
769
|
-
1.0e5,
|
770
|
-
1.0e6,
|
771
|
-
1.0e7,
|
772
|
-
1.0e8,
|
773
|
-
1.0e9,
|
774
|
-
1.0e10,
|
775
|
-
1.0e11,
|
776
|
-
1.0e12,
|
777
|
-
1.0e13,
|
778
|
-
1.0e14,
|
779
|
-
1.0e15,
|
780
|
-
1.0e16,
|
781
|
-
1.0e17,
|
782
|
-
1.0e18,
|
783
|
-
1.0e19,
|
784
|
-
1.0e20,
|
785
|
-
1.0e21,
|
786
|
-
1.0e22,
|
787
|
-
1.0e23,
|
788
|
-
1.0e24,
|
789
|
-
1.0e25,
|
790
|
-
1.0e26,
|
791
|
-
1.0e27,
|
792
|
-
1.0e28,
|
793
|
-
1.0e29,
|
794
|
-
1.0e30,
|
795
|
-
1.0e31,
|
796
|
-
1.0e32,
|
797
|
-
1.0e33,
|
798
|
-
1.0e34,
|
799
|
-
1.0e35,
|
800
|
-
1.0e36,
|
801
|
-
1.0e37,
|
802
|
-
1.0e38,
|
803
|
-
1.0e39,
|
804
|
-
1.0e40,
|
805
|
-
1.0e41,
|
806
|
-
1.0e42,
|
807
|
-
1.0e43,
|
808
|
-
1.0e44,
|
809
|
-
1.0e45,
|
810
|
-
1.0e46,
|
811
|
-
1.0e47,
|
812
|
-
1.0e48,
|
813
|
-
1.0e49,
|
798
|
+
static long double exp_plus[] = {
|
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,
|
814
803
|
};
|
815
804
|
|
816
805
|
VALUE
|
817
806
|
oj_num_as_value(NumInfo ni) {
|
818
|
-
|
807
|
+
VALUE rnum = Qnil;
|
819
808
|
|
820
809
|
if (ni->infinity) {
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
810
|
+
if (ni->neg) {
|
811
|
+
rnum = rb_float_new(-OJ_INFINITY);
|
812
|
+
} else {
|
813
|
+
rnum = rb_float_new(OJ_INFINITY);
|
814
|
+
}
|
826
815
|
} else if (ni->nan) {
|
827
|
-
|
828
|
-
} else if (1 == ni->div && 0 == ni->exp && !ni->has_exp) {
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
} else {
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
816
|
+
rnum = rb_float_new(0.0 / 0.0);
|
817
|
+
} else if (1 == ni->div && 0 == ni->exp && !ni->has_exp) { // fixnum
|
818
|
+
if (ni->big) {
|
819
|
+
if (256 > ni->len) {
|
820
|
+
char buf[256];
|
821
|
+
|
822
|
+
memcpy(buf, ni->str, ni->len);
|
823
|
+
buf[ni->len] = '\0';
|
824
|
+
rnum = rb_cstr_to_inum(buf, 10, 0);
|
825
|
+
} else {
|
826
|
+
char *buf = OJ_R_ALLOC_N(char, ni->len + 1);
|
827
|
+
|
828
|
+
memcpy(buf, ni->str, ni->len);
|
829
|
+
buf[ni->len] = '\0';
|
830
|
+
rnum = rb_cstr_to_inum(buf, 10, 0);
|
831
|
+
OJ_R_FREE(buf);
|
832
|
+
}
|
833
|
+
} else {
|
834
|
+
if (ni->neg) {
|
835
|
+
rnum = rb_ll2inum(-ni->i);
|
836
|
+
} else {
|
837
|
+
rnum = rb_ll2inum(ni->i);
|
838
|
+
}
|
839
|
+
}
|
840
|
+
} else { // decimal
|
841
|
+
if (ni->big) {
|
842
|
+
VALUE bd = rb_str_new(ni->str, ni->len);
|
843
|
+
|
844
|
+
rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
|
845
|
+
if (ni->no_big) {
|
846
|
+
rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
|
847
|
+
}
|
848
|
+
} else if (FastDec == ni->bigdec_load) {
|
849
|
+
long double ld = (long double)ni->i * (long double)ni->div + (long double)ni->num;
|
850
|
+
int x = (int)((int64_t)ni->exp - ni->di);
|
851
|
+
|
852
|
+
if (0 < x) {
|
853
|
+
if (x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
|
854
|
+
ld *= exp_plus[x];
|
855
|
+
} else {
|
856
|
+
ld *= powl(10.0, x);
|
857
|
+
}
|
858
|
+
} else if (x < 0) {
|
859
|
+
if (-x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
|
860
|
+
ld /= exp_plus[-x];
|
861
|
+
} else {
|
862
|
+
ld /= powl(10.0, -x);
|
863
|
+
}
|
864
|
+
}
|
865
|
+
if (ni->neg) {
|
866
|
+
ld = -ld;
|
867
|
+
}
|
868
|
+
rnum = rb_float_new((double)ld);
|
869
|
+
} else if (RubyDec == ni->bigdec_load) {
|
870
|
+
VALUE sv = rb_str_new(ni->str, ni->len);
|
871
|
+
|
872
|
+
rnum = rb_funcall(sv, rb_intern("to_f"), 0);
|
873
|
+
} else {
|
874
|
+
char *end;
|
875
|
+
double d = strtod(ni->str, &end);
|
876
|
+
|
877
|
+
if ((long)ni->len != (long)(end - ni->str)) {
|
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
|
+
}
|
883
|
+
}
|
884
|
+
rnum = rb_float_new(d);
|
885
|
+
}
|
893
886
|
}
|
894
887
|
return rnum;
|
895
888
|
}
|
896
889
|
|
897
|
-
void
|
898
|
-
|
899
|
-
|
900
|
-
char
|
901
|
-
char
|
902
|
-
char
|
903
|
-
|
904
|
-
|
890
|
+
void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, const char *format, ...) {
|
891
|
+
va_list ap;
|
892
|
+
char msg[256];
|
893
|
+
char *p = msg;
|
894
|
+
char *end = p + sizeof(msg) - 2;
|
895
|
+
char *start;
|
896
|
+
Val vp;
|
897
|
+
int mlen;
|
905
898
|
|
906
899
|
va_start(ap, format);
|
907
|
-
|
900
|
+
mlen = vsnprintf(msg, sizeof(msg) - 1, format, ap);
|
901
|
+
if (0 < mlen) {
|
902
|
+
if (sizeof(msg) - 2 < (size_t)mlen) {
|
903
|
+
p = end - 2;
|
904
|
+
} else {
|
905
|
+
p += mlen;
|
906
|
+
}
|
907
|
+
}
|
908
908
|
va_end(ap);
|
909
909
|
pi->err.clas = err_clas;
|
910
910
|
if (p + 3 < end) {
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
911
|
+
*p++ = ' ';
|
912
|
+
*p++ = '(';
|
913
|
+
*p++ = 'a';
|
914
|
+
*p++ = 'f';
|
915
|
+
*p++ = 't';
|
916
|
+
*p++ = 'e';
|
917
|
+
*p++ = 'r';
|
918
|
+
*p++ = ' ';
|
919
|
+
start = p;
|
920
|
+
for (vp = pi->stack.head; vp < pi->stack.tail; vp++) {
|
921
|
+
if (end <= p + 1 + vp->klen) {
|
922
|
+
break;
|
923
|
+
}
|
924
|
+
if (NULL != vp->key) {
|
925
|
+
if (start < p) {
|
926
|
+
*p++ = '.';
|
927
|
+
}
|
928
|
+
memcpy(p, vp->key, vp->klen);
|
929
|
+
p += vp->klen;
|
930
|
+
} else {
|
931
|
+
if (RUBY_T_ARRAY == rb_type(vp->val)) {
|
932
|
+
if (end <= p + 12) {
|
933
|
+
break;
|
934
|
+
}
|
935
|
+
p += snprintf(p, end - p, "[%ld]", RARRAY_LEN(vp->val));
|
936
|
+
}
|
937
|
+
}
|
938
|
+
}
|
939
|
+
*p++ = ')';
|
940
940
|
}
|
941
941
|
*p = '\0';
|
942
942
|
if (0 == pi->json) {
|
943
|
-
|
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);
|
944
944
|
} else {
|
945
|
-
|
945
|
+
_oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
|
946
946
|
}
|
947
947
|
}
|
948
948
|
|
949
|
-
static VALUE
|
950
|
-
protect_parse(VALUE pip) {
|
949
|
+
static VALUE protect_parse(VALUE pip) {
|
951
950
|
oj_parse2((ParseInfo)pip);
|
952
951
|
|
953
952
|
return Qnil;
|
@@ -955,102 +954,102 @@ protect_parse(VALUE pip) {
|
|
955
954
|
|
956
955
|
extern int oj_utf8_index;
|
957
956
|
|
958
|
-
static void
|
959
|
-
|
960
|
-
rb_encoding *enc = rb_to_encoding(rb_obj_encoding(*inputp));
|
957
|
+
static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
|
958
|
+
int idx = RB_ENCODING_GET(*inputp);
|
961
959
|
|
962
|
-
if (
|
963
|
-
|
960
|
+
if (oj_utf8_encoding_index != idx) {
|
961
|
+
rb_encoding *enc = rb_enc_from_index(idx);
|
962
|
+
*inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
|
964
963
|
}
|
965
|
-
pi->json =
|
966
|
-
pi->end
|
964
|
+
pi->json = RSTRING_PTR(*inputp);
|
965
|
+
pi->end = pi->json + RSTRING_LEN(*inputp);
|
967
966
|
}
|
968
967
|
|
969
968
|
VALUE
|
970
969
|
oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
|
971
|
-
char
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
int
|
976
|
-
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;
|
977
976
|
|
978
977
|
if (argc < 1) {
|
979
|
-
|
978
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
980
979
|
}
|
981
980
|
input = argv[0];
|
982
981
|
if (2 <= argc) {
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
982
|
+
if (T_HASH == rb_type(argv[1])) {
|
983
|
+
oj_parse_options(argv[1], &pi->options);
|
984
|
+
} else if (3 <= argc && T_HASH == rb_type(argv[2])) {
|
985
|
+
oj_parse_options(argv[2], &pi->options);
|
986
|
+
}
|
988
987
|
}
|
989
988
|
if (yieldOk && rb_block_given_p()) {
|
990
|
-
|
989
|
+
pi->proc = Qnil;
|
991
990
|
} else {
|
992
|
-
|
991
|
+
pi->proc = Qundef;
|
993
992
|
}
|
994
993
|
if (0 != json) {
|
995
|
-
|
996
|
-
|
997
|
-
|
994
|
+
pi->json = json;
|
995
|
+
pi->end = json + len;
|
996
|
+
free_json = 1;
|
998
997
|
} else if (T_STRING == rb_type(input)) {
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
998
|
+
if (CompatMode == pi->options.mode) {
|
999
|
+
if (No == pi->options.nilnil && 0 == RSTRING_LEN(input)) {
|
1000
|
+
rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string.");
|
1001
|
+
}
|
1002
|
+
}
|
1003
|
+
oj_pi_set_input_str(pi, &input);
|
1005
1004
|
} else if (Qnil == input) {
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1005
|
+
if (Yes == pi->options.nilnil) {
|
1006
|
+
return Qnil;
|
1007
|
+
} else {
|
1008
|
+
rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
|
1009
|
+
}
|
1011
1010
|
} else {
|
1012
|
-
|
1013
|
-
|
1011
|
+
VALUE clas = rb_obj_class(input);
|
1012
|
+
VALUE s;
|
1014
1013
|
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1014
|
+
if (oj_stringio_class == clas) {
|
1015
|
+
s = rb_funcall2(input, oj_string_id, 0, 0);
|
1016
|
+
oj_pi_set_input_str(pi, &s);
|
1018
1017
|
#if !IS_WINDOWS
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1018
|
+
} else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
|
1019
|
+
int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
|
1020
|
+
ssize_t cnt;
|
1021
|
+
size_t len = lseek(fd, 0, SEEK_END);
|
1022
|
+
|
1023
|
+
lseek(fd, 0, SEEK_SET);
|
1024
|
+
buf = OJ_R_ALLOC_N(char, len + 1);
|
1025
|
+
pi->json = buf;
|
1026
|
+
pi->end = buf + len;
|
1027
|
+
if (0 >= (cnt = read(fd, (char *)pi->json, len)) || cnt != (ssize_t)len) {
|
1028
|
+
if (0 != buf) {
|
1029
|
+
OJ_R_FREE(buf);
|
1030
|
+
}
|
1031
|
+
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
1032
|
+
}
|
1033
|
+
((char *)pi->json)[len] = '\0';
|
1034
|
+
/* skip UTF-8 BOM if present */
|
1035
|
+
if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) {
|
1036
|
+
pi->cur += 3;
|
1037
|
+
}
|
1039
1038
|
#endif
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
}
|
1039
|
+
} else if (rb_respond_to(input, oj_read_id)) {
|
1040
|
+
// use stream parser instead
|
1041
|
+
return oj_pi_sparse(argc, argv, pi, 0);
|
1042
|
+
} else {
|
1043
|
+
rb_raise(rb_eArgError, "parse() expected a String or IO Object.");
|
1044
|
+
}
|
1046
1045
|
}
|
1047
1046
|
if (Yes == pi->options.circular) {
|
1048
|
-
|
1047
|
+
pi->circ_array = oj_circ_array_new();
|
1049
1048
|
} else {
|
1050
|
-
|
1049
|
+
pi->circ_array = 0;
|
1051
1050
|
}
|
1052
1051
|
if (No == pi->options.allow_gc) {
|
1053
|
-
|
1052
|
+
rb_gc_disable();
|
1054
1053
|
}
|
1055
1054
|
// GC can run at any time. When it runs any Object created by C will be
|
1056
1055
|
// freed. We protect against this by wrapping the value stack in a ruby
|
@@ -1059,116 +1058,113 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1059
1058
|
wrapped_stack = oj_stack_init(&pi->stack);
|
1060
1059
|
rb_protect(protect_parse, (VALUE)pi, &line);
|
1061
1060
|
if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1061
|
+
if (No == pi->options.nilnil || (CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
|
1062
|
+
oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input");
|
1063
|
+
}
|
1065
1064
|
}
|
1066
|
-
result
|
1065
|
+
result = stack_head_val(&pi->stack);
|
1067
1066
|
DATA_PTR(wrapped_stack) = 0;
|
1068
1067
|
if (No == pi->options.allow_gc) {
|
1069
|
-
|
1068
|
+
rb_gc_enable();
|
1070
1069
|
}
|
1071
1070
|
if (!err_has(&pi->err)) {
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1098
|
-
|
1099
|
-
|
1100
|
-
|
1101
|
-
oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated");
|
1102
|
-
}
|
1103
|
-
}
|
1071
|
+
// If the stack is not empty then the JSON terminated early.
|
1072
|
+
Val v;
|
1073
|
+
VALUE err_class = oj_parse_error_class;
|
1074
|
+
|
1075
|
+
if (0 != line) {
|
1076
|
+
VALUE ec = rb_obj_class(rb_errinfo());
|
1077
|
+
|
1078
|
+
if (rb_eArgError != ec && 0 != ec) {
|
1079
|
+
err_class = ec;
|
1080
|
+
}
|
1081
|
+
if (rb_eIOError != ec) {
|
1082
|
+
goto CLEANUP;
|
1083
|
+
}
|
1084
|
+
}
|
1085
|
+
if (NULL != (v = stack_peek(&pi->stack))) {
|
1086
|
+
switch (v->next) {
|
1087
|
+
case NEXT_ARRAY_NEW:
|
1088
|
+
case NEXT_ARRAY_ELEMENT:
|
1089
|
+
case NEXT_ARRAY_COMMA: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); break;
|
1090
|
+
case NEXT_HASH_NEW:
|
1091
|
+
case NEXT_HASH_KEY:
|
1092
|
+
case NEXT_HASH_COLON:
|
1093
|
+
case NEXT_HASH_VALUE:
|
1094
|
+
case NEXT_HASH_COMMA:
|
1095
|
+
oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated");
|
1096
|
+
break;
|
1097
|
+
default: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated");
|
1098
|
+
}
|
1099
|
+
}
|
1104
1100
|
}
|
1105
1101
|
CLEANUP:
|
1106
1102
|
// proceed with cleanup
|
1107
1103
|
if (0 != pi->circ_array) {
|
1108
|
-
|
1104
|
+
oj_circ_array_free(pi->circ_array);
|
1109
1105
|
}
|
1110
1106
|
if (0 != buf) {
|
1111
|
-
|
1107
|
+
OJ_R_FREE(buf);
|
1112
1108
|
} else if (free_json) {
|
1113
|
-
|
1109
|
+
OJ_R_FREE(json);
|
1114
1110
|
}
|
1115
1111
|
stack_cleanup(&pi->stack);
|
1116
1112
|
if (pi->str_rx.head != oj_default_options.str_rx.head) {
|
1117
|
-
|
1113
|
+
oj_rxclass_cleanup(&pi->str_rx);
|
1118
1114
|
}
|
1119
1115
|
if (err_has(&pi->err)) {
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1116
|
+
rb_set_errinfo(Qnil);
|
1117
|
+
if (Qnil != pi->err_class) {
|
1118
|
+
pi->err.clas = pi->err_class;
|
1119
|
+
}
|
1120
|
+
if ((CompatMode == pi->options.mode || RailsMode == pi->options.mode) && Yes != pi->options.safe) {
|
1121
|
+
// The json gem requires the error message be UTF-8 encoded. In
|
1122
|
+
// additional the complete JSON source must be returned. There
|
1123
|
+
// does not seem to be a size limit.
|
1124
|
+
VALUE msg = oj_encode(rb_str_new2(pi->err.msg));
|
1125
|
+
VALUE args[1];
|
1126
|
+
|
1127
|
+
if (NULL != pi->json) {
|
1128
|
+
msg = rb_str_append(msg, oj_encode(rb_str_new2(" in '")));
|
1129
|
+
msg = rb_str_append(msg, oj_encode(rb_str_new2(pi->json)));
|
1130
|
+
}
|
1131
|
+
args[0] = msg;
|
1132
|
+
if (pi->err.clas == oj_parse_error_class) {
|
1133
|
+
// The error was an Oj::ParseError so change to a JSON::ParserError.
|
1134
|
+
pi->err.clas = oj_json_parser_error_class;
|
1135
|
+
}
|
1136
|
+
rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
|
1137
|
+
} else {
|
1138
|
+
oj_err_raise(&pi->err);
|
1139
|
+
}
|
1144
1140
|
} else if (0 != line) {
|
1145
|
-
|
1141
|
+
rb_jump_tag(line);
|
1146
1142
|
}
|
1147
1143
|
if (pi->options.quirks_mode == No) {
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1144
|
+
switch (rb_type(result)) {
|
1145
|
+
case T_NIL:
|
1146
|
+
case T_TRUE:
|
1147
|
+
case T_FALSE:
|
1148
|
+
case T_FIXNUM:
|
1149
|
+
case T_FLOAT:
|
1150
|
+
case T_CLASS:
|
1151
|
+
case T_STRING:
|
1152
|
+
case T_SYMBOL: {
|
1153
|
+
struct _err err;
|
1154
|
+
|
1155
|
+
if (Qnil == pi->err_class) {
|
1156
|
+
err.clas = oj_parse_error_class;
|
1157
|
+
} else {
|
1158
|
+
err.clas = pi->err_class;
|
1159
|
+
}
|
1160
|
+
snprintf(err.msg, sizeof(err.msg), "unexpected non-document value");
|
1161
|
+
oj_err_raise(&err);
|
1162
|
+
break;
|
1163
|
+
}
|
1164
|
+
default:
|
1165
|
+
// okay
|
1166
|
+
break;
|
1167
|
+
}
|
1172
1168
|
}
|
1173
1169
|
return result;
|
1174
1170
|
}
|