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/scp.c
CHANGED
@@ -1,42 +1,35 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2012 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 <math.h>
|
7
5
|
#include <stdio.h>
|
6
|
+
#include <stdlib.h>
|
8
7
|
#include <string.h>
|
9
|
-
#include <math.h>
|
10
8
|
#include <sys/types.h>
|
11
9
|
#include <unistd.h>
|
12
10
|
|
11
|
+
#include "encode.h"
|
12
|
+
#include "hash.h"
|
13
13
|
#include "oj.h"
|
14
14
|
#include "parse.h"
|
15
|
-
#include "encode.h"
|
16
15
|
|
17
|
-
static VALUE
|
18
|
-
noop_start(ParseInfo pi) {
|
16
|
+
static VALUE noop_start(ParseInfo pi) {
|
19
17
|
return Qnil;
|
20
18
|
}
|
21
19
|
|
22
|
-
static void
|
23
|
-
noop_end(ParseInfo pi) {
|
20
|
+
static void noop_end(ParseInfo pi) {
|
24
21
|
}
|
25
22
|
|
26
|
-
static void
|
27
|
-
noop_add_value(ParseInfo pi, VALUE val) {
|
23
|
+
static void noop_add_value(ParseInfo pi, VALUE val) {
|
28
24
|
}
|
29
25
|
|
30
|
-
static void
|
31
|
-
noop_add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
26
|
+
static void noop_add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
32
27
|
}
|
33
28
|
|
34
|
-
static void
|
35
|
-
noop_add_num(ParseInfo pi, NumInfo ni) {
|
29
|
+
static void noop_add_num(ParseInfo pi, NumInfo ni) {
|
36
30
|
}
|
37
31
|
|
38
|
-
static VALUE
|
39
|
-
noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
32
|
+
static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
40
33
|
return Qundef;
|
41
34
|
}
|
42
35
|
|
@@ -44,181 +37,163 @@ static void
|
|
44
37
|
noop_hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
45
38
|
}
|
46
39
|
|
47
|
-
static void
|
48
|
-
noop_hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
40
|
+
static void noop_hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
49
41
|
}
|
50
42
|
|
51
|
-
static void
|
52
|
-
noop_hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
43
|
+
static void noop_hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
53
44
|
}
|
54
45
|
|
55
|
-
static void
|
56
|
-
noop_array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
46
|
+
static void noop_array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
57
47
|
}
|
58
48
|
|
59
|
-
static void
|
60
|
-
noop_array_append_num(ParseInfo pi, NumInfo ni) {
|
49
|
+
static void noop_array_append_num(ParseInfo pi, NumInfo ni) {
|
61
50
|
}
|
62
51
|
|
63
|
-
static void
|
64
|
-
noop_array_append_value(ParseInfo pi, VALUE value) {
|
52
|
+
static void noop_array_append_value(ParseInfo pi, VALUE value) {
|
65
53
|
}
|
66
54
|
|
67
|
-
static void
|
68
|
-
add_value(ParseInfo pi, VALUE val) {
|
55
|
+
static void add_value(ParseInfo pi, VALUE val) {
|
69
56
|
rb_funcall(pi->handler, oj_add_value_id, 1, val);
|
70
57
|
}
|
71
58
|
|
72
|
-
static void
|
73
|
-
|
74
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
59
|
+
static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
60
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
75
61
|
|
76
62
|
rstr = oj_encode(rstr);
|
77
63
|
rb_funcall(pi->handler, oj_add_value_id, 1, rstr);
|
78
64
|
}
|
79
65
|
|
80
|
-
static void
|
81
|
-
add_num(ParseInfo pi, NumInfo ni) {
|
66
|
+
static void add_num(ParseInfo pi, NumInfo ni) {
|
82
67
|
rb_funcall(pi->handler, oj_add_value_id, 1, oj_num_as_value(ni));
|
83
68
|
}
|
84
69
|
|
85
|
-
static VALUE
|
86
|
-
start_hash(ParseInfo pi) {
|
70
|
+
static VALUE start_hash(ParseInfo pi) {
|
87
71
|
return rb_funcall(pi->handler, oj_hash_start_id, 0);
|
88
72
|
}
|
89
73
|
|
90
|
-
static void
|
91
|
-
end_hash(ParseInfo pi) {
|
74
|
+
static void end_hash(ParseInfo pi) {
|
92
75
|
rb_funcall(pi->handler, oj_hash_end_id, 0);
|
93
76
|
}
|
94
77
|
|
95
|
-
static VALUE
|
96
|
-
start_array(ParseInfo pi) {
|
78
|
+
static VALUE start_array(ParseInfo pi) {
|
97
79
|
return rb_funcall(pi->handler, oj_array_start_id, 0);
|
98
80
|
}
|
99
81
|
|
100
|
-
static void
|
101
|
-
end_array(ParseInfo pi) {
|
82
|
+
static void end_array(ParseInfo pi) {
|
102
83
|
rb_funcall(pi->handler, oj_array_end_id, 0);
|
103
84
|
}
|
104
85
|
|
105
|
-
static VALUE
|
106
|
-
calc_hash_key(ParseInfo pi, Val kval) {
|
107
|
-
volatile VALUE rkey = kval->key_val;
|
108
|
-
|
109
|
-
if (Qundef == rkey) {
|
110
|
-
rkey = rb_str_new(kval->key, kval->klen);
|
111
|
-
rkey = oj_encode(rkey);
|
112
|
-
if (Yes == pi->options.sym_key) {
|
113
|
-
rkey = rb_str_intern(rkey);
|
114
|
-
}
|
115
|
-
}
|
116
|
-
return rkey;
|
117
|
-
}
|
118
|
-
|
119
|
-
static VALUE
|
120
|
-
hash_key(ParseInfo pi, const char *key, size_t klen) {
|
86
|
+
static VALUE hash_key(ParseInfo pi, const char *key, size_t klen) {
|
121
87
|
return rb_funcall(pi->handler, oj_hash_key_id, 1, rb_str_new(key, klen));
|
122
88
|
}
|
123
89
|
|
124
|
-
static void
|
125
|
-
|
126
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
90
|
+
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
91
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
127
92
|
|
128
93
|
rstr = oj_encode(rstr);
|
129
|
-
rb_funcall(pi->handler,
|
94
|
+
rb_funcall(pi->handler,
|
95
|
+
oj_hash_set_id,
|
96
|
+
3,
|
97
|
+
stack_peek(&pi->stack)->val,
|
98
|
+
oj_calc_hash_key(pi, kval),
|
99
|
+
rstr);
|
130
100
|
}
|
131
101
|
|
132
|
-
static void
|
133
|
-
|
134
|
-
|
102
|
+
static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
103
|
+
rb_funcall(pi->handler,
|
104
|
+
oj_hash_set_id,
|
105
|
+
3,
|
106
|
+
stack_peek(&pi->stack)->val,
|
107
|
+
oj_calc_hash_key(pi, kval),
|
108
|
+
oj_num_as_value(ni));
|
135
109
|
}
|
136
110
|
|
137
|
-
static void
|
138
|
-
|
139
|
-
|
111
|
+
static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
112
|
+
rb_funcall(pi->handler,
|
113
|
+
oj_hash_set_id,
|
114
|
+
3,
|
115
|
+
stack_peek(&pi->stack)->val,
|
116
|
+
oj_calc_hash_key(pi, kval),
|
117
|
+
value);
|
140
118
|
}
|
141
119
|
|
142
|
-
static void
|
143
|
-
|
144
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
120
|
+
static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
121
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
145
122
|
|
146
123
|
rstr = oj_encode(rstr);
|
147
124
|
rb_funcall(pi->handler, oj_array_append_id, 2, stack_peek(&pi->stack)->val, rstr);
|
148
125
|
}
|
149
126
|
|
150
|
-
static void
|
151
|
-
array_append_num(ParseInfo pi, NumInfo ni) {
|
127
|
+
static void array_append_num(ParseInfo pi, NumInfo ni) {
|
152
128
|
rb_funcall(pi->handler, oj_array_append_id, 2, stack_peek(&pi->stack)->val, oj_num_as_value(ni));
|
153
129
|
}
|
154
130
|
|
155
|
-
static void
|
156
|
-
array_append_value(ParseInfo pi, VALUE value) {
|
131
|
+
static void array_append_value(ParseInfo pi, VALUE value) {
|
157
132
|
rb_funcall(pi->handler, oj_array_append_id, 2, stack_peek(&pi->stack)->val, value);
|
158
133
|
}
|
159
134
|
|
160
135
|
VALUE
|
161
136
|
oj_sc_parse(int argc, VALUE *argv, VALUE self) {
|
162
|
-
struct _parseInfo
|
163
|
-
VALUE
|
137
|
+
struct _parseInfo pi;
|
138
|
+
VALUE input = argv[1];
|
164
139
|
|
165
140
|
parse_info_init(&pi);
|
166
141
|
pi.err_class = Qnil;
|
167
142
|
pi.max_depth = 0;
|
168
|
-
pi.options
|
143
|
+
pi.options = oj_default_options;
|
169
144
|
if (3 == argc) {
|
170
|
-
|
145
|
+
oj_parse_options(argv[2], &pi.options);
|
171
146
|
}
|
172
147
|
if (rb_block_given_p()) {
|
173
|
-
|
148
|
+
pi.proc = Qnil;
|
174
149
|
} else {
|
175
|
-
|
150
|
+
pi.proc = Qundef;
|
176
151
|
}
|
177
152
|
pi.handler = *argv;
|
178
153
|
|
179
|
-
pi.start_hash
|
180
|
-
pi.end_hash
|
181
|
-
pi.hash_key
|
154
|
+
pi.start_hash = rb_respond_to(pi.handler, oj_hash_start_id) ? start_hash : noop_start;
|
155
|
+
pi.end_hash = rb_respond_to(pi.handler, oj_hash_end_id) ? end_hash : noop_end;
|
156
|
+
pi.hash_key = rb_respond_to(pi.handler, oj_hash_key_id) ? hash_key : noop_hash_key;
|
182
157
|
pi.start_array = rb_respond_to(pi.handler, oj_array_start_id) ? start_array : noop_start;
|
183
|
-
pi.end_array
|
158
|
+
pi.end_array = rb_respond_to(pi.handler, oj_array_end_id) ? end_array : noop_end;
|
184
159
|
if (rb_respond_to(pi.handler, oj_hash_set_id)) {
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
160
|
+
pi.hash_set_value = hash_set_value;
|
161
|
+
pi.hash_set_cstr = hash_set_cstr;
|
162
|
+
pi.hash_set_num = hash_set_num;
|
163
|
+
pi.expect_value = 1;
|
189
164
|
} else {
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
165
|
+
pi.hash_set_value = noop_hash_set_value;
|
166
|
+
pi.hash_set_cstr = noop_hash_set_cstr;
|
167
|
+
pi.hash_set_num = noop_hash_set_num;
|
168
|
+
pi.expect_value = 0;
|
194
169
|
}
|
195
170
|
if (rb_respond_to(pi.handler, oj_array_append_id)) {
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
171
|
+
pi.array_append_value = array_append_value;
|
172
|
+
pi.array_append_cstr = array_append_cstr;
|
173
|
+
pi.array_append_num = array_append_num;
|
174
|
+
pi.expect_value = 1;
|
200
175
|
} else {
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
176
|
+
pi.array_append_value = noop_array_append_value;
|
177
|
+
pi.array_append_cstr = noop_array_append_cstr;
|
178
|
+
pi.array_append_num = noop_array_append_num;
|
179
|
+
pi.expect_value = 0;
|
205
180
|
}
|
206
181
|
if (rb_respond_to(pi.handler, oj_add_value_id)) {
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
182
|
+
pi.add_cstr = add_cstr;
|
183
|
+
pi.add_num = add_num;
|
184
|
+
pi.add_value = add_value;
|
185
|
+
pi.expect_value = 1;
|
211
186
|
} else {
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
187
|
+
pi.add_cstr = noop_add_cstr;
|
188
|
+
pi.add_num = noop_add_num;
|
189
|
+
pi.add_value = noop_add_value;
|
190
|
+
pi.expect_value = 0;
|
216
191
|
}
|
217
192
|
pi.has_callbacks = true;
|
218
193
|
|
219
194
|
if (T_STRING == rb_type(input)) {
|
220
|
-
|
195
|
+
return oj_pi_parse(argc - 1, argv + 1, &pi, 0, 0, 1);
|
221
196
|
} else {
|
222
|
-
|
197
|
+
return oj_pi_sparse(argc - 1, argv + 1, &pi, 0);
|
223
198
|
}
|
224
199
|
}
|
data/ext/oj/sparse.c
CHANGED
@@ -1,785 +1,854 @@
|
|
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 <math.h>
|
7
5
|
#include <stdio.h>
|
6
|
+
#include <stdlib.h>
|
8
7
|
#include <string.h>
|
9
8
|
#include <unistd.h>
|
10
|
-
#include <math.h>
|
11
9
|
|
12
|
-
#include "
|
10
|
+
#include "buf.h"
|
13
11
|
#include "encode.h"
|
12
|
+
#include "hash.h" // for oj_strndup()
|
13
|
+
#include "oj.h"
|
14
14
|
#include "parse.h"
|
15
|
-
#include "buf.h"
|
16
|
-
#include "hash.h" // for oj_strndup()
|
17
15
|
#include "val_stack.h"
|
18
16
|
|
19
17
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
20
|
-
#define OJ_INFINITY
|
18
|
+
#define OJ_INFINITY (1.0 / 0.0)
|
21
19
|
|
22
20
|
#ifdef RUBINIUS_RUBY
|
23
|
-
#define NUM_MAX
|
21
|
+
#define NUM_MAX 0x07FFFFFF
|
24
22
|
#else
|
25
|
-
#define NUM_MAX
|
23
|
+
#define NUM_MAX (FIXNUM_MAX >> 8)
|
26
24
|
#endif
|
27
|
-
#define EXP_MAX
|
28
|
-
#define DEC_MAX
|
25
|
+
#define EXP_MAX 100000
|
26
|
+
#define DEC_MAX 15
|
29
27
|
|
30
|
-
static void
|
31
|
-
|
32
|
-
char c = reader_get(&pi->rd);
|
28
|
+
static void skip_comment(ParseInfo pi) {
|
29
|
+
char c = reader_get(&pi->rd);
|
33
30
|
|
34
31
|
if ('*' == c) {
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
32
|
+
while ('\0' != (c = reader_get(&pi->rd))) {
|
33
|
+
if ('*' == c) {
|
34
|
+
c = reader_get(&pi->rd);
|
35
|
+
if ('/' == c) {
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
43
40
|
} else if ('/' == c) {
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
}
|
54
|
-
}
|
41
|
+
while ('\0' != (c = reader_get(&pi->rd))) {
|
42
|
+
switch (c) {
|
43
|
+
case '\n':
|
44
|
+
case '\r':
|
45
|
+
case '\f':
|
46
|
+
case '\0': return;
|
47
|
+
default: break;
|
48
|
+
}
|
49
|
+
}
|
55
50
|
} else {
|
56
|
-
|
51
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
|
57
52
|
}
|
58
53
|
if ('\0' == c) {
|
59
|
-
|
60
|
-
|
54
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
|
55
|
+
return;
|
61
56
|
}
|
62
57
|
}
|
63
58
|
|
64
|
-
static void
|
65
|
-
|
66
|
-
Val parent = stack_peek(&pi->stack);
|
59
|
+
static void add_value(ParseInfo pi, VALUE rval) {
|
60
|
+
Val parent = stack_peek(&pi->stack);
|
67
61
|
|
68
|
-
if (0 == parent) {
|
69
|
-
|
62
|
+
if (0 == parent) { // simple add
|
63
|
+
pi->add_value(pi, rval);
|
70
64
|
} else {
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
65
|
+
switch (parent->next) {
|
66
|
+
case NEXT_ARRAY_NEW:
|
67
|
+
case NEXT_ARRAY_ELEMENT:
|
68
|
+
pi->array_append_value(pi, rval);
|
69
|
+
parent->next = NEXT_ARRAY_COMMA;
|
70
|
+
break;
|
71
|
+
case NEXT_HASH_VALUE:
|
72
|
+
pi->hash_set_value(pi, parent, rval);
|
73
|
+
if (parent->kalloc) {
|
74
|
+
xfree((char *)parent->key);
|
75
|
+
}
|
76
|
+
parent->key = 0;
|
77
|
+
parent->kalloc = 0;
|
78
|
+
parent->next = NEXT_HASH_COMMA;
|
79
|
+
break;
|
80
|
+
case NEXT_HASH_NEW:
|
81
|
+
case NEXT_HASH_KEY:
|
82
|
+
case NEXT_HASH_COMMA:
|
83
|
+
case NEXT_NONE:
|
84
|
+
case NEXT_ARRAY_COMMA:
|
85
|
+
case NEXT_HASH_COLON:
|
86
|
+
default:
|
87
|
+
oj_set_error_at(pi,
|
88
|
+
oj_parse_error_class,
|
89
|
+
__FILE__,
|
90
|
+
__LINE__,
|
91
|
+
"expected %s",
|
92
|
+
oj_stack_next_string(parent->next));
|
93
|
+
break;
|
94
|
+
}
|
96
95
|
}
|
97
96
|
}
|
98
97
|
|
99
|
-
static void
|
100
|
-
|
101
|
-
Val parent = stack_peek(&pi->stack);
|
98
|
+
static void add_num_value(ParseInfo pi, NumInfo ni) {
|
99
|
+
Val parent = stack_peek(&pi->stack);
|
102
100
|
|
103
101
|
if (0 == parent) {
|
104
|
-
|
102
|
+
pi->add_num(pi, ni);
|
105
103
|
} else {
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
104
|
+
switch (parent->next) {
|
105
|
+
case NEXT_ARRAY_NEW:
|
106
|
+
case NEXT_ARRAY_ELEMENT:
|
107
|
+
pi->array_append_num(pi, ni);
|
108
|
+
parent->next = NEXT_ARRAY_COMMA;
|
109
|
+
break;
|
110
|
+
case NEXT_HASH_VALUE:
|
111
|
+
pi->hash_set_num(pi, parent, ni);
|
112
|
+
if (parent->kalloc) {
|
113
|
+
xfree((char *)parent->key);
|
114
|
+
}
|
115
|
+
parent->key = 0;
|
116
|
+
parent->kalloc = 0;
|
117
|
+
parent->next = NEXT_HASH_COMMA;
|
118
|
+
break;
|
119
|
+
default:
|
120
|
+
oj_set_error_at(pi,
|
121
|
+
oj_parse_error_class,
|
122
|
+
__FILE__,
|
123
|
+
__LINE__,
|
124
|
+
"expected %s",
|
125
|
+
oj_stack_next_string(parent->next));
|
126
|
+
break;
|
127
|
+
}
|
125
128
|
}
|
126
129
|
}
|
127
130
|
|
128
|
-
static void
|
129
|
-
read_true(ParseInfo pi) {
|
131
|
+
static void read_true(ParseInfo pi) {
|
130
132
|
if (0 == reader_expect(&pi->rd, "rue")) {
|
131
|
-
|
133
|
+
add_value(pi, Qtrue);
|
132
134
|
} else {
|
133
|
-
|
135
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
|
134
136
|
}
|
135
137
|
}
|
136
138
|
|
137
|
-
static void
|
138
|
-
read_false(ParseInfo pi) {
|
139
|
+
static void read_false(ParseInfo pi) {
|
139
140
|
if (0 == reader_expect(&pi->rd, "alse")) {
|
140
|
-
|
141
|
+
add_value(pi, Qfalse);
|
141
142
|
} else {
|
142
|
-
|
143
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
|
143
144
|
}
|
144
145
|
}
|
145
146
|
|
146
|
-
static uint32_t
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
char c;
|
147
|
+
static uint32_t read_hex(ParseInfo pi) {
|
148
|
+
uint32_t b = 0;
|
149
|
+
int i;
|
150
|
+
char c;
|
151
151
|
|
152
152
|
for (i = 0; i < 4; i++) {
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
153
|
+
c = reader_get(&pi->rd);
|
154
|
+
b = b << 4;
|
155
|
+
if ('0' <= c && c <= '9') {
|
156
|
+
b += c - '0';
|
157
|
+
} else if ('A' <= c && c <= 'F') {
|
158
|
+
b += c - 'A' + 10;
|
159
|
+
} else if ('a' <= c && c <= 'f') {
|
160
|
+
b += c - 'a' + 10;
|
161
|
+
} else {
|
162
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character");
|
163
|
+
return 0;
|
164
|
+
}
|
165
165
|
}
|
166
166
|
return b;
|
167
167
|
}
|
168
168
|
|
169
|
-
static void
|
170
|
-
unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
169
|
+
static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
171
170
|
if (0x0000007F >= code) {
|
172
|
-
|
171
|
+
buf_append(buf, (char)code);
|
173
172
|
} else if (0x000007FF >= code) {
|
174
|
-
|
175
|
-
|
173
|
+
buf_append(buf, 0xC0 | (code >> 6));
|
174
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
176
175
|
} else if (0x0000FFFF >= code) {
|
177
|
-
|
178
|
-
|
179
|
-
|
176
|
+
buf_append(buf, 0xE0 | (code >> 12));
|
177
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
178
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
180
179
|
} else if (0x001FFFFF >= code) {
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
180
|
+
buf_append(buf, 0xF0 | (code >> 18));
|
181
|
+
buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
|
182
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
183
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
185
184
|
} else if (0x03FFFFFF >= code) {
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
185
|
+
buf_append(buf, 0xF8 | (code >> 24));
|
186
|
+
buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
|
187
|
+
buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
|
188
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
189
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
191
190
|
} else if (0x7FFFFFFF >= code) {
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
191
|
+
buf_append(buf, 0xFC | (code >> 30));
|
192
|
+
buf_append(buf, 0x80 | ((code >> 24) & 0x3F));
|
193
|
+
buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
|
194
|
+
buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
|
195
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
196
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
198
197
|
} else {
|
199
|
-
|
198
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
|
200
199
|
}
|
201
200
|
}
|
202
201
|
|
203
202
|
// entered at backslash
|
204
|
-
static void
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
Val parent = stack_peek(&pi->stack);
|
203
|
+
static void read_escaped_str(ParseInfo pi) {
|
204
|
+
struct _buf buf;
|
205
|
+
char c;
|
206
|
+
uint32_t code;
|
207
|
+
Val parent = stack_peek(&pi->stack);
|
210
208
|
|
211
209
|
buf_init(&buf);
|
212
210
|
if (pi->rd.str < pi->rd.tail) {
|
213
|
-
|
211
|
+
buf_append_string(&buf, pi->rd.str, pi->rd.tail - pi->rd.str);
|
214
212
|
}
|
215
213
|
while ('\"' != (c = reader_get(&pi->rd))) {
|
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
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
214
|
+
if ('\0' == c) {
|
215
|
+
oj_set_error_at(pi,
|
216
|
+
oj_parse_error_class,
|
217
|
+
__FILE__,
|
218
|
+
__LINE__,
|
219
|
+
"quoted string not terminated");
|
220
|
+
buf_cleanup(&buf);
|
221
|
+
return;
|
222
|
+
} else if ('\\' == c) {
|
223
|
+
c = reader_get(&pi->rd);
|
224
|
+
switch (c) {
|
225
|
+
case 'n': buf_append(&buf, '\n'); break;
|
226
|
+
case 'r': buf_append(&buf, '\r'); break;
|
227
|
+
case 't': buf_append(&buf, '\t'); break;
|
228
|
+
case 'f': buf_append(&buf, '\f'); break;
|
229
|
+
case 'b': buf_append(&buf, '\b'); break;
|
230
|
+
case '"': buf_append(&buf, '"'); break;
|
231
|
+
case '/': buf_append(&buf, '/'); break;
|
232
|
+
case '\\': buf_append(&buf, '\\'); break;
|
233
|
+
case 'u':
|
234
|
+
if (0 == (code = read_hex(pi)) && err_has(&pi->err)) {
|
235
|
+
buf_cleanup(&buf);
|
236
|
+
return;
|
237
|
+
}
|
238
|
+
if (0x0000D800 <= code && code <= 0x0000DFFF) {
|
239
|
+
uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
|
240
|
+
uint32_t c2;
|
241
|
+
char ch2;
|
242
|
+
|
243
|
+
c = reader_get(&pi->rd);
|
244
|
+
ch2 = reader_get(&pi->rd);
|
245
|
+
if ('\\' != c || 'u' != ch2) {
|
246
|
+
if (Yes == pi->options.allow_invalid) {
|
247
|
+
unicode_to_chars(pi, &buf, code);
|
248
|
+
reader_backup(&pi->rd);
|
249
|
+
reader_backup(&pi->rd);
|
250
|
+
break;
|
251
|
+
}
|
252
|
+
oj_set_error_at(pi,
|
253
|
+
oj_parse_error_class,
|
254
|
+
__FILE__,
|
255
|
+
__LINE__,
|
256
|
+
"invalid escaped character");
|
257
|
+
buf_cleanup(&buf);
|
258
|
+
return;
|
259
|
+
}
|
260
|
+
if (0 == (c2 = read_hex(pi)) && err_has(&pi->err)) {
|
261
|
+
buf_cleanup(&buf);
|
262
|
+
return;
|
263
|
+
}
|
264
|
+
c2 = (c2 - 0x0000DC00) & 0x000003FF;
|
265
|
+
code = ((c1 << 10) | c2) + 0x00010000;
|
266
|
+
}
|
267
|
+
unicode_to_chars(pi, &buf, code);
|
268
|
+
if (err_has(&pi->err)) {
|
269
|
+
buf_cleanup(&buf);
|
270
|
+
return;
|
271
|
+
}
|
272
|
+
break;
|
273
|
+
default:
|
274
|
+
// The json gem claims this is not an error despite the
|
275
|
+
// ECMA-404 indicating it is not valid.
|
276
|
+
if (CompatMode == pi->options.mode) {
|
277
|
+
buf_append(&buf, c);
|
278
|
+
break;
|
279
|
+
}
|
280
|
+
oj_set_error_at(pi,
|
281
|
+
oj_parse_error_class,
|
282
|
+
__FILE__,
|
283
|
+
__LINE__,
|
284
|
+
"invalid escaped character");
|
285
|
+
buf_cleanup(&buf);
|
286
|
+
return;
|
287
|
+
}
|
288
|
+
} else {
|
289
|
+
buf_append(&buf, c);
|
290
|
+
}
|
286
291
|
}
|
287
292
|
if (0 == parent) {
|
288
|
-
|
293
|
+
pi->add_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
|
289
294
|
} else {
|
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
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
295
|
+
switch (parent->next) {
|
296
|
+
case NEXT_ARRAY_NEW:
|
297
|
+
case NEXT_ARRAY_ELEMENT:
|
298
|
+
pi->array_append_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
|
299
|
+
parent->next = NEXT_ARRAY_COMMA;
|
300
|
+
break;
|
301
|
+
case NEXT_HASH_NEW:
|
302
|
+
case NEXT_HASH_KEY:
|
303
|
+
if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
|
304
|
+
parent->klen = buf_len(&buf);
|
305
|
+
parent->key = malloc(parent->klen + 1);
|
306
|
+
memcpy((char *)parent->key, buf.head, parent->klen);
|
307
|
+
*(char *)(parent->key + parent->klen) = '\0';
|
308
|
+
} else {
|
309
|
+
parent->key = "";
|
310
|
+
parent->klen = 0;
|
311
|
+
}
|
312
|
+
parent->k1 = *pi->rd.str;
|
313
|
+
parent->next = NEXT_HASH_COLON;
|
314
|
+
break;
|
315
|
+
case NEXT_HASH_VALUE:
|
316
|
+
pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), pi->rd.str);
|
317
|
+
if (parent->kalloc) {
|
318
|
+
xfree((char *)parent->key);
|
319
|
+
}
|
320
|
+
parent->key = 0;
|
321
|
+
parent->kalloc = 0;
|
322
|
+
parent->next = NEXT_HASH_COMMA;
|
323
|
+
break;
|
324
|
+
case NEXT_HASH_COMMA:
|
325
|
+
case NEXT_NONE:
|
326
|
+
case NEXT_ARRAY_COMMA:
|
327
|
+
case NEXT_HASH_COLON:
|
328
|
+
default:
|
329
|
+
oj_set_error_at(pi,
|
330
|
+
oj_parse_error_class,
|
331
|
+
__FILE__,
|
332
|
+
__LINE__,
|
333
|
+
"expected %s, not a string",
|
334
|
+
oj_stack_next_string(parent->next));
|
335
|
+
break;
|
336
|
+
}
|
327
337
|
}
|
328
338
|
buf_cleanup(&buf);
|
329
339
|
}
|
330
340
|
|
331
|
-
static void
|
332
|
-
|
333
|
-
|
334
|
-
char c;
|
341
|
+
static void read_str(ParseInfo pi) {
|
342
|
+
Val parent = stack_peek(&pi->stack);
|
343
|
+
char c;
|
335
344
|
|
336
345
|
reader_protect(&pi->rd);
|
337
346
|
while ('\"' != (c = reader_get(&pi->rd))) {
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
347
|
+
if ('\0' == c) {
|
348
|
+
oj_set_error_at(pi,
|
349
|
+
oj_parse_error_class,
|
350
|
+
__FILE__,
|
351
|
+
__LINE__,
|
352
|
+
"quoted string not terminated");
|
353
|
+
return;
|
354
|
+
} else if ('\\' == c) {
|
355
|
+
reader_backup(&pi->rd);
|
356
|
+
read_escaped_str(pi);
|
357
|
+
reader_release(&pi->rd);
|
358
|
+
return;
|
359
|
+
}
|
360
|
+
}
|
361
|
+
if (0 == parent) { // simple add
|
362
|
+
pi->add_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
|
350
363
|
} else {
|
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
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
364
|
+
switch (parent->next) {
|
365
|
+
case NEXT_ARRAY_NEW:
|
366
|
+
case NEXT_ARRAY_ELEMENT:
|
367
|
+
pi->array_append_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
|
368
|
+
parent->next = NEXT_ARRAY_COMMA;
|
369
|
+
break;
|
370
|
+
case NEXT_HASH_NEW:
|
371
|
+
case NEXT_HASH_KEY:
|
372
|
+
parent->klen = pi->rd.tail - pi->rd.str - 1;
|
373
|
+
if (sizeof(parent->karray) <= parent->klen) {
|
374
|
+
parent->key = oj_strndup(pi->rd.str, parent->klen);
|
375
|
+
parent->kalloc = 1;
|
376
|
+
} else {
|
377
|
+
memcpy(parent->karray, pi->rd.str, parent->klen);
|
378
|
+
parent->karray[parent->klen] = '\0';
|
379
|
+
parent->key = parent->karray;
|
380
|
+
parent->kalloc = 0;
|
381
|
+
}
|
382
|
+
parent->key_val = pi->hash_key(pi, parent->key, parent->klen);
|
383
|
+
parent->k1 = *pi->rd.str;
|
384
|
+
parent->next = NEXT_HASH_COLON;
|
385
|
+
break;
|
386
|
+
case NEXT_HASH_VALUE:
|
387
|
+
pi->hash_set_cstr(pi, parent, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
|
388
|
+
if (parent->kalloc) {
|
389
|
+
xfree((char *)parent->key);
|
390
|
+
}
|
391
|
+
parent->key = 0;
|
392
|
+
parent->kalloc = 0;
|
393
|
+
parent->next = NEXT_HASH_COMMA;
|
394
|
+
break;
|
395
|
+
case NEXT_HASH_COMMA:
|
396
|
+
case NEXT_NONE:
|
397
|
+
case NEXT_ARRAY_COMMA:
|
398
|
+
case NEXT_HASH_COLON:
|
399
|
+
default:
|
400
|
+
oj_set_error_at(pi,
|
401
|
+
oj_parse_error_class,
|
402
|
+
__FILE__,
|
403
|
+
__LINE__,
|
404
|
+
"expected %s, not a string",
|
405
|
+
oj_stack_next_string(parent->next));
|
406
|
+
break;
|
407
|
+
}
|
390
408
|
}
|
391
409
|
reader_release(&pi->rd);
|
392
410
|
}
|
393
411
|
|
394
|
-
static void
|
395
|
-
|
396
|
-
|
397
|
-
char c;
|
412
|
+
static void read_num(ParseInfo pi) {
|
413
|
+
struct _numInfo ni;
|
414
|
+
char c;
|
398
415
|
|
399
416
|
reader_protect(&pi->rd);
|
400
|
-
ni.i
|
401
|
-
ni.num
|
402
|
-
ni.div
|
403
|
-
ni.di
|
404
|
-
ni.len
|
405
|
-
ni.exp
|
406
|
-
ni.big
|
417
|
+
ni.i = 0;
|
418
|
+
ni.num = 0;
|
419
|
+
ni.div = 1;
|
420
|
+
ni.di = 0;
|
421
|
+
ni.len = 0;
|
422
|
+
ni.exp = 0;
|
423
|
+
ni.big = 0;
|
407
424
|
ni.infinity = 0;
|
408
|
-
ni.nan
|
409
|
-
ni.neg
|
410
|
-
ni.
|
411
|
-
|
425
|
+
ni.nan = 0;
|
426
|
+
ni.neg = 0;
|
427
|
+
ni.has_exp = 0;
|
428
|
+
if (CompatMode == pi->options.mode) {
|
429
|
+
ni.no_big = !pi->options.compat_bigdec;
|
430
|
+
ni.bigdec_load = pi->options.compat_bigdec;
|
431
|
+
} else {
|
432
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
|
433
|
+
RubyDec == pi->options.bigdec_load);
|
434
|
+
ni.bigdec_load = pi->options.bigdec_load;
|
435
|
+
}
|
436
|
+
|
412
437
|
c = reader_get(&pi->rd);
|
413
438
|
if ('-' == c) {
|
414
|
-
|
415
|
-
|
439
|
+
c = reader_get(&pi->rd);
|
440
|
+
ni.neg = 1;
|
416
441
|
} else if ('+' == c) {
|
417
|
-
|
442
|
+
c = reader_get(&pi->rd);
|
418
443
|
}
|
419
444
|
if ('I' == c) {
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
445
|
+
if (No == pi->options.allow_nan) {
|
446
|
+
oj_set_error_at(pi,
|
447
|
+
oj_parse_error_class,
|
448
|
+
__FILE__,
|
449
|
+
__LINE__,
|
450
|
+
"not a number or other value");
|
451
|
+
return;
|
452
|
+
} else if (0 != reader_expect(&pi->rd, "nfinity")) {
|
453
|
+
oj_set_error_at(pi,
|
454
|
+
oj_parse_error_class,
|
455
|
+
__FILE__,
|
456
|
+
__LINE__,
|
457
|
+
"not a number or other value");
|
458
|
+
return;
|
459
|
+
}
|
460
|
+
ni.infinity = 1;
|
428
461
|
} else {
|
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
|
-
|
462
|
+
int dec_cnt = 0;
|
463
|
+
bool zero1 = false;
|
464
|
+
|
465
|
+
for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
|
466
|
+
if (0 == ni.i && '0' == c) {
|
467
|
+
zero1 = true;
|
468
|
+
}
|
469
|
+
if (0 < ni.i) {
|
470
|
+
dec_cnt++;
|
471
|
+
}
|
472
|
+
if (ni.big) {
|
473
|
+
ni.big++;
|
474
|
+
} else {
|
475
|
+
int d = (c - '0');
|
476
|
+
|
477
|
+
if (0 < d) {
|
478
|
+
if (zero1 && CompatMode == pi->options.mode) {
|
479
|
+
oj_set_error_at(pi,
|
480
|
+
oj_parse_error_class,
|
481
|
+
__FILE__,
|
482
|
+
__LINE__,
|
483
|
+
"not a number");
|
484
|
+
return;
|
485
|
+
}
|
486
|
+
zero1 = false;
|
487
|
+
}
|
488
|
+
ni.i = ni.i * 10 + d;
|
489
|
+
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
490
|
+
ni.big = 1;
|
491
|
+
}
|
492
|
+
}
|
493
|
+
}
|
494
|
+
if ('.' == c) {
|
495
|
+
c = reader_get(&pi->rd);
|
496
|
+
// A trailing . is not a valid decimal but if encountered allow it
|
497
|
+
// except when mimicing the JSON gem.
|
498
|
+
if (CompatMode == pi->options.mode) {
|
499
|
+
if (c < '0' || '9' < c) {
|
500
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
501
|
+
}
|
502
|
+
}
|
503
|
+
for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
|
504
|
+
int d = (c - '0');
|
505
|
+
|
506
|
+
if (0 < ni.num || 0 < ni.i) {
|
507
|
+
dec_cnt++;
|
508
|
+
}
|
509
|
+
if (INT64_MAX <= ni.div) {
|
510
|
+
if (!ni.no_big) {
|
511
|
+
ni.big = true;
|
512
|
+
}
|
513
|
+
} else {
|
514
|
+
ni.num = ni.num * 10 + d;
|
515
|
+
ni.div *= 10;
|
516
|
+
ni.di++;
|
517
|
+
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
518
|
+
if (!ni.no_big) {
|
519
|
+
ni.big = true;
|
520
|
+
}
|
521
|
+
}
|
522
|
+
}
|
523
|
+
}
|
524
|
+
}
|
525
|
+
if ('e' == c || 'E' == c) {
|
526
|
+
int eneg = 0;
|
527
|
+
|
528
|
+
ni.has_exp = 1;
|
529
|
+
c = reader_get(&pi->rd);
|
530
|
+
if ('-' == c) {
|
531
|
+
c = reader_get(&pi->rd);
|
532
|
+
eneg = 1;
|
533
|
+
} else if ('+' == c) {
|
534
|
+
c = reader_get(&pi->rd);
|
535
|
+
}
|
536
|
+
for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
|
537
|
+
ni.exp = ni.exp * 10 + (c - '0');
|
538
|
+
if (EXP_MAX <= ni.exp) {
|
539
|
+
ni.big = 1;
|
540
|
+
}
|
541
|
+
}
|
542
|
+
if (eneg) {
|
543
|
+
ni.exp = -ni.exp;
|
544
|
+
}
|
545
|
+
}
|
546
|
+
ni.len = pi->rd.tail - pi->rd.str;
|
547
|
+
if (0 != c) {
|
548
|
+
reader_backup(&pi->rd);
|
549
|
+
}
|
505
550
|
}
|
506
551
|
ni.str = pi->rd.str;
|
507
552
|
ni.len = pi->rd.tail - pi->rd.str;
|
508
553
|
// Check for special reserved values for Infinity and NaN.
|
509
554
|
if (ni.big) {
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
}
|
519
|
-
if (
|
520
|
-
|
555
|
+
if (0 == strcasecmp(INF_VAL, ni.str)) {
|
556
|
+
ni.infinity = 1;
|
557
|
+
} else if (0 == strcasecmp(NINF_VAL, ni.str)) {
|
558
|
+
ni.infinity = 1;
|
559
|
+
ni.neg = 1;
|
560
|
+
} else if (0 == strcasecmp(NAN_VAL, ni.str)) {
|
561
|
+
ni.nan = 1;
|
562
|
+
}
|
563
|
+
}
|
564
|
+
if (CompatMode == pi->options.mode) {
|
565
|
+
if (pi->options.compat_bigdec) {
|
566
|
+
ni.big = 1;
|
567
|
+
}
|
568
|
+
} else if (BigDec == pi->options.bigdec_load) {
|
569
|
+
ni.big = 1;
|
521
570
|
}
|
522
571
|
add_num_value(pi, &ni);
|
523
572
|
reader_release(&pi->rd);
|
524
573
|
}
|
525
574
|
|
526
|
-
static void
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
ni.
|
532
|
-
ni.
|
533
|
-
ni.
|
534
|
-
ni.
|
535
|
-
ni.
|
536
|
-
ni.
|
537
|
-
ni.
|
538
|
-
ni.big = 0;
|
575
|
+
static void read_nan(ParseInfo pi) {
|
576
|
+
struct _numInfo ni;
|
577
|
+
char c;
|
578
|
+
|
579
|
+
ni.str = pi->rd.str;
|
580
|
+
ni.i = 0;
|
581
|
+
ni.num = 0;
|
582
|
+
ni.div = 1;
|
583
|
+
ni.di = 0;
|
584
|
+
ni.len = 0;
|
585
|
+
ni.exp = 0;
|
586
|
+
ni.big = 0;
|
539
587
|
ni.infinity = 0;
|
540
|
-
ni.nan
|
541
|
-
ni.neg
|
542
|
-
|
588
|
+
ni.nan = 1;
|
589
|
+
ni.neg = 0;
|
590
|
+
if (CompatMode == pi->options.mode) {
|
591
|
+
ni.no_big = !pi->options.compat_bigdec;
|
592
|
+
ni.bigdec_load = pi->options.compat_bigdec;
|
593
|
+
} else {
|
594
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
|
595
|
+
RubyDec == pi->options.bigdec_load);
|
596
|
+
ni.bigdec_load = pi->options.bigdec_load;
|
597
|
+
}
|
543
598
|
|
544
|
-
if ('a' != reader_get(&pi->rd) ||
|
545
|
-
|
546
|
-
|
547
|
-
return;
|
599
|
+
if ('a' != reader_get(&pi->rd) || ('N' != (c = reader_get(&pi->rd)) && 'n' != c)) {
|
600
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
601
|
+
return;
|
548
602
|
}
|
549
|
-
if (
|
550
|
-
|
603
|
+
if (CompatMode == pi->options.mode) {
|
604
|
+
if (pi->options.compat_bigdec) {
|
605
|
+
ni.big = 1;
|
606
|
+
}
|
607
|
+
} else if (BigDec == pi->options.bigdec_load) {
|
608
|
+
ni.big = 1;
|
551
609
|
}
|
552
610
|
add_num_value(pi, &ni);
|
553
611
|
}
|
554
612
|
|
555
|
-
static void
|
556
|
-
|
557
|
-
VALUE v = pi->start_array(pi);
|
613
|
+
static void array_start(ParseInfo pi) {
|
614
|
+
VALUE v = pi->start_array(pi);
|
558
615
|
|
559
616
|
stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
|
560
617
|
}
|
561
618
|
|
562
|
-
static void
|
563
|
-
|
564
|
-
Val array = stack_pop(&pi->stack);
|
619
|
+
static void array_end(ParseInfo pi) {
|
620
|
+
Val array = stack_pop(&pi->stack);
|
565
621
|
|
566
622
|
if (0 == array) {
|
567
|
-
|
623
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
|
568
624
|
} else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
|
569
|
-
|
625
|
+
oj_set_error_at(pi,
|
626
|
+
oj_parse_error_class,
|
627
|
+
__FILE__,
|
628
|
+
__LINE__,
|
629
|
+
"expected %s, not an array close",
|
630
|
+
oj_stack_next_string(array->next));
|
570
631
|
} else {
|
571
|
-
|
572
|
-
|
632
|
+
pi->end_array(pi);
|
633
|
+
add_value(pi, array->val);
|
573
634
|
}
|
574
635
|
}
|
575
636
|
|
576
|
-
static void
|
577
|
-
|
578
|
-
volatile VALUE v = pi->start_hash(pi);
|
637
|
+
static void hash_start(ParseInfo pi) {
|
638
|
+
volatile VALUE v = pi->start_hash(pi);
|
579
639
|
|
580
640
|
stack_push(&pi->stack, v, NEXT_HASH_NEW);
|
581
641
|
}
|
582
642
|
|
583
|
-
static void
|
584
|
-
|
585
|
-
volatile Val hash = stack_peek(&pi->stack);
|
643
|
+
static void hash_end(ParseInfo pi) {
|
644
|
+
volatile Val hash = stack_peek(&pi->stack);
|
586
645
|
|
587
646
|
// leave hash on stack until just before
|
588
647
|
if (0 == hash) {
|
589
|
-
|
648
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
|
590
649
|
} else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
|
591
|
-
|
650
|
+
oj_set_error_at(pi,
|
651
|
+
oj_parse_error_class,
|
652
|
+
__FILE__,
|
653
|
+
__LINE__,
|
654
|
+
"expected %s, not a hash close",
|
655
|
+
oj_stack_next_string(hash->next));
|
592
656
|
} else {
|
593
|
-
|
594
|
-
|
595
|
-
|
657
|
+
pi->end_hash(pi);
|
658
|
+
stack_pop(&pi->stack);
|
659
|
+
add_value(pi, hash->val);
|
596
660
|
}
|
597
661
|
}
|
598
662
|
|
599
|
-
static void
|
600
|
-
|
601
|
-
Val parent = stack_peek(&pi->stack);
|
663
|
+
static void comma(ParseInfo pi) {
|
664
|
+
Val parent = stack_peek(&pi->stack);
|
602
665
|
|
603
666
|
if (0 == parent) {
|
604
|
-
|
667
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
605
668
|
} else if (NEXT_ARRAY_COMMA == parent->next) {
|
606
|
-
|
669
|
+
parent->next = NEXT_ARRAY_ELEMENT;
|
607
670
|
} else if (NEXT_HASH_COMMA == parent->next) {
|
608
|
-
|
671
|
+
parent->next = NEXT_HASH_KEY;
|
609
672
|
} else {
|
610
|
-
|
673
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
611
674
|
}
|
612
675
|
}
|
613
676
|
|
614
|
-
static void
|
615
|
-
|
616
|
-
Val parent = stack_peek(&pi->stack);
|
677
|
+
static void colon(ParseInfo pi) {
|
678
|
+
Val parent = stack_peek(&pi->stack);
|
617
679
|
|
618
680
|
if (0 != parent && NEXT_HASH_COLON == parent->next) {
|
619
|
-
|
681
|
+
parent->next = NEXT_HASH_VALUE;
|
620
682
|
} else {
|
621
|
-
|
683
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
|
622
684
|
}
|
623
685
|
}
|
624
686
|
|
625
|
-
void
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
long start = 0;
|
687
|
+
void oj_sparse2(ParseInfo pi) {
|
688
|
+
int first = 1;
|
689
|
+
char c;
|
690
|
+
long start = 0;
|
630
691
|
|
631
692
|
err_init(&pi->err);
|
632
693
|
while (1) {
|
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
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
694
|
+
if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
|
695
|
+
VALUE err_clas = oj_get_json_err_class("NestingError");
|
696
|
+
|
697
|
+
oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
|
698
|
+
pi->err_class = err_clas;
|
699
|
+
return;
|
700
|
+
}
|
701
|
+
c = reader_next_non_white(&pi->rd);
|
702
|
+
if (!first && '\0' != c) {
|
703
|
+
oj_set_error_at(pi,
|
704
|
+
oj_parse_error_class,
|
705
|
+
__FILE__,
|
706
|
+
__LINE__,
|
707
|
+
"unexpected characters after the JSON document");
|
708
|
+
}
|
709
|
+
switch (c) {
|
710
|
+
case '{': hash_start(pi); break;
|
711
|
+
case '}': hash_end(pi); break;
|
712
|
+
case ':': colon(pi); break;
|
713
|
+
case '[': array_start(pi); break;
|
714
|
+
case ']': array_end(pi); break;
|
715
|
+
case ',': comma(pi); break;
|
716
|
+
case '"': read_str(pi); break;
|
717
|
+
case '+':
|
718
|
+
if (CompatMode == pi->options.mode) {
|
719
|
+
oj_set_error_at(pi,
|
720
|
+
oj_parse_error_class,
|
721
|
+
__FILE__,
|
722
|
+
__LINE__,
|
723
|
+
"unexpected character");
|
724
|
+
return;
|
725
|
+
}
|
726
|
+
pi->cur--;
|
727
|
+
read_num(pi);
|
728
|
+
break;
|
729
|
+
case '-':
|
730
|
+
case '0':
|
731
|
+
case '1':
|
732
|
+
case '2':
|
733
|
+
case '3':
|
734
|
+
case '4':
|
735
|
+
case '5':
|
736
|
+
case '6':
|
737
|
+
case '7':
|
738
|
+
case '8':
|
739
|
+
case '9':
|
740
|
+
reader_backup(&pi->rd);
|
741
|
+
read_num(pi);
|
742
|
+
break;
|
743
|
+
case 'I':
|
744
|
+
if (Yes == pi->options.allow_nan) {
|
745
|
+
reader_backup(&pi->rd);
|
746
|
+
read_num(pi);
|
747
|
+
} else {
|
748
|
+
oj_set_error_at(pi,
|
749
|
+
oj_parse_error_class,
|
750
|
+
__FILE__,
|
751
|
+
__LINE__,
|
752
|
+
"unexpected character");
|
753
|
+
return;
|
754
|
+
}
|
755
|
+
break;
|
756
|
+
case 'N':
|
757
|
+
if (Yes == pi->options.allow_nan) {
|
758
|
+
read_nan(pi);
|
759
|
+
} else {
|
760
|
+
oj_set_error_at(pi,
|
761
|
+
oj_parse_error_class,
|
762
|
+
__FILE__,
|
763
|
+
__LINE__,
|
764
|
+
"unexpected character");
|
765
|
+
return;
|
766
|
+
}
|
767
|
+
break;
|
768
|
+
case 't': read_true(pi); break;
|
769
|
+
case 'f': read_false(pi); break;
|
770
|
+
case 'n':
|
771
|
+
c = reader_get(&pi->rd);
|
772
|
+
if ('u' == c) {
|
773
|
+
if (0 == reader_expect(&pi->rd, "ll")) {
|
774
|
+
add_value(pi, Qnil);
|
775
|
+
} else {
|
776
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null");
|
777
|
+
return;
|
778
|
+
}
|
779
|
+
} else if ('a' == c) {
|
780
|
+
struct _numInfo ni;
|
781
|
+
|
782
|
+
c = reader_get(&pi->rd);
|
783
|
+
if ('N' != c && 'n' != c) {
|
784
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected NaN");
|
785
|
+
return;
|
786
|
+
}
|
787
|
+
ni.str = pi->rd.str;
|
788
|
+
ni.i = 0;
|
789
|
+
ni.num = 0;
|
790
|
+
ni.div = 1;
|
791
|
+
ni.di = 0;
|
792
|
+
ni.len = 0;
|
793
|
+
ni.exp = 0;
|
794
|
+
ni.big = 0;
|
795
|
+
ni.infinity = 0;
|
796
|
+
ni.nan = 1;
|
797
|
+
ni.neg = 0;
|
798
|
+
if (CompatMode == pi->options.mode) {
|
799
|
+
ni.no_big = !pi->options.compat_bigdec;
|
800
|
+
ni.bigdec_load = pi->options.compat_bigdec;
|
801
|
+
} else {
|
802
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load ||
|
803
|
+
FastDec == pi->options.bigdec_load ||
|
804
|
+
RubyDec == pi->options.bigdec_load);
|
805
|
+
ni.bigdec_load = pi->options.bigdec_load;
|
806
|
+
}
|
807
|
+
add_num_value(pi, &ni);
|
808
|
+
} else {
|
809
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid token");
|
810
|
+
return;
|
811
|
+
}
|
812
|
+
break;
|
813
|
+
case '/': skip_comment(pi); break;
|
814
|
+
case '\0': return;
|
815
|
+
default:
|
816
|
+
oj_set_error_at(pi,
|
817
|
+
oj_parse_error_class,
|
818
|
+
__FILE__,
|
819
|
+
__LINE__,
|
820
|
+
"unexpected character '%c' [0x%02x]",
|
821
|
+
c,
|
822
|
+
c);
|
823
|
+
return;
|
824
|
+
}
|
825
|
+
if (err_has(&pi->err)) {
|
826
|
+
return;
|
827
|
+
}
|
828
|
+
if (stack_empty(&pi->stack)) {
|
829
|
+
if (Qundef != pi->proc) {
|
830
|
+
VALUE args[3];
|
831
|
+
long len = pi->rd.pos - start;
|
832
|
+
|
833
|
+
*args = stack_head_val(&pi->stack);
|
834
|
+
args[1] = LONG2NUM(start);
|
835
|
+
args[2] = LONG2NUM(len);
|
836
|
+
|
837
|
+
if (Qnil == pi->proc) {
|
838
|
+
rb_yield_values2(3, args);
|
839
|
+
} else {
|
840
|
+
rb_proc_call_with_block(pi->proc, 3, args, Qnil);
|
841
|
+
}
|
842
|
+
} else if (!pi->has_callbacks) {
|
843
|
+
first = 0;
|
844
|
+
}
|
845
|
+
start = pi->rd.pos;
|
846
|
+
// TBD break if option set to allow that
|
847
|
+
}
|
778
848
|
}
|
779
849
|
}
|
780
850
|
|
781
|
-
static VALUE
|
782
|
-
protect_parse(VALUE pip) {
|
851
|
+
static VALUE protect_parse(VALUE pip) {
|
783
852
|
oj_sparse2((ParseInfo)pip);
|
784
853
|
|
785
854
|
return Qnil;
|
@@ -787,46 +856,47 @@ protect_parse(VALUE pip) {
|
|
787
856
|
|
788
857
|
VALUE
|
789
858
|
oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
|
790
|
-
volatile VALUE
|
791
|
-
volatile VALUE
|
792
|
-
VALUE
|
793
|
-
int
|
859
|
+
volatile VALUE input;
|
860
|
+
volatile VALUE wrapped_stack;
|
861
|
+
VALUE result = Qnil;
|
862
|
+
int line = 0;
|
794
863
|
|
795
864
|
if (argc < 1) {
|
796
|
-
|
865
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
797
866
|
}
|
798
867
|
input = argv[0];
|
799
868
|
if (2 <= argc) {
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
869
|
+
if (T_HASH == rb_type(argv[1])) {
|
870
|
+
oj_parse_options(argv[1], &pi->options);
|
871
|
+
} else if (3 <= argc && T_HASH == rb_type(argv[2])) {
|
872
|
+
oj_parse_options(argv[2], &pi->options);
|
873
|
+
}
|
805
874
|
}
|
806
875
|
if (Qnil == input) {
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
} else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) &&
|
813
|
-
|
876
|
+
if (Yes == pi->options.nilnil) {
|
877
|
+
return Qnil;
|
878
|
+
} else {
|
879
|
+
rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
|
880
|
+
}
|
881
|
+
} else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) &&
|
882
|
+
No == pi->options.nilnil && 0 == RSTRING_LEN(input)) {
|
883
|
+
rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string.");
|
814
884
|
}
|
815
885
|
if (rb_block_given_p()) {
|
816
|
-
|
886
|
+
pi->proc = Qnil;
|
817
887
|
} else {
|
818
|
-
|
888
|
+
pi->proc = Qundef;
|
819
889
|
}
|
820
890
|
oj_reader_init(&pi->rd, input, fd, CompatMode == pi->options.mode);
|
821
|
-
pi->json = 0;
|
891
|
+
pi->json = 0; // indicates reader is in use
|
822
892
|
|
823
893
|
if (Yes == pi->options.circular) {
|
824
|
-
|
894
|
+
pi->circ_array = oj_circ_array_new();
|
825
895
|
} else {
|
826
|
-
|
896
|
+
pi->circ_array = 0;
|
827
897
|
}
|
828
898
|
if (No == pi->options.allow_gc) {
|
829
|
-
|
899
|
+
rb_gc_disable();
|
830
900
|
}
|
831
901
|
// GC can run at any time. When it runs any Object created by C will be
|
832
902
|
// freed. We protect against this by wrapping the value stack in a ruby
|
@@ -835,81 +905,80 @@ oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
|
|
835
905
|
wrapped_stack = oj_stack_init(&pi->stack);
|
836
906
|
rb_protect(protect_parse, (VALUE)pi, &line);
|
837
907
|
if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
|
838
|
-
|
908
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Empty input");
|
839
909
|
}
|
840
|
-
result
|
910
|
+
result = stack_head_val(&pi->stack);
|
841
911
|
DATA_PTR(wrapped_stack) = 0;
|
842
912
|
if (No == pi->options.allow_gc) {
|
843
|
-
|
913
|
+
rb_gc_enable();
|
844
914
|
}
|
845
915
|
if (!err_has(&pi->err)) {
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
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
|
-
}
|
916
|
+
// If the stack is not empty then the JSON terminated early.
|
917
|
+
Val v;
|
918
|
+
VALUE err_class = oj_parse_error_class;
|
919
|
+
|
920
|
+
if (0 != line) {
|
921
|
+
VALUE ec = rb_obj_class(rb_errinfo());
|
922
|
+
|
923
|
+
if (rb_eIOError != ec) {
|
924
|
+
goto CLEANUP;
|
925
|
+
}
|
926
|
+
// Sometimes the class of the error is 0 which seems broken.
|
927
|
+
if (rb_eArgError != ec && 0 != ec) {
|
928
|
+
err_class = ec;
|
929
|
+
}
|
930
|
+
}
|
931
|
+
if (0 != (v = stack_peek(&pi->stack))) {
|
932
|
+
switch (v->next) {
|
933
|
+
case NEXT_ARRAY_NEW:
|
934
|
+
case NEXT_ARRAY_ELEMENT:
|
935
|
+
case NEXT_ARRAY_COMMA:
|
936
|
+
oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
|
937
|
+
break;
|
938
|
+
case NEXT_HASH_NEW:
|
939
|
+
case NEXT_HASH_KEY:
|
940
|
+
case NEXT_HASH_COLON:
|
941
|
+
case NEXT_HASH_VALUE:
|
942
|
+
case NEXT_HASH_COMMA:
|
943
|
+
oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated");
|
944
|
+
break;
|
945
|
+
default: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated");
|
946
|
+
}
|
947
|
+
}
|
879
948
|
}
|
880
949
|
CLEANUP:
|
881
950
|
// proceed with cleanup
|
882
951
|
if (0 != pi->circ_array) {
|
883
|
-
|
952
|
+
oj_circ_array_free(pi->circ_array);
|
884
953
|
}
|
885
954
|
stack_cleanup(&pi->stack);
|
886
955
|
if (0 != fd) {
|
887
|
-
|
956
|
+
close(fd);
|
888
957
|
}
|
889
958
|
if (err_has(&pi->err)) {
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
959
|
+
rb_set_errinfo(Qnil);
|
960
|
+
if (Qnil != pi->err_class && 0 != pi->err_class) {
|
961
|
+
pi->err.clas = pi->err_class;
|
962
|
+
}
|
963
|
+
if (CompatMode == pi->options.mode && Yes != pi->options.safe) {
|
964
|
+
// The json gem requires the error message be UTF-8 encoded. In
|
965
|
+
// additional the complete JSON source should be returned but that
|
966
|
+
// is not possible without stored all the bytes read and reading
|
967
|
+
// the remaining bytes on the stream. Both seem like a very bad
|
968
|
+
// idea.
|
969
|
+
VALUE args[] = {oj_encode(rb_str_new2(pi->err.msg))};
|
970
|
+
|
971
|
+
if (pi->err.clas == oj_parse_error_class) {
|
972
|
+
// The error was an Oj::ParseError so change to a JSON::ParserError.
|
973
|
+
pi->err.clas = oj_json_parser_error_class;
|
974
|
+
}
|
975
|
+
rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
|
976
|
+
} else {
|
977
|
+
oj_err_raise(&pi->err);
|
978
|
+
}
|
979
|
+
oj_err_raise(&pi->err);
|
911
980
|
} else if (0 != line) {
|
912
|
-
|
981
|
+
rb_jump_tag(line);
|
913
982
|
}
|
914
983
|
return result;
|
915
984
|
}
|