oj 3.10.18 → 3.11.4
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 +2 -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 +1008 -1038
- 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 +406 -407
- 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 +1132 -918
- data/ext/oj/oj.h +286 -297
- data/ext/oj/parse.c +943 -926
- 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 +781 -716
- 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/pages/Modes.md +2 -1
- data/pages/Options.md +8 -0
- data/test/activerecord/result_test.rb +7 -2
- data/test/foo.rb +35 -32
- data/test/helper.rb +10 -0
- data/test/json_gem/json_generator_test.rb +15 -3
- data/test/json_gem/test_helper.rb +8 -0
- data/test/test_compat.rb +3 -3
- data/test/test_hash.rb +10 -0
- data/test/test_scp.rb +1 -1
- data/test/test_various.rb +1 -0
- metadata +82 -82
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,789 +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
|
403
|
-
|
404
|
-
|
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
|
+
}
|
405
436
|
|
406
437
|
c = reader_get(&pi->rd);
|
407
438
|
if ('-' == c) {
|
408
|
-
|
409
|
-
|
439
|
+
c = reader_get(&pi->rd);
|
440
|
+
ni.neg = 1;
|
410
441
|
} else if ('+' == c) {
|
411
|
-
|
442
|
+
c = reader_get(&pi->rd);
|
412
443
|
}
|
413
444
|
if ('I' == c) {
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
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;
|
422
461
|
} else {
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
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
|
+
}
|
507
550
|
}
|
508
551
|
ni.str = pi->rd.str;
|
509
552
|
ni.len = pi->rd.tail - pi->rd.str;
|
510
553
|
// Check for special reserved values for Infinity and NaN.
|
511
554
|
if (ni.big) {
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
}
|
521
|
-
if (
|
522
|
-
|
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;
|
523
570
|
}
|
524
571
|
add_num_value(pi, &ni);
|
525
572
|
reader_release(&pi->rd);
|
526
573
|
}
|
527
574
|
|
528
|
-
static void
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
ni.
|
534
|
-
ni.
|
535
|
-
ni.
|
536
|
-
ni.
|
537
|
-
ni.
|
538
|
-
ni.
|
539
|
-
ni.
|
540
|
-
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;
|
541
587
|
ni.infinity = 0;
|
542
|
-
ni.nan
|
543
|
-
ni.neg
|
544
|
-
|
545
|
-
|
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
|
+
}
|
546
598
|
|
547
|
-
if ('a' != reader_get(&pi->rd) ||
|
548
|
-
|
549
|
-
|
550
|
-
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;
|
551
602
|
}
|
552
|
-
if (
|
553
|
-
|
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;
|
554
609
|
}
|
555
610
|
add_num_value(pi, &ni);
|
556
611
|
}
|
557
612
|
|
558
|
-
static void
|
559
|
-
|
560
|
-
VALUE v = pi->start_array(pi);
|
613
|
+
static void array_start(ParseInfo pi) {
|
614
|
+
VALUE v = pi->start_array(pi);
|
561
615
|
|
562
616
|
stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
|
563
617
|
}
|
564
618
|
|
565
|
-
static void
|
566
|
-
|
567
|
-
Val array = stack_pop(&pi->stack);
|
619
|
+
static void array_end(ParseInfo pi) {
|
620
|
+
Val array = stack_pop(&pi->stack);
|
568
621
|
|
569
622
|
if (0 == array) {
|
570
|
-
|
623
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
|
571
624
|
} else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
|
572
|
-
|
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));
|
573
631
|
} else {
|
574
|
-
|
575
|
-
|
632
|
+
pi->end_array(pi);
|
633
|
+
add_value(pi, array->val);
|
576
634
|
}
|
577
635
|
}
|
578
636
|
|
579
|
-
static void
|
580
|
-
|
581
|
-
volatile VALUE v = pi->start_hash(pi);
|
637
|
+
static void hash_start(ParseInfo pi) {
|
638
|
+
volatile VALUE v = pi->start_hash(pi);
|
582
639
|
|
583
640
|
stack_push(&pi->stack, v, NEXT_HASH_NEW);
|
584
641
|
}
|
585
642
|
|
586
|
-
static void
|
587
|
-
|
588
|
-
volatile Val hash = stack_peek(&pi->stack);
|
643
|
+
static void hash_end(ParseInfo pi) {
|
644
|
+
volatile Val hash = stack_peek(&pi->stack);
|
589
645
|
|
590
646
|
// leave hash on stack until just before
|
591
647
|
if (0 == hash) {
|
592
|
-
|
648
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
|
593
649
|
} else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
|
594
|
-
|
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));
|
595
656
|
} else {
|
596
|
-
|
597
|
-
|
598
|
-
|
657
|
+
pi->end_hash(pi);
|
658
|
+
stack_pop(&pi->stack);
|
659
|
+
add_value(pi, hash->val);
|
599
660
|
}
|
600
661
|
}
|
601
662
|
|
602
|
-
static void
|
603
|
-
|
604
|
-
Val parent = stack_peek(&pi->stack);
|
663
|
+
static void comma(ParseInfo pi) {
|
664
|
+
Val parent = stack_peek(&pi->stack);
|
605
665
|
|
606
666
|
if (0 == parent) {
|
607
|
-
|
667
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
608
668
|
} else if (NEXT_ARRAY_COMMA == parent->next) {
|
609
|
-
|
669
|
+
parent->next = NEXT_ARRAY_ELEMENT;
|
610
670
|
} else if (NEXT_HASH_COMMA == parent->next) {
|
611
|
-
|
671
|
+
parent->next = NEXT_HASH_KEY;
|
612
672
|
} else {
|
613
|
-
|
673
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
614
674
|
}
|
615
675
|
}
|
616
676
|
|
617
|
-
static void
|
618
|
-
|
619
|
-
Val parent = stack_peek(&pi->stack);
|
677
|
+
static void colon(ParseInfo pi) {
|
678
|
+
Val parent = stack_peek(&pi->stack);
|
620
679
|
|
621
680
|
if (0 != parent && NEXT_HASH_COLON == parent->next) {
|
622
|
-
|
681
|
+
parent->next = NEXT_HASH_VALUE;
|
623
682
|
} else {
|
624
|
-
|
683
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
|
625
684
|
}
|
626
685
|
}
|
627
686
|
|
628
|
-
void
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
long start = 0;
|
687
|
+
void oj_sparse2(ParseInfo pi) {
|
688
|
+
int first = 1;
|
689
|
+
char c;
|
690
|
+
long start = 0;
|
633
691
|
|
634
692
|
err_init(&pi->err);
|
635
693
|
while (1) {
|
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
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
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
|
+
}
|
782
848
|
}
|
783
849
|
}
|
784
850
|
|
785
|
-
static VALUE
|
786
|
-
protect_parse(VALUE pip) {
|
851
|
+
static VALUE protect_parse(VALUE pip) {
|
787
852
|
oj_sparse2((ParseInfo)pip);
|
788
853
|
|
789
854
|
return Qnil;
|
@@ -791,46 +856,47 @@ protect_parse(VALUE pip) {
|
|
791
856
|
|
792
857
|
VALUE
|
793
858
|
oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
|
794
|
-
volatile VALUE
|
795
|
-
volatile VALUE
|
796
|
-
VALUE
|
797
|
-
int
|
859
|
+
volatile VALUE input;
|
860
|
+
volatile VALUE wrapped_stack;
|
861
|
+
VALUE result = Qnil;
|
862
|
+
int line = 0;
|
798
863
|
|
799
864
|
if (argc < 1) {
|
800
|
-
|
865
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
801
866
|
}
|
802
867
|
input = argv[0];
|
803
868
|
if (2 <= argc) {
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
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
|
+
}
|
809
874
|
}
|
810
875
|
if (Qnil == input) {
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
} else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) &&
|
817
|
-
|
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.");
|
818
884
|
}
|
819
885
|
if (rb_block_given_p()) {
|
820
|
-
|
886
|
+
pi->proc = Qnil;
|
821
887
|
} else {
|
822
|
-
|
888
|
+
pi->proc = Qundef;
|
823
889
|
}
|
824
890
|
oj_reader_init(&pi->rd, input, fd, CompatMode == pi->options.mode);
|
825
|
-
pi->json = 0;
|
891
|
+
pi->json = 0; // indicates reader is in use
|
826
892
|
|
827
893
|
if (Yes == pi->options.circular) {
|
828
|
-
|
894
|
+
pi->circ_array = oj_circ_array_new();
|
829
895
|
} else {
|
830
|
-
|
896
|
+
pi->circ_array = 0;
|
831
897
|
}
|
832
898
|
if (No == pi->options.allow_gc) {
|
833
|
-
|
899
|
+
rb_gc_disable();
|
834
900
|
}
|
835
901
|
// GC can run at any time. When it runs any Object created by C will be
|
836
902
|
// freed. We protect against this by wrapping the value stack in a ruby
|
@@ -839,81 +905,80 @@ oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
|
|
839
905
|
wrapped_stack = oj_stack_init(&pi->stack);
|
840
906
|
rb_protect(protect_parse, (VALUE)pi, &line);
|
841
907
|
if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
|
842
|
-
|
908
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Empty input");
|
843
909
|
}
|
844
|
-
result
|
910
|
+
result = stack_head_val(&pi->stack);
|
845
911
|
DATA_PTR(wrapped_stack) = 0;
|
846
912
|
if (No == pi->options.allow_gc) {
|
847
|
-
|
913
|
+
rb_gc_enable();
|
848
914
|
}
|
849
915
|
if (!err_has(&pi->err)) {
|
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
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
}
|
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
|
+
}
|
883
948
|
}
|
884
949
|
CLEANUP:
|
885
950
|
// proceed with cleanup
|
886
951
|
if (0 != pi->circ_array) {
|
887
|
-
|
952
|
+
oj_circ_array_free(pi->circ_array);
|
888
953
|
}
|
889
954
|
stack_cleanup(&pi->stack);
|
890
955
|
if (0 != fd) {
|
891
|
-
|
956
|
+
close(fd);
|
892
957
|
}
|
893
958
|
if (err_has(&pi->err)) {
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
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);
|
915
980
|
} else if (0 != line) {
|
916
|
-
|
981
|
+
rb_jump_tag(line);
|
917
982
|
}
|
918
983
|
return result;
|
919
984
|
}
|