oj 2.0.14 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oj might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +47 -332
- data/ext/oj/buf.h +103 -0
- data/ext/oj/circarray.c +93 -0
- data/ext/oj/circarray.h +48 -0
- data/ext/oj/compat.c +112 -0
- data/ext/oj/dump.c +2 -1
- data/ext/oj/err.c +82 -0
- data/ext/oj/err.h +64 -0
- data/ext/oj/extconf.rb +1 -0
- data/ext/oj/hash.c +149 -0
- data/ext/oj/{cache.h → hash.h} +9 -10
- data/ext/oj/hash_test.c +501 -0
- data/ext/oj/object.c +514 -0
- data/ext/oj/odd.c +159 -0
- data/ext/oj/odd.h +61 -0
- data/ext/oj/oj.c +235 -305
- data/ext/oj/oj.h +18 -23
- data/ext/oj/parse.c +798 -0
- data/ext/oj/parse.h +88 -0
- data/ext/oj/resolve.c +117 -0
- data/ext/oj/resolve.h +38 -0
- data/ext/oj/saj.c +58 -86
- data/ext/oj/scp.c +308 -0
- data/ext/oj/strict.c +166 -0
- data/ext/oj/val_stack.c +48 -0
- data/ext/oj/val_stack.h +167 -0
- data/lib/oj.rb +1 -0
- data/lib/oj/saj.rb +11 -8
- data/lib/oj/schandler.rb +70 -0
- data/lib/oj/version.rb +1 -1
- data/test/bug.rb +14 -22
- data/test/perf_compat.rb +128 -0
- data/test/{perf_obj.rb → perf_object.rb} +18 -6
- data/test/perf_scp.rb +151 -0
- data/test/perf_strict.rb +23 -122
- data/test/sample.rb +2 -2
- data/test/test_compat.rb +342 -0
- data/test/test_object.rb +390 -0
- data/test/test_saj.rb +1 -1
- data/test/test_scp.rb +224 -0
- data/test/test_strict.rb +250 -0
- data/test/tests.rb +8 -18
- metadata +31 -10
- data/ext/oj/cache.c +0 -148
- data/ext/oj/load.c +0 -1089
- data/test/perf1.rb +0 -64
- data/test/perf2.rb +0 -76
- data/test/perf_obj_old.rb +0 -213
data/ext/oj/object.c
ADDED
@@ -0,0 +1,514 @@
|
|
1
|
+
/* object.c
|
2
|
+
* Copyright (c) 2012, Peter Ohler
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without
|
6
|
+
* modification, are permitted provided that the following conditions are met:
|
7
|
+
*
|
8
|
+
* - Redistributions of source code must retain the above copyright notice, this
|
9
|
+
* list of conditions and the following disclaimer.
|
10
|
+
*
|
11
|
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
12
|
+
* this list of conditions and the following disclaimer in the documentation
|
13
|
+
* and/or other materials provided with the distribution.
|
14
|
+
*
|
15
|
+
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
16
|
+
* used to endorse or promote products derived from this software without
|
17
|
+
* specific prior written permission.
|
18
|
+
*
|
19
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
*/
|
30
|
+
|
31
|
+
#include <stdio.h>
|
32
|
+
|
33
|
+
#include "oj.h"
|
34
|
+
#include "err.h"
|
35
|
+
#include "parse.h"
|
36
|
+
#include "resolve.h"
|
37
|
+
#include "hash.h"
|
38
|
+
#include "odd.h"
|
39
|
+
|
40
|
+
inline static long
|
41
|
+
read_long(const char *str, size_t len) {
|
42
|
+
long n = 0;
|
43
|
+
|
44
|
+
for (; 0 < len; str++, len--) {
|
45
|
+
if ('0' <= *str && *str <= '9') {
|
46
|
+
n = n * 10 + (*str - '0');
|
47
|
+
} else {
|
48
|
+
return -1;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
return n;
|
52
|
+
}
|
53
|
+
|
54
|
+
static VALUE
|
55
|
+
hash_key(ParseInfo pi, const char *key, size_t klen, char k1) {
|
56
|
+
VALUE rkey;
|
57
|
+
|
58
|
+
if (':' == k1) {
|
59
|
+
rkey = rb_str_new(key + 1, klen - 1);
|
60
|
+
#if HAS_ENCODING_SUPPORT
|
61
|
+
rb_enc_associate(rkey, oj_utf8_encoding);
|
62
|
+
#endif
|
63
|
+
rkey = rb_funcall(rkey, oj_to_sym_id, 0);
|
64
|
+
} else {
|
65
|
+
rkey = rb_str_new(key, klen);
|
66
|
+
|
67
|
+
#if HAS_ENCODING_SUPPORT
|
68
|
+
rb_enc_associate(rkey, oj_utf8_encoding);
|
69
|
+
#endif
|
70
|
+
if (Yes == pi->options.sym_key) {
|
71
|
+
rkey = rb_str_intern(rkey);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
return rkey;
|
75
|
+
}
|
76
|
+
|
77
|
+
static VALUE
|
78
|
+
str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
79
|
+
VALUE rstr = Qnil;
|
80
|
+
|
81
|
+
if (':' == *orig && 0 < len) {
|
82
|
+
rstr = rb_str_new(str + 1, len - 1);
|
83
|
+
#if HAS_ENCODING_SUPPORT
|
84
|
+
rb_enc_associate(rstr, oj_utf8_encoding);
|
85
|
+
#endif
|
86
|
+
rstr = rb_funcall(rstr, oj_to_sym_id, 0);
|
87
|
+
} else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
|
88
|
+
long i = read_long(str + 2, len - 2);
|
89
|
+
|
90
|
+
if (0 > i) {
|
91
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a valid ID number");
|
92
|
+
return Qnil;
|
93
|
+
}
|
94
|
+
rstr = oj_circ_array_get(pi->circ_array, i);
|
95
|
+
} else {
|
96
|
+
rstr = rb_str_new(str, len);
|
97
|
+
#if HAS_ENCODING_SUPPORT
|
98
|
+
rb_enc_associate(rstr, oj_utf8_encoding);
|
99
|
+
#endif
|
100
|
+
}
|
101
|
+
return rstr;
|
102
|
+
}
|
103
|
+
|
104
|
+
static int
|
105
|
+
hat_cstr(ParseInfo pi, Val parent, const char *key, size_t klen, const char *str, size_t len) {
|
106
|
+
if (2 == klen) {
|
107
|
+
switch (key[1]) {
|
108
|
+
case 'o': // object
|
109
|
+
{ // name2class sets and error if the class is not found or created
|
110
|
+
VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define);
|
111
|
+
|
112
|
+
if (Qundef != clas) {
|
113
|
+
parent->val = rb_obj_alloc(clas);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
break;
|
117
|
+
case 'O': // odd object
|
118
|
+
{
|
119
|
+
Odd odd = oj_get_oddc(str, len);
|
120
|
+
|
121
|
+
if (0 == odd) {
|
122
|
+
return 0;
|
123
|
+
}
|
124
|
+
parent->val = odd->clas;
|
125
|
+
parent->odd_args = oj_odd_alloc_args(odd);
|
126
|
+
}
|
127
|
+
break;
|
128
|
+
case 'm':
|
129
|
+
parent->val = rb_str_new(str + 1, len - 1);
|
130
|
+
#if HAS_ENCODING_SUPPORT
|
131
|
+
rb_enc_associate(parent->val, oj_utf8_encoding);
|
132
|
+
#endif
|
133
|
+
parent->val = rb_funcall(parent->val, oj_to_sym_id, 0);
|
134
|
+
break;
|
135
|
+
case 's':
|
136
|
+
parent->val = rb_str_new(str, len);
|
137
|
+
#if HAS_ENCODING_SUPPORT
|
138
|
+
rb_enc_associate(parent->val, oj_utf8_encoding);
|
139
|
+
#endif
|
140
|
+
break;
|
141
|
+
case 'c': // class
|
142
|
+
parent->val = oj_name2class(pi, str, len, Yes == pi->options.auto_define);
|
143
|
+
break;
|
144
|
+
default:
|
145
|
+
return 0;
|
146
|
+
break;
|
147
|
+
}
|
148
|
+
return 1; // handled
|
149
|
+
}
|
150
|
+
return 0;
|
151
|
+
}
|
152
|
+
|
153
|
+
static int
|
154
|
+
hat_num(ParseInfo pi, Val parent, const char *key, size_t klen, NumInfo ni) {
|
155
|
+
if (2 == klen) {
|
156
|
+
switch (key[1]) {
|
157
|
+
case 't': // time as a float
|
158
|
+
{
|
159
|
+
int64_t nsec = ni->num * 1000000000LL / ni->div;
|
160
|
+
|
161
|
+
if (ni->neg) {
|
162
|
+
ni->i = -ni->i;
|
163
|
+
if (0 < nsec) {
|
164
|
+
ni->i--;
|
165
|
+
nsec = 1000000000LL - nsec;
|
166
|
+
}
|
167
|
+
}
|
168
|
+
#if HAS_NANO_TIME
|
169
|
+
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
170
|
+
#else
|
171
|
+
parent->val = rb_time_new(ni->i, (long)(nsec / 1000));
|
172
|
+
#endif
|
173
|
+
}
|
174
|
+
break;
|
175
|
+
case 'i': // circular index
|
176
|
+
if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
|
177
|
+
if (Qnil == parent->val) {
|
178
|
+
parent->val = rb_hash_new();
|
179
|
+
}
|
180
|
+
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
181
|
+
} else {
|
182
|
+
return 0;
|
183
|
+
}
|
184
|
+
break;
|
185
|
+
default:
|
186
|
+
return 0;
|
187
|
+
break;
|
188
|
+
}
|
189
|
+
return 1; // handled
|
190
|
+
}
|
191
|
+
return 0;
|
192
|
+
}
|
193
|
+
|
194
|
+
static int
|
195
|
+
hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, VALUE value) {
|
196
|
+
if (2 == klen && 'u' == key[1] && T_ARRAY == rb_type(value)) {
|
197
|
+
#if HAS_RSTRUCT
|
198
|
+
long len = RARRAY_LEN(value);
|
199
|
+
VALUE *a = RARRAY_PTR(value);
|
200
|
+
VALUE sc;
|
201
|
+
VALUE s;
|
202
|
+
VALUE *sv;
|
203
|
+
|
204
|
+
if (0 == len) {
|
205
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
|
206
|
+
return 1;
|
207
|
+
}
|
208
|
+
sc = rb_const_get(oj_struct_class, rb_to_id(*a));
|
209
|
+
//sc = rb_const_get(oj_struct_class, rb_intern_str(*a));
|
210
|
+
// use encoding as the indicator for Ruby 1.8.7 or 1.9.x
|
211
|
+
#if HAS_ENCODING_SUPPORT
|
212
|
+
s = rb_struct_alloc_noinit(sc);
|
213
|
+
#else
|
214
|
+
s = rb_struct_new(sc);
|
215
|
+
#endif
|
216
|
+
sv = RSTRUCT_PTR(s);
|
217
|
+
if (RSTRUCT_LEN(s) < len - 1) {
|
218
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Too many elements for Struct");
|
219
|
+
return 1;
|
220
|
+
}
|
221
|
+
for (a++; 0 < len; len--, a++, sv++) {
|
222
|
+
*sv = *a;
|
223
|
+
}
|
224
|
+
parent->val = s;
|
225
|
+
#else
|
226
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Ruby structs not supported with this version of Ruby");
|
227
|
+
#endif
|
228
|
+
return 1;
|
229
|
+
} else if (3 <= klen && '#' == key[1] && T_ARRAY == rb_type(value)) {
|
230
|
+
long len = RARRAY_LEN(value);
|
231
|
+
VALUE *a = RARRAY_PTR(value);
|
232
|
+
|
233
|
+
if (2 != len) {
|
234
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
235
|
+
return 1;
|
236
|
+
}
|
237
|
+
parent->val = rb_hash_new();
|
238
|
+
rb_hash_aset(parent->val, *a, a[1]);
|
239
|
+
return 1;
|
240
|
+
}
|
241
|
+
return 0;
|
242
|
+
}
|
243
|
+
|
244
|
+
static void
|
245
|
+
set_obj_ivar(Val parent, const char *key, size_t klen, VALUE value) {
|
246
|
+
ID var_id;
|
247
|
+
ID *slot;
|
248
|
+
|
249
|
+
if ('~' == *key && Qtrue == rb_obj_is_kind_of(parent->val, rb_eException)) {
|
250
|
+
if (5 == klen && 0 == strncmp("~mesg", key, klen)) {
|
251
|
+
VALUE args[1];
|
252
|
+
|
253
|
+
args[0] = value;
|
254
|
+
parent->val = rb_class_new_instance(1, args, rb_class_of(parent->val));
|
255
|
+
} else if (3 == klen && 0 == strncmp("~bt", key, klen)) {
|
256
|
+
rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
|
257
|
+
}
|
258
|
+
}
|
259
|
+
#if SAFE_CACHE
|
260
|
+
pthread_mutex_lock(&oj_cache_mutex);
|
261
|
+
#endif
|
262
|
+
if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
|
263
|
+
char attr[256];
|
264
|
+
|
265
|
+
if (sizeof(attr) <= klen + 2) {
|
266
|
+
char *buf = ALLOC_N(char, klen + 2);
|
267
|
+
|
268
|
+
if ('~' == *key) {
|
269
|
+
strncpy(buf, key + 1, klen - 1);
|
270
|
+
buf[klen - 1] = '\0';
|
271
|
+
} else {
|
272
|
+
*buf = '@';
|
273
|
+
strncpy(buf + 1, key, klen);
|
274
|
+
buf[klen + 1] = '\0';
|
275
|
+
}
|
276
|
+
var_id = rb_intern(buf);
|
277
|
+
xfree(buf);
|
278
|
+
} else {
|
279
|
+
if ('~' == *key) {
|
280
|
+
strncpy(attr, key + 1, klen - 1);
|
281
|
+
attr[klen - 1] = '\0';
|
282
|
+
} else {
|
283
|
+
*attr = '@';
|
284
|
+
strncpy(attr + 1, key, klen);
|
285
|
+
attr[klen + 1] = '\0';
|
286
|
+
}
|
287
|
+
var_id = rb_intern(attr);
|
288
|
+
}
|
289
|
+
*slot = var_id;
|
290
|
+
}
|
291
|
+
#if SAFE_CACHE
|
292
|
+
pthread_mutex_unlock(&oj_cache_mutex);
|
293
|
+
#endif
|
294
|
+
rb_ivar_set(parent->val, var_id, value);
|
295
|
+
}
|
296
|
+
|
297
|
+
static void
|
298
|
+
hash_set_cstr(ParseInfo pi, const char *key, size_t klen, const char *str, size_t len, const char *orig) {
|
299
|
+
Val parent = stack_peek(&pi->stack);
|
300
|
+
|
301
|
+
WHICH_TYPE:
|
302
|
+
switch (rb_type(parent->val)) {
|
303
|
+
case T_NIL:
|
304
|
+
parent->odd_args = 0; // make sure it is 0 in case not odd
|
305
|
+
if ('^' != *key || !hat_cstr(pi, parent, key, klen, str, len)) {
|
306
|
+
parent->val = rb_hash_new();
|
307
|
+
goto WHICH_TYPE;
|
308
|
+
}
|
309
|
+
break;
|
310
|
+
case T_HASH:
|
311
|
+
rb_hash_aset(parent->val, hash_key(pi, key, klen, parent->k1), str_to_value(pi, str, len, orig));
|
312
|
+
break;
|
313
|
+
case T_OBJECT:
|
314
|
+
set_obj_ivar(parent, key, klen, str_to_value(pi, str, len, orig));
|
315
|
+
break;
|
316
|
+
case T_CLASS:
|
317
|
+
if (0 == parent->odd_args) {
|
318
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
|
319
|
+
return;
|
320
|
+
} else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, str_to_value(pi, str, len, orig))) {
|
321
|
+
char buf[256];
|
322
|
+
|
323
|
+
if (sizeof(buf) - 1 <= klen) {
|
324
|
+
klen = sizeof(buf) - 2;
|
325
|
+
}
|
326
|
+
memcpy(buf, key, klen);
|
327
|
+
buf[klen] = '\0';
|
328
|
+
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)));
|
329
|
+
}
|
330
|
+
break;
|
331
|
+
default:
|
332
|
+
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)));
|
333
|
+
return;
|
334
|
+
}
|
335
|
+
}
|
336
|
+
|
337
|
+
static void
|
338
|
+
hash_set_num(ParseInfo pi, const char *key, size_t klen, NumInfo ni) {
|
339
|
+
Val parent = stack_peek(&pi->stack);
|
340
|
+
|
341
|
+
WHICH_TYPE:
|
342
|
+
switch (rb_type(parent->val)) {
|
343
|
+
case T_NIL:
|
344
|
+
parent->odd_args = 0; // make sure it is 0 in case not odd
|
345
|
+
if ('^' != *key || !hat_num(pi, parent, key, klen, ni)) {
|
346
|
+
parent->val = rb_hash_new();
|
347
|
+
goto WHICH_TYPE;
|
348
|
+
}
|
349
|
+
break;
|
350
|
+
case T_HASH:
|
351
|
+
rb_hash_aset(parent->val, hash_key(pi, key, klen, parent->k1), oj_num_as_value(ni));
|
352
|
+
break;
|
353
|
+
case T_OBJECT:
|
354
|
+
if (2 == klen && '^' == *key && 'i' == key[1] &&
|
355
|
+
!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
|
356
|
+
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
357
|
+
} else {
|
358
|
+
set_obj_ivar(parent, key, klen, oj_num_as_value(ni));
|
359
|
+
}
|
360
|
+
break;
|
361
|
+
case T_CLASS:
|
362
|
+
if (0 == parent->odd_args) {
|
363
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
|
364
|
+
return;
|
365
|
+
} else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, oj_num_as_value(ni))) {
|
366
|
+
char buf[256];
|
367
|
+
|
368
|
+
if (sizeof(buf) - 1 <= klen) {
|
369
|
+
klen = sizeof(buf) - 2;
|
370
|
+
}
|
371
|
+
memcpy(buf, key, klen);
|
372
|
+
buf[klen] = '\0';
|
373
|
+
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)));
|
374
|
+
}
|
375
|
+
break;
|
376
|
+
default:
|
377
|
+
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)));
|
378
|
+
return;
|
379
|
+
}
|
380
|
+
}
|
381
|
+
|
382
|
+
static void
|
383
|
+
hash_set_value(ParseInfo pi, const char *key, size_t klen, VALUE value) {
|
384
|
+
Val parent = stack_peek(&pi->stack);
|
385
|
+
|
386
|
+
WHICH_TYPE:
|
387
|
+
switch (rb_type(parent->val)) {
|
388
|
+
case T_NIL:
|
389
|
+
parent->odd_args = 0; // make sure it is 0 in case not odd
|
390
|
+
if ('^' != *key || !hat_value(pi, parent, key, klen, value)) {
|
391
|
+
parent->val = rb_hash_new();
|
392
|
+
goto WHICH_TYPE;
|
393
|
+
}
|
394
|
+
break;
|
395
|
+
case T_HASH:
|
396
|
+
if (3 <= klen && '#' == key[1] && T_ARRAY == rb_type(value)) {
|
397
|
+
long len = RARRAY_LEN(value);
|
398
|
+
VALUE *a = RARRAY_PTR(value);
|
399
|
+
|
400
|
+
if (2 != len) {
|
401
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
402
|
+
return;
|
403
|
+
}
|
404
|
+
rb_hash_aset(parent->val, *a, a[1]);
|
405
|
+
} else {
|
406
|
+
rb_hash_aset(parent->val, hash_key(pi, key, klen, parent->k1), value);
|
407
|
+
}
|
408
|
+
break;
|
409
|
+
case T_OBJECT:
|
410
|
+
set_obj_ivar(parent, key, klen, value);
|
411
|
+
break;
|
412
|
+
case T_CLASS:
|
413
|
+
if (0 == parent->odd_args) {
|
414
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
|
415
|
+
return;
|
416
|
+
} else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
|
417
|
+
char buf[256];
|
418
|
+
|
419
|
+
if (sizeof(buf) - 1 <= klen) {
|
420
|
+
klen = sizeof(buf) - 2;
|
421
|
+
}
|
422
|
+
memcpy(buf, key, klen);
|
423
|
+
buf[klen] = '\0';
|
424
|
+
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)));
|
425
|
+
}
|
426
|
+
break;
|
427
|
+
default:
|
428
|
+
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)));
|
429
|
+
return;
|
430
|
+
}
|
431
|
+
}
|
432
|
+
|
433
|
+
|
434
|
+
static VALUE
|
435
|
+
start_hash(ParseInfo pi) {
|
436
|
+
return Qnil;
|
437
|
+
}
|
438
|
+
|
439
|
+
static void
|
440
|
+
end_hash(struct _ParseInfo *pi) {
|
441
|
+
Val parent = stack_peek(&pi->stack);
|
442
|
+
|
443
|
+
if (Qnil == parent->val) {
|
444
|
+
parent->val = rb_hash_new();
|
445
|
+
} else if (0 != parent->odd_args) {
|
446
|
+
OddArgs oa = parent->odd_args;
|
447
|
+
|
448
|
+
parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
|
449
|
+
oj_odd_free(oa);
|
450
|
+
parent->odd_args = 0;
|
451
|
+
}
|
452
|
+
}
|
453
|
+
|
454
|
+
static void
|
455
|
+
array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
456
|
+
if (3 <= len && 0 != pi->circ_array) {
|
457
|
+
if ('i' == str[1]) {
|
458
|
+
long i = read_long(str + 2, len - 2);
|
459
|
+
|
460
|
+
if (0 < i) {
|
461
|
+
oj_circ_array_set(pi->circ_array, stack_peek(&pi->stack)->val, i);
|
462
|
+
return;
|
463
|
+
}
|
464
|
+
} else if ('r' == str[1]) {
|
465
|
+
long i = read_long(str + 2, len - 2);
|
466
|
+
|
467
|
+
if (0 < i) {
|
468
|
+
rb_ary_push(stack_peek(&pi->stack)->val, oj_circ_array_get(pi->circ_array, i));
|
469
|
+
return;
|
470
|
+
}
|
471
|
+
|
472
|
+
}
|
473
|
+
}
|
474
|
+
rb_ary_push(stack_peek(&pi->stack)->val, str_to_value(pi, str, len, orig));
|
475
|
+
}
|
476
|
+
|
477
|
+
static void
|
478
|
+
add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
479
|
+
pi->stack.head->val = str_to_value(pi, str, len, orig);
|
480
|
+
}
|
481
|
+
|
482
|
+
VALUE
|
483
|
+
oj_object_parse(int argc, VALUE *argv, VALUE self) {
|
484
|
+
struct _ParseInfo pi;
|
485
|
+
|
486
|
+
pi.options = oj_default_options;
|
487
|
+
oj_set_strict_callbacks(&pi);
|
488
|
+
pi.end_hash = end_hash;
|
489
|
+
pi.start_hash = start_hash;
|
490
|
+
pi.hash_set_cstr = hash_set_cstr;
|
491
|
+
pi.hash_set_num = hash_set_num;
|
492
|
+
pi.hash_set_value = hash_set_value;
|
493
|
+
pi.add_cstr = add_cstr;
|
494
|
+
pi.array_append_cstr = array_append_cstr;
|
495
|
+
|
496
|
+
return oj_pi_parse(argc, argv, &pi, 0);
|
497
|
+
}
|
498
|
+
|
499
|
+
VALUE
|
500
|
+
oj_object_parse_cstr(int argc, VALUE *argv, char *json) {
|
501
|
+
struct _ParseInfo pi;
|
502
|
+
|
503
|
+
pi.options = oj_default_options;
|
504
|
+
oj_set_strict_callbacks(&pi);
|
505
|
+
pi.end_hash = end_hash;
|
506
|
+
pi.start_hash = start_hash;
|
507
|
+
pi.hash_set_cstr = hash_set_cstr;
|
508
|
+
pi.hash_set_num = hash_set_num;
|
509
|
+
pi.hash_set_value = hash_set_value;
|
510
|
+
pi.add_cstr = add_cstr;
|
511
|
+
pi.array_append_cstr = array_append_cstr;
|
512
|
+
|
513
|
+
return oj_pi_parse(argc, argv, &pi, json);
|
514
|
+
}
|