oj 3.9.1 → 3.16.11
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 +1452 -0
- data/README.md +21 -6
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +50 -68
- 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 +9 -36
- data/ext/oj/circarray.c +38 -42
- data/ext/oj/circarray.h +12 -13
- data/ext/oj/code.c +158 -179
- data/ext/oj/code.h +20 -22
- data/ext/oj/compat.c +145 -205
- data/ext/oj/custom.c +740 -880
- data/ext/oj/debug.c +126 -0
- data/ext/oj/dump.c +1145 -844
- data/ext/oj/dump.h +71 -57
- data/ext/oj/dump_compat.c +575 -655
- data/ext/oj/dump_leaf.c +96 -186
- data/ext/oj/dump_object.c +533 -660
- data/ext/oj/dump_strict.c +306 -340
- data/ext/oj/encode.h +4 -33
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +28 -28
- data/ext/oj/err.h +39 -42
- data/ext/oj/extconf.rb +28 -7
- data/ext/oj/fast.c +1052 -1113
- 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 +471 -430
- data/ext/oj/object.c +532 -580
- data/ext/oj/odd.c +156 -142
- data/ext/oj/odd.h +25 -26
- data/ext/oj/oj.c +1346 -961
- data/ext/oj/oj.h +307 -290
- data/ext/oj/parse.c +954 -858
- data/ext/oj/parse.h +74 -72
- data/ext/oj/parser.c +1600 -0
- data/ext/oj/parser.h +103 -0
- data/ext/oj/rails.c +819 -836
- data/ext/oj/rails.h +8 -11
- data/ext/oj/reader.c +136 -147
- data/ext/oj/reader.h +69 -83
- data/ext/oj/resolve.c +41 -63
- data/ext/oj/resolve.h +4 -6
- data/ext/oj/rxclass.c +69 -72
- data/ext/oj/rxclass.h +12 -13
- data/ext/oj/saj.c +440 -485
- data/ext/oj/saj2.c +584 -0
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +79 -118
- data/ext/oj/simd.h +10 -0
- data/ext/oj/sparse.c +739 -709
- data/ext/oj/stream_writer.c +141 -175
- data/ext/oj/strict.c +103 -128
- data/ext/oj/string_writer.c +244 -261
- data/ext/oj/trace.c +34 -41
- data/ext/oj/trace.h +42 -15
- data/ext/oj/usual.c +1218 -0
- data/ext/oj/usual.h +69 -0
- data/ext/oj/util.c +107 -107
- data/ext/oj/util.h +4 -3
- data/ext/oj/val_stack.c +61 -78
- data/ext/oj/val_stack.h +80 -114
- data/ext/oj/validate.c +46 -0
- data/ext/oj/wab.c +316 -361
- 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 +54 -20
- 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 -8
- data/pages/Compatibility.md +1 -1
- data/pages/Encoding.md +1 -1
- data/pages/InstallOptions.md +20 -0
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +9 -3
- data/pages/Options.md +62 -12
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +73 -22
- metadata +68 -192
- data/ext/oj/hash.c +0 -163
- data/ext/oj/hash.h +0 -46
- data/ext/oj/hash_test.c +0 -512
- data/test/_test_active.rb +0 -76
- data/test/_test_active_mimic.rb +0 -96
- data/test/_test_mimic_rails.rb +0 -126
- data/test/activerecord/result_test.rb +0 -27
- 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/decoding_test.rb +0 -125
- data/test/activesupport5/encoding_test.rb +0 -485
- data/test/activesupport5/encoding_test_cases.rb +0 -90
- data/test/activesupport5/test_helper.rb +0 -50
- data/test/activesupport5/time_zone_test_helpers.rb +0 -24
- data/test/bar.rb +0 -25
- data/test/files.rb +0 -29
- data/test/foo.rb +0 -21
- data/test/helper.rb +0 -26
- data/test/isolated/shared.rb +0 -308
- data/test/isolated/test_mimic_after.rb +0 -13
- data/test/isolated/test_mimic_alone.rb +0 -12
- data/test/isolated/test_mimic_as_json.rb +0 -45
- data/test/isolated/test_mimic_before.rb +0 -13
- data/test/isolated/test_mimic_define.rb +0 -28
- data/test/isolated/test_mimic_rails_after.rb +0 -22
- data/test/isolated/test_mimic_rails_before.rb +0 -21
- data/test/isolated/test_mimic_redefine.rb +0 -15
- data/test/json_gem/json_addition_test.rb +0 -216
- data/test/json_gem/json_common_interface_test.rb +0 -148
- data/test/json_gem/json_encoding_test.rb +0 -107
- data/test/json_gem/json_ext_parser_test.rb +0 -20
- data/test/json_gem/json_fixtures_test.rb +0 -35
- data/test/json_gem/json_generator_test.rb +0 -383
- data/test/json_gem/json_generic_object_test.rb +0 -90
- data/test/json_gem/json_parser_test.rb +0 -470
- data/test/json_gem/json_string_matching_test.rb +0 -42
- data/test/json_gem/test_helper.rb +0 -18
- data/test/perf.rb +0 -107
- data/test/perf_compat.rb +0 -130
- data/test/perf_fast.rb +0 -164
- data/test/perf_file.rb +0 -64
- data/test/perf_object.rb +0 -138
- data/test/perf_saj.rb +0 -109
- data/test/perf_scp.rb +0 -151
- data/test/perf_simple.rb +0 -287
- data/test/perf_strict.rb +0 -145
- data/test/perf_wab.rb +0 -131
- data/test/sample/change.rb +0 -14
- data/test/sample/dir.rb +0 -19
- data/test/sample/doc.rb +0 -36
- data/test/sample/file.rb +0 -48
- data/test/sample/group.rb +0 -16
- data/test/sample/hasprops.rb +0 -16
- data/test/sample/layer.rb +0 -12
- data/test/sample/line.rb +0 -20
- data/test/sample/oval.rb +0 -10
- data/test/sample/rect.rb +0 -10
- data/test/sample/shape.rb +0 -35
- data/test/sample/text.rb +0 -20
- data/test/sample.rb +0 -54
- data/test/sample_json.rb +0 -37
- data/test/test_compat.rb +0 -509
- data/test/test_custom.rb +0 -503
- data/test/test_debian.rb +0 -53
- data/test/test_fast.rb +0 -470
- data/test/test_file.rb +0 -239
- data/test/test_gc.rb +0 -49
- data/test/test_hash.rb +0 -29
- data/test/test_integer_range.rb +0 -73
- data/test/test_null.rb +0 -376
- data/test/test_object.rb +0 -1018
- data/test/test_saj.rb +0 -186
- data/test/test_scp.rb +0 -433
- data/test/test_strict.rb +0 -410
- data/test/test_various.rb +0 -741
- data/test/test_wab.rb +0 -307
- data/test/test_writer.rb +0 -380
- data/test/tests.rb +0 -24
- data/test/tests_mimic.rb +0 -14
- data/test/tests_mimic_addition.rb +0 -7
- data/test/zoo.rb +0 -13
data/ext/oj/object.c
CHANGED
@@ -1,774 +1,726 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
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.
|
5
3
|
|
6
4
|
#include <stdint.h>
|
7
5
|
#include <stdio.h>
|
8
6
|
#include <time.h>
|
9
7
|
|
10
|
-
#include "
|
8
|
+
#include "encode.h"
|
11
9
|
#include "err.h"
|
10
|
+
#include "intern.h"
|
11
|
+
#include "odd.h"
|
12
|
+
#include "oj.h"
|
12
13
|
#include "parse.h"
|
13
14
|
#include "resolve.h"
|
14
|
-
#include "hash.h"
|
15
|
-
#include "odd.h"
|
16
|
-
#include "encode.h"
|
17
15
|
#include "trace.h"
|
18
16
|
#include "util.h"
|
19
17
|
|
20
|
-
inline static long
|
21
|
-
|
22
|
-
long n = 0;
|
18
|
+
inline static long read_long(const char *str, size_t len) {
|
19
|
+
long n = 0;
|
23
20
|
|
24
21
|
for (; 0 < len; str++, len--) {
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
22
|
+
if ('0' <= *str && *str <= '9') {
|
23
|
+
n = n * 10 + (*str - '0');
|
24
|
+
} else {
|
25
|
+
return -1;
|
26
|
+
}
|
30
27
|
}
|
31
28
|
return n;
|
32
29
|
}
|
33
30
|
|
34
|
-
static VALUE
|
35
|
-
|
36
|
-
volatile VALUE rkey;
|
31
|
+
static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
|
32
|
+
volatile VALUE rkey;
|
37
33
|
|
38
34
|
if (':' == k1) {
|
39
|
-
|
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
|
-
}
|
35
|
+
return ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
|
48
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
|
49
46
|
return rkey;
|
50
47
|
}
|
51
48
|
|
52
|
-
static VALUE
|
53
|
-
|
54
|
-
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;
|
55
51
|
|
56
52
|
if (':' == *orig && 0 < len) {
|
57
|
-
|
58
|
-
rstr = oj_encode(rstr);
|
59
|
-
rstr = rb_funcall(rstr, oj_to_sym_id, 0);
|
53
|
+
rstr = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
|
60
54
|
} else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
|
61
|
-
|
55
|
+
long i = read_long(str + 2, len - 2);
|
62
56
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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);
|
68
62
|
} else {
|
69
|
-
|
70
|
-
rstr = oj_encode(rstr);
|
63
|
+
rstr = rb_utf8_str_new(str, len);
|
71
64
|
}
|
72
65
|
return rstr;
|
73
66
|
}
|
74
67
|
|
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
68
|
// The much faster approach (4x faster)
|
82
|
-
static int
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
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;
|
87
73
|
|
88
74
|
for (i = cnt; 0 < i; i--, str++) {
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
75
|
+
c = *str;
|
76
|
+
if (end <= str || c < '0' || '9' < c) {
|
77
|
+
return -1;
|
78
|
+
}
|
79
|
+
n = n * 10 + (c - '0');
|
94
80
|
}
|
95
81
|
return n;
|
96
82
|
}
|
97
83
|
|
98
84
|
VALUE
|
99
85
|
oj_parse_xml_time(const char *str, int len) {
|
100
|
-
VALUE
|
101
|
-
const char
|
102
|
-
|
86
|
+
VALUE args[7];
|
87
|
+
const char *end = str + len;
|
88
|
+
const char *orig = str;
|
89
|
+
int n;
|
103
90
|
|
104
91
|
// year
|
105
92
|
if (0 > (n = parse_num(str, end, 4))) {
|
106
|
-
|
93
|
+
return Qnil;
|
107
94
|
}
|
108
95
|
str += 4;
|
109
96
|
args[0] = LONG2NUM(n);
|
110
97
|
if ('-' != *str++) {
|
111
|
-
|
98
|
+
return Qnil;
|
112
99
|
}
|
113
100
|
// month
|
114
101
|
if (0 > (n = parse_num(str, end, 2))) {
|
115
|
-
|
102
|
+
return Qnil;
|
116
103
|
}
|
117
104
|
str += 2;
|
118
105
|
args[1] = LONG2NUM(n);
|
119
106
|
if ('-' != *str++) {
|
120
|
-
|
107
|
+
return Qnil;
|
121
108
|
}
|
122
109
|
// day
|
123
110
|
if (0 > (n = parse_num(str, end, 2))) {
|
124
|
-
|
111
|
+
return Qnil;
|
125
112
|
}
|
126
113
|
str += 2;
|
127
114
|
args[2] = LONG2NUM(n);
|
128
115
|
if ('T' != *str++) {
|
129
|
-
|
116
|
+
return Qnil;
|
130
117
|
}
|
131
118
|
// hour
|
132
119
|
if (0 > (n = parse_num(str, end, 2))) {
|
133
|
-
|
120
|
+
return Qnil;
|
134
121
|
}
|
135
122
|
str += 2;
|
136
123
|
args[3] = LONG2NUM(n);
|
137
124
|
if (':' != *str++) {
|
138
|
-
|
125
|
+
return Qnil;
|
139
126
|
}
|
140
127
|
// minute
|
141
128
|
if (0 > (n = parse_num(str, end, 2))) {
|
142
|
-
|
129
|
+
return Qnil;
|
143
130
|
}
|
144
131
|
str += 2;
|
145
132
|
args[4] = LONG2NUM(n);
|
146
133
|
if (':' != *str++) {
|
147
|
-
|
134
|
+
return Qnil;
|
148
135
|
}
|
149
136
|
// second
|
150
137
|
if (0 > (n = parse_num(str, end, 2))) {
|
151
|
-
|
138
|
+
return Qnil;
|
152
139
|
}
|
153
140
|
str += 2;
|
154
141
|
if (str == end) {
|
155
|
-
|
156
|
-
|
142
|
+
args[5] = LONG2NUM(n);
|
143
|
+
args[6] = LONG2NUM(0);
|
157
144
|
} else {
|
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
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
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
|
+
}
|
210
204
|
}
|
211
205
|
return rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
212
206
|
}
|
213
|
-
#endif
|
214
207
|
|
215
|
-
static int
|
216
|
-
|
217
|
-
|
218
|
-
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;
|
219
211
|
|
220
212
|
if (2 == klen) {
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
}
|
261
|
-
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
|
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
|
270
252
|
}
|
271
253
|
return 0;
|
272
254
|
}
|
273
255
|
|
274
|
-
static int
|
275
|
-
hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
256
|
+
static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
276
257
|
if (2 == kval->klen) {
|
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
|
-
|
320
|
-
|
321
|
-
}
|
322
|
-
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
323
|
-
} else {
|
324
|
-
return 0;
|
325
|
-
}
|
326
|
-
break;
|
327
|
-
default:
|
328
|
-
return 0;
|
329
|
-
break;
|
330
|
-
}
|
331
|
-
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
|
332
302
|
}
|
333
303
|
return 0;
|
334
304
|
}
|
335
305
|
|
336
|
-
static int
|
337
|
-
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) {
|
338
307
|
if (T_ARRAY == rb_type(value)) {
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
volatile VALUE
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
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.
|
369
342
|
#ifdef RSTRUCT_LEN
|
370
343
|
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
371
|
-
|
372
|
-
#else
|
373
|
-
|
374
|
-
#endif
|
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
|
375
348
|
#else
|
376
|
-
|
349
|
+
slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
|
377
350
|
#endif
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
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;
|
383
365
|
|
384
|
-
|
385
|
-
|
386
|
-
|
366
|
+
if (2 != len) {
|
367
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
368
|
+
return 1;
|
387
369
|
}
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
return 1;
|
395
|
-
}
|
396
|
-
parent->val = rb_hash_new();
|
397
|
-
a = RARRAY_PTR(value);
|
398
|
-
rb_hash_aset(parent->val, *a, a[1]);
|
399
|
-
|
400
|
-
return 1;
|
401
|
-
}
|
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
|
+
}
|
402
376
|
}
|
403
377
|
return 0;
|
404
378
|
}
|
405
379
|
|
406
|
-
void
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
414
|
-
pthread_mutex_lock(&oj_cache_mutex);
|
415
|
-
#else
|
416
|
-
rb_mutex_lock(oj_cache_mutex);
|
417
|
-
#endif
|
418
|
-
if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
|
419
|
-
char attr[256];
|
420
|
-
|
421
|
-
if ((int)sizeof(attr) <= klen + 2) {
|
422
|
-
char *buf = ALLOC_N(char, klen + 2);
|
423
|
-
|
424
|
-
if ('~' == *key) {
|
425
|
-
strncpy(buf, key + 1, klen - 1);
|
426
|
-
buf[klen - 1] = '\0';
|
427
|
-
} else {
|
428
|
-
*buf = '@';
|
429
|
-
strncpy(buf + 1, key, klen);
|
430
|
-
buf[klen + 1] = '\0';
|
431
|
-
}
|
432
|
-
var_id = rb_intern(buf);
|
433
|
-
xfree(buf);
|
434
|
-
} else {
|
435
|
-
if ('~' == *key) {
|
436
|
-
strncpy(attr, key + 1, klen - 1);
|
437
|
-
attr[klen - 1] = '\0';
|
438
|
-
} else {
|
439
|
-
*attr = '@';
|
440
|
-
strncpy(attr + 1, key, klen);
|
441
|
-
attr[klen + 1] = '\0';
|
442
|
-
}
|
443
|
-
var_id = rb_intern(attr);
|
444
|
-
}
|
445
|
-
*slot = var_id;
|
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);
|
446
387
|
}
|
447
|
-
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
448
|
-
pthread_mutex_unlock(&oj_cache_mutex);
|
449
|
-
#else
|
450
|
-
rb_mutex_unlock(oj_cache_mutex);
|
451
|
-
#endif
|
452
|
-
rb_ivar_set(parent->val, var_id, value);
|
453
388
|
}
|
454
389
|
|
455
|
-
static void
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
volatile VALUE rval = Qnil;
|
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;
|
461
395
|
|
462
|
-
|
396
|
+
WHICH_TYPE:
|
463
397
|
switch (rb_type(parent->val)) {
|
464
398
|
case T_NIL:
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
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;
|
471
405
|
case T_HASH:
|
472
|
-
|
473
|
-
|
406
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
|
407
|
+
break;
|
474
408
|
case T_STRING:
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
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;
|
482
416
|
case T_OBJECT:
|
483
|
-
|
484
|
-
|
485
|
-
|
417
|
+
rval = str_to_value(pi, str, len, orig);
|
418
|
+
oj_set_obj_ivar(parent, kval, rval);
|
419
|
+
break;
|
486
420
|
case T_CLASS:
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
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;
|
504
449
|
default:
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
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);
|
511
459
|
}
|
512
460
|
|
513
|
-
static void
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
volatile VALUE rval = Qnil;
|
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;
|
519
466
|
|
520
|
-
|
467
|
+
WHICH_TYPE:
|
521
468
|
switch (rb_type(parent->val)) {
|
522
469
|
case T_NIL:
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
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;
|
529
476
|
case T_HASH:
|
530
|
-
|
531
|
-
|
532
|
-
|
477
|
+
rval = oj_num_as_value(ni);
|
478
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
|
479
|
+
break;
|
533
480
|
case T_OBJECT:
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
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;
|
542
489
|
case T_CLASS:
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
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;
|
560
518
|
default:
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
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);
|
567
528
|
}
|
568
529
|
|
569
|
-
static void
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
Val parent = stack_peek(&pi->stack);
|
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);
|
574
534
|
|
575
|
-
|
535
|
+
WHICH_TYPE:
|
576
536
|
switch (rb_type(parent->val)) {
|
577
537
|
case T_NIL:
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
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;
|
584
544
|
case T_HASH:
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
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;
|
606
566
|
case T_ARRAY:
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
case T_STRING:
|
614
|
-
case T_OBJECT:
|
615
|
-
oj_set_obj_ivar(parent, kval, value);
|
616
|
-
break;
|
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;
|
617
575
|
case T_MODULE:
|
618
576
|
case T_CLASS:
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
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;
|
633
602
|
default:
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
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);
|
640
612
|
}
|
641
613
|
|
642
|
-
static VALUE
|
643
|
-
|
644
|
-
if (Yes == pi->options.trace) {
|
645
|
-
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
646
|
-
}
|
614
|
+
static VALUE start_hash(ParseInfo pi) {
|
615
|
+
TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
|
647
616
|
return Qnil;
|
648
617
|
}
|
649
618
|
|
650
|
-
static void
|
651
|
-
|
652
|
-
Val parent = stack_peek(&pi->stack);
|
619
|
+
static void end_hash(ParseInfo pi) {
|
620
|
+
Val parent = stack_peek(&pi->stack);
|
653
621
|
|
654
622
|
if (Qnil == parent->val) {
|
655
|
-
|
623
|
+
parent->val = rb_hash_new();
|
656
624
|
} else if (NULL != parent->odd_args) {
|
657
|
-
|
625
|
+
OddArgs oa = parent->odd_args;
|
658
626
|
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
}
|
663
|
-
if (Yes == pi->options.trace) {
|
664
|
-
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
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;
|
665
630
|
}
|
631
|
+
TRACE_PARSE_HASH_END(pi->options.trace, pi);
|
666
632
|
}
|
667
633
|
|
668
|
-
static void
|
669
|
-
|
670
|
-
volatile VALUE rval = Qnil;
|
634
|
+
static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
635
|
+
volatile VALUE rval = Qnil;
|
671
636
|
|
672
|
-
|
673
|
-
|
674
|
-
|
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);
|
675
641
|
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
if (0 < i) {
|
684
|
-
rb_ary_push(stack_peek(&pi->stack)->val, oj_circ_array_get(pi->circ_array, i));
|
685
|
-
return;
|
686
|
-
}
|
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);
|
687
648
|
|
688
|
-
|
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
|
+
}
|
689
654
|
}
|
690
655
|
rval = str_to_value(pi, str, len, orig);
|
691
656
|
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
692
|
-
|
693
|
-
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
|
694
|
-
}
|
657
|
+
TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rval);
|
695
658
|
}
|
696
659
|
|
697
|
-
static void
|
698
|
-
|
699
|
-
volatile VALUE rval = oj_num_as_value(ni);
|
660
|
+
static void array_append_num(ParseInfo pi, NumInfo ni) {
|
661
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
700
662
|
|
701
663
|
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
702
|
-
|
703
|
-
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
704
|
-
}
|
664
|
+
TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
|
705
665
|
}
|
706
666
|
|
707
|
-
static void
|
708
|
-
add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
667
|
+
static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
709
668
|
pi->stack.head->val = str_to_value(pi, str, len, orig);
|
710
|
-
|
711
|
-
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
|
712
|
-
}
|
669
|
+
TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, pi->stack.head->val);
|
713
670
|
}
|
714
671
|
|
715
|
-
static void
|
716
|
-
add_num(ParseInfo pi, NumInfo ni) {
|
672
|
+
static void add_num(ParseInfo pi, NumInfo ni) {
|
717
673
|
pi->stack.head->val = oj_num_as_value(ni);
|
718
|
-
|
719
|
-
oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
|
720
|
-
}
|
674
|
+
TRACE_PARSE_CALL(pi->options.trace, "add_num", pi, pi->stack.head->val);
|
721
675
|
}
|
722
676
|
|
723
|
-
void
|
724
|
-
oj_set_object_callbacks(ParseInfo pi) {
|
677
|
+
void oj_set_object_callbacks(ParseInfo pi) {
|
725
678
|
oj_set_strict_callbacks(pi);
|
726
|
-
pi->end_hash
|
727
|
-
pi->start_hash
|
728
|
-
pi->hash_set_cstr
|
729
|
-
pi->hash_set_num
|
730
|
-
pi->hash_set_value
|
731
|
-
pi->add_cstr
|
732
|
-
pi->add_num
|
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;
|
733
686
|
pi->array_append_cstr = array_append_cstr;
|
734
|
-
pi->array_append_num
|
687
|
+
pi->array_append_num = array_append_num;
|
735
688
|
}
|
736
689
|
|
737
690
|
VALUE
|
738
691
|
oj_object_parse(int argc, VALUE *argv, VALUE self) {
|
739
|
-
struct _parseInfo
|
692
|
+
struct _parseInfo pi;
|
740
693
|
|
741
694
|
parse_info_init(&pi);
|
742
|
-
pi.options
|
743
|
-
pi.handler
|
695
|
+
pi.options = oj_default_options;
|
696
|
+
pi.handler = Qnil;
|
744
697
|
pi.err_class = Qnil;
|
745
698
|
oj_set_object_callbacks(&pi);
|
746
699
|
|
747
700
|
if (T_STRING == rb_type(*argv)) {
|
748
|
-
|
749
|
-
} else {
|
750
|
-
return oj_pi_sparse(argc, argv, &pi, 0);
|
701
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
|
751
702
|
}
|
703
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
752
704
|
}
|
753
705
|
|
754
706
|
VALUE
|
755
707
|
oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
756
|
-
struct _parseInfo
|
708
|
+
struct _parseInfo pi;
|
757
709
|
|
758
710
|
parse_info_init(&pi);
|
759
|
-
pi.options
|
760
|
-
pi.handler
|
711
|
+
pi.options = oj_default_options;
|
712
|
+
pi.handler = Qnil;
|
761
713
|
pi.err_class = Qnil;
|
762
714
|
oj_set_strict_callbacks(&pi);
|
763
|
-
pi.end_hash
|
764
|
-
pi.start_hash
|
765
|
-
pi.hash_set_cstr
|
766
|
-
pi.hash_set_num
|
767
|
-
pi.hash_set_value
|
768
|
-
pi.add_cstr
|
769
|
-
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;
|
770
722
|
pi.array_append_cstr = array_append_cstr;
|
771
|
-
pi.array_append_num
|
723
|
+
pi.array_append_num = array_append_num;
|
772
724
|
|
773
725
|
return oj_pi_parse(argc, argv, &pi, json, len, 1);
|
774
726
|
}
|