oj 2.18.5 → 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 +5 -5
- data/CHANGELOG.md +1452 -0
- data/README.md +53 -221
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +54 -72
- data/ext/oj/cache.c +329 -0
- data/ext/oj/cache.h +22 -0
- data/ext/oj/cache8.c +61 -63
- data/ext/oj/cache8.h +12 -39
- data/ext/oj/circarray.c +38 -67
- data/ext/oj/circarray.h +16 -42
- data/ext/oj/code.c +214 -0
- data/ext/oj/code.h +40 -0
- data/ext/oj/compat.c +194 -110
- data/ext/oj/custom.c +1074 -0
- data/ext/oj/debug.c +126 -0
- data/ext/oj/dump.c +1276 -2494
- data/ext/oj/dump.h +110 -0
- data/ext/oj/dump_compat.c +897 -0
- data/ext/oj/dump_leaf.c +162 -0
- data/ext/oj/dump_object.c +710 -0
- data/ext/oj/dump_strict.c +399 -0
- data/ext/oj/encode.h +7 -42
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +28 -53
- data/ext/oj/err.h +49 -46
- data/ext/oj/extconf.rb +33 -32
- data/ext/oj/fast.c +1082 -1098
- 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 +919 -0
- data/ext/oj/object.c +545 -625
- data/ext/oj/odd.c +158 -168
- data/ext/oj/odd.h +32 -58
- data/ext/oj/oj.c +1727 -2080
- data/ext/oj/oj.h +334 -259
- data/ext/oj/parse.c +974 -753
- data/ext/oj/parse.h +97 -90
- data/ext/oj/parser.c +1600 -0
- data/ext/oj/parser.h +103 -0
- data/ext/oj/rails.c +1478 -0
- data/ext/oj/rails.h +18 -0
- data/ext/oj/reader.c +136 -163
- data/ext/oj/reader.h +76 -112
- data/ext/oj/resolve.c +45 -94
- data/ext/oj/resolve.h +7 -34
- data/ext/oj/rxclass.c +144 -0
- data/ext/oj/rxclass.h +26 -0
- data/ext/oj/saj.c +445 -511
- data/ext/oj/saj2.c +584 -0
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +82 -143
- data/ext/oj/simd.h +10 -0
- data/ext/oj/sparse.c +749 -644
- data/ext/oj/stream_writer.c +329 -0
- data/ext/oj/strict.c +114 -112
- data/ext/oj/string_writer.c +517 -0
- data/ext/oj/trace.c +72 -0
- data/ext/oj/trace.h +55 -0
- data/ext/oj/usual.c +1218 -0
- data/ext/oj/usual.h +69 -0
- data/ext/oj/util.c +136 -0
- data/ext/oj/util.h +20 -0
- data/ext/oj/val_stack.c +75 -72
- data/ext/oj/val_stack.h +94 -127
- data/ext/oj/validate.c +46 -0
- data/ext/oj/wab.c +586 -0
- data/lib/oj/active_support_helper.rb +1 -3
- data/lib/oj/bag.rb +8 -1
- data/lib/oj/easy_hash.rb +21 -13
- data/lib/oj/error.rb +10 -12
- data/lib/oj/json.rb +188 -0
- data/lib/oj/mimic.rb +165 -26
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/state.rb +135 -0
- data/lib/oj/version.rb +2 -3
- data/lib/oj.rb +3 -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/InstallOptions.md +20 -0
- data/pages/JsonGem.md +94 -0
- data/pages/Modes.md +161 -0
- data/pages/Options.md +337 -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
- metadata +126 -163
- 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/activesupport_datetime_test.rb +0 -23
- data/test/bug.rb +0 -51
- 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/files.rb +0 -29
- data/test/foo.rb +0 -24
- data/test/helper.rb +0 -27
- data/test/io.rb +0 -48
- data/test/isolated/shared.rb +0 -310
- 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_rails_datetime.rb +0 -27
- data/test/isolated/test_mimic_redefine.rb +0 -15
- data/test/mod.rb +0 -16
- data/test/perf.rb +0 -107
- data/test/perf_compat.rb +0 -128
- 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 -128
- data/test/rails.rb +0 -50
- data/test/russian.rb +0 -18
- 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 -55
- data/test/sample_json.rb +0 -37
- data/test/struct.rb +0 -29
- data/test/test_compat.rb +0 -398
- data/test/test_debian.rb +0 -53
- data/test/test_fast.rb +0 -458
- data/test/test_file.rb +0 -245
- data/test/test_gc.rb +0 -49
- data/test/test_hash.rb +0 -29
- data/test/test_object.rb +0 -745
- data/test/test_saj.rb +0 -186
- data/test/test_scp.rb +0 -396
- data/test/test_serializer.rb +0 -59
- data/test/test_strict.rb +0 -254
- data/test/test_various.rb +0 -1383
- data/test/test_writer.rb +0 -308
- data/test/write_timebars.rb +0 -31
data/ext/oj/object.c
CHANGED
@@ -1,806 +1,726 @@
|
|
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
|
-
|
84
|
+
VALUE
|
85
|
+
oj_parse_xml_time(const char *str, int len) {
|
86
|
+
VALUE args[7];
|
87
|
+
const char *end = str + len;
|
88
|
+
const char *orig = str;
|
89
|
+
int n;
|
125
90
|
|
126
91
|
// year
|
127
92
|
if (0 > (n = parse_num(str, end, 4))) {
|
128
|
-
|
93
|
+
return Qnil;
|
129
94
|
}
|
130
95
|
str += 4;
|
131
96
|
args[0] = LONG2NUM(n);
|
132
97
|
if ('-' != *str++) {
|
133
|
-
|
98
|
+
return Qnil;
|
134
99
|
}
|
135
100
|
// month
|
136
101
|
if (0 > (n = parse_num(str, end, 2))) {
|
137
|
-
|
102
|
+
return Qnil;
|
138
103
|
}
|
139
104
|
str += 2;
|
140
105
|
args[1] = LONG2NUM(n);
|
141
106
|
if ('-' != *str++) {
|
142
|
-
|
107
|
+
return Qnil;
|
143
108
|
}
|
144
109
|
// day
|
145
110
|
if (0 > (n = parse_num(str, end, 2))) {
|
146
|
-
|
111
|
+
return Qnil;
|
147
112
|
}
|
148
113
|
str += 2;
|
149
114
|
args[2] = LONG2NUM(n);
|
150
115
|
if ('T' != *str++) {
|
151
|
-
|
116
|
+
return Qnil;
|
152
117
|
}
|
153
118
|
// hour
|
154
119
|
if (0 > (n = parse_num(str, end, 2))) {
|
155
|
-
|
120
|
+
return Qnil;
|
156
121
|
}
|
157
122
|
str += 2;
|
158
123
|
args[3] = LONG2NUM(n);
|
159
124
|
if (':' != *str++) {
|
160
|
-
|
125
|
+
return Qnil;
|
161
126
|
}
|
162
127
|
// minute
|
163
128
|
if (0 > (n = parse_num(str, end, 2))) {
|
164
|
-
|
129
|
+
return Qnil;
|
165
130
|
}
|
166
131
|
str += 2;
|
167
132
|
args[4] = LONG2NUM(n);
|
168
133
|
if (':' != *str++) {
|
169
|
-
|
134
|
+
return Qnil;
|
170
135
|
}
|
171
136
|
// second
|
172
137
|
if (0 > (n = parse_num(str, end, 2))) {
|
173
|
-
|
138
|
+
return Qnil;
|
174
139
|
}
|
175
140
|
str += 2;
|
176
141
|
if (str == end) {
|
177
|
-
|
178
|
-
|
142
|
+
args[5] = LONG2NUM(n);
|
143
|
+
args[6] = LONG2NUM(0);
|
179
144
|
} 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
|
-
|
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
|
+
}
|
232
204
|
}
|
233
205
|
return rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
234
206
|
}
|
235
|
-
#endif
|
236
207
|
|
237
|
-
static int
|
238
|
-
|
239
|
-
|
240
|
-
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;
|
241
211
|
|
242
212
|
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
|
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
|
292
252
|
}
|
293
253
|
return 0;
|
294
254
|
}
|
295
255
|
|
296
|
-
static int
|
297
|
-
hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
256
|
+
static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
298
257
|
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
|
-
args[0] = LONG2NUM(1900 + st->tm_year);
|
345
|
-
args[1] = LONG2NUM(1 + st->tm_mon);
|
346
|
-
args[2] = LONG2NUM(st->tm_mday);
|
347
|
-
args[3] = LONG2NUM(st->tm_hour);
|
348
|
-
args[4] = LONG2NUM(st->tm_min);
|
349
|
-
#if NO_TIME_ROUND_PAD
|
350
|
-
args[5] = rb_float_new((double)st->tm_sec + ((double)nsec) / 1000000000.0);
|
351
|
-
#else
|
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
|
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
|
381
302
|
}
|
382
303
|
return 0;
|
383
304
|
}
|
384
305
|
|
385
|
-
static int
|
386
|
-
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) {
|
387
307
|
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
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
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.
|
418
342
|
#ifdef RSTRUCT_LEN
|
419
|
-
#if
|
420
|
-
|
421
|
-
#else
|
422
|
-
|
423
|
-
#endif
|
343
|
+
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
344
|
+
slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
|
345
|
+
#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
346
|
+
slen = (int)RSTRUCT_LEN(parent->val);
|
347
|
+
#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
424
348
|
#else
|
425
|
-
|
349
|
+
slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
|
426
350
|
#endif
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
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;
|
432
365
|
|
433
|
-
|
434
|
-
|
435
|
-
|
366
|
+
if (2 != len) {
|
367
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
368
|
+
return 1;
|
436
369
|
}
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
return 1;
|
444
|
-
}
|
445
|
-
parent->val = rb_hash_new();
|
446
|
-
a = RARRAY_PTR(value);
|
447
|
-
rb_hash_aset(parent->val, *a, a[1]);
|
448
|
-
|
449
|
-
return 1;
|
450
|
-
}
|
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
|
+
}
|
451
376
|
}
|
452
377
|
return 0;
|
453
378
|
}
|
454
379
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
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
|
-
}
|
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);
|
469
387
|
}
|
470
388
|
}
|
471
389
|
|
472
|
-
static void
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
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);
|
531
|
-
}
|
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;
|
532
395
|
|
533
|
-
|
534
|
-
hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
535
|
-
const char *key = kval->key;
|
536
|
-
int klen = kval->klen;
|
537
|
-
Val parent = stack_peek(&pi->stack);
|
538
|
-
|
539
|
-
WHICH_TYPE:
|
396
|
+
WHICH_TYPE:
|
540
397
|
switch (rb_type(parent->val)) {
|
541
398
|
case T_NIL:
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
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;
|
548
405
|
case T_HASH:
|
549
|
-
|
550
|
-
|
406
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
|
407
|
+
break;
|
551
408
|
case T_STRING:
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
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;
|
558
416
|
case T_OBJECT:
|
559
|
-
|
560
|
-
|
417
|
+
rval = str_to_value(pi, str, len, orig);
|
418
|
+
oj_set_obj_ivar(parent, kval, rval);
|
419
|
+
break;
|
561
420
|
case T_CLASS:
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
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;
|
576
449
|
default:
|
577
|
-
|
578
|
-
|
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;
|
579
457
|
}
|
458
|
+
TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rval);
|
580
459
|
}
|
581
460
|
|
582
|
-
static void
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
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;
|
587
466
|
|
588
|
-
|
467
|
+
WHICH_TYPE:
|
589
468
|
switch (rb_type(parent->val)) {
|
590
469
|
case T_NIL:
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
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;
|
597
476
|
case T_HASH:
|
598
|
-
|
599
|
-
|
477
|
+
rval = oj_num_as_value(ni);
|
478
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
|
479
|
+
break;
|
600
480
|
case T_OBJECT:
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
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;
|
608
489
|
case T_CLASS:
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
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;
|
623
518
|
default:
|
624
|
-
|
625
|
-
|
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;
|
626
526
|
}
|
527
|
+
TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, rval);
|
627
528
|
}
|
628
529
|
|
629
|
-
static void
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
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);
|
634
534
|
|
635
|
-
|
535
|
+
WHICH_TYPE:
|
636
536
|
switch (rb_type(parent->val)) {
|
637
537
|
case T_NIL:
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
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;
|
644
544
|
case T_HASH:
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
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;
|
666
566
|
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;
|
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;
|
677
575
|
case T_MODULE:
|
678
576
|
case T_CLASS:
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
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;
|
693
602
|
default:
|
694
|
-
|
695
|
-
|
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;
|
696
610
|
}
|
611
|
+
TRACE_PARSE_CALL(pi->options.trace, "add_value", pi, value);
|
697
612
|
}
|
698
613
|
|
699
|
-
static VALUE
|
700
|
-
|
614
|
+
static VALUE start_hash(ParseInfo pi) {
|
615
|
+
TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
|
701
616
|
return Qnil;
|
702
617
|
}
|
703
618
|
|
704
|
-
static void
|
705
|
-
|
706
|
-
Val parent = stack_peek(&pi->stack);
|
619
|
+
static void end_hash(ParseInfo pi) {
|
620
|
+
Val parent = stack_peek(&pi->stack);
|
707
621
|
|
708
622
|
if (Qnil == parent->val) {
|
709
|
-
|
710
|
-
} else if (
|
711
|
-
|
623
|
+
parent->val = rb_hash_new();
|
624
|
+
} else if (NULL != parent->odd_args) {
|
625
|
+
OddArgs oa = parent->odd_args;
|
712
626
|
|
713
|
-
|
714
|
-
|
715
|
-
|
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;
|
716
630
|
}
|
631
|
+
TRACE_PARSE_HASH_END(pi->options.trace, pi);
|
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
|
-
|
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
|
+
}
|
738
654
|
}
|
739
|
-
|
655
|
+
rval = str_to_value(pi, str, len, orig);
|
656
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
657
|
+
TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rval);
|
740
658
|
}
|
741
659
|
|
742
|
-
static void
|
743
|
-
|
744
|
-
|
660
|
+
static void array_append_num(ParseInfo pi, NumInfo ni) {
|
661
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
662
|
+
|
663
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
664
|
+
TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
|
745
665
|
}
|
746
666
|
|
747
|
-
static void
|
748
|
-
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) {
|
749
668
|
pi->stack.head->val = str_to_value(pi, str, len, orig);
|
669
|
+
TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, pi->stack.head->val);
|
750
670
|
}
|
751
671
|
|
752
|
-
static void
|
753
|
-
add_num(ParseInfo pi, NumInfo ni) {
|
672
|
+
static void add_num(ParseInfo pi, NumInfo ni) {
|
754
673
|
pi->stack.head->val = oj_num_as_value(ni);
|
674
|
+
TRACE_PARSE_CALL(pi->options.trace, "add_num", pi, pi->stack.head->val);
|
755
675
|
}
|
756
676
|
|
757
|
-
void
|
758
|
-
oj_set_object_callbacks(ParseInfo pi) {
|
677
|
+
void oj_set_object_callbacks(ParseInfo pi) {
|
759
678
|
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
|
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;
|
767
686
|
pi->array_append_cstr = array_append_cstr;
|
768
|
-
pi->array_append_num
|
687
|
+
pi->array_append_num = array_append_num;
|
769
688
|
}
|
770
689
|
|
771
690
|
VALUE
|
772
691
|
oj_object_parse(int argc, VALUE *argv, VALUE self) {
|
773
|
-
struct
|
692
|
+
struct _parseInfo pi;
|
774
693
|
|
775
|
-
pi
|
776
|
-
pi.
|
694
|
+
parse_info_init(&pi);
|
695
|
+
pi.options = oj_default_options;
|
696
|
+
pi.handler = Qnil;
|
777
697
|
pi.err_class = Qnil;
|
778
698
|
oj_set_object_callbacks(&pi);
|
779
699
|
|
780
700
|
if (T_STRING == rb_type(*argv)) {
|
781
|
-
|
782
|
-
} else {
|
783
|
-
return oj_pi_sparse(argc, argv, &pi, 0);
|
701
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
|
784
702
|
}
|
703
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
785
704
|
}
|
786
705
|
|
787
706
|
VALUE
|
788
707
|
oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
789
|
-
struct
|
708
|
+
struct _parseInfo pi;
|
790
709
|
|
791
|
-
pi
|
792
|
-
pi.
|
710
|
+
parse_info_init(&pi);
|
711
|
+
pi.options = oj_default_options;
|
712
|
+
pi.handler = Qnil;
|
793
713
|
pi.err_class = Qnil;
|
794
714
|
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
|
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;
|
802
722
|
pi.array_append_cstr = array_append_cstr;
|
803
|
-
pi.array_append_num
|
723
|
+
pi.array_append_num = array_append_num;
|
804
724
|
|
805
725
|
return oj_pi_parse(argc, argv, &pi, json, len, 1);
|
806
726
|
}
|