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