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