oj 3.11.1 → 3.11.6
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 +34 -38
- data/ext/oj/cache8.c +59 -62
- data/ext/oj/cache8.h +8 -7
- data/ext/oj/circarray.c +33 -35
- data/ext/oj/circarray.h +11 -9
- data/ext/oj/code.c +170 -174
- data/ext/oj/code.h +21 -20
- data/ext/oj/compat.c +159 -166
- data/ext/oj/custom.c +802 -851
- data/ext/oj/dump.c +766 -778
- data/ext/oj/dump.h +49 -51
- data/ext/oj/dump_compat.c +1 -0
- data/ext/oj/dump_leaf.c +116 -157
- data/ext/oj/dump_object.c +609 -628
- data/ext/oj/dump_strict.c +318 -327
- data/ext/oj/encode.h +3 -4
- data/ext/oj/err.c +39 -25
- data/ext/oj/err.h +24 -15
- data/ext/oj/extconf.rb +2 -1
- data/ext/oj/fast.c +1042 -1041
- data/ext/oj/hash.c +62 -66
- data/ext/oj/hash.h +7 -6
- data/ext/oj/hash_test.c +450 -443
- data/ext/oj/mimic_json.c +412 -402
- data/ext/oj/object.c +559 -528
- data/ext/oj/odd.c +123 -128
- data/ext/oj/odd.h +27 -25
- data/ext/oj/oj.c +1123 -924
- data/ext/oj/oj.h +286 -298
- data/ext/oj/parse.c +938 -930
- data/ext/oj/parse.h +70 -69
- data/ext/oj/rails.c +836 -839
- data/ext/oj/rails.h +7 -7
- data/ext/oj/reader.c +135 -140
- data/ext/oj/reader.h +66 -79
- data/ext/oj/resolve.c +43 -43
- data/ext/oj/resolve.h +3 -2
- data/ext/oj/rxclass.c +67 -68
- data/ext/oj/rxclass.h +12 -10
- data/ext/oj/saj.c +451 -479
- data/ext/oj/scp.c +93 -103
- data/ext/oj/sparse.c +770 -730
- data/ext/oj/stream_writer.c +120 -149
- data/ext/oj/strict.c +71 -86
- data/ext/oj/string_writer.c +198 -243
- data/ext/oj/trace.c +29 -33
- data/ext/oj/trace.h +14 -11
- data/ext/oj/util.c +103 -103
- data/ext/oj/util.h +3 -2
- data/ext/oj/val_stack.c +47 -47
- data/ext/oj/val_stack.h +79 -86
- data/ext/oj/wab.c +291 -309
- data/lib/oj/bag.rb +1 -0
- data/lib/oj/easy_hash.rb +5 -4
- data/lib/oj/mimic.rb +0 -12
- data/lib/oj/version.rb +1 -1
- data/test/activerecord/result_test.rb +7 -2
- data/test/foo.rb +35 -32
- data/test/test_fast.rb +32 -2
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +10 -0
- data/test/test_scp.rb +1 -1
- metadata +4 -2
data/ext/oj/parse.c
CHANGED
@@ -1,953 +1,961 @@
|
|
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 "oj.h"
|
15
16
|
#include "rxclass.h"
|
17
|
+
#include "val_stack.h"
|
16
18
|
|
17
19
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
18
|
-
#define OJ_INFINITY
|
20
|
+
#define OJ_INFINITY (1.0 / 0.0)
|
19
21
|
|
20
22
|
//#define EXP_MAX 1023
|
21
|
-
#define EXP_MAX
|
22
|
-
#define DEC_MAX
|
23
|
+
#define EXP_MAX 100000
|
24
|
+
#define DEC_MAX 15
|
23
25
|
|
24
|
-
static void
|
25
|
-
next_non_white(ParseInfo pi) {
|
26
|
+
static void next_non_white(ParseInfo pi) {
|
26
27
|
for (; 1; pi->cur++) {
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
return;
|
36
|
-
}
|
28
|
+
switch (*pi->cur) {
|
29
|
+
case ' ':
|
30
|
+
case '\t':
|
31
|
+
case '\f':
|
32
|
+
case '\n':
|
33
|
+
case '\r': break;
|
34
|
+
default: return;
|
35
|
+
}
|
37
36
|
}
|
38
37
|
}
|
39
38
|
|
40
|
-
static void
|
41
|
-
skip_comment(ParseInfo pi) {
|
39
|
+
static void skip_comment(ParseInfo pi) {
|
42
40
|
if ('*' == *pi->cur) {
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
+
}
|
53
55
|
} else if ('/' == *pi->cur) {
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
}
|
64
|
-
}
|
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
|
+
}
|
65
65
|
} else {
|
66
|
-
|
66
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
|
67
67
|
}
|
68
68
|
}
|
69
69
|
|
70
|
-
static void
|
71
|
-
|
72
|
-
Val parent = stack_peek(&pi->stack);
|
70
|
+
static void add_value(ParseInfo pi, VALUE rval) {
|
71
|
+
Val parent = stack_peek(&pi->stack);
|
73
72
|
|
74
|
-
if (0 == parent) {
|
75
|
-
|
73
|
+
if (0 == parent) { // simple add
|
74
|
+
pi->add_value(pi, rval);
|
76
75
|
} 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
|
-
|
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
|
+
}
|
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
183
|
}
|
184
184
|
}
|
185
185
|
|
186
186
|
// entered at /
|
187
|
-
static void
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
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);
|
194
193
|
|
195
194
|
buf_init(&buf);
|
196
195
|
if (0 < cnt) {
|
197
|
-
|
196
|
+
buf_append_string(&buf, start, cnt);
|
198
197
|
}
|
199
198
|
for (s = pi->cur; '"' != *s; s++) {
|
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
|
-
|
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
|
+
}
|
268
279
|
}
|
269
280
|
if (0 == parent) {
|
270
|
-
|
281
|
+
pi->add_cstr(pi, buf.head, buf_len(&buf), start);
|
271
282
|
} 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
|
-
|
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
|
+
}
|
308
325
|
}
|
309
326
|
pi->cur = s + 1;
|
310
327
|
buf_cleanup(&buf);
|
311
328
|
}
|
312
329
|
|
313
|
-
static void
|
314
|
-
|
315
|
-
|
316
|
-
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);
|
317
333
|
|
318
334
|
for (; '"' != *pi->cur; pi->cur++) {
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
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
|
+
}
|
329
349
|
}
|
330
|
-
if (0 == parent) {
|
331
|
-
|
350
|
+
if (0 == parent) { // simple add
|
351
|
+
pi->add_cstr(pi, str, pi->cur - str, str);
|
332
352
|
} 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
|
-
|
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
|
+
}
|
367
393
|
}
|
368
|
-
pi->cur++;
|
394
|
+
pi->cur++; // move past "
|
369
395
|
}
|
370
396
|
|
371
|
-
static void
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
ni.
|
377
|
-
ni.
|
378
|
-
ni.
|
379
|
-
ni.
|
380
|
-
ni.
|
381
|
-
ni.
|
382
|
-
ni.
|
383
|
-
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;
|
384
409
|
ni.infinity = 0;
|
385
|
-
ni.nan
|
386
|
-
ni.neg
|
387
|
-
ni.has_exp
|
410
|
+
ni.nan = 0;
|
411
|
+
ni.neg = 0;
|
412
|
+
ni.has_exp = 0;
|
388
413
|
if (CompatMode == pi->options.mode) {
|
389
|
-
|
390
|
-
|
414
|
+
ni.no_big = !pi->options.compat_bigdec;
|
415
|
+
ni.bigdec_load = pi->options.compat_bigdec;
|
391
416
|
} else {
|
392
|
-
|
393
|
-
|
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;
|
394
420
|
}
|
395
421
|
|
396
422
|
if ('-' == *pi->cur) {
|
397
|
-
|
398
|
-
|
423
|
+
pi->cur++;
|
424
|
+
ni.neg = 1;
|
399
425
|
} else if ('+' == *pi->cur) {
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
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++;
|
405
435
|
}
|
406
436
|
if ('I' == *pi->cur) {
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
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;
|
413
447
|
} else if ('N' == *pi->cur || 'n' == *pi->cur) {
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
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;
|
420
458
|
} 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
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
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;
|
507
549
|
}
|
508
550
|
// Check for special reserved values for Infinity and NaN.
|
509
551
|
if (ni.big) {
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
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
|
+
}
|
518
560
|
}
|
519
561
|
if (CompatMode == pi->options.mode) {
|
520
|
-
|
521
|
-
|
522
|
-
|
562
|
+
if (pi->options.compat_bigdec) {
|
563
|
+
ni.big = 1;
|
564
|
+
}
|
523
565
|
} else if (BigDec == pi->options.bigdec_load) {
|
524
|
-
|
566
|
+
ni.big = 1;
|
525
567
|
}
|
526
568
|
if (0 == parent) {
|
527
|
-
|
569
|
+
pi->add_num(pi, &ni);
|
528
570
|
} else {
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
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
|
+
}
|
547
595
|
}
|
548
596
|
}
|
549
597
|
|
550
|
-
static void
|
551
|
-
|
552
|
-
volatile VALUE v = pi->start_array(pi);
|
598
|
+
static void array_start(ParseInfo pi) {
|
599
|
+
volatile VALUE v = pi->start_array(pi);
|
553
600
|
|
554
601
|
stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
|
555
602
|
}
|
556
603
|
|
557
|
-
static void
|
558
|
-
|
559
|
-
Val array = stack_pop(&pi->stack);
|
604
|
+
static void array_end(ParseInfo pi) {
|
605
|
+
Val array = stack_pop(&pi->stack);
|
560
606
|
|
561
607
|
if (0 == array) {
|
562
|
-
|
608
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
|
563
609
|
} else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
|
564
|
-
|
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));
|
565
616
|
} else {
|
566
|
-
|
567
|
-
|
617
|
+
pi->end_array(pi);
|
618
|
+
add_value(pi, array->val);
|
568
619
|
}
|
569
620
|
}
|
570
621
|
|
571
|
-
static void
|
572
|
-
|
573
|
-
volatile VALUE v = pi->start_hash(pi);
|
622
|
+
static void hash_start(ParseInfo pi) {
|
623
|
+
volatile VALUE v = pi->start_hash(pi);
|
574
624
|
|
575
625
|
stack_push(&pi->stack, v, NEXT_HASH_NEW);
|
576
626
|
}
|
577
627
|
|
578
|
-
static void
|
579
|
-
|
580
|
-
volatile Val hash = stack_peek(&pi->stack);
|
628
|
+
static void hash_end(ParseInfo pi) {
|
629
|
+
volatile Val hash = stack_peek(&pi->stack);
|
581
630
|
|
582
631
|
// leave hash on stack until just before
|
583
632
|
if (0 == hash) {
|
584
|
-
|
633
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
|
585
634
|
} else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
|
586
|
-
|
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));
|
587
641
|
} else {
|
588
|
-
|
589
|
-
|
590
|
-
|
642
|
+
pi->end_hash(pi);
|
643
|
+
stack_pop(&pi->stack);
|
644
|
+
add_value(pi, hash->val);
|
591
645
|
}
|
592
646
|
}
|
593
647
|
|
594
|
-
static void
|
595
|
-
|
596
|
-
Val parent = stack_peek(&pi->stack);
|
648
|
+
static void comma(ParseInfo pi) {
|
649
|
+
Val parent = stack_peek(&pi->stack);
|
597
650
|
|
598
651
|
if (0 == parent) {
|
599
|
-
|
652
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
600
653
|
} else if (NEXT_ARRAY_COMMA == parent->next) {
|
601
|
-
|
654
|
+
parent->next = NEXT_ARRAY_ELEMENT;
|
602
655
|
} else if (NEXT_HASH_COMMA == parent->next) {
|
603
|
-
|
656
|
+
parent->next = NEXT_HASH_KEY;
|
604
657
|
} else {
|
605
|
-
|
658
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
606
659
|
}
|
607
660
|
}
|
608
661
|
|
609
|
-
static void
|
610
|
-
|
611
|
-
Val parent = stack_peek(&pi->stack);
|
662
|
+
static void colon(ParseInfo pi) {
|
663
|
+
Val parent = stack_peek(&pi->stack);
|
612
664
|
|
613
665
|
if (0 != parent && NEXT_HASH_COLON == parent->next) {
|
614
|
-
|
666
|
+
parent->next = NEXT_HASH_VALUE;
|
615
667
|
} else {
|
616
|
-
|
668
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
|
617
669
|
}
|
618
670
|
}
|
619
671
|
|
620
|
-
void
|
621
|
-
|
622
|
-
|
623
|
-
long start = 0;
|
672
|
+
void oj_parse2(ParseInfo pi) {
|
673
|
+
int first = 1;
|
674
|
+
long start = 0;
|
624
675
|
|
625
676
|
pi->cur = pi->json;
|
626
677
|
err_init(&pi->err);
|
627
678
|
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
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
}
|
744
|
-
} else if (!pi->has_callbacks) {
|
745
|
-
first = 0;
|
746
|
-
}
|
747
|
-
start = pi->cur - pi->json;
|
748
|
-
}
|
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
|
+
}
|
749
794
|
}
|
750
795
|
}
|
751
796
|
|
752
|
-
static VALUE
|
753
|
-
rescue_big_decimal(VALUE str, VALUE ignore) {
|
797
|
+
static VALUE rescue_big_decimal(VALUE str, VALUE ignore) {
|
754
798
|
rb_raise(oj_parse_error_class, "Invalid value for BigDecimal()");
|
755
799
|
return Qnil;
|
756
800
|
}
|
757
801
|
|
758
|
-
static VALUE
|
759
|
-
parse_big_decimal(VALUE str) {
|
802
|
+
static VALUE parse_big_decimal(VALUE str) {
|
760
803
|
return rb_funcall(rb_cObject, oj_bigdecimal_id, 1, str);
|
761
804
|
}
|
762
805
|
|
763
|
-
static long double
|
764
|
-
1.0,
|
765
|
-
1.
|
766
|
-
1.
|
767
|
-
1.
|
768
|
-
1.
|
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,
|
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,
|
814
812
|
};
|
815
813
|
|
816
814
|
VALUE
|
817
815
|
oj_num_as_value(NumInfo ni) {
|
818
|
-
volatile VALUE
|
816
|
+
volatile VALUE rnum = Qnil;
|
819
817
|
|
820
818
|
if (ni->infinity) {
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
819
|
+
if (ni->neg) {
|
820
|
+
rnum = rb_float_new(-OJ_INFINITY);
|
821
|
+
} else {
|
822
|
+
rnum = rb_float_new(OJ_INFINITY);
|
823
|
+
}
|
826
824
|
} 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
|
-
|
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
|
+
}
|
893
891
|
}
|
894
892
|
return rnum;
|
895
893
|
}
|
896
894
|
|
897
|
-
void
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
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;
|
905
907
|
|
906
908
|
va_start(ap, format);
|
907
909
|
p += vsnprintf(msg, sizeof(msg) - 1, format, ap);
|
908
910
|
va_end(ap);
|
909
911
|
pi->err.clas = err_clas;
|
910
912
|
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
|
-
|
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++ = ')';
|
940
942
|
}
|
941
943
|
*p = '\0';
|
942
944
|
if (0 == pi->json) {
|
943
|
-
|
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);
|
944
953
|
} else {
|
945
|
-
|
954
|
+
_oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
|
946
955
|
}
|
947
956
|
}
|
948
957
|
|
949
|
-
static VALUE
|
950
|
-
protect_parse(VALUE pip) {
|
958
|
+
static VALUE protect_parse(VALUE pip) {
|
951
959
|
oj_parse2((ParseInfo)pip);
|
952
960
|
|
953
961
|
return Qnil;
|
@@ -955,102 +963,102 @@ protect_parse(VALUE pip) {
|
|
955
963
|
|
956
964
|
extern int oj_utf8_index;
|
957
965
|
|
958
|
-
static void
|
959
|
-
|
960
|
-
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));
|
961
968
|
|
962
969
|
if (rb_utf8_encoding() != enc) {
|
963
|
-
|
970
|
+
*inputp = rb_str_conv_enc(*inputp, enc, rb_utf8_encoding());
|
964
971
|
}
|
965
|
-
pi->json = rb_string_value_ptr((VALUE*)inputp);
|
966
|
-
pi->end
|
972
|
+
pi->json = rb_string_value_ptr((VALUE *)inputp);
|
973
|
+
pi->end = pi->json + RSTRING_LEN(*inputp);
|
967
974
|
}
|
968
975
|
|
969
976
|
VALUE
|
970
977
|
oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
|
971
|
-
char
|
972
|
-
volatile VALUE
|
973
|
-
volatile VALUE
|
974
|
-
volatile VALUE
|
975
|
-
int
|
976
|
-
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;
|
977
984
|
|
978
985
|
if (argc < 1) {
|
979
|
-
|
986
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
980
987
|
}
|
981
988
|
input = argv[0];
|
982
989
|
if (2 <= argc) {
|
983
|
-
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
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
|
+
}
|
988
995
|
}
|
989
996
|
if (yieldOk && rb_block_given_p()) {
|
990
|
-
|
997
|
+
pi->proc = Qnil;
|
991
998
|
} else {
|
992
|
-
|
999
|
+
pi->proc = Qundef;
|
993
1000
|
}
|
994
1001
|
if (0 != json) {
|
995
|
-
|
996
|
-
|
997
|
-
|
1002
|
+
pi->json = json;
|
1003
|
+
pi->end = json + len;
|
1004
|
+
free_json = 1;
|
998
1005
|
} else if (T_STRING == rb_type(input)) {
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
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);
|
1005
1012
|
} else if (Qnil == input) {
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1013
|
+
if (Yes == pi->options.nilnil) {
|
1014
|
+
return Qnil;
|
1015
|
+
} else {
|
1016
|
+
rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
|
1017
|
+
}
|
1011
1018
|
} else {
|
1012
|
-
|
1013
|
-
|
1019
|
+
VALUE clas = rb_obj_class(input);
|
1020
|
+
volatile VALUE s;
|
1014
1021
|
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1022
|
+
if (oj_stringio_class == clas) {
|
1023
|
+
s = rb_funcall2(input, oj_string_id, 0, 0);
|
1024
|
+
oj_pi_set_input_str(pi, &s);
|
1018
1025
|
#if !IS_WINDOWS
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
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
|
+
}
|
1039
1047
|
#endif
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
}
|
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
|
+
}
|
1046
1054
|
}
|
1047
1055
|
if (Yes == pi->options.circular) {
|
1048
|
-
|
1056
|
+
pi->circ_array = oj_circ_array_new();
|
1049
1057
|
} else {
|
1050
|
-
|
1058
|
+
pi->circ_array = 0;
|
1051
1059
|
}
|
1052
1060
|
if (No == pi->options.allow_gc) {
|
1053
|
-
|
1061
|
+
rb_gc_disable();
|
1054
1062
|
}
|
1055
1063
|
// GC can run at any time. When it runs any Object created by C will be
|
1056
1064
|
// freed. We protect against this by wrapping the value stack in a ruby
|
@@ -1059,116 +1067,116 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1059
1067
|
wrapped_stack = oj_stack_init(&pi->stack);
|
1060
1068
|
rb_protect(protect_parse, (VALUE)pi, &line);
|
1061
1069
|
if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
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
|
+
}
|
1065
1074
|
}
|
1066
|
-
result
|
1075
|
+
result = stack_head_val(&pi->stack);
|
1067
1076
|
DATA_PTR(wrapped_stack) = 0;
|
1068
1077
|
if (No == pi->options.allow_gc) {
|
1069
|
-
|
1078
|
+
rb_gc_enable();
|
1070
1079
|
}
|
1071
1080
|
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
|
-
|
1102
|
-
|
1103
|
-
}
|
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
|
+
}
|
1104
1112
|
}
|
1105
1113
|
CLEANUP:
|
1106
1114
|
// proceed with cleanup
|
1107
1115
|
if (0 != pi->circ_array) {
|
1108
|
-
|
1116
|
+
oj_circ_array_free(pi->circ_array);
|
1109
1117
|
}
|
1110
1118
|
if (0 != buf) {
|
1111
|
-
|
1119
|
+
xfree(buf);
|
1112
1120
|
} else if (free_json) {
|
1113
|
-
|
1121
|
+
xfree(json);
|
1114
1122
|
}
|
1115
1123
|
stack_cleanup(&pi->stack);
|
1116
1124
|
if (pi->str_rx.head != oj_default_options.str_rx.head) {
|
1117
|
-
|
1125
|
+
oj_rxclass_cleanup(&pi->str_rx);
|
1118
1126
|
}
|
1119
1127
|
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
|
-
|
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 && 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
|
+
}
|
1144
1152
|
} else if (0 != line) {
|
1145
|
-
|
1153
|
+
rb_jump_tag(line);
|
1146
1154
|
}
|
1147
1155
|
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
|
-
|
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
|
+
}
|
1172
1180
|
}
|
1173
1181
|
return result;
|
1174
1182
|
}
|