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