oj 3.7.12
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +96 -0
- data/ext/oj/buf.h +103 -0
- data/ext/oj/cache8.c +107 -0
- data/ext/oj/cache8.h +48 -0
- data/ext/oj/circarray.c +68 -0
- data/ext/oj/circarray.h +23 -0
- data/ext/oj/code.c +235 -0
- data/ext/oj/code.h +42 -0
- data/ext/oj/compat.c +299 -0
- data/ext/oj/custom.c +1188 -0
- data/ext/oj/dump.c +1232 -0
- data/ext/oj/dump.h +94 -0
- data/ext/oj/dump_compat.c +973 -0
- data/ext/oj/dump_leaf.c +252 -0
- data/ext/oj/dump_object.c +837 -0
- data/ext/oj/dump_strict.c +433 -0
- data/ext/oj/encode.h +45 -0
- data/ext/oj/err.c +57 -0
- data/ext/oj/err.h +70 -0
- data/ext/oj/extconf.rb +47 -0
- data/ext/oj/fast.c +1771 -0
- data/ext/oj/hash.c +163 -0
- data/ext/oj/hash.h +46 -0
- data/ext/oj/hash_test.c +512 -0
- data/ext/oj/mimic_json.c +873 -0
- data/ext/oj/object.c +771 -0
- data/ext/oj/odd.c +231 -0
- data/ext/oj/odd.h +44 -0
- data/ext/oj/oj.c +1694 -0
- data/ext/oj/oj.h +381 -0
- data/ext/oj/parse.c +1085 -0
- data/ext/oj/parse.h +111 -0
- data/ext/oj/rails.c +1485 -0
- data/ext/oj/rails.h +21 -0
- data/ext/oj/reader.c +231 -0
- data/ext/oj/reader.h +151 -0
- data/ext/oj/resolve.c +102 -0
- data/ext/oj/resolve.h +14 -0
- data/ext/oj/rxclass.c +147 -0
- data/ext/oj/rxclass.h +27 -0
- data/ext/oj/saj.c +714 -0
- data/ext/oj/scp.c +224 -0
- data/ext/oj/sparse.c +910 -0
- data/ext/oj/stream_writer.c +363 -0
- data/ext/oj/strict.c +212 -0
- data/ext/oj/string_writer.c +512 -0
- data/ext/oj/trace.c +79 -0
- data/ext/oj/trace.h +28 -0
- data/ext/oj/util.c +136 -0
- data/ext/oj/util.h +19 -0
- data/ext/oj/val_stack.c +118 -0
- data/ext/oj/val_stack.h +185 -0
- data/ext/oj/wab.c +631 -0
- data/lib/oj.rb +21 -0
- data/lib/oj/active_support_helper.rb +41 -0
- data/lib/oj/bag.rb +88 -0
- data/lib/oj/easy_hash.rb +52 -0
- data/lib/oj/error.rb +22 -0
- data/lib/oj/json.rb +176 -0
- data/lib/oj/mimic.rb +267 -0
- data/lib/oj/saj.rb +66 -0
- data/lib/oj/schandler.rb +142 -0
- data/lib/oj/state.rb +131 -0
- data/lib/oj/version.rb +5 -0
- data/pages/Advanced.md +22 -0
- data/pages/Compatibility.md +25 -0
- data/pages/Custom.md +23 -0
- data/pages/Encoding.md +65 -0
- data/pages/JsonGem.md +79 -0
- data/pages/Modes.md +154 -0
- data/pages/Options.md +266 -0
- data/pages/Rails.md +116 -0
- data/pages/Security.md +20 -0
- data/pages/WAB.md +13 -0
- data/test/_test_active.rb +76 -0
- data/test/_test_active_mimic.rb +96 -0
- data/test/_test_mimic_rails.rb +126 -0
- data/test/activerecord/result_test.rb +27 -0
- data/test/activesupport4/decoding_test.rb +108 -0
- data/test/activesupport4/encoding_test.rb +531 -0
- data/test/activesupport4/test_helper.rb +41 -0
- data/test/activesupport5/decoding_test.rb +125 -0
- data/test/activesupport5/encoding_test.rb +485 -0
- data/test/activesupport5/encoding_test_cases.rb +90 -0
- data/test/activesupport5/test_helper.rb +50 -0
- data/test/activesupport5/time_zone_test_helpers.rb +24 -0
- data/test/big.rb +15 -0
- data/test/files.rb +29 -0
- data/test/foo.rb +33 -0
- data/test/helper.rb +26 -0
- data/test/isolated/shared.rb +308 -0
- data/test/isolated/test_mimic_after.rb +13 -0
- data/test/isolated/test_mimic_alone.rb +12 -0
- data/test/isolated/test_mimic_as_json.rb +45 -0
- data/test/isolated/test_mimic_before.rb +13 -0
- data/test/isolated/test_mimic_define.rb +28 -0
- data/test/isolated/test_mimic_rails_after.rb +22 -0
- data/test/isolated/test_mimic_rails_before.rb +21 -0
- data/test/isolated/test_mimic_redefine.rb +15 -0
- data/test/json_gem/json_addition_test.rb +216 -0
- data/test/json_gem/json_common_interface_test.rb +148 -0
- data/test/json_gem/json_encoding_test.rb +107 -0
- data/test/json_gem/json_ext_parser_test.rb +20 -0
- data/test/json_gem/json_fixtures_test.rb +35 -0
- data/test/json_gem/json_generator_test.rb +383 -0
- data/test/json_gem/json_generic_object_test.rb +90 -0
- data/test/json_gem/json_parser_test.rb +470 -0
- data/test/json_gem/json_string_matching_test.rb +42 -0
- data/test/json_gem/test_helper.rb +18 -0
- data/test/mem.rb +35 -0
- data/test/perf.rb +107 -0
- data/test/perf_compat.rb +130 -0
- data/test/perf_fast.rb +164 -0
- data/test/perf_file.rb +64 -0
- data/test/perf_object.rb +138 -0
- data/test/perf_saj.rb +109 -0
- data/test/perf_scp.rb +151 -0
- data/test/perf_simple.rb +287 -0
- data/test/perf_strict.rb +145 -0
- data/test/perf_wab.rb +131 -0
- data/test/sample.rb +54 -0
- data/test/sample/change.rb +14 -0
- data/test/sample/dir.rb +19 -0
- data/test/sample/doc.rb +36 -0
- data/test/sample/file.rb +48 -0
- data/test/sample/group.rb +16 -0
- data/test/sample/hasprops.rb +16 -0
- data/test/sample/layer.rb +12 -0
- data/test/sample/line.rb +20 -0
- data/test/sample/oval.rb +10 -0
- data/test/sample/rect.rb +10 -0
- data/test/sample/shape.rb +35 -0
- data/test/sample/text.rb +20 -0
- data/test/sample_json.rb +37 -0
- data/test/test_compat.rb +509 -0
- data/test/test_custom.rb +406 -0
- data/test/test_debian.rb +53 -0
- data/test/test_fast.rb +470 -0
- data/test/test_file.rb +239 -0
- data/test/test_gc.rb +49 -0
- data/test/test_hash.rb +29 -0
- data/test/test_integer_range.rb +73 -0
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +1018 -0
- data/test/test_saj.rb +186 -0
- data/test/test_scp.rb +433 -0
- data/test/test_strict.rb +410 -0
- data/test/test_various.rb +739 -0
- data/test/test_wab.rb +307 -0
- data/test/test_writer.rb +380 -0
- data/test/tests.rb +24 -0
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- metadata +359 -0
data/ext/oj/object.c
ADDED
|
@@ -0,0 +1,771 @@
|
|
|
1
|
+
/* object.c
|
|
2
|
+
* Copyright (c) 2012, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include <stdint.h>
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <time.h>
|
|
9
|
+
|
|
10
|
+
#include "oj.h"
|
|
11
|
+
#include "err.h"
|
|
12
|
+
#include "parse.h"
|
|
13
|
+
#include "resolve.h"
|
|
14
|
+
#include "hash.h"
|
|
15
|
+
#include "odd.h"
|
|
16
|
+
#include "encode.h"
|
|
17
|
+
#include "trace.h"
|
|
18
|
+
#include "util.h"
|
|
19
|
+
|
|
20
|
+
inline static long
|
|
21
|
+
read_long(const char *str, size_t len) {
|
|
22
|
+
long n = 0;
|
|
23
|
+
|
|
24
|
+
for (; 0 < len; str++, len--) {
|
|
25
|
+
if ('0' <= *str && *str <= '9') {
|
|
26
|
+
n = n * 10 + (*str - '0');
|
|
27
|
+
} else {
|
|
28
|
+
return -1;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return n;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static VALUE
|
|
35
|
+
calc_hash_key(ParseInfo pi, Val kval, char k1) {
|
|
36
|
+
volatile VALUE rkey;
|
|
37
|
+
|
|
38
|
+
if (':' == k1) {
|
|
39
|
+
rkey = rb_str_new(kval->key + 1, kval->klen - 1);
|
|
40
|
+
rkey = oj_encode(rkey);
|
|
41
|
+
rkey = rb_funcall(rkey, oj_to_sym_id, 0);
|
|
42
|
+
} else {
|
|
43
|
+
rkey = rb_str_new(kval->key, kval->klen);
|
|
44
|
+
rkey = oj_encode(rkey);
|
|
45
|
+
if (Yes == pi->options.sym_key) {
|
|
46
|
+
rkey = rb_str_intern(rkey);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return rkey;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static VALUE
|
|
53
|
+
str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
54
|
+
volatile VALUE rstr = Qnil;
|
|
55
|
+
|
|
56
|
+
if (':' == *orig && 0 < len) {
|
|
57
|
+
rstr = rb_str_new(str + 1, len - 1);
|
|
58
|
+
rstr = oj_encode(rstr);
|
|
59
|
+
rstr = rb_funcall(rstr, oj_to_sym_id, 0);
|
|
60
|
+
} else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
|
|
61
|
+
long i = read_long(str + 2, len - 2);
|
|
62
|
+
|
|
63
|
+
if (0 > i) {
|
|
64
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a valid ID number");
|
|
65
|
+
return Qnil;
|
|
66
|
+
}
|
|
67
|
+
rstr = oj_circ_array_get(pi->circ_array, i);
|
|
68
|
+
} else {
|
|
69
|
+
rstr = rb_str_new(str, len);
|
|
70
|
+
rstr = oj_encode(rstr);
|
|
71
|
+
}
|
|
72
|
+
return rstr;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#if (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
|
|
76
|
+
static VALUE
|
|
77
|
+
oj_parse_xml_time(const char *str, int len) {
|
|
78
|
+
return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(str, len));
|
|
79
|
+
}
|
|
80
|
+
#else
|
|
81
|
+
// The much faster approach (4x faster)
|
|
82
|
+
static int
|
|
83
|
+
parse_num(const char *str, const char *end, int cnt) {
|
|
84
|
+
int n = 0;
|
|
85
|
+
char c;
|
|
86
|
+
int i;
|
|
87
|
+
|
|
88
|
+
for (i = cnt; 0 < i; i--, str++) {
|
|
89
|
+
c = *str;
|
|
90
|
+
if (end <= str || c < '0' || '9' < c) {
|
|
91
|
+
return -1;
|
|
92
|
+
}
|
|
93
|
+
n = n * 10 + (c - '0');
|
|
94
|
+
}
|
|
95
|
+
return n;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
VALUE
|
|
99
|
+
oj_parse_xml_time(const char *str, int len) {
|
|
100
|
+
VALUE args[8];
|
|
101
|
+
const char *end = str + len;
|
|
102
|
+
int n;
|
|
103
|
+
|
|
104
|
+
// year
|
|
105
|
+
if (0 > (n = parse_num(str, end, 4))) {
|
|
106
|
+
return Qnil;
|
|
107
|
+
}
|
|
108
|
+
str += 4;
|
|
109
|
+
args[0] = LONG2NUM(n);
|
|
110
|
+
if ('-' != *str++) {
|
|
111
|
+
return Qnil;
|
|
112
|
+
}
|
|
113
|
+
// month
|
|
114
|
+
if (0 > (n = parse_num(str, end, 2))) {
|
|
115
|
+
return Qnil;
|
|
116
|
+
}
|
|
117
|
+
str += 2;
|
|
118
|
+
args[1] = LONG2NUM(n);
|
|
119
|
+
if ('-' != *str++) {
|
|
120
|
+
return Qnil;
|
|
121
|
+
}
|
|
122
|
+
// day
|
|
123
|
+
if (0 > (n = parse_num(str, end, 2))) {
|
|
124
|
+
return Qnil;
|
|
125
|
+
}
|
|
126
|
+
str += 2;
|
|
127
|
+
args[2] = LONG2NUM(n);
|
|
128
|
+
if ('T' != *str++) {
|
|
129
|
+
return Qnil;
|
|
130
|
+
}
|
|
131
|
+
// hour
|
|
132
|
+
if (0 > (n = parse_num(str, end, 2))) {
|
|
133
|
+
return Qnil;
|
|
134
|
+
}
|
|
135
|
+
str += 2;
|
|
136
|
+
args[3] = LONG2NUM(n);
|
|
137
|
+
if (':' != *str++) {
|
|
138
|
+
return Qnil;
|
|
139
|
+
}
|
|
140
|
+
// minute
|
|
141
|
+
if (0 > (n = parse_num(str, end, 2))) {
|
|
142
|
+
return Qnil;
|
|
143
|
+
}
|
|
144
|
+
str += 2;
|
|
145
|
+
args[4] = LONG2NUM(n);
|
|
146
|
+
if (':' != *str++) {
|
|
147
|
+
return Qnil;
|
|
148
|
+
}
|
|
149
|
+
// second
|
|
150
|
+
if (0 > (n = parse_num(str, end, 2))) {
|
|
151
|
+
return Qnil;
|
|
152
|
+
}
|
|
153
|
+
str += 2;
|
|
154
|
+
if (str == end) {
|
|
155
|
+
args[5] = LONG2NUM(n);
|
|
156
|
+
args[6] = LONG2NUM(0);
|
|
157
|
+
} else {
|
|
158
|
+
char c = *str++;
|
|
159
|
+
|
|
160
|
+
if ('.' == c) {
|
|
161
|
+
long long nsec = 0;
|
|
162
|
+
|
|
163
|
+
for (; str < end; str++) {
|
|
164
|
+
c = *str;
|
|
165
|
+
if (c < '0' || '9' < c) {
|
|
166
|
+
str++;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
nsec = nsec * 10 + (c - '0');
|
|
170
|
+
}
|
|
171
|
+
args[5] = rb_float_new((double)n + ((double)nsec + 0.5) / 1000000000.0);
|
|
172
|
+
} else {
|
|
173
|
+
args[5] = rb_ll2inum(n);
|
|
174
|
+
}
|
|
175
|
+
if (end < str) {
|
|
176
|
+
args[6] = LONG2NUM(0);
|
|
177
|
+
} else {
|
|
178
|
+
if ('Z' == c) {
|
|
179
|
+
return rb_funcall2(rb_cTime, oj_utc_id, 6, args);
|
|
180
|
+
} else if ('+' == c) {
|
|
181
|
+
int hr = parse_num(str, end, 2);
|
|
182
|
+
int min;
|
|
183
|
+
|
|
184
|
+
str += 2;
|
|
185
|
+
if (0 > hr || ':' != *str++) {
|
|
186
|
+
return Qnil;
|
|
187
|
+
}
|
|
188
|
+
min = parse_num(str, end, 2);
|
|
189
|
+
if (0 > min) {
|
|
190
|
+
return Qnil;
|
|
191
|
+
}
|
|
192
|
+
args[6] = LONG2NUM(hr * 3600 + min * 60);
|
|
193
|
+
} else if ('-' == c) {
|
|
194
|
+
int hr = parse_num(str, end, 2);
|
|
195
|
+
int min;
|
|
196
|
+
|
|
197
|
+
str += 2;
|
|
198
|
+
if (0 > hr || ':' != *str++) {
|
|
199
|
+
return Qnil;
|
|
200
|
+
}
|
|
201
|
+
min = parse_num(str, end, 2);
|
|
202
|
+
if (0 > min) {
|
|
203
|
+
return Qnil;
|
|
204
|
+
}
|
|
205
|
+
args[6] = LONG2NUM(-(hr * 3600 + min * 60));
|
|
206
|
+
} else {
|
|
207
|
+
args[6] = LONG2NUM(0);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
|
212
|
+
}
|
|
213
|
+
#endif
|
|
214
|
+
|
|
215
|
+
static int
|
|
216
|
+
hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
|
|
217
|
+
const char *key = kval->key;
|
|
218
|
+
int klen = kval->klen;
|
|
219
|
+
|
|
220
|
+
if (2 == klen) {
|
|
221
|
+
switch (key[1]) {
|
|
222
|
+
case 'o': // object
|
|
223
|
+
{ // name2class sets an error if the class is not found or created
|
|
224
|
+
VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
|
|
225
|
+
|
|
226
|
+
if (Qundef != clas) {
|
|
227
|
+
parent->val = rb_obj_alloc(clas);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
break;
|
|
231
|
+
case 'O': // odd object
|
|
232
|
+
{
|
|
233
|
+
Odd odd = oj_get_oddc(str, len);
|
|
234
|
+
|
|
235
|
+
if (0 == odd) {
|
|
236
|
+
return 0;
|
|
237
|
+
}
|
|
238
|
+
parent->val = odd->clas;
|
|
239
|
+
parent->odd_args = oj_odd_alloc_args(odd);
|
|
240
|
+
}
|
|
241
|
+
break;
|
|
242
|
+
case 'm':
|
|
243
|
+
parent->val = rb_str_new(str + 1, len - 1);
|
|
244
|
+
parent->val = oj_encode(parent->val);
|
|
245
|
+
parent->val = rb_funcall(parent->val, oj_to_sym_id, 0);
|
|
246
|
+
break;
|
|
247
|
+
case 's':
|
|
248
|
+
parent->val = rb_str_new(str, len);
|
|
249
|
+
parent->val = oj_encode(parent->val);
|
|
250
|
+
break;
|
|
251
|
+
case 'c': // class
|
|
252
|
+
{
|
|
253
|
+
VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
|
|
254
|
+
|
|
255
|
+
if (Qundef == clas) {
|
|
256
|
+
return 0;
|
|
257
|
+
} else {
|
|
258
|
+
parent->val = clas;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
break;
|
|
262
|
+
case 't': // time
|
|
263
|
+
parent->val = oj_parse_xml_time(str, (int)len);
|
|
264
|
+
break;
|
|
265
|
+
default:
|
|
266
|
+
return 0;
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
return 1; // handled
|
|
270
|
+
}
|
|
271
|
+
return 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
static int
|
|
275
|
+
hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
276
|
+
if (2 == kval->klen) {
|
|
277
|
+
switch (kval->key[1]) {
|
|
278
|
+
case 't': // time as a float
|
|
279
|
+
{
|
|
280
|
+
int64_t nsec = ni->num * 1000000000LL / ni->div;
|
|
281
|
+
|
|
282
|
+
if (ni->neg) {
|
|
283
|
+
ni->i = -ni->i;
|
|
284
|
+
if (0 < nsec) {
|
|
285
|
+
ni->i--;
|
|
286
|
+
nsec = 1000000000LL - nsec;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
if (86400 == ni->exp) { // UTC time
|
|
290
|
+
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
|
291
|
+
// Since the ruby C routines alway create local time, the
|
|
292
|
+
// offset and then a conversion to UTC keeps makes the time
|
|
293
|
+
// match the expected value.
|
|
294
|
+
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
|
295
|
+
} else if (ni->hasExp) {
|
|
296
|
+
int64_t t = (int64_t)(ni->i + ni->exp);
|
|
297
|
+
struct _timeInfo ti;
|
|
298
|
+
VALUE args[8];
|
|
299
|
+
|
|
300
|
+
sec_as_time(t, &ti);
|
|
301
|
+
args[0] = LONG2NUM((long)(ti.year));
|
|
302
|
+
args[1] = LONG2NUM(ti.mon);
|
|
303
|
+
args[2] = LONG2NUM(ti.day);
|
|
304
|
+
args[3] = LONG2NUM(ti.hour);
|
|
305
|
+
args[4] = LONG2NUM(ti.min);
|
|
306
|
+
args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
|
|
307
|
+
args[6] = LONG2NUM(ni->exp);
|
|
308
|
+
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
|
309
|
+
} else {
|
|
310
|
+
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
break;
|
|
314
|
+
case 'i': // circular index
|
|
315
|
+
if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
|
|
316
|
+
if (Qnil == parent->val) {
|
|
317
|
+
parent->val = rb_hash_new();
|
|
318
|
+
}
|
|
319
|
+
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
|
320
|
+
} else {
|
|
321
|
+
return 0;
|
|
322
|
+
}
|
|
323
|
+
break;
|
|
324
|
+
default:
|
|
325
|
+
return 0;
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
return 1; // handled
|
|
329
|
+
}
|
|
330
|
+
return 0;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
static int
|
|
334
|
+
hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) {
|
|
335
|
+
if (T_ARRAY == rb_type(value)) {
|
|
336
|
+
int len = (int)RARRAY_LEN(value);
|
|
337
|
+
|
|
338
|
+
if (2 == klen && 'u' == key[1]) {
|
|
339
|
+
volatile VALUE sc;
|
|
340
|
+
volatile VALUE e1;
|
|
341
|
+
int slen;
|
|
342
|
+
|
|
343
|
+
if (0 == len) {
|
|
344
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
|
|
345
|
+
return 1;
|
|
346
|
+
}
|
|
347
|
+
e1 = *RARRAY_PTR(value);
|
|
348
|
+
// check for anonymous Struct
|
|
349
|
+
if (T_ARRAY == rb_type(e1)) {
|
|
350
|
+
VALUE args[1024];
|
|
351
|
+
volatile VALUE rstr;
|
|
352
|
+
int i, cnt = (int)RARRAY_LEN(e1);
|
|
353
|
+
|
|
354
|
+
for (i = 0; i < cnt; i++) {
|
|
355
|
+
rstr = rb_ary_entry(e1, i);
|
|
356
|
+
args[i] = rb_funcall(rstr, oj_to_sym_id, 0);
|
|
357
|
+
}
|
|
358
|
+
sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args);
|
|
359
|
+
} else {
|
|
360
|
+
// If struct is not defined then we let this fail and raise an exception.
|
|
361
|
+
sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
|
|
362
|
+
}
|
|
363
|
+
// Create a properly initialized struct instance without calling the initialize method.
|
|
364
|
+
parent->val = rb_obj_alloc(sc);
|
|
365
|
+
// If the JSON array has more entries than the struct class allows, we record an error.
|
|
366
|
+
#ifdef RSTRUCT_LEN
|
|
367
|
+
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
368
|
+
slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
|
|
369
|
+
#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
370
|
+
slen = (int)RSTRUCT_LEN(parent->val);
|
|
371
|
+
#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
372
|
+
#else
|
|
373
|
+
slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
|
|
374
|
+
#endif
|
|
375
|
+
// MRI >= 1.9
|
|
376
|
+
if (len - 1 > slen) {
|
|
377
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
|
|
378
|
+
} else {
|
|
379
|
+
int i;
|
|
380
|
+
|
|
381
|
+
for (i = 0; i < len - 1; i++) {
|
|
382
|
+
rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return 1;
|
|
386
|
+
} else if (3 <= klen && '#' == key[1]) {
|
|
387
|
+
volatile VALUE *a;
|
|
388
|
+
|
|
389
|
+
if (2 != len) {
|
|
390
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
|
391
|
+
return 1;
|
|
392
|
+
}
|
|
393
|
+
parent->val = rb_hash_new();
|
|
394
|
+
a = RARRAY_PTR(value);
|
|
395
|
+
rb_hash_aset(parent->val, *a, a[1]);
|
|
396
|
+
|
|
397
|
+
return 1;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return 0;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
void
|
|
404
|
+
oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
|
405
|
+
const char *key = kval->key;
|
|
406
|
+
int klen = kval->klen;
|
|
407
|
+
ID var_id;
|
|
408
|
+
ID *slot;
|
|
409
|
+
|
|
410
|
+
#if HAVE_LIBPTHREAD
|
|
411
|
+
pthread_mutex_lock(&oj_cache_mutex);
|
|
412
|
+
#else
|
|
413
|
+
rb_mutex_lock(oj_cache_mutex);
|
|
414
|
+
#endif
|
|
415
|
+
if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
|
|
416
|
+
char attr[256];
|
|
417
|
+
|
|
418
|
+
if ((int)sizeof(attr) <= klen + 2) {
|
|
419
|
+
char *buf = ALLOC_N(char, klen + 2);
|
|
420
|
+
|
|
421
|
+
if ('~' == *key) {
|
|
422
|
+
strncpy(buf, key + 1, klen - 1);
|
|
423
|
+
buf[klen - 1] = '\0';
|
|
424
|
+
} else {
|
|
425
|
+
*buf = '@';
|
|
426
|
+
strncpy(buf + 1, key, klen);
|
|
427
|
+
buf[klen + 1] = '\0';
|
|
428
|
+
}
|
|
429
|
+
var_id = rb_intern(buf);
|
|
430
|
+
xfree(buf);
|
|
431
|
+
} else {
|
|
432
|
+
if ('~' == *key) {
|
|
433
|
+
strncpy(attr, key + 1, klen - 1);
|
|
434
|
+
attr[klen - 1] = '\0';
|
|
435
|
+
} else {
|
|
436
|
+
*attr = '@';
|
|
437
|
+
strncpy(attr + 1, key, klen);
|
|
438
|
+
attr[klen + 1] = '\0';
|
|
439
|
+
}
|
|
440
|
+
var_id = rb_intern(attr);
|
|
441
|
+
}
|
|
442
|
+
*slot = var_id;
|
|
443
|
+
}
|
|
444
|
+
#if HAVE_LIBPTHREAD
|
|
445
|
+
pthread_mutex_unlock(&oj_cache_mutex);
|
|
446
|
+
#else
|
|
447
|
+
rb_mutex_unlock(oj_cache_mutex);
|
|
448
|
+
#endif
|
|
449
|
+
rb_ivar_set(parent->val, var_id, value);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
static void
|
|
453
|
+
hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
|
454
|
+
const char *key = kval->key;
|
|
455
|
+
int klen = kval->klen;
|
|
456
|
+
Val parent = stack_peek(&pi->stack);
|
|
457
|
+
volatile VALUE rval = Qnil;
|
|
458
|
+
|
|
459
|
+
WHICH_TYPE:
|
|
460
|
+
switch (rb_type(parent->val)) {
|
|
461
|
+
case T_NIL:
|
|
462
|
+
parent->odd_args = NULL; // make sure it is NULL in case not odd
|
|
463
|
+
if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) {
|
|
464
|
+
parent->val = rb_hash_new();
|
|
465
|
+
goto WHICH_TYPE;
|
|
466
|
+
}
|
|
467
|
+
break;
|
|
468
|
+
case T_HASH:
|
|
469
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
|
|
470
|
+
break;
|
|
471
|
+
case T_STRING:
|
|
472
|
+
rval = str_to_value(pi, str, len, orig);
|
|
473
|
+
if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
|
|
474
|
+
rb_funcall(parent->val, oj_replace_id, 1, rval);
|
|
475
|
+
} else {
|
|
476
|
+
oj_set_obj_ivar(parent, kval, rval);
|
|
477
|
+
}
|
|
478
|
+
break;
|
|
479
|
+
case T_OBJECT:
|
|
480
|
+
rval = str_to_value(pi, str, len, orig);
|
|
481
|
+
oj_set_obj_ivar(parent, kval, rval);
|
|
482
|
+
break;
|
|
483
|
+
case T_CLASS:
|
|
484
|
+
if (NULL == parent->odd_args) {
|
|
485
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
|
|
486
|
+
return;
|
|
487
|
+
} else {
|
|
488
|
+
rval = str_to_value(pi, str, len, orig);
|
|
489
|
+
if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) {
|
|
490
|
+
char buf[256];
|
|
491
|
+
|
|
492
|
+
if ((int)sizeof(buf) - 1 <= klen) {
|
|
493
|
+
klen = sizeof(buf) - 2;
|
|
494
|
+
}
|
|
495
|
+
memcpy(buf, key, klen);
|
|
496
|
+
buf[klen] = '\0';
|
|
497
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
break;
|
|
501
|
+
default:
|
|
502
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
if (Yes == pi->options.trace) {
|
|
506
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
static void
|
|
511
|
+
hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
|
512
|
+
const char *key = kval->key;
|
|
513
|
+
int klen = kval->klen;
|
|
514
|
+
Val parent = stack_peek(&pi->stack);
|
|
515
|
+
volatile VALUE rval = Qnil;
|
|
516
|
+
|
|
517
|
+
WHICH_TYPE:
|
|
518
|
+
switch (rb_type(parent->val)) {
|
|
519
|
+
case T_NIL:
|
|
520
|
+
parent->odd_args = NULL; // make sure it is NULL in case not odd
|
|
521
|
+
if ('^' != *key || !hat_num(pi, parent, kval, ni)) {
|
|
522
|
+
parent->val = rb_hash_new();
|
|
523
|
+
goto WHICH_TYPE;
|
|
524
|
+
}
|
|
525
|
+
break;
|
|
526
|
+
case T_HASH:
|
|
527
|
+
rval = oj_num_as_value(ni);
|
|
528
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
|
|
529
|
+
break;
|
|
530
|
+
case T_OBJECT:
|
|
531
|
+
if (2 == klen && '^' == *key && 'i' == key[1] &&
|
|
532
|
+
!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
|
|
533
|
+
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
|
534
|
+
} else {
|
|
535
|
+
rval = oj_num_as_value(ni);
|
|
536
|
+
oj_set_obj_ivar(parent, kval, rval);
|
|
537
|
+
}
|
|
538
|
+
break;
|
|
539
|
+
case T_CLASS:
|
|
540
|
+
if (NULL == parent->odd_args) {
|
|
541
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
|
|
542
|
+
return;
|
|
543
|
+
} else {
|
|
544
|
+
rval = oj_num_as_value(ni);
|
|
545
|
+
if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) {
|
|
546
|
+
char buf[256];
|
|
547
|
+
|
|
548
|
+
if ((int)sizeof(buf) - 1 <= klen) {
|
|
549
|
+
klen = sizeof(buf) - 2;
|
|
550
|
+
}
|
|
551
|
+
memcpy(buf, key, klen);
|
|
552
|
+
buf[klen] = '\0';
|
|
553
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
break;
|
|
557
|
+
default:
|
|
558
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
if (Yes == pi->options.trace) {
|
|
562
|
+
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
static void
|
|
567
|
+
hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
|
568
|
+
const char *key = kval->key;
|
|
569
|
+
int klen = kval->klen;
|
|
570
|
+
Val parent = stack_peek(&pi->stack);
|
|
571
|
+
|
|
572
|
+
WHICH_TYPE:
|
|
573
|
+
switch (rb_type(parent->val)) {
|
|
574
|
+
case T_NIL:
|
|
575
|
+
parent->odd_args = NULL; // make sure it is NULL in case not odd
|
|
576
|
+
if ('^' != *key || !hat_value(pi, parent, key, klen, value)) {
|
|
577
|
+
parent->val = rb_hash_new();
|
|
578
|
+
goto WHICH_TYPE;
|
|
579
|
+
}
|
|
580
|
+
break;
|
|
581
|
+
case T_HASH:
|
|
582
|
+
if (rb_cHash != rb_obj_class(parent->val)) {
|
|
583
|
+
if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
|
|
584
|
+
rb_funcall(parent->val, oj_replace_id, 1, value);
|
|
585
|
+
} else {
|
|
586
|
+
oj_set_obj_ivar(parent, kval, value);
|
|
587
|
+
}
|
|
588
|
+
} else {
|
|
589
|
+
if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
|
|
590
|
+
long len = RARRAY_LEN(value);
|
|
591
|
+
volatile VALUE *a = RARRAY_PTR(value);
|
|
592
|
+
|
|
593
|
+
if (2 != len) {
|
|
594
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
rb_hash_aset(parent->val, *a, a[1]);
|
|
598
|
+
} else {
|
|
599
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), value);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
break;
|
|
603
|
+
case T_ARRAY:
|
|
604
|
+
if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
|
|
605
|
+
rb_funcall(parent->val, oj_replace_id, 1, value);
|
|
606
|
+
} else {
|
|
607
|
+
oj_set_obj_ivar(parent, kval, value);
|
|
608
|
+
}
|
|
609
|
+
break;
|
|
610
|
+
case T_STRING: // for subclassed strings
|
|
611
|
+
case T_OBJECT:
|
|
612
|
+
oj_set_obj_ivar(parent, kval, value);
|
|
613
|
+
break;
|
|
614
|
+
case T_MODULE:
|
|
615
|
+
case T_CLASS:
|
|
616
|
+
if (NULL == parent->odd_args) {
|
|
617
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
|
|
618
|
+
return;
|
|
619
|
+
} else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
|
|
620
|
+
char buf[256];
|
|
621
|
+
|
|
622
|
+
if ((int)sizeof(buf) - 1 <= klen) {
|
|
623
|
+
klen = sizeof(buf) - 2;
|
|
624
|
+
}
|
|
625
|
+
memcpy(buf, key, klen);
|
|
626
|
+
buf[klen] = '\0';
|
|
627
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
|
|
628
|
+
}
|
|
629
|
+
break;
|
|
630
|
+
default:
|
|
631
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
if (Yes == pi->options.trace) {
|
|
635
|
+
oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
static VALUE
|
|
640
|
+
start_hash(ParseInfo pi) {
|
|
641
|
+
if (Yes == pi->options.trace) {
|
|
642
|
+
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
|
643
|
+
}
|
|
644
|
+
return Qnil;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
static void
|
|
648
|
+
end_hash(ParseInfo pi) {
|
|
649
|
+
Val parent = stack_peek(&pi->stack);
|
|
650
|
+
|
|
651
|
+
if (Qnil == parent->val) {
|
|
652
|
+
parent->val = rb_hash_new();
|
|
653
|
+
} else if (NULL != parent->odd_args) {
|
|
654
|
+
OddArgs oa = parent->odd_args;
|
|
655
|
+
|
|
656
|
+
parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
|
|
657
|
+
oj_odd_free(oa);
|
|
658
|
+
parent->odd_args = NULL;
|
|
659
|
+
}
|
|
660
|
+
if (Yes == pi->options.trace) {
|
|
661
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
static void
|
|
666
|
+
array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
667
|
+
volatile VALUE rval = Qnil;
|
|
668
|
+
|
|
669
|
+
if (3 <= len && 0 != pi->circ_array) {
|
|
670
|
+
if ('i' == str[1]) {
|
|
671
|
+
long i = read_long(str + 2, len - 2);
|
|
672
|
+
|
|
673
|
+
if (0 < i) {
|
|
674
|
+
oj_circ_array_set(pi->circ_array, stack_peek(&pi->stack)->val, i);
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
} else if ('r' == str[1]) {
|
|
678
|
+
long i = read_long(str + 2, len - 2);
|
|
679
|
+
|
|
680
|
+
if (0 < i) {
|
|
681
|
+
rb_ary_push(stack_peek(&pi->stack)->val, oj_circ_array_get(pi->circ_array, i));
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
rval = str_to_value(pi, str, len, orig);
|
|
688
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
|
689
|
+
if (Yes == pi->options.trace) {
|
|
690
|
+
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
static void
|
|
695
|
+
array_append_num(ParseInfo pi, NumInfo ni) {
|
|
696
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
|
697
|
+
|
|
698
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
|
699
|
+
if (Yes == pi->options.trace) {
|
|
700
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
static void
|
|
705
|
+
add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
706
|
+
pi->stack.head->val = str_to_value(pi, str, len, orig);
|
|
707
|
+
if (Yes == pi->options.trace) {
|
|
708
|
+
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
static void
|
|
713
|
+
add_num(ParseInfo pi, NumInfo ni) {
|
|
714
|
+
pi->stack.head->val = oj_num_as_value(ni);
|
|
715
|
+
if (Yes == pi->options.trace) {
|
|
716
|
+
oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
void
|
|
721
|
+
oj_set_object_callbacks(ParseInfo pi) {
|
|
722
|
+
oj_set_strict_callbacks(pi);
|
|
723
|
+
pi->end_hash = end_hash;
|
|
724
|
+
pi->start_hash = start_hash;
|
|
725
|
+
pi->hash_set_cstr = hash_set_cstr;
|
|
726
|
+
pi->hash_set_num = hash_set_num;
|
|
727
|
+
pi->hash_set_value = hash_set_value;
|
|
728
|
+
pi->add_cstr = add_cstr;
|
|
729
|
+
pi->add_num = add_num;
|
|
730
|
+
pi->array_append_cstr = array_append_cstr;
|
|
731
|
+
pi->array_append_num = array_append_num;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
VALUE
|
|
735
|
+
oj_object_parse(int argc, VALUE *argv, VALUE self) {
|
|
736
|
+
struct _parseInfo pi;
|
|
737
|
+
|
|
738
|
+
parse_info_init(&pi);
|
|
739
|
+
pi.options = oj_default_options;
|
|
740
|
+
pi.handler = Qnil;
|
|
741
|
+
pi.err_class = Qnil;
|
|
742
|
+
oj_set_object_callbacks(&pi);
|
|
743
|
+
|
|
744
|
+
if (T_STRING == rb_type(*argv)) {
|
|
745
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
|
|
746
|
+
} else {
|
|
747
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
VALUE
|
|
752
|
+
oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
|
753
|
+
struct _parseInfo pi;
|
|
754
|
+
|
|
755
|
+
parse_info_init(&pi);
|
|
756
|
+
pi.options = oj_default_options;
|
|
757
|
+
pi.handler = Qnil;
|
|
758
|
+
pi.err_class = Qnil;
|
|
759
|
+
oj_set_strict_callbacks(&pi);
|
|
760
|
+
pi.end_hash = end_hash;
|
|
761
|
+
pi.start_hash = start_hash;
|
|
762
|
+
pi.hash_set_cstr = hash_set_cstr;
|
|
763
|
+
pi.hash_set_num = hash_set_num;
|
|
764
|
+
pi.hash_set_value = hash_set_value;
|
|
765
|
+
pi.add_cstr = add_cstr;
|
|
766
|
+
pi.add_num = add_num;
|
|
767
|
+
pi.array_append_cstr = array_append_cstr;
|
|
768
|
+
pi.array_append_num = array_append_num;
|
|
769
|
+
|
|
770
|
+
return oj_pi_parse(argc, argv, &pi, json, len, 1);
|
|
771
|
+
}
|