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/scp.c
CHANGED
@@ -1,39 +1,34 @@
|
|
1
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.
|
2
3
|
|
3
|
-
#include <
|
4
|
+
#include <math.h>
|
4
5
|
#include <stdio.h>
|
6
|
+
#include <stdlib.h>
|
5
7
|
#include <string.h>
|
6
|
-
#include <math.h>
|
7
8
|
#include <sys/types.h>
|
8
9
|
#include <unistd.h>
|
9
10
|
|
11
|
+
#include "encode.h"
|
10
12
|
#include "oj.h"
|
11
13
|
#include "parse.h"
|
12
|
-
#include "encode.h"
|
13
14
|
|
14
|
-
static VALUE
|
15
|
-
noop_start(ParseInfo pi) {
|
15
|
+
static VALUE noop_start(ParseInfo pi) {
|
16
16
|
return Qnil;
|
17
17
|
}
|
18
18
|
|
19
|
-
static void
|
20
|
-
noop_end(ParseInfo pi) {
|
19
|
+
static void noop_end(ParseInfo pi) {
|
21
20
|
}
|
22
21
|
|
23
|
-
static void
|
24
|
-
noop_add_value(ParseInfo pi, VALUE val) {
|
22
|
+
static void noop_add_value(ParseInfo pi, VALUE val) {
|
25
23
|
}
|
26
24
|
|
27
|
-
static void
|
28
|
-
noop_add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
25
|
+
static void noop_add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
29
26
|
}
|
30
27
|
|
31
|
-
static void
|
32
|
-
noop_add_num(ParseInfo pi, NumInfo ni) {
|
28
|
+
static void noop_add_num(ParseInfo pi, NumInfo ni) {
|
33
29
|
}
|
34
30
|
|
35
|
-
static VALUE
|
36
|
-
noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
31
|
+
static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
37
32
|
return Qundef;
|
38
33
|
}
|
39
34
|
|
@@ -41,181 +36,176 @@ static void
|
|
41
36
|
noop_hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
42
37
|
}
|
43
38
|
|
44
|
-
static void
|
45
|
-
noop_hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
39
|
+
static void noop_hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
46
40
|
}
|
47
41
|
|
48
|
-
static void
|
49
|
-
noop_hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
42
|
+
static void noop_hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
50
43
|
}
|
51
44
|
|
52
|
-
static void
|
53
|
-
noop_array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
45
|
+
static void noop_array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
54
46
|
}
|
55
47
|
|
56
|
-
static void
|
57
|
-
noop_array_append_num(ParseInfo pi, NumInfo ni) {
|
48
|
+
static void noop_array_append_num(ParseInfo pi, NumInfo ni) {
|
58
49
|
}
|
59
50
|
|
60
|
-
static void
|
61
|
-
noop_array_append_value(ParseInfo pi, VALUE value) {
|
51
|
+
static void noop_array_append_value(ParseInfo pi, VALUE value) {
|
62
52
|
}
|
63
53
|
|
64
|
-
static void
|
65
|
-
add_value(ParseInfo pi, VALUE val) {
|
54
|
+
static void add_value(ParseInfo pi, VALUE val) {
|
66
55
|
rb_funcall(pi->handler, oj_add_value_id, 1, val);
|
67
56
|
}
|
68
57
|
|
69
|
-
static void
|
70
|
-
|
71
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
58
|
+
static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
59
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
72
60
|
|
73
61
|
rstr = oj_encode(rstr);
|
74
62
|
rb_funcall(pi->handler, oj_add_value_id, 1, rstr);
|
75
63
|
}
|
76
64
|
|
77
|
-
static void
|
78
|
-
add_num(ParseInfo pi, NumInfo ni) {
|
65
|
+
static void add_num(ParseInfo pi, NumInfo ni) {
|
79
66
|
rb_funcall(pi->handler, oj_add_value_id, 1, oj_num_as_value(ni));
|
80
67
|
}
|
81
68
|
|
82
|
-
static VALUE
|
83
|
-
start_hash(ParseInfo pi) {
|
69
|
+
static VALUE start_hash(ParseInfo pi) {
|
84
70
|
return rb_funcall(pi->handler, oj_hash_start_id, 0);
|
85
71
|
}
|
86
72
|
|
87
|
-
static void
|
88
|
-
end_hash(ParseInfo pi) {
|
73
|
+
static void end_hash(ParseInfo pi) {
|
89
74
|
rb_funcall(pi->handler, oj_hash_end_id, 0);
|
90
75
|
}
|
91
76
|
|
92
|
-
static VALUE
|
93
|
-
start_array(ParseInfo pi) {
|
77
|
+
static VALUE start_array(ParseInfo pi) {
|
94
78
|
return rb_funcall(pi->handler, oj_array_start_id, 0);
|
95
79
|
}
|
96
80
|
|
97
|
-
static void
|
98
|
-
end_array(ParseInfo pi) {
|
81
|
+
static void end_array(ParseInfo pi) {
|
99
82
|
rb_funcall(pi->handler, oj_array_end_id, 0);
|
100
83
|
}
|
101
84
|
|
102
|
-
static VALUE
|
103
|
-
|
104
|
-
volatile VALUE rkey = kval->key_val;
|
85
|
+
static VALUE calc_hash_key(ParseInfo pi, Val kval) {
|
86
|
+
volatile VALUE rkey = kval->key_val;
|
105
87
|
|
106
88
|
if (Qundef == rkey) {
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
89
|
+
rkey = rb_str_new(kval->key, kval->klen);
|
90
|
+
rkey = oj_encode(rkey);
|
91
|
+
if (Yes == pi->options.sym_key) {
|
92
|
+
rkey = rb_str_intern(rkey);
|
93
|
+
}
|
112
94
|
}
|
113
95
|
return rkey;
|
114
96
|
}
|
115
97
|
|
116
|
-
static VALUE
|
117
|
-
hash_key(ParseInfo pi, const char *key, size_t klen) {
|
98
|
+
static VALUE hash_key(ParseInfo pi, const char *key, size_t klen) {
|
118
99
|
return rb_funcall(pi->handler, oj_hash_key_id, 1, rb_str_new(key, klen));
|
119
100
|
}
|
120
101
|
|
121
|
-
static void
|
122
|
-
|
123
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
102
|
+
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
103
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
124
104
|
|
125
105
|
rstr = oj_encode(rstr);
|
126
|
-
rb_funcall(pi->handler,
|
106
|
+
rb_funcall(pi->handler,
|
107
|
+
oj_hash_set_id,
|
108
|
+
3,
|
109
|
+
stack_peek(&pi->stack)->val,
|
110
|
+
calc_hash_key(pi, kval),
|
111
|
+
rstr);
|
127
112
|
}
|
128
113
|
|
129
|
-
static void
|
130
|
-
|
131
|
-
|
114
|
+
static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
115
|
+
rb_funcall(pi->handler,
|
116
|
+
oj_hash_set_id,
|
117
|
+
3,
|
118
|
+
stack_peek(&pi->stack)->val,
|
119
|
+
calc_hash_key(pi, kval),
|
120
|
+
oj_num_as_value(ni));
|
132
121
|
}
|
133
122
|
|
134
|
-
static void
|
135
|
-
|
136
|
-
|
123
|
+
static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
124
|
+
rb_funcall(pi->handler,
|
125
|
+
oj_hash_set_id,
|
126
|
+
3,
|
127
|
+
stack_peek(&pi->stack)->val,
|
128
|
+
calc_hash_key(pi, kval),
|
129
|
+
value);
|
137
130
|
}
|
138
131
|
|
139
|
-
static void
|
140
|
-
|
141
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
132
|
+
static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
133
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
142
134
|
|
143
135
|
rstr = oj_encode(rstr);
|
144
136
|
rb_funcall(pi->handler, oj_array_append_id, 2, stack_peek(&pi->stack)->val, rstr);
|
145
137
|
}
|
146
138
|
|
147
|
-
static void
|
148
|
-
array_append_num(ParseInfo pi, NumInfo ni) {
|
139
|
+
static void array_append_num(ParseInfo pi, NumInfo ni) {
|
149
140
|
rb_funcall(pi->handler, oj_array_append_id, 2, stack_peek(&pi->stack)->val, oj_num_as_value(ni));
|
150
141
|
}
|
151
142
|
|
152
|
-
static void
|
153
|
-
array_append_value(ParseInfo pi, VALUE value) {
|
143
|
+
static void array_append_value(ParseInfo pi, VALUE value) {
|
154
144
|
rb_funcall(pi->handler, oj_array_append_id, 2, stack_peek(&pi->stack)->val, value);
|
155
145
|
}
|
156
146
|
|
157
147
|
VALUE
|
158
148
|
oj_sc_parse(int argc, VALUE *argv, VALUE self) {
|
159
|
-
struct _parseInfo
|
160
|
-
VALUE
|
149
|
+
struct _parseInfo pi;
|
150
|
+
VALUE input = argv[1];
|
161
151
|
|
162
152
|
parse_info_init(&pi);
|
163
153
|
pi.err_class = Qnil;
|
164
154
|
pi.max_depth = 0;
|
165
|
-
pi.options
|
155
|
+
pi.options = oj_default_options;
|
166
156
|
if (3 == argc) {
|
167
|
-
|
157
|
+
oj_parse_options(argv[2], &pi.options);
|
168
158
|
}
|
169
159
|
if (rb_block_given_p()) {
|
170
|
-
|
160
|
+
pi.proc = Qnil;
|
171
161
|
} else {
|
172
|
-
|
162
|
+
pi.proc = Qundef;
|
173
163
|
}
|
174
164
|
pi.handler = *argv;
|
175
165
|
|
176
|
-
pi.start_hash
|
177
|
-
pi.end_hash
|
178
|
-
pi.hash_key
|
166
|
+
pi.start_hash = rb_respond_to(pi.handler, oj_hash_start_id) ? start_hash : noop_start;
|
167
|
+
pi.end_hash = rb_respond_to(pi.handler, oj_hash_end_id) ? end_hash : noop_end;
|
168
|
+
pi.hash_key = rb_respond_to(pi.handler, oj_hash_key_id) ? hash_key : noop_hash_key;
|
179
169
|
pi.start_array = rb_respond_to(pi.handler, oj_array_start_id) ? start_array : noop_start;
|
180
|
-
pi.end_array
|
170
|
+
pi.end_array = rb_respond_to(pi.handler, oj_array_end_id) ? end_array : noop_end;
|
181
171
|
if (rb_respond_to(pi.handler, oj_hash_set_id)) {
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
172
|
+
pi.hash_set_value = hash_set_value;
|
173
|
+
pi.hash_set_cstr = hash_set_cstr;
|
174
|
+
pi.hash_set_num = hash_set_num;
|
175
|
+
pi.expect_value = 1;
|
186
176
|
} else {
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
177
|
+
pi.hash_set_value = noop_hash_set_value;
|
178
|
+
pi.hash_set_cstr = noop_hash_set_cstr;
|
179
|
+
pi.hash_set_num = noop_hash_set_num;
|
180
|
+
pi.expect_value = 0;
|
191
181
|
}
|
192
182
|
if (rb_respond_to(pi.handler, oj_array_append_id)) {
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
183
|
+
pi.array_append_value = array_append_value;
|
184
|
+
pi.array_append_cstr = array_append_cstr;
|
185
|
+
pi.array_append_num = array_append_num;
|
186
|
+
pi.expect_value = 1;
|
197
187
|
} else {
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
188
|
+
pi.array_append_value = noop_array_append_value;
|
189
|
+
pi.array_append_cstr = noop_array_append_cstr;
|
190
|
+
pi.array_append_num = noop_array_append_num;
|
191
|
+
pi.expect_value = 0;
|
202
192
|
}
|
203
193
|
if (rb_respond_to(pi.handler, oj_add_value_id)) {
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
194
|
+
pi.add_cstr = add_cstr;
|
195
|
+
pi.add_num = add_num;
|
196
|
+
pi.add_value = add_value;
|
197
|
+
pi.expect_value = 1;
|
208
198
|
} else {
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
199
|
+
pi.add_cstr = noop_add_cstr;
|
200
|
+
pi.add_num = noop_add_num;
|
201
|
+
pi.add_value = noop_add_value;
|
202
|
+
pi.expect_value = 0;
|
213
203
|
}
|
214
204
|
pi.has_callbacks = true;
|
215
205
|
|
216
206
|
if (T_STRING == rb_type(input)) {
|
217
|
-
|
207
|
+
return oj_pi_parse(argc - 1, argv + 1, &pi, 0, 0, 1);
|
218
208
|
} else {
|
219
|
-
|
209
|
+
return oj_pi_sparse(argc - 1, argv + 1, &pi, 0);
|
220
210
|
}
|
221
211
|
}
|
data/ext/oj/sparse.c
CHANGED
@@ -1,814 +1,854 @@
|
|
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 <math.h>
|
4
5
|
#include <stdio.h>
|
6
|
+
#include <stdlib.h>
|
5
7
|
#include <string.h>
|
6
8
|
#include <unistd.h>
|
7
|
-
#include <math.h>
|
8
9
|
|
9
|
-
#include "
|
10
|
+
#include "buf.h"
|
10
11
|
#include "encode.h"
|
12
|
+
#include "hash.h" // for oj_strndup()
|
13
|
+
#include "oj.h"
|
11
14
|
#include "parse.h"
|
12
|
-
#include "buf.h"
|
13
|
-
#include "hash.h" // for oj_strndup()
|
14
15
|
#include "val_stack.h"
|
15
16
|
|
16
17
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
17
|
-
#define OJ_INFINITY
|
18
|
+
#define OJ_INFINITY (1.0 / 0.0)
|
18
19
|
|
19
20
|
#ifdef RUBINIUS_RUBY
|
20
|
-
#define NUM_MAX
|
21
|
+
#define NUM_MAX 0x07FFFFFF
|
21
22
|
#else
|
22
|
-
#define NUM_MAX
|
23
|
+
#define NUM_MAX (FIXNUM_MAX >> 8)
|
23
24
|
#endif
|
24
|
-
#define EXP_MAX
|
25
|
-
#define DEC_MAX
|
25
|
+
#define EXP_MAX 100000
|
26
|
+
#define DEC_MAX 15
|
26
27
|
|
27
|
-
static void
|
28
|
-
|
29
|
-
char c = reader_get(&pi->rd);
|
28
|
+
static void skip_comment(ParseInfo pi) {
|
29
|
+
char c = reader_get(&pi->rd);
|
30
30
|
|
31
31
|
if ('*' == c) {
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
+
}
|
40
40
|
} else if ('/' == c) {
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
}
|
51
|
-
}
|
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
|
+
}
|
52
50
|
} else {
|
53
|
-
|
51
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
|
54
52
|
}
|
55
53
|
if ('\0' == c) {
|
56
|
-
|
57
|
-
|
54
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
|
55
|
+
return;
|
58
56
|
}
|
59
57
|
}
|
60
58
|
|
61
|
-
static void
|
62
|
-
|
63
|
-
Val parent = stack_peek(&pi->stack);
|
59
|
+
static void add_value(ParseInfo pi, VALUE rval) {
|
60
|
+
Val parent = stack_peek(&pi->stack);
|
64
61
|
|
65
|
-
if (0 == parent) {
|
66
|
-
|
62
|
+
if (0 == parent) { // simple add
|
63
|
+
pi->add_value(pi, rval);
|
67
64
|
} else {
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
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
|
+
}
|
93
95
|
}
|
94
96
|
}
|
95
97
|
|
96
|
-
static void
|
97
|
-
|
98
|
-
Val parent = stack_peek(&pi->stack);
|
98
|
+
static void add_num_value(ParseInfo pi, NumInfo ni) {
|
99
|
+
Val parent = stack_peek(&pi->stack);
|
99
100
|
|
100
101
|
if (0 == parent) {
|
101
|
-
|
102
|
+
pi->add_num(pi, ni);
|
102
103
|
} else {
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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
|
+
}
|
122
128
|
}
|
123
129
|
}
|
124
130
|
|
125
|
-
static void
|
126
|
-
read_true(ParseInfo pi) {
|
131
|
+
static void read_true(ParseInfo pi) {
|
127
132
|
if (0 == reader_expect(&pi->rd, "rue")) {
|
128
|
-
|
133
|
+
add_value(pi, Qtrue);
|
129
134
|
} else {
|
130
|
-
|
135
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
|
131
136
|
}
|
132
137
|
}
|
133
138
|
|
134
|
-
static void
|
135
|
-
read_false(ParseInfo pi) {
|
139
|
+
static void read_false(ParseInfo pi) {
|
136
140
|
if (0 == reader_expect(&pi->rd, "alse")) {
|
137
|
-
|
141
|
+
add_value(pi, Qfalse);
|
138
142
|
} else {
|
139
|
-
|
143
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
|
140
144
|
}
|
141
145
|
}
|
142
146
|
|
143
|
-
static uint32_t
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
char c;
|
147
|
+
static uint32_t read_hex(ParseInfo pi) {
|
148
|
+
uint32_t b = 0;
|
149
|
+
int i;
|
150
|
+
char c;
|
148
151
|
|
149
152
|
for (i = 0; i < 4; i++) {
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
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
|
+
}
|
162
165
|
}
|
163
166
|
return b;
|
164
167
|
}
|
165
168
|
|
166
|
-
static void
|
167
|
-
unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
169
|
+
static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
168
170
|
if (0x0000007F >= code) {
|
169
|
-
|
171
|
+
buf_append(buf, (char)code);
|
170
172
|
} else if (0x000007FF >= code) {
|
171
|
-
|
172
|
-
|
173
|
+
buf_append(buf, 0xC0 | (code >> 6));
|
174
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
173
175
|
} else if (0x0000FFFF >= code) {
|
174
|
-
|
175
|
-
|
176
|
-
|
176
|
+
buf_append(buf, 0xE0 | (code >> 12));
|
177
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
178
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
177
179
|
} else if (0x001FFFFF >= code) {
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
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));
|
182
184
|
} else if (0x03FFFFFF >= code) {
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
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));
|
188
190
|
} else if (0x7FFFFFFF >= code) {
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
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));
|
195
197
|
} else {
|
196
|
-
|
198
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
|
197
199
|
}
|
198
200
|
}
|
199
201
|
|
200
202
|
// entered at backslash
|
201
|
-
static void
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
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);
|
207
208
|
|
208
209
|
buf_init(&buf);
|
209
210
|
if (pi->rd.str < pi->rd.tail) {
|
210
|
-
|
211
|
+
buf_append_string(&buf, pi->rd.str, pi->rd.tail - pi->rd.str);
|
211
212
|
}
|
212
213
|
while ('\"' != (c = reader_get(&pi->rd))) {
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
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
|
+
}
|
278
291
|
}
|
279
292
|
if (0 == parent) {
|
280
|
-
|
293
|
+
pi->add_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
|
281
294
|
} else {
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
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
|
+
}
|
319
337
|
}
|
320
338
|
buf_cleanup(&buf);
|
321
339
|
}
|
322
340
|
|
323
|
-
static void
|
324
|
-
|
325
|
-
|
326
|
-
char c;
|
341
|
+
static void read_str(ParseInfo pi) {
|
342
|
+
Val parent = stack_peek(&pi->stack);
|
343
|
+
char c;
|
327
344
|
|
328
345
|
reader_protect(&pi->rd);
|
329
346
|
while ('\"' != (c = reader_get(&pi->rd))) {
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
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);
|
342
363
|
} else {
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
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
|
+
}
|
382
408
|
}
|
383
409
|
reader_release(&pi->rd);
|
384
410
|
}
|
385
411
|
|
386
|
-
static void
|
387
|
-
|
388
|
-
|
389
|
-
char c;
|
412
|
+
static void read_num(ParseInfo pi) {
|
413
|
+
struct _numInfo ni;
|
414
|
+
char c;
|
390
415
|
|
391
416
|
reader_protect(&pi->rd);
|
392
|
-
ni.i
|
393
|
-
ni.num
|
394
|
-
ni.div
|
395
|
-
ni.di
|
396
|
-
ni.len
|
397
|
-
ni.exp
|
398
|
-
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;
|
399
424
|
ni.infinity = 0;
|
400
|
-
ni.nan
|
401
|
-
ni.neg
|
402
|
-
ni.has_exp
|
425
|
+
ni.nan = 0;
|
426
|
+
ni.neg = 0;
|
427
|
+
ni.has_exp = 0;
|
403
428
|
if (CompatMode == pi->options.mode) {
|
404
|
-
|
405
|
-
|
429
|
+
ni.no_big = !pi->options.compat_bigdec;
|
430
|
+
ni.bigdec_load = pi->options.compat_bigdec;
|
406
431
|
} else {
|
407
|
-
|
408
|
-
|
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;
|
409
435
|
}
|
410
436
|
|
411
437
|
c = reader_get(&pi->rd);
|
412
438
|
if ('-' == c) {
|
413
|
-
|
414
|
-
|
439
|
+
c = reader_get(&pi->rd);
|
440
|
+
ni.neg = 1;
|
415
441
|
} else if ('+' == c) {
|
416
|
-
|
442
|
+
c = reader_get(&pi->rd);
|
417
443
|
}
|
418
444
|
if ('I' == c) {
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
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;
|
427
461
|
} else {
|
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
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
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
|
+
}
|
512
550
|
}
|
513
551
|
ni.str = pi->rd.str;
|
514
552
|
ni.len = pi->rd.tail - pi->rd.str;
|
515
553
|
// Check for special reserved values for Infinity and NaN.
|
516
554
|
if (ni.big) {
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
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
|
+
}
|
525
563
|
}
|
526
564
|
if (CompatMode == pi->options.mode) {
|
527
|
-
|
528
|
-
|
529
|
-
|
565
|
+
if (pi->options.compat_bigdec) {
|
566
|
+
ni.big = 1;
|
567
|
+
}
|
530
568
|
} else if (BigDec == pi->options.bigdec_load) {
|
531
|
-
|
569
|
+
ni.big = 1;
|
532
570
|
}
|
533
571
|
add_num_value(pi, &ni);
|
534
572
|
reader_release(&pi->rd);
|
535
573
|
}
|
536
574
|
|
537
|
-
static void
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
ni.
|
543
|
-
ni.
|
544
|
-
ni.
|
545
|
-
ni.
|
546
|
-
ni.
|
547
|
-
ni.
|
548
|
-
ni.
|
549
|
-
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;
|
550
587
|
ni.infinity = 0;
|
551
|
-
ni.nan
|
552
|
-
ni.neg
|
588
|
+
ni.nan = 1;
|
589
|
+
ni.neg = 0;
|
553
590
|
if (CompatMode == pi->options.mode) {
|
554
|
-
|
555
|
-
|
591
|
+
ni.no_big = !pi->options.compat_bigdec;
|
592
|
+
ni.bigdec_load = pi->options.compat_bigdec;
|
556
593
|
} else {
|
557
|
-
|
558
|
-
|
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;
|
559
597
|
}
|
560
598
|
|
561
|
-
if ('a' != reader_get(&pi->rd) ||
|
562
|
-
|
563
|
-
|
564
|
-
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;
|
565
602
|
}
|
566
603
|
if (CompatMode == pi->options.mode) {
|
567
|
-
|
568
|
-
|
569
|
-
|
604
|
+
if (pi->options.compat_bigdec) {
|
605
|
+
ni.big = 1;
|
606
|
+
}
|
570
607
|
} else if (BigDec == pi->options.bigdec_load) {
|
571
|
-
|
608
|
+
ni.big = 1;
|
572
609
|
}
|
573
610
|
add_num_value(pi, &ni);
|
574
611
|
}
|
575
612
|
|
576
|
-
static void
|
577
|
-
|
578
|
-
VALUE v = pi->start_array(pi);
|
613
|
+
static void array_start(ParseInfo pi) {
|
614
|
+
VALUE v = pi->start_array(pi);
|
579
615
|
|
580
616
|
stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
|
581
617
|
}
|
582
618
|
|
583
|
-
static void
|
584
|
-
|
585
|
-
Val array = stack_pop(&pi->stack);
|
619
|
+
static void array_end(ParseInfo pi) {
|
620
|
+
Val array = stack_pop(&pi->stack);
|
586
621
|
|
587
622
|
if (0 == array) {
|
588
|
-
|
623
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
|
589
624
|
} else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
|
590
|
-
|
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));
|
591
631
|
} else {
|
592
|
-
|
593
|
-
|
632
|
+
pi->end_array(pi);
|
633
|
+
add_value(pi, array->val);
|
594
634
|
}
|
595
635
|
}
|
596
636
|
|
597
|
-
static void
|
598
|
-
|
599
|
-
volatile VALUE v = pi->start_hash(pi);
|
637
|
+
static void hash_start(ParseInfo pi) {
|
638
|
+
volatile VALUE v = pi->start_hash(pi);
|
600
639
|
|
601
640
|
stack_push(&pi->stack, v, NEXT_HASH_NEW);
|
602
641
|
}
|
603
642
|
|
604
|
-
static void
|
605
|
-
|
606
|
-
volatile Val hash = stack_peek(&pi->stack);
|
643
|
+
static void hash_end(ParseInfo pi) {
|
644
|
+
volatile Val hash = stack_peek(&pi->stack);
|
607
645
|
|
608
646
|
// leave hash on stack until just before
|
609
647
|
if (0 == hash) {
|
610
|
-
|
648
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
|
611
649
|
} else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
|
612
|
-
|
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));
|
613
656
|
} else {
|
614
|
-
|
615
|
-
|
616
|
-
|
657
|
+
pi->end_hash(pi);
|
658
|
+
stack_pop(&pi->stack);
|
659
|
+
add_value(pi, hash->val);
|
617
660
|
}
|
618
661
|
}
|
619
662
|
|
620
|
-
static void
|
621
|
-
|
622
|
-
Val parent = stack_peek(&pi->stack);
|
663
|
+
static void comma(ParseInfo pi) {
|
664
|
+
Val parent = stack_peek(&pi->stack);
|
623
665
|
|
624
666
|
if (0 == parent) {
|
625
|
-
|
667
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
626
668
|
} else if (NEXT_ARRAY_COMMA == parent->next) {
|
627
|
-
|
669
|
+
parent->next = NEXT_ARRAY_ELEMENT;
|
628
670
|
} else if (NEXT_HASH_COMMA == parent->next) {
|
629
|
-
|
671
|
+
parent->next = NEXT_HASH_KEY;
|
630
672
|
} else {
|
631
|
-
|
673
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
632
674
|
}
|
633
675
|
}
|
634
676
|
|
635
|
-
static void
|
636
|
-
|
637
|
-
Val parent = stack_peek(&pi->stack);
|
677
|
+
static void colon(ParseInfo pi) {
|
678
|
+
Val parent = stack_peek(&pi->stack);
|
638
679
|
|
639
680
|
if (0 != parent && NEXT_HASH_COLON == parent->next) {
|
640
|
-
|
681
|
+
parent->next = NEXT_HASH_VALUE;
|
641
682
|
} else {
|
642
|
-
|
683
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
|
643
684
|
}
|
644
685
|
}
|
645
686
|
|
646
|
-
void
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
long start = 0;
|
687
|
+
void oj_sparse2(ParseInfo pi) {
|
688
|
+
int first = 1;
|
689
|
+
char c;
|
690
|
+
long start = 0;
|
651
691
|
|
652
692
|
err_init(&pi->err);
|
653
693
|
while (1) {
|
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
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
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
|
+
}
|
807
848
|
}
|
808
849
|
}
|
809
850
|
|
810
|
-
static VALUE
|
811
|
-
protect_parse(VALUE pip) {
|
851
|
+
static VALUE protect_parse(VALUE pip) {
|
812
852
|
oj_sparse2((ParseInfo)pip);
|
813
853
|
|
814
854
|
return Qnil;
|
@@ -816,46 +856,47 @@ protect_parse(VALUE pip) {
|
|
816
856
|
|
817
857
|
VALUE
|
818
858
|
oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
|
819
|
-
volatile VALUE
|
820
|
-
volatile VALUE
|
821
|
-
VALUE
|
822
|
-
int
|
859
|
+
volatile VALUE input;
|
860
|
+
volatile VALUE wrapped_stack;
|
861
|
+
VALUE result = Qnil;
|
862
|
+
int line = 0;
|
823
863
|
|
824
864
|
if (argc < 1) {
|
825
|
-
|
865
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
826
866
|
}
|
827
867
|
input = argv[0];
|
828
868
|
if (2 <= argc) {
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
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
|
+
}
|
834
874
|
}
|
835
875
|
if (Qnil == input) {
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
} else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) &&
|
842
|
-
|
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.");
|
843
884
|
}
|
844
885
|
if (rb_block_given_p()) {
|
845
|
-
|
886
|
+
pi->proc = Qnil;
|
846
887
|
} else {
|
847
|
-
|
888
|
+
pi->proc = Qundef;
|
848
889
|
}
|
849
890
|
oj_reader_init(&pi->rd, input, fd, CompatMode == pi->options.mode);
|
850
|
-
pi->json = 0;
|
891
|
+
pi->json = 0; // indicates reader is in use
|
851
892
|
|
852
893
|
if (Yes == pi->options.circular) {
|
853
|
-
|
894
|
+
pi->circ_array = oj_circ_array_new();
|
854
895
|
} else {
|
855
|
-
|
896
|
+
pi->circ_array = 0;
|
856
897
|
}
|
857
898
|
if (No == pi->options.allow_gc) {
|
858
|
-
|
899
|
+
rb_gc_disable();
|
859
900
|
}
|
860
901
|
// GC can run at any time. When it runs any Object created by C will be
|
861
902
|
// freed. We protect against this by wrapping the value stack in a ruby
|
@@ -864,81 +905,80 @@ oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
|
|
864
905
|
wrapped_stack = oj_stack_init(&pi->stack);
|
865
906
|
rb_protect(protect_parse, (VALUE)pi, &line);
|
866
907
|
if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
|
867
|
-
|
908
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Empty input");
|
868
909
|
}
|
869
|
-
result
|
910
|
+
result = stack_head_val(&pi->stack);
|
870
911
|
DATA_PTR(wrapped_stack) = 0;
|
871
912
|
if (No == pi->options.allow_gc) {
|
872
|
-
|
913
|
+
rb_gc_enable();
|
873
914
|
}
|
874
915
|
if (!err_has(&pi->err)) {
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
}
|
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
|
+
}
|
908
948
|
}
|
909
949
|
CLEANUP:
|
910
950
|
// proceed with cleanup
|
911
951
|
if (0 != pi->circ_array) {
|
912
|
-
|
952
|
+
oj_circ_array_free(pi->circ_array);
|
913
953
|
}
|
914
954
|
stack_cleanup(&pi->stack);
|
915
955
|
if (0 != fd) {
|
916
|
-
|
956
|
+
close(fd);
|
917
957
|
}
|
918
958
|
if (err_has(&pi->err)) {
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
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);
|
940
980
|
} else if (0 != line) {
|
941
|
-
|
981
|
+
rb_jump_tag(line);
|
942
982
|
}
|
943
983
|
return result;
|
944
984
|
}
|