oj 2.18.3 → 3.13.14
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 +5 -5
- data/CHANGELOG.md +1324 -0
- data/README.md +51 -204
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +49 -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 -68
- data/ext/oj/circarray.h +16 -42
- data/ext/oj/code.c +221 -0
- data/ext/oj/code.h +40 -0
- data/ext/oj/compat.c +231 -107
- data/ext/oj/custom.c +1125 -0
- data/ext/oj/debug.c +132 -0
- data/ext/oj/dump.c +935 -2513
- data/ext/oj/dump.h +108 -0
- data/ext/oj/dump_compat.c +936 -0
- data/ext/oj/dump_leaf.c +164 -0
- data/ext/oj/dump_object.c +761 -0
- data/ext/oj/dump_strict.c +410 -0
- data/ext/oj/encode.h +7 -42
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +40 -54
- data/ext/oj/err.h +52 -46
- data/ext/oj/extconf.rb +21 -30
- data/ext/oj/fast.c +1097 -1080
- data/ext/oj/intern.c +301 -0
- data/ext/oj/intern.h +26 -0
- data/ext/oj/mimic_json.c +893 -0
- data/ext/oj/object.c +549 -620
- data/ext/oj/odd.c +155 -167
- data/ext/oj/odd.h +37 -63
- data/ext/oj/oj.c +1661 -2063
- data/ext/oj/oj.h +341 -270
- data/ext/oj/parse.c +974 -737
- data/ext/oj/parse.h +105 -97
- data/ext/oj/parser.c +1526 -0
- data/ext/oj/parser.h +90 -0
- data/ext/oj/rails.c +1504 -0
- data/ext/oj/rails.h +18 -0
- data/ext/oj/reader.c +141 -163
- data/ext/oj/reader.h +75 -113
- data/ext/oj/resolve.c +45 -93
- data/ext/oj/resolve.h +7 -34
- data/ext/oj/rxclass.c +143 -0
- data/ext/oj/rxclass.h +26 -0
- data/ext/oj/saj.c +447 -511
- data/ext/oj/saj2.c +348 -0
- data/ext/oj/scp.c +91 -138
- data/ext/oj/sparse.c +793 -644
- data/ext/oj/stream_writer.c +331 -0
- data/ext/oj/strict.c +145 -109
- data/ext/oj/string_writer.c +493 -0
- data/ext/oj/trace.c +72 -0
- data/ext/oj/trace.h +28 -0
- data/ext/oj/usual.c +1254 -0
- data/ext/oj/util.c +136 -0
- data/ext/oj/util.h +20 -0
- data/ext/oj/val_stack.c +62 -70
- data/ext/oj/val_stack.h +95 -129
- data/ext/oj/validate.c +51 -0
- data/ext/oj/wab.c +622 -0
- data/lib/oj/bag.rb +1 -0
- data/lib/oj/easy_hash.rb +17 -8
- data/lib/oj/error.rb +10 -11
- data/lib/oj/json.rb +176 -0
- data/lib/oj/mimic.rb +158 -19
- data/lib/oj/state.rb +132 -0
- data/lib/oj/version.rb +2 -2
- data/lib/oj.rb +1 -31
- data/pages/Advanced.md +22 -0
- data/pages/Compatibility.md +25 -0
- data/pages/Custom.md +23 -0
- data/pages/Encoding.md +65 -0
- data/pages/JsonGem.md +94 -0
- data/pages/Modes.md +161 -0
- data/pages/Options.md +327 -0
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +167 -0
- data/pages/Security.md +20 -0
- data/pages/WAB.md +13 -0
- data/test/activerecord/result_test.rb +32 -0
- data/test/activesupport4/decoding_test.rb +108 -0
- data/test/activesupport4/encoding_test.rb +531 -0
- data/test/activesupport4/test_helper.rb +41 -0
- data/test/activesupport5/abstract_unit.rb +45 -0
- data/test/activesupport5/decoding_test.rb +133 -0
- data/test/activesupport5/encoding_test.rb +500 -0
- data/test/activesupport5/encoding_test_cases.rb +98 -0
- data/test/activesupport5/test_helper.rb +72 -0
- data/test/activesupport5/time_zone_test_helpers.rb +39 -0
- 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 +9 -0
- data/test/baz.rb +16 -0
- data/test/bug.rb +11 -46
- data/test/foo.rb +69 -16
- data/test/helper.rb +10 -1
- data/test/isolated/shared.rb +12 -8
- data/test/isolated/test_mimic_rails_after.rb +3 -3
- data/test/isolated/test_mimic_rails_before.rb +3 -3
- data/test/json_gem/json_addition_test.rb +216 -0
- data/test/json_gem/json_common_interface_test.rb +153 -0
- data/test/json_gem/json_encoding_test.rb +107 -0
- data/test/json_gem/json_ext_parser_test.rb +20 -0
- data/test/json_gem/json_fixtures_test.rb +35 -0
- data/test/json_gem/json_generator_test.rb +397 -0
- data/test/json_gem/json_generic_object_test.rb +90 -0
- data/test/json_gem/json_parser_test.rb +470 -0
- data/test/json_gem/json_string_matching_test.rb +42 -0
- data/test/json_gem/test_helper.rb +26 -0
- data/test/mem.rb +33 -0
- data/test/perf.rb +1 -1
- data/test/perf_compat.rb +30 -28
- data/test/perf_dump.rb +50 -0
- data/test/perf_object.rb +1 -1
- 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 +30 -19
- data/test/perf_wab.rb +131 -0
- data/test/prec.rb +23 -0
- data/test/sample.rb +0 -1
- data/test/sample_json.rb +1 -1
- data/test/test_compat.rb +219 -102
- data/test/test_custom.rb +533 -0
- data/test/test_fast.rb +107 -35
- data/test/test_file.rb +19 -25
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +11 -1
- data/test/test_integer_range.rb +72 -0
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +357 -70
- data/test/test_parser.rb +27 -0
- data/test/test_parser_saj.rb +245 -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 +39 -2
- data/test/test_strict.rb +186 -7
- data/test/test_various.rb +160 -774
- data/test/test_wab.rb +307 -0
- data/test/test_writer.rb +90 -2
- data/test/tests.rb +24 -0
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- data/test/zoo.rb +13 -0
- metadata +194 -56
- data/ext/oj/hash.c +0 -163
- data/ext/oj/hash.h +0 -46
- data/ext/oj/hash_test.c +0 -512
- data/test/activesupport_datetime_test.rb +0 -23
- data/test/bug2.rb +0 -10
- data/test/bug3.rb +0 -46
- data/test/bug_fast.rb +0 -32
- data/test/bug_load.rb +0 -24
- data/test/crash.rb +0 -111
- data/test/curl/curl_oj.rb +0 -46
- data/test/curl/get_oj.rb +0 -24
- data/test/curl/just_curl.rb +0 -31
- data/test/curl/just_oj.rb +0 -51
- data/test/example.rb +0 -11
- data/test/io.rb +0 -48
- data/test/isolated/test_mimic_rails_datetime.rb +0 -27
- data/test/mod.rb +0 -16
- data/test/rails.rb +0 -50
- data/test/russian.rb +0 -18
- data/test/struct.rb +0 -29
- data/test/test_serializer.rb +0 -59
- data/test/write_timebars.rb +0 -31
data/ext/oj/object.c
CHANGED
|
@@ -1,806 +1,735 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* All rights reserved.
|
|
4
|
-
*
|
|
5
|
-
* Redistribution and use in source and binary forms, with or without
|
|
6
|
-
* modification, are permitted provided that the following conditions are met:
|
|
7
|
-
*
|
|
8
|
-
* - Redistributions of source code must retain the above copyright notice, this
|
|
9
|
-
* list of conditions and the following disclaimer.
|
|
10
|
-
*
|
|
11
|
-
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
-
* this list of conditions and the following disclaimer in the documentation
|
|
13
|
-
* and/or other materials provided with the distribution.
|
|
14
|
-
*
|
|
15
|
-
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
|
16
|
-
* used to endorse or promote products derived from this software without
|
|
17
|
-
* specific prior written permission.
|
|
18
|
-
*
|
|
19
|
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
-
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
-
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
-
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
-
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
-
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
-
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
-
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
29
|
-
*/
|
|
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.
|
|
30
3
|
|
|
4
|
+
#include <stdint.h>
|
|
31
5
|
#include <stdio.h>
|
|
32
6
|
#include <time.h>
|
|
33
7
|
|
|
34
|
-
#include "
|
|
8
|
+
#include "encode.h"
|
|
35
9
|
#include "err.h"
|
|
10
|
+
#include "intern.h"
|
|
11
|
+
#include "odd.h"
|
|
12
|
+
#include "oj.h"
|
|
36
13
|
#include "parse.h"
|
|
37
14
|
#include "resolve.h"
|
|
38
|
-
#include "
|
|
39
|
-
#include "
|
|
40
|
-
#include "encode.h"
|
|
15
|
+
#include "trace.h"
|
|
16
|
+
#include "util.h"
|
|
41
17
|
|
|
42
|
-
inline static long
|
|
43
|
-
|
|
44
|
-
long n = 0;
|
|
18
|
+
inline static long read_long(const char *str, size_t len) {
|
|
19
|
+
long n = 0;
|
|
45
20
|
|
|
46
21
|
for (; 0 < len; str++, len--) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
22
|
+
if ('0' <= *str && *str <= '9') {
|
|
23
|
+
n = n * 10 + (*str - '0');
|
|
24
|
+
} else {
|
|
25
|
+
return -1;
|
|
26
|
+
}
|
|
52
27
|
}
|
|
53
28
|
return n;
|
|
54
29
|
}
|
|
55
30
|
|
|
56
|
-
static VALUE
|
|
57
|
-
|
|
58
|
-
volatile VALUE rkey;
|
|
31
|
+
static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
|
|
32
|
+
volatile VALUE rkey;
|
|
59
33
|
|
|
60
34
|
if (':' == k1) {
|
|
61
|
-
|
|
62
|
-
rkey = oj_encode(rkey);
|
|
63
|
-
rkey = rb_funcall(rkey, oj_to_sym_id, 0);
|
|
64
|
-
} else {
|
|
65
|
-
rkey = rb_str_new(kval->key, kval->klen);
|
|
66
|
-
rkey = oj_encode(rkey);
|
|
67
|
-
if (Yes == pi->options.sym_key) {
|
|
68
|
-
rkey = rb_str_intern(rkey);
|
|
69
|
-
}
|
|
35
|
+
return ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
|
|
70
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
|
|
71
46
|
return rkey;
|
|
72
47
|
}
|
|
73
48
|
|
|
74
|
-
static VALUE
|
|
75
|
-
|
|
76
|
-
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;
|
|
77
51
|
|
|
78
52
|
if (':' == *orig && 0 < len) {
|
|
79
|
-
|
|
80
|
-
rstr = oj_encode(rstr);
|
|
81
|
-
rstr = rb_funcall(rstr, oj_to_sym_id, 0);
|
|
53
|
+
rstr = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
|
|
82
54
|
} else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
|
|
83
|
-
|
|
55
|
+
long i = read_long(str + 2, len - 2);
|
|
84
56
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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);
|
|
90
62
|
} else {
|
|
91
|
-
|
|
92
|
-
rstr = oj_encode(rstr);
|
|
63
|
+
rstr = rb_utf8_str_new(str, len);
|
|
93
64
|
}
|
|
94
65
|
return rstr;
|
|
95
66
|
}
|
|
96
67
|
|
|
97
|
-
#if (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
|
|
98
|
-
static VALUE
|
|
99
|
-
parse_xml_time(const char *str, int len) {
|
|
100
|
-
return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(str, len));
|
|
101
|
-
}
|
|
102
|
-
#else
|
|
103
68
|
// The much faster approach (4x faster)
|
|
104
|
-
static int
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
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;
|
|
109
73
|
|
|
110
74
|
for (i = cnt; 0 < i; i--, str++) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
75
|
+
c = *str;
|
|
76
|
+
if (end <= str || c < '0' || '9' < c) {
|
|
77
|
+
return -1;
|
|
78
|
+
}
|
|
79
|
+
n = n * 10 + (c - '0');
|
|
116
80
|
}
|
|
117
81
|
return n;
|
|
118
82
|
}
|
|
119
83
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
VALUE
|
|
123
|
-
const char
|
|
124
|
-
int
|
|
84
|
+
VALUE
|
|
85
|
+
oj_parse_xml_time(const char *str, int len) {
|
|
86
|
+
VALUE args[8];
|
|
87
|
+
const char *end = str + len;
|
|
88
|
+
int n;
|
|
125
89
|
|
|
126
90
|
// year
|
|
127
91
|
if (0 > (n = parse_num(str, end, 4))) {
|
|
128
|
-
|
|
92
|
+
return Qnil;
|
|
129
93
|
}
|
|
130
94
|
str += 4;
|
|
131
95
|
args[0] = LONG2NUM(n);
|
|
132
96
|
if ('-' != *str++) {
|
|
133
|
-
|
|
97
|
+
return Qnil;
|
|
134
98
|
}
|
|
135
99
|
// month
|
|
136
100
|
if (0 > (n = parse_num(str, end, 2))) {
|
|
137
|
-
|
|
101
|
+
return Qnil;
|
|
138
102
|
}
|
|
139
103
|
str += 2;
|
|
140
104
|
args[1] = LONG2NUM(n);
|
|
141
105
|
if ('-' != *str++) {
|
|
142
|
-
|
|
106
|
+
return Qnil;
|
|
143
107
|
}
|
|
144
108
|
// day
|
|
145
109
|
if (0 > (n = parse_num(str, end, 2))) {
|
|
146
|
-
|
|
110
|
+
return Qnil;
|
|
147
111
|
}
|
|
148
112
|
str += 2;
|
|
149
113
|
args[2] = LONG2NUM(n);
|
|
150
114
|
if ('T' != *str++) {
|
|
151
|
-
|
|
115
|
+
return Qnil;
|
|
152
116
|
}
|
|
153
117
|
// hour
|
|
154
118
|
if (0 > (n = parse_num(str, end, 2))) {
|
|
155
|
-
|
|
119
|
+
return Qnil;
|
|
156
120
|
}
|
|
157
121
|
str += 2;
|
|
158
122
|
args[3] = LONG2NUM(n);
|
|
159
123
|
if (':' != *str++) {
|
|
160
|
-
|
|
124
|
+
return Qnil;
|
|
161
125
|
}
|
|
162
126
|
// minute
|
|
163
127
|
if (0 > (n = parse_num(str, end, 2))) {
|
|
164
|
-
|
|
128
|
+
return Qnil;
|
|
165
129
|
}
|
|
166
130
|
str += 2;
|
|
167
131
|
args[4] = LONG2NUM(n);
|
|
168
132
|
if (':' != *str++) {
|
|
169
|
-
|
|
133
|
+
return Qnil;
|
|
170
134
|
}
|
|
171
135
|
// second
|
|
172
136
|
if (0 > (n = parse_num(str, end, 2))) {
|
|
173
|
-
|
|
137
|
+
return Qnil;
|
|
174
138
|
}
|
|
175
139
|
str += 2;
|
|
176
140
|
if (str == end) {
|
|
177
|
-
|
|
178
|
-
|
|
141
|
+
args[5] = LONG2NUM(n);
|
|
142
|
+
args[6] = LONG2NUM(0);
|
|
179
143
|
} else {
|
|
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
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
+
}
|
|
232
196
|
}
|
|
233
197
|
return rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
|
234
198
|
}
|
|
235
|
-
#endif
|
|
236
199
|
|
|
237
|
-
static int
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
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;
|
|
241
203
|
|
|
242
204
|
if (2 == klen) {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
break;
|
|
284
|
-
case 't': // time
|
|
285
|
-
parent->val = parse_xml_time(str, len);
|
|
286
|
-
break;
|
|
287
|
-
default:
|
|
288
|
-
return 0;
|
|
289
|
-
break;
|
|
290
|
-
}
|
|
291
|
-
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
|
|
292
244
|
}
|
|
293
245
|
return 0;
|
|
294
246
|
}
|
|
295
247
|
|
|
296
|
-
static int
|
|
297
|
-
hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
248
|
+
static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
298
249
|
if (2 == kval->klen) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
args[5] = rb_float_new((double)st->tm_sec + ((double)nsec + 0.5) / 1000000000.0);
|
|
353
|
-
#endif
|
|
354
|
-
args[6] = LONG2NUM(ni->exp);
|
|
355
|
-
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
|
356
|
-
#endif
|
|
357
|
-
} else {
|
|
358
|
-
#if HAS_NANO_TIME
|
|
359
|
-
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
|
360
|
-
#else
|
|
361
|
-
parent->val = rb_time_new(ni->i, (long)(nsec / 1000));
|
|
362
|
-
#endif
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
break;
|
|
366
|
-
case 'i': // circular index
|
|
367
|
-
if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
|
|
368
|
-
if (Qnil == parent->val) {
|
|
369
|
-
parent->val = rb_hash_new();
|
|
370
|
-
}
|
|
371
|
-
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
|
372
|
-
} else {
|
|
373
|
-
return 0;
|
|
374
|
-
}
|
|
375
|
-
break;
|
|
376
|
-
default:
|
|
377
|
-
return 0;
|
|
378
|
-
break;
|
|
379
|
-
}
|
|
380
|
-
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
|
+
int64_t t = (int64_t)(ni->i + ni->exp);
|
|
273
|
+
struct _timeInfo ti;
|
|
274
|
+
VALUE args[8];
|
|
275
|
+
|
|
276
|
+
sec_as_time(t, &ti);
|
|
277
|
+
args[0] = LONG2NUM((long)(ti.year));
|
|
278
|
+
args[1] = LONG2NUM(ti.mon);
|
|
279
|
+
args[2] = LONG2NUM(ti.day);
|
|
280
|
+
args[3] = LONG2NUM(ti.hour);
|
|
281
|
+
args[4] = LONG2NUM(ti.min);
|
|
282
|
+
args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
|
|
283
|
+
args[6] = LONG2NUM(ni->exp);
|
|
284
|
+
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
|
285
|
+
} else {
|
|
286
|
+
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
break;
|
|
290
|
+
case 'i': // circular index
|
|
291
|
+
if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
|
|
292
|
+
if (Qnil == parent->val) {
|
|
293
|
+
parent->val = rb_hash_new();
|
|
294
|
+
}
|
|
295
|
+
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
|
296
|
+
} else {
|
|
297
|
+
return 0;
|
|
298
|
+
}
|
|
299
|
+
break;
|
|
300
|
+
default: return 0; break;
|
|
301
|
+
}
|
|
302
|
+
return 1; // handled
|
|
381
303
|
}
|
|
382
304
|
return 0;
|
|
383
305
|
}
|
|
384
306
|
|
|
385
|
-
static int
|
|
386
|
-
hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) {
|
|
307
|
+
static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) {
|
|
387
308
|
if (T_ARRAY == rb_type(value)) {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
volatile VALUE
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
309
|
+
int len = (int)RARRAY_LEN(value);
|
|
310
|
+
|
|
311
|
+
if (2 == klen && 'u' == key[1]) {
|
|
312
|
+
volatile VALUE sc;
|
|
313
|
+
volatile VALUE e1;
|
|
314
|
+
int slen;
|
|
315
|
+
|
|
316
|
+
if (0 == len) {
|
|
317
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
|
|
318
|
+
return 1;
|
|
319
|
+
}
|
|
320
|
+
e1 = *RARRAY_PTR(value);
|
|
321
|
+
// check for anonymous Struct
|
|
322
|
+
if (T_ARRAY == rb_type(e1)) {
|
|
323
|
+
VALUE args[1024];
|
|
324
|
+
volatile VALUE rstr;
|
|
325
|
+
int i, cnt = (int)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, 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_PTR(value), rb_eArgError);
|
|
335
|
+
}
|
|
415
336
|
// Create a properly initialized struct instance without calling the initialize method.
|
|
416
337
|
parent->val = rb_obj_alloc(sc);
|
|
417
338
|
// If the JSON array has more entries than the struct class allows, we record an error.
|
|
418
339
|
#ifdef RSTRUCT_LEN
|
|
419
|
-
#if
|
|
420
|
-
|
|
421
|
-
#else
|
|
422
|
-
|
|
423
|
-
#endif
|
|
340
|
+
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
341
|
+
slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
|
|
342
|
+
#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
343
|
+
slen = (int)RSTRUCT_LEN(parent->val);
|
|
344
|
+
#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
424
345
|
#else
|
|
425
|
-
|
|
346
|
+
slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
|
|
426
347
|
#endif
|
|
427
348
|
// MRI >= 1.9
|
|
428
349
|
if (len - 1 > slen) {
|
|
429
|
-
|
|
350
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
|
|
430
351
|
} else {
|
|
431
|
-
|
|
352
|
+
int i;
|
|
432
353
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
354
|
+
for (i = 0; i < len - 1; i++) {
|
|
355
|
+
rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
|
|
356
|
+
}
|
|
436
357
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
return 1;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
return 0;
|
|
453
|
-
}
|
|
358
|
+
return 1;
|
|
359
|
+
} else if (3 <= klen && '#' == key[1]) {
|
|
360
|
+
volatile VALUE *a;
|
|
361
|
+
|
|
362
|
+
if (2 != len) {
|
|
363
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
|
364
|
+
return 1;
|
|
365
|
+
}
|
|
366
|
+
parent->val = rb_hash_new();
|
|
367
|
+
a = RARRAY_PTR(value);
|
|
368
|
+
rb_hash_aset(parent->val, *a, a[1]);
|
|
454
369
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
volatile VALUE vars = rb_funcall(src, oj_instance_variables_id, 0);
|
|
458
|
-
volatile VALUE *np = RARRAY_PTR(vars);
|
|
459
|
-
ID vid;
|
|
460
|
-
int i, cnt = (int)RARRAY_LEN(vars);
|
|
461
|
-
const char *attr;
|
|
462
|
-
|
|
463
|
-
for (i = cnt; 0 < i; i--, np++) {
|
|
464
|
-
vid = rb_to_id(*np);
|
|
465
|
-
attr = rb_id2name(vid);
|
|
466
|
-
if ('@' == *attr) {
|
|
467
|
-
rb_ivar_set(target, vid, rb_ivar_get(src, vid));
|
|
468
|
-
}
|
|
370
|
+
return 1;
|
|
371
|
+
}
|
|
469
372
|
}
|
|
373
|
+
return 0;
|
|
470
374
|
}
|
|
471
375
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
const char *key = kval->key;
|
|
475
|
-
int klen = kval->klen;
|
|
476
|
-
ID var_id;
|
|
477
|
-
ID *slot;
|
|
478
|
-
|
|
479
|
-
if ('~' == *key && Qtrue == rb_obj_is_kind_of(parent->val, rb_eException)) {
|
|
480
|
-
if (5 == klen && 0 == strncmp("~mesg", key, klen)) {
|
|
481
|
-
VALUE args[1];
|
|
482
|
-
volatile VALUE prev = parent->val;
|
|
483
|
-
|
|
484
|
-
args[0] = value;
|
|
485
|
-
parent->val = rb_class_new_instance(1, args, rb_class_of(parent->val));
|
|
486
|
-
copy_ivars(parent->val, prev);
|
|
487
|
-
} else if (3 == klen && 0 == strncmp("~bt", key, klen)) {
|
|
488
|
-
rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
#if USE_PTHREAD_MUTEX
|
|
492
|
-
pthread_mutex_lock(&oj_cache_mutex);
|
|
493
|
-
#elif USE_RB_MUTEX
|
|
494
|
-
rb_mutex_lock(oj_cache_mutex);
|
|
495
|
-
#endif
|
|
496
|
-
if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
|
|
497
|
-
char attr[256];
|
|
498
|
-
|
|
499
|
-
if ((int)sizeof(attr) <= klen + 2) {
|
|
500
|
-
char *buf = ALLOC_N(char, klen + 2);
|
|
501
|
-
|
|
502
|
-
if ('~' == *key) {
|
|
503
|
-
strncpy(buf, key + 1, klen - 1);
|
|
504
|
-
buf[klen - 1] = '\0';
|
|
505
|
-
} else {
|
|
506
|
-
*buf = '@';
|
|
507
|
-
strncpy(buf + 1, key, klen);
|
|
508
|
-
buf[klen + 1] = '\0';
|
|
509
|
-
}
|
|
510
|
-
var_id = rb_intern(buf);
|
|
511
|
-
xfree(buf);
|
|
512
|
-
} else {
|
|
513
|
-
if ('~' == *key) {
|
|
514
|
-
strncpy(attr, key + 1, klen - 1);
|
|
515
|
-
attr[klen - 1] = '\0';
|
|
516
|
-
} else {
|
|
517
|
-
*attr = '@';
|
|
518
|
-
strncpy(attr + 1, key, klen);
|
|
519
|
-
attr[klen + 1] = '\0';
|
|
520
|
-
}
|
|
521
|
-
var_id = rb_intern(attr);
|
|
522
|
-
}
|
|
523
|
-
*slot = var_id;
|
|
524
|
-
}
|
|
525
|
-
#if USE_PTHREAD_MUTEX
|
|
526
|
-
pthread_mutex_unlock(&oj_cache_mutex);
|
|
527
|
-
#elif USE_RB_MUTEX
|
|
528
|
-
rb_mutex_unlock(oj_cache_mutex);
|
|
529
|
-
#endif
|
|
530
|
-
rb_ivar_set(parent->val, var_id, value);
|
|
376
|
+
void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
|
377
|
+
rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
|
|
531
378
|
}
|
|
532
379
|
|
|
533
|
-
static void
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
380
|
+
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
|
381
|
+
const char * key = kval->key;
|
|
382
|
+
int klen = kval->klen;
|
|
383
|
+
Val parent = stack_peek(&pi->stack);
|
|
384
|
+
volatile VALUE rval = Qnil;
|
|
538
385
|
|
|
539
|
-
|
|
386
|
+
WHICH_TYPE:
|
|
540
387
|
switch (rb_type(parent->val)) {
|
|
541
388
|
case T_NIL:
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
389
|
+
parent->odd_args = NULL; // make sure it is NULL in case not odd
|
|
390
|
+
if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) {
|
|
391
|
+
parent->val = rb_hash_new();
|
|
392
|
+
goto WHICH_TYPE;
|
|
393
|
+
}
|
|
394
|
+
break;
|
|
548
395
|
case T_HASH:
|
|
549
|
-
|
|
550
|
-
|
|
396
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
|
|
397
|
+
break;
|
|
551
398
|
case T_STRING:
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
399
|
+
rval = str_to_value(pi, str, len, orig);
|
|
400
|
+
if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
|
|
401
|
+
rb_funcall(parent->val, oj_replace_id, 1, rval);
|
|
402
|
+
} else {
|
|
403
|
+
oj_set_obj_ivar(parent, kval, rval);
|
|
404
|
+
}
|
|
405
|
+
break;
|
|
558
406
|
case T_OBJECT:
|
|
559
|
-
|
|
560
|
-
|
|
407
|
+
rval = str_to_value(pi, str, len, orig);
|
|
408
|
+
oj_set_obj_ivar(parent, kval, rval);
|
|
409
|
+
break;
|
|
561
410
|
case T_CLASS:
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
411
|
+
if (NULL == parent->odd_args) {
|
|
412
|
+
oj_set_error_at(pi,
|
|
413
|
+
oj_parse_error_class,
|
|
414
|
+
__FILE__,
|
|
415
|
+
__LINE__,
|
|
416
|
+
"%s is not an odd class",
|
|
417
|
+
rb_class2name(rb_obj_class(parent->val)));
|
|
418
|
+
return;
|
|
419
|
+
} else {
|
|
420
|
+
rval = str_to_value(pi, str, len, orig);
|
|
421
|
+
if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) {
|
|
422
|
+
char buf[256];
|
|
423
|
+
|
|
424
|
+
if ((int)sizeof(buf) - 1 <= klen) {
|
|
425
|
+
klen = sizeof(buf) - 2;
|
|
426
|
+
}
|
|
427
|
+
memcpy(buf, key, klen);
|
|
428
|
+
buf[klen] = '\0';
|
|
429
|
+
oj_set_error_at(pi,
|
|
430
|
+
oj_parse_error_class,
|
|
431
|
+
__FILE__,
|
|
432
|
+
__LINE__,
|
|
433
|
+
"%s is not an attribute of %s",
|
|
434
|
+
buf,
|
|
435
|
+
rb_class2name(rb_obj_class(parent->val)));
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
break;
|
|
576
439
|
default:
|
|
577
|
-
|
|
578
|
-
|
|
440
|
+
oj_set_error_at(pi,
|
|
441
|
+
oj_parse_error_class,
|
|
442
|
+
__FILE__,
|
|
443
|
+
__LINE__,
|
|
444
|
+
"can not add attributes to a %s",
|
|
445
|
+
rb_class2name(rb_obj_class(parent->val)));
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
if (Yes == pi->options.trace) {
|
|
449
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
|
|
579
450
|
}
|
|
580
451
|
}
|
|
581
452
|
|
|
582
|
-
static void
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
453
|
+
static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
|
454
|
+
const char * key = kval->key;
|
|
455
|
+
int klen = kval->klen;
|
|
456
|
+
Val parent = stack_peek(&pi->stack);
|
|
457
|
+
volatile VALUE rval = Qnil;
|
|
587
458
|
|
|
588
|
-
|
|
459
|
+
WHICH_TYPE:
|
|
589
460
|
switch (rb_type(parent->val)) {
|
|
590
461
|
case T_NIL:
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
462
|
+
parent->odd_args = NULL; // make sure it is NULL in case not odd
|
|
463
|
+
if ('^' != *key || !hat_num(pi, parent, kval, ni)) {
|
|
464
|
+
parent->val = rb_hash_new();
|
|
465
|
+
goto WHICH_TYPE;
|
|
466
|
+
}
|
|
467
|
+
break;
|
|
597
468
|
case T_HASH:
|
|
598
|
-
|
|
599
|
-
|
|
469
|
+
rval = oj_num_as_value(ni);
|
|
470
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
|
|
471
|
+
break;
|
|
600
472
|
case T_OBJECT:
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
473
|
+
if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp &&
|
|
474
|
+
0 != pi->circ_array) { // fixnum
|
|
475
|
+
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
|
476
|
+
} else {
|
|
477
|
+
rval = oj_num_as_value(ni);
|
|
478
|
+
oj_set_obj_ivar(parent, kval, rval);
|
|
479
|
+
}
|
|
480
|
+
break;
|
|
608
481
|
case T_CLASS:
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
482
|
+
if (NULL == parent->odd_args) {
|
|
483
|
+
oj_set_error_at(pi,
|
|
484
|
+
oj_parse_error_class,
|
|
485
|
+
__FILE__,
|
|
486
|
+
__LINE__,
|
|
487
|
+
"%s is not an odd class",
|
|
488
|
+
rb_class2name(rb_obj_class(parent->val)));
|
|
489
|
+
return;
|
|
490
|
+
} else {
|
|
491
|
+
rval = oj_num_as_value(ni);
|
|
492
|
+
if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) {
|
|
493
|
+
char buf[256];
|
|
494
|
+
|
|
495
|
+
if ((int)sizeof(buf) - 1 <= klen) {
|
|
496
|
+
klen = sizeof(buf) - 2;
|
|
497
|
+
}
|
|
498
|
+
memcpy(buf, key, klen);
|
|
499
|
+
buf[klen] = '\0';
|
|
500
|
+
oj_set_error_at(pi,
|
|
501
|
+
oj_parse_error_class,
|
|
502
|
+
__FILE__,
|
|
503
|
+
__LINE__,
|
|
504
|
+
"%s is not an attribute of %s",
|
|
505
|
+
buf,
|
|
506
|
+
rb_class2name(rb_obj_class(parent->val)));
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
break;
|
|
623
510
|
default:
|
|
624
|
-
|
|
625
|
-
|
|
511
|
+
oj_set_error_at(pi,
|
|
512
|
+
oj_parse_error_class,
|
|
513
|
+
__FILE__,
|
|
514
|
+
__LINE__,
|
|
515
|
+
"can not add attributes to a %s",
|
|
516
|
+
rb_class2name(rb_obj_class(parent->val)));
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
if (Yes == pi->options.trace) {
|
|
520
|
+
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
|
|
626
521
|
}
|
|
627
522
|
}
|
|
628
523
|
|
|
629
|
-
static void
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
Val parent = stack_peek(&pi->stack);
|
|
524
|
+
static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
|
525
|
+
const char *key = kval->key;
|
|
526
|
+
int klen = kval->klen;
|
|
527
|
+
Val parent = stack_peek(&pi->stack);
|
|
634
528
|
|
|
635
|
-
|
|
529
|
+
WHICH_TYPE:
|
|
636
530
|
switch (rb_type(parent->val)) {
|
|
637
531
|
case T_NIL:
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
532
|
+
parent->odd_args = NULL; // make sure it is NULL in case not odd
|
|
533
|
+
if ('^' != *key || !hat_value(pi, parent, key, klen, value)) {
|
|
534
|
+
parent->val = rb_hash_new();
|
|
535
|
+
goto WHICH_TYPE;
|
|
536
|
+
}
|
|
537
|
+
break;
|
|
644
538
|
case T_HASH:
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
539
|
+
if (rb_cHash != rb_obj_class(parent->val)) {
|
|
540
|
+
if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
|
|
541
|
+
rb_funcall(parent->val, oj_replace_id, 1, value);
|
|
542
|
+
} else {
|
|
543
|
+
oj_set_obj_ivar(parent, kval, value);
|
|
544
|
+
}
|
|
545
|
+
} else {
|
|
546
|
+
if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
|
|
547
|
+
long len = RARRAY_LEN(value);
|
|
548
|
+
volatile VALUE *a = RARRAY_PTR(value);
|
|
549
|
+
|
|
550
|
+
if (2 != len) {
|
|
551
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
rb_hash_aset(parent->val, *a, a[1]);
|
|
555
|
+
} else {
|
|
556
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), value);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
break;
|
|
666
560
|
case T_ARRAY:
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
case T_STRING:
|
|
674
|
-
case T_OBJECT:
|
|
675
|
-
set_obj_ivar(parent, kval, value);
|
|
676
|
-
break;
|
|
561
|
+
if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
|
|
562
|
+
rb_funcall(parent->val, oj_replace_id, 1, value);
|
|
563
|
+
} else {
|
|
564
|
+
oj_set_obj_ivar(parent, kval, value);
|
|
565
|
+
}
|
|
566
|
+
break;
|
|
567
|
+
case T_STRING: // for subclassed strings
|
|
568
|
+
case T_OBJECT: oj_set_obj_ivar(parent, kval, value); break;
|
|
677
569
|
case T_MODULE:
|
|
678
570
|
case T_CLASS:
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
571
|
+
if (NULL == parent->odd_args) {
|
|
572
|
+
oj_set_error_at(pi,
|
|
573
|
+
oj_parse_error_class,
|
|
574
|
+
__FILE__,
|
|
575
|
+
__LINE__,
|
|
576
|
+
"%s is not an odd class",
|
|
577
|
+
rb_class2name(rb_obj_class(parent->val)));
|
|
578
|
+
return;
|
|
579
|
+
} else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
|
|
580
|
+
char buf[256];
|
|
581
|
+
|
|
582
|
+
if ((int)sizeof(buf) - 1 <= klen) {
|
|
583
|
+
klen = sizeof(buf) - 2;
|
|
584
|
+
}
|
|
585
|
+
memcpy(buf, key, klen);
|
|
586
|
+
buf[klen] = '\0';
|
|
587
|
+
oj_set_error_at(pi,
|
|
588
|
+
oj_parse_error_class,
|
|
589
|
+
__FILE__,
|
|
590
|
+
__LINE__,
|
|
591
|
+
"%s is not an attribute of %s",
|
|
592
|
+
buf,
|
|
593
|
+
rb_class2name(rb_obj_class(parent->val)));
|
|
594
|
+
}
|
|
595
|
+
break;
|
|
693
596
|
default:
|
|
694
|
-
|
|
695
|
-
|
|
597
|
+
oj_set_error_at(pi,
|
|
598
|
+
oj_parse_error_class,
|
|
599
|
+
__FILE__,
|
|
600
|
+
__LINE__,
|
|
601
|
+
"can not add attributes to a %s",
|
|
602
|
+
rb_class2name(rb_obj_class(parent->val)));
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
if (Yes == pi->options.trace) {
|
|
606
|
+
oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
|
|
696
607
|
}
|
|
697
608
|
}
|
|
698
609
|
|
|
699
|
-
static VALUE
|
|
700
|
-
|
|
610
|
+
static VALUE start_hash(ParseInfo pi) {
|
|
611
|
+
if (Yes == pi->options.trace) {
|
|
612
|
+
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
|
613
|
+
}
|
|
701
614
|
return Qnil;
|
|
702
615
|
}
|
|
703
616
|
|
|
704
|
-
static void
|
|
705
|
-
|
|
706
|
-
Val parent = stack_peek(&pi->stack);
|
|
617
|
+
static void end_hash(ParseInfo pi) {
|
|
618
|
+
Val parent = stack_peek(&pi->stack);
|
|
707
619
|
|
|
708
620
|
if (Qnil == parent->val) {
|
|
709
|
-
|
|
710
|
-
} else if (
|
|
711
|
-
|
|
621
|
+
parent->val = rb_hash_new();
|
|
622
|
+
} else if (NULL != parent->odd_args) {
|
|
623
|
+
OddArgs oa = parent->odd_args;
|
|
712
624
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
625
|
+
parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
|
|
626
|
+
oj_odd_free(oa);
|
|
627
|
+
parent->odd_args = NULL;
|
|
628
|
+
}
|
|
629
|
+
if (Yes == pi->options.trace) {
|
|
630
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
|
716
631
|
}
|
|
717
632
|
}
|
|
718
633
|
|
|
719
|
-
static void
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
634
|
+
static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
635
|
+
volatile VALUE rval = Qnil;
|
|
636
|
+
|
|
637
|
+
// orig lets us know whether the string was ^r1 or \u005er1
|
|
638
|
+
if (3 <= len && 0 != pi->circ_array && '^' == orig[0] && 0 == rb_array_len(stack_peek(&pi->stack)->val)) {
|
|
639
|
+
if ('i' == str[1]) {
|
|
640
|
+
long i = read_long(str + 2, len - 2);
|
|
641
|
+
|
|
642
|
+
if (0 < i) {
|
|
643
|
+
oj_circ_array_set(pi->circ_array, stack_peek(&pi->stack)->val, i);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
} else if ('r' == str[1]) {
|
|
647
|
+
long i = read_long(str + 2, len - 2);
|
|
648
|
+
|
|
649
|
+
if (0 < i) {
|
|
650
|
+
rb_ary_push(stack_peek(&pi->stack)->val, oj_circ_array_get(pi->circ_array, i));
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
rval = str_to_value(pi, str, len, orig);
|
|
656
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
|
657
|
+
if (Yes == pi->options.trace) {
|
|
658
|
+
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
|
|
659
|
+
}
|
|
740
660
|
}
|
|
741
661
|
|
|
742
|
-
static void
|
|
743
|
-
|
|
744
|
-
|
|
662
|
+
static void array_append_num(ParseInfo pi, NumInfo ni) {
|
|
663
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
|
664
|
+
|
|
665
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
|
666
|
+
if (Yes == pi->options.trace) {
|
|
667
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
|
668
|
+
}
|
|
745
669
|
}
|
|
746
670
|
|
|
747
|
-
static void
|
|
748
|
-
add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
671
|
+
static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
749
672
|
pi->stack.head->val = str_to_value(pi, str, len, orig);
|
|
673
|
+
if (Yes == pi->options.trace) {
|
|
674
|
+
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
|
|
675
|
+
}
|
|
750
676
|
}
|
|
751
677
|
|
|
752
|
-
static void
|
|
753
|
-
add_num(ParseInfo pi, NumInfo ni) {
|
|
678
|
+
static void add_num(ParseInfo pi, NumInfo ni) {
|
|
754
679
|
pi->stack.head->val = oj_num_as_value(ni);
|
|
680
|
+
if (Yes == pi->options.trace) {
|
|
681
|
+
oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
|
|
682
|
+
}
|
|
755
683
|
}
|
|
756
684
|
|
|
757
|
-
void
|
|
758
|
-
oj_set_object_callbacks(ParseInfo pi) {
|
|
685
|
+
void oj_set_object_callbacks(ParseInfo pi) {
|
|
759
686
|
oj_set_strict_callbacks(pi);
|
|
760
|
-
pi->end_hash
|
|
761
|
-
pi->start_hash
|
|
762
|
-
pi->hash_set_cstr
|
|
763
|
-
pi->hash_set_num
|
|
764
|
-
pi->hash_set_value
|
|
765
|
-
pi->add_cstr
|
|
766
|
-
pi->add_num
|
|
687
|
+
pi->end_hash = end_hash;
|
|
688
|
+
pi->start_hash = start_hash;
|
|
689
|
+
pi->hash_set_cstr = hash_set_cstr;
|
|
690
|
+
pi->hash_set_num = hash_set_num;
|
|
691
|
+
pi->hash_set_value = hash_set_value;
|
|
692
|
+
pi->add_cstr = add_cstr;
|
|
693
|
+
pi->add_num = add_num;
|
|
767
694
|
pi->array_append_cstr = array_append_cstr;
|
|
768
|
-
pi->array_append_num
|
|
695
|
+
pi->array_append_num = array_append_num;
|
|
769
696
|
}
|
|
770
697
|
|
|
771
698
|
VALUE
|
|
772
699
|
oj_object_parse(int argc, VALUE *argv, VALUE self) {
|
|
773
|
-
struct
|
|
700
|
+
struct _parseInfo pi;
|
|
774
701
|
|
|
775
|
-
pi
|
|
776
|
-
pi.
|
|
702
|
+
parse_info_init(&pi);
|
|
703
|
+
pi.options = oj_default_options;
|
|
704
|
+
pi.handler = Qnil;
|
|
777
705
|
pi.err_class = Qnil;
|
|
778
706
|
oj_set_object_callbacks(&pi);
|
|
779
707
|
|
|
780
708
|
if (T_STRING == rb_type(*argv)) {
|
|
781
|
-
|
|
709
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
|
|
782
710
|
} else {
|
|
783
|
-
|
|
711
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
|
784
712
|
}
|
|
785
713
|
}
|
|
786
714
|
|
|
787
715
|
VALUE
|
|
788
716
|
oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
|
789
|
-
struct
|
|
717
|
+
struct _parseInfo pi;
|
|
790
718
|
|
|
791
|
-
pi
|
|
792
|
-
pi.
|
|
719
|
+
parse_info_init(&pi);
|
|
720
|
+
pi.options = oj_default_options;
|
|
721
|
+
pi.handler = Qnil;
|
|
793
722
|
pi.err_class = Qnil;
|
|
794
723
|
oj_set_strict_callbacks(&pi);
|
|
795
|
-
pi.end_hash
|
|
796
|
-
pi.start_hash
|
|
797
|
-
pi.hash_set_cstr
|
|
798
|
-
pi.hash_set_num
|
|
799
|
-
pi.hash_set_value
|
|
800
|
-
pi.add_cstr
|
|
801
|
-
pi.add_num
|
|
724
|
+
pi.end_hash = end_hash;
|
|
725
|
+
pi.start_hash = start_hash;
|
|
726
|
+
pi.hash_set_cstr = hash_set_cstr;
|
|
727
|
+
pi.hash_set_num = hash_set_num;
|
|
728
|
+
pi.hash_set_value = hash_set_value;
|
|
729
|
+
pi.add_cstr = add_cstr;
|
|
730
|
+
pi.add_num = add_num;
|
|
802
731
|
pi.array_append_cstr = array_append_cstr;
|
|
803
|
-
pi.array_append_num
|
|
732
|
+
pi.array_append_num = array_append_num;
|
|
804
733
|
|
|
805
734
|
return oj_pi_parse(argc, argv, &pi, json, len, 1);
|
|
806
735
|
}
|