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