oj 3.7.12
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +96 -0
- data/ext/oj/buf.h +103 -0
- data/ext/oj/cache8.c +107 -0
- data/ext/oj/cache8.h +48 -0
- data/ext/oj/circarray.c +68 -0
- data/ext/oj/circarray.h +23 -0
- data/ext/oj/code.c +235 -0
- data/ext/oj/code.h +42 -0
- data/ext/oj/compat.c +299 -0
- data/ext/oj/custom.c +1188 -0
- data/ext/oj/dump.c +1232 -0
- data/ext/oj/dump.h +94 -0
- data/ext/oj/dump_compat.c +973 -0
- data/ext/oj/dump_leaf.c +252 -0
- data/ext/oj/dump_object.c +837 -0
- data/ext/oj/dump_strict.c +433 -0
- data/ext/oj/encode.h +45 -0
- data/ext/oj/err.c +57 -0
- data/ext/oj/err.h +70 -0
- data/ext/oj/extconf.rb +47 -0
- data/ext/oj/fast.c +1771 -0
- data/ext/oj/hash.c +163 -0
- data/ext/oj/hash.h +46 -0
- data/ext/oj/hash_test.c +512 -0
- data/ext/oj/mimic_json.c +873 -0
- data/ext/oj/object.c +771 -0
- data/ext/oj/odd.c +231 -0
- data/ext/oj/odd.h +44 -0
- data/ext/oj/oj.c +1694 -0
- data/ext/oj/oj.h +381 -0
- data/ext/oj/parse.c +1085 -0
- data/ext/oj/parse.h +111 -0
- data/ext/oj/rails.c +1485 -0
- data/ext/oj/rails.h +21 -0
- data/ext/oj/reader.c +231 -0
- data/ext/oj/reader.h +151 -0
- data/ext/oj/resolve.c +102 -0
- data/ext/oj/resolve.h +14 -0
- data/ext/oj/rxclass.c +147 -0
- data/ext/oj/rxclass.h +27 -0
- data/ext/oj/saj.c +714 -0
- data/ext/oj/scp.c +224 -0
- data/ext/oj/sparse.c +910 -0
- data/ext/oj/stream_writer.c +363 -0
- data/ext/oj/strict.c +212 -0
- data/ext/oj/string_writer.c +512 -0
- data/ext/oj/trace.c +79 -0
- data/ext/oj/trace.h +28 -0
- data/ext/oj/util.c +136 -0
- data/ext/oj/util.h +19 -0
- data/ext/oj/val_stack.c +118 -0
- data/ext/oj/val_stack.h +185 -0
- data/ext/oj/wab.c +631 -0
- data/lib/oj.rb +21 -0
- data/lib/oj/active_support_helper.rb +41 -0
- data/lib/oj/bag.rb +88 -0
- data/lib/oj/easy_hash.rb +52 -0
- data/lib/oj/error.rb +22 -0
- data/lib/oj/json.rb +176 -0
- data/lib/oj/mimic.rb +267 -0
- data/lib/oj/saj.rb +66 -0
- data/lib/oj/schandler.rb +142 -0
- data/lib/oj/state.rb +131 -0
- data/lib/oj/version.rb +5 -0
- 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 +79 -0
- data/pages/Modes.md +154 -0
- data/pages/Options.md +266 -0
- data/pages/Rails.md +116 -0
- data/pages/Security.md +20 -0
- data/pages/WAB.md +13 -0
- data/test/_test_active.rb +76 -0
- data/test/_test_active_mimic.rb +96 -0
- data/test/_test_mimic_rails.rb +126 -0
- data/test/activerecord/result_test.rb +27 -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/decoding_test.rb +125 -0
- data/test/activesupport5/encoding_test.rb +485 -0
- data/test/activesupport5/encoding_test_cases.rb +90 -0
- data/test/activesupport5/test_helper.rb +50 -0
- data/test/activesupport5/time_zone_test_helpers.rb +24 -0
- data/test/big.rb +15 -0
- data/test/files.rb +29 -0
- data/test/foo.rb +33 -0
- data/test/helper.rb +26 -0
- data/test/isolated/shared.rb +308 -0
- data/test/isolated/test_mimic_after.rb +13 -0
- data/test/isolated/test_mimic_alone.rb +12 -0
- data/test/isolated/test_mimic_as_json.rb +45 -0
- data/test/isolated/test_mimic_before.rb +13 -0
- data/test/isolated/test_mimic_define.rb +28 -0
- data/test/isolated/test_mimic_rails_after.rb +22 -0
- data/test/isolated/test_mimic_rails_before.rb +21 -0
- data/test/isolated/test_mimic_redefine.rb +15 -0
- data/test/json_gem/json_addition_test.rb +216 -0
- data/test/json_gem/json_common_interface_test.rb +148 -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 +383 -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 +18 -0
- data/test/mem.rb +35 -0
- data/test/perf.rb +107 -0
- data/test/perf_compat.rb +130 -0
- data/test/perf_fast.rb +164 -0
- data/test/perf_file.rb +64 -0
- data/test/perf_object.rb +138 -0
- data/test/perf_saj.rb +109 -0
- data/test/perf_scp.rb +151 -0
- data/test/perf_simple.rb +287 -0
- data/test/perf_strict.rb +145 -0
- data/test/perf_wab.rb +131 -0
- data/test/sample.rb +54 -0
- data/test/sample/change.rb +14 -0
- data/test/sample/dir.rb +19 -0
- data/test/sample/doc.rb +36 -0
- data/test/sample/file.rb +48 -0
- data/test/sample/group.rb +16 -0
- data/test/sample/hasprops.rb +16 -0
- data/test/sample/layer.rb +12 -0
- data/test/sample/line.rb +20 -0
- data/test/sample/oval.rb +10 -0
- data/test/sample/rect.rb +10 -0
- data/test/sample/shape.rb +35 -0
- data/test/sample/text.rb +20 -0
- data/test/sample_json.rb +37 -0
- data/test/test_compat.rb +509 -0
- data/test/test_custom.rb +406 -0
- data/test/test_debian.rb +53 -0
- data/test/test_fast.rb +470 -0
- data/test/test_file.rb +239 -0
- data/test/test_gc.rb +49 -0
- data/test/test_hash.rb +29 -0
- data/test/test_integer_range.rb +73 -0
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +1018 -0
- data/test/test_saj.rb +186 -0
- data/test/test_scp.rb +433 -0
- data/test/test_strict.rb +410 -0
- data/test/test_various.rb +739 -0
- data/test/test_wab.rb +307 -0
- data/test/test_writer.rb +380 -0
- data/test/tests.rb +24 -0
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- metadata +359 -0
data/ext/oj/wab.c
ADDED
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
/* wab.c
|
|
2
|
+
* Copyright (c) 2012, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include <stdlib.h>
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <string.h>
|
|
9
|
+
#include <time.h>
|
|
10
|
+
#include <unistd.h>
|
|
11
|
+
|
|
12
|
+
#include "oj.h"
|
|
13
|
+
#include "err.h"
|
|
14
|
+
#include "parse.h"
|
|
15
|
+
#include "encode.h"
|
|
16
|
+
#include "dump.h"
|
|
17
|
+
#include "trace.h"
|
|
18
|
+
#include "util.h"
|
|
19
|
+
|
|
20
|
+
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
|
21
|
+
#define OJ_INFINITY (1.0/0.0)
|
|
22
|
+
|
|
23
|
+
static char hex_chars[256] = "\
|
|
24
|
+
................................\
|
|
25
|
+
................xxxxxxxxxx......\
|
|
26
|
+
.xxxxxx.........................\
|
|
27
|
+
.xxxxxx.........................\
|
|
28
|
+
................................\
|
|
29
|
+
................................\
|
|
30
|
+
................................\
|
|
31
|
+
................................";
|
|
32
|
+
|
|
33
|
+
static VALUE wab_uuid_clas = Qundef;
|
|
34
|
+
static VALUE uri_clas = Qundef;
|
|
35
|
+
static VALUE uri_http_clas = Qundef;
|
|
36
|
+
|
|
37
|
+
///// dump functions /////
|
|
38
|
+
|
|
39
|
+
static VALUE
|
|
40
|
+
resolve_wab_uuid_class() {
|
|
41
|
+
if (Qundef == wab_uuid_clas) {
|
|
42
|
+
volatile VALUE wab_module;
|
|
43
|
+
|
|
44
|
+
wab_uuid_clas = Qnil;
|
|
45
|
+
if (rb_const_defined_at(rb_cObject, rb_intern("WAB"))) {
|
|
46
|
+
wab_module = rb_const_get_at(rb_cObject, rb_intern("WAB"));
|
|
47
|
+
if (rb_const_defined_at(wab_module, rb_intern("UUID"))) {
|
|
48
|
+
wab_uuid_clas = rb_const_get(wab_module, rb_intern("UUID"));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return wab_uuid_clas;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static VALUE
|
|
56
|
+
resolve_uri_class() {
|
|
57
|
+
if (Qundef == uri_clas) {
|
|
58
|
+
|
|
59
|
+
uri_clas = Qnil;
|
|
60
|
+
if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) {
|
|
61
|
+
uri_clas = rb_const_get_at(rb_cObject, rb_intern("URI"));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return uri_clas;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static VALUE
|
|
68
|
+
resolve_uri_http_class() {
|
|
69
|
+
if (Qundef == uri_http_clas) {
|
|
70
|
+
volatile VALUE uri_module;
|
|
71
|
+
|
|
72
|
+
uri_http_clas = Qnil;
|
|
73
|
+
if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) {
|
|
74
|
+
uri_module = rb_const_get_at(rb_cObject, rb_intern("URI"));
|
|
75
|
+
if (rb_const_defined_at(uri_module, rb_intern("HTTP"))) {
|
|
76
|
+
uri_http_clas = rb_const_get(uri_module, rb_intern("HTTP"));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return uri_http_clas;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static void
|
|
84
|
+
raise_wab(VALUE obj) {
|
|
85
|
+
rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in wab mode.\n", rb_class2name(rb_obj_class(obj)));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Removed dependencies on math due to problems with CentOS 5.4.
|
|
89
|
+
static void
|
|
90
|
+
dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
91
|
+
char buf[64];
|
|
92
|
+
char *b;
|
|
93
|
+
double d = rb_num2dbl(obj);
|
|
94
|
+
int cnt = 0;
|
|
95
|
+
|
|
96
|
+
if (0.0 == d) {
|
|
97
|
+
b = buf;
|
|
98
|
+
*b++ = '0';
|
|
99
|
+
*b++ = '.';
|
|
100
|
+
*b++ = '0';
|
|
101
|
+
*b++ = '\0';
|
|
102
|
+
cnt = 3;
|
|
103
|
+
} else {
|
|
104
|
+
if (OJ_INFINITY == d || -OJ_INFINITY == d || isnan(d)) {
|
|
105
|
+
raise_wab(obj);
|
|
106
|
+
} else if (d == (double)(long long int)d) {
|
|
107
|
+
cnt = snprintf(buf, sizeof(buf), "%.1f", d);
|
|
108
|
+
} else {
|
|
109
|
+
cnt = snprintf(buf, sizeof(buf), "%0.16g", d);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
assure_size(out, cnt);
|
|
113
|
+
for (b = buf; '\0' != *b; b++) {
|
|
114
|
+
*out->cur++ = *b;
|
|
115
|
+
}
|
|
116
|
+
*out->cur = '\0';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static void
|
|
120
|
+
dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
121
|
+
size_t size;
|
|
122
|
+
int i, cnt;
|
|
123
|
+
int d2 = depth + 1;
|
|
124
|
+
|
|
125
|
+
cnt = (int)RARRAY_LEN(a);
|
|
126
|
+
*out->cur++ = '[';
|
|
127
|
+
size = 2;
|
|
128
|
+
assure_size(out, size);
|
|
129
|
+
if (0 == cnt) {
|
|
130
|
+
*out->cur++ = ']';
|
|
131
|
+
} else {
|
|
132
|
+
size = d2 * out->indent + 2;
|
|
133
|
+
cnt--;
|
|
134
|
+
for (i = 0; i <= cnt; i++) {
|
|
135
|
+
assure_size(out, size);
|
|
136
|
+
fill_indent(out, d2);
|
|
137
|
+
oj_dump_wab_val(rb_ary_entry(a, i), d2, out);
|
|
138
|
+
if (i < cnt) {
|
|
139
|
+
*out->cur++ = ',';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
size = depth * out->indent + 1;
|
|
143
|
+
assure_size(out, size);
|
|
144
|
+
fill_indent(out, depth);
|
|
145
|
+
*out->cur++ = ']';
|
|
146
|
+
}
|
|
147
|
+
*out->cur = '\0';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
static int
|
|
151
|
+
hash_cb(VALUE key, VALUE value, Out out) {
|
|
152
|
+
int depth = out->depth;
|
|
153
|
+
long size;
|
|
154
|
+
int rtype = rb_type(key);
|
|
155
|
+
|
|
156
|
+
if (rtype != T_SYMBOL) {
|
|
157
|
+
rb_raise(rb_eTypeError, "In :wab mode all Hash keys must be Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));
|
|
158
|
+
}
|
|
159
|
+
size = depth * out->indent + 1;
|
|
160
|
+
assure_size(out, size);
|
|
161
|
+
fill_indent(out, depth);
|
|
162
|
+
oj_dump_sym(key, 0, out, false);
|
|
163
|
+
*out->cur++ = ':';
|
|
164
|
+
oj_dump_wab_val(value, depth, out);
|
|
165
|
+
out->depth = depth;
|
|
166
|
+
*out->cur++ = ',';
|
|
167
|
+
|
|
168
|
+
return ST_CONTINUE;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static void
|
|
172
|
+
dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
173
|
+
int cnt;
|
|
174
|
+
size_t size;
|
|
175
|
+
|
|
176
|
+
cnt = (int)RHASH_SIZE(obj);
|
|
177
|
+
size = depth * out->indent + 2;
|
|
178
|
+
assure_size(out, 2);
|
|
179
|
+
*out->cur++ = '{';
|
|
180
|
+
if (0 == cnt) {
|
|
181
|
+
*out->cur++ = '}';
|
|
182
|
+
} else {
|
|
183
|
+
out->depth = depth + 1;
|
|
184
|
+
rb_hash_foreach(obj, hash_cb, (VALUE)out);
|
|
185
|
+
if (',' == *(out->cur - 1)) {
|
|
186
|
+
out->cur--; // backup to overwrite last comma
|
|
187
|
+
}
|
|
188
|
+
assure_size(out, size);
|
|
189
|
+
fill_indent(out, depth);
|
|
190
|
+
*out->cur++ = '}';
|
|
191
|
+
}
|
|
192
|
+
*out->cur = '\0';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
static void
|
|
196
|
+
dump_time(VALUE obj, Out out) {
|
|
197
|
+
char buf[64];
|
|
198
|
+
struct _timeInfo ti;
|
|
199
|
+
int len;
|
|
200
|
+
time_t sec;
|
|
201
|
+
long long nsec;
|
|
202
|
+
|
|
203
|
+
#ifdef HAVE_RB_TIME_TIMESPEC
|
|
204
|
+
if (16 <= sizeof(struct timespec)) {
|
|
205
|
+
struct timespec ts = rb_time_timespec(obj);
|
|
206
|
+
|
|
207
|
+
sec = ts.tv_sec;
|
|
208
|
+
nsec = ts.tv_nsec;
|
|
209
|
+
} else {
|
|
210
|
+
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
|
211
|
+
nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
|
212
|
+
}
|
|
213
|
+
#else
|
|
214
|
+
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
|
215
|
+
nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
|
216
|
+
#endif
|
|
217
|
+
|
|
218
|
+
assure_size(out, 36);
|
|
219
|
+
// 2012-01-05T23:58:07.123456000Z
|
|
220
|
+
sec_as_time(sec, &ti);
|
|
221
|
+
|
|
222
|
+
len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec);
|
|
223
|
+
oj_dump_cstr(buf, len, 0, 0, out);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
static void
|
|
227
|
+
dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
228
|
+
volatile VALUE clas = rb_obj_class(obj);
|
|
229
|
+
|
|
230
|
+
if (rb_cTime == clas) {
|
|
231
|
+
dump_time(obj, out);
|
|
232
|
+
} else if (oj_bigdecimal_class == clas) {
|
|
233
|
+
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
234
|
+
|
|
235
|
+
oj_dump_raw(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), out);
|
|
236
|
+
} else if (resolve_wab_uuid_class() == clas) {
|
|
237
|
+
oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false);
|
|
238
|
+
} else if (resolve_uri_http_class() == clas) {
|
|
239
|
+
oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false);
|
|
240
|
+
} else {
|
|
241
|
+
raise_wab(obj);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
static DumpFunc wab_funcs[] = {
|
|
246
|
+
NULL, // RUBY_T_NONE = 0x00,
|
|
247
|
+
dump_obj, // RUBY_T_OBJECT = 0x01,
|
|
248
|
+
NULL, // RUBY_T_CLASS = 0x02,
|
|
249
|
+
NULL, // RUBY_T_MODULE = 0x03,
|
|
250
|
+
dump_float, // RUBY_T_FLOAT = 0x04,
|
|
251
|
+
oj_dump_str, // RUBY_T_STRING = 0x05,
|
|
252
|
+
NULL, // RUBY_T_REGEXP = 0x06,
|
|
253
|
+
dump_array, // RUBY_T_ARRAY = 0x07,
|
|
254
|
+
dump_hash, // RUBY_T_HASH = 0x08,
|
|
255
|
+
NULL, // RUBY_T_STRUCT = 0x09,
|
|
256
|
+
oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
|
|
257
|
+
NULL, // RUBY_T_FILE = 0x0b,
|
|
258
|
+
dump_obj, // RUBY_T_DATA = 0x0c,
|
|
259
|
+
NULL, // RUBY_T_MATCH = 0x0d,
|
|
260
|
+
NULL, // RUBY_T_COMPLEX = 0x0e,
|
|
261
|
+
NULL, // RUBY_T_RATIONAL = 0x0f,
|
|
262
|
+
NULL, // 0x10
|
|
263
|
+
oj_dump_nil, // RUBY_T_NIL = 0x11,
|
|
264
|
+
oj_dump_true, // RUBY_T_TRUE = 0x12,
|
|
265
|
+
oj_dump_false, // RUBY_T_FALSE = 0x13,
|
|
266
|
+
oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
|
|
267
|
+
oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
void
|
|
271
|
+
oj_dump_wab_val(VALUE obj, int depth, Out out) {
|
|
272
|
+
int type = rb_type(obj);
|
|
273
|
+
|
|
274
|
+
if (Yes == out->opts->trace) {
|
|
275
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
|
276
|
+
}
|
|
277
|
+
if (MAX_DEPTH < depth) {
|
|
278
|
+
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
|
279
|
+
}
|
|
280
|
+
if (0 < type && type <= RUBY_T_FIXNUM) {
|
|
281
|
+
DumpFunc f = wab_funcs[type];
|
|
282
|
+
|
|
283
|
+
if (NULL != f) {
|
|
284
|
+
f(obj, depth, out, false);
|
|
285
|
+
if (Yes == out->opts->trace) {
|
|
286
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
|
287
|
+
}
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
raise_wab(obj);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
///// load functions /////
|
|
295
|
+
|
|
296
|
+
static void
|
|
297
|
+
hash_end(ParseInfo pi) {
|
|
298
|
+
if (Yes == pi->options.trace) {
|
|
299
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
static void
|
|
304
|
+
array_end(ParseInfo pi) {
|
|
305
|
+
if (Yes == pi->options.trace) {
|
|
306
|
+
oj_trace_parse_array_end(pi, __FILE__, __LINE__);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
static VALUE
|
|
311
|
+
noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
|
312
|
+
return Qundef;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
static void
|
|
316
|
+
add_value(ParseInfo pi, VALUE val) {
|
|
317
|
+
if (Yes == pi->options.trace) {
|
|
318
|
+
oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
|
|
319
|
+
}
|
|
320
|
+
pi->stack.head->val = val;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// 123e4567-e89b-12d3-a456-426655440000
|
|
324
|
+
static bool
|
|
325
|
+
uuid_check(const char *str, int len) {
|
|
326
|
+
int i;
|
|
327
|
+
|
|
328
|
+
for (i = 0; i < 8; i++, str++) {
|
|
329
|
+
if ('x' != hex_chars[*(uint8_t*)str]) {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
str++;
|
|
334
|
+
for (i = 0; i < 4; i++, str++) {
|
|
335
|
+
if ('x' != hex_chars[*(uint8_t*)str]) {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
str++;
|
|
340
|
+
for (i = 0; i < 4; i++, str++) {
|
|
341
|
+
if ('x' != hex_chars[*(uint8_t*)str]) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
str++;
|
|
346
|
+
for (i = 0; i < 4; i++, str++) {
|
|
347
|
+
if ('x' != hex_chars[*(uint8_t*)str]) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
str++;
|
|
352
|
+
for (i = 0; i < 12; i++, str++) {
|
|
353
|
+
if ('x' != hex_chars[*(uint8_t*)str]) {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
static const char*
|
|
361
|
+
read_num(const char *s, int len, int *vp) {
|
|
362
|
+
uint32_t v = 0;
|
|
363
|
+
|
|
364
|
+
for (; 0 < len; len--, s++) {
|
|
365
|
+
if ('0' <= *s && *s <= '9') {
|
|
366
|
+
v = v * 10 + *s - '0';
|
|
367
|
+
} else {
|
|
368
|
+
return NULL;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
*vp = (int)v;
|
|
372
|
+
|
|
373
|
+
return s;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
static VALUE
|
|
377
|
+
time_parse(const char *s, int len) {
|
|
378
|
+
struct tm tm;
|
|
379
|
+
bool neg = false;
|
|
380
|
+
long nsecs = 0;
|
|
381
|
+
int i;
|
|
382
|
+
time_t secs;
|
|
383
|
+
|
|
384
|
+
memset(&tm, 0, sizeof(tm));
|
|
385
|
+
if ('-' == *s) {
|
|
386
|
+
s++;
|
|
387
|
+
neg = true;
|
|
388
|
+
}
|
|
389
|
+
if (NULL == (s = read_num(s, 4, &tm.tm_year))) {
|
|
390
|
+
return Qnil;
|
|
391
|
+
}
|
|
392
|
+
if (neg) {
|
|
393
|
+
tm.tm_year = -tm.tm_year;
|
|
394
|
+
neg = false;
|
|
395
|
+
}
|
|
396
|
+
tm.tm_year -= 1900;
|
|
397
|
+
s++;
|
|
398
|
+
if (NULL == (s = read_num(s, 2, &tm.tm_mon))) {
|
|
399
|
+
return Qnil;
|
|
400
|
+
}
|
|
401
|
+
tm.tm_mon--;
|
|
402
|
+
s++;
|
|
403
|
+
if (NULL == (s = read_num(s, 2, &tm.tm_mday))) {
|
|
404
|
+
return Qnil;
|
|
405
|
+
}
|
|
406
|
+
s++;
|
|
407
|
+
if (NULL == (s = read_num(s, 2, &tm.tm_hour))) {
|
|
408
|
+
return Qnil;
|
|
409
|
+
}
|
|
410
|
+
s++;
|
|
411
|
+
if (NULL == (s = read_num(s, 2, &tm.tm_min))) {
|
|
412
|
+
return Qnil;
|
|
413
|
+
}
|
|
414
|
+
s++;
|
|
415
|
+
if (NULL == (s = read_num(s, 2, &tm.tm_sec))) {
|
|
416
|
+
return Qnil;
|
|
417
|
+
}
|
|
418
|
+
s++;
|
|
419
|
+
|
|
420
|
+
for (i = 9; 0 < i; i--, s++) {
|
|
421
|
+
if ('0' <= *s && *s <= '9') {
|
|
422
|
+
nsecs = nsecs * 10 + *s - '0';
|
|
423
|
+
} else {
|
|
424
|
+
return Qnil;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
#if IS_WINDOWS
|
|
428
|
+
secs = (time_t)mktime(&tm);
|
|
429
|
+
memset(&tm, 0, sizeof(tm));
|
|
430
|
+
tm.tm_year = 70;
|
|
431
|
+
tm.tm_mday = 1;
|
|
432
|
+
secs -= (time_t)mktime(&tm);
|
|
433
|
+
#else
|
|
434
|
+
secs = (time_t)timegm(&tm);
|
|
435
|
+
#endif
|
|
436
|
+
return rb_funcall(rb_time_nano_new(secs, nsecs), oj_utc_id, 0);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
static VALUE
|
|
440
|
+
protect_uri(VALUE rstr) {
|
|
441
|
+
return rb_funcall(resolve_uri_class(), oj_parse_id, 1, rstr);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
static VALUE
|
|
445
|
+
cstr_to_rstr(const char *str, size_t len) {
|
|
446
|
+
volatile VALUE v = Qnil;
|
|
447
|
+
|
|
448
|
+
if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] && ':' == str[16] && '.' == str[19] && 'Z' == str[29]) {
|
|
449
|
+
if (Qnil != (v = time_parse(str, (int)len))) {
|
|
450
|
+
return v;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (36 == len && '-' == str[8] && '-' == str[13] && '-' == str[18] && '-' == str[23] && uuid_check(str, (int)len) && Qnil != resolve_wab_uuid_class()) {
|
|
454
|
+
return rb_funcall(wab_uuid_clas, oj_new_id, 1, rb_str_new(str, len));
|
|
455
|
+
}
|
|
456
|
+
v = rb_str_new(str, len);
|
|
457
|
+
if (7 < len && 0 == strncasecmp("http://", str, 7)) {
|
|
458
|
+
int err = 0;
|
|
459
|
+
volatile VALUE uri = rb_protect(protect_uri, v, &err);
|
|
460
|
+
|
|
461
|
+
if (0 == err) {
|
|
462
|
+
return uri;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return oj_encode(v);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
static void
|
|
469
|
+
add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
470
|
+
pi->stack.head->val = cstr_to_rstr(str, len);
|
|
471
|
+
if (Yes == pi->options.trace) {
|
|
472
|
+
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
static void
|
|
477
|
+
add_num(ParseInfo pi, NumInfo ni) {
|
|
478
|
+
if (ni->infinity || ni->nan) {
|
|
479
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
|
480
|
+
}
|
|
481
|
+
pi->stack.head->val = oj_num_as_value(ni);
|
|
482
|
+
if (Yes == pi->options.trace) {
|
|
483
|
+
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
static VALUE
|
|
488
|
+
start_hash(ParseInfo pi) {
|
|
489
|
+
if (Yes == pi->options.trace) {
|
|
490
|
+
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
|
491
|
+
}
|
|
492
|
+
if (Qnil != pi->options.hash_class) {
|
|
493
|
+
return rb_class_new_instance(0, NULL, pi->options.hash_class);
|
|
494
|
+
}
|
|
495
|
+
return rb_hash_new();
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
static VALUE
|
|
499
|
+
calc_hash_key(ParseInfo pi, Val parent) {
|
|
500
|
+
volatile VALUE rkey = parent->key_val;
|
|
501
|
+
|
|
502
|
+
if (Qundef == rkey) {
|
|
503
|
+
rkey = rb_str_new(parent->key, parent->klen);
|
|
504
|
+
}
|
|
505
|
+
rkey = oj_encode(rkey);
|
|
506
|
+
rkey = rb_str_intern(rkey);
|
|
507
|
+
|
|
508
|
+
return rkey;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
static void
|
|
512
|
+
hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
|
|
513
|
+
volatile VALUE rval = cstr_to_rstr(str, len);
|
|
514
|
+
|
|
515
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
|
|
516
|
+
if (Yes == pi->options.trace) {
|
|
517
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
static void
|
|
522
|
+
hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
|
|
523
|
+
volatile VALUE rval = Qnil;
|
|
524
|
+
|
|
525
|
+
if (ni->infinity || ni->nan) {
|
|
526
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
|
527
|
+
}
|
|
528
|
+
rval = oj_num_as_value(ni);
|
|
529
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
|
|
530
|
+
if (Yes == pi->options.trace) {
|
|
531
|
+
oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
static void
|
|
536
|
+
hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
|
537
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
|
|
538
|
+
if (Yes == pi->options.trace) {
|
|
539
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
static VALUE
|
|
544
|
+
start_array(ParseInfo pi) {
|
|
545
|
+
if (Yes == pi->options.trace) {
|
|
546
|
+
oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
|
|
547
|
+
}
|
|
548
|
+
return rb_ary_new();
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
static void
|
|
552
|
+
array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
553
|
+
volatile VALUE rval = cstr_to_rstr(str, len);
|
|
554
|
+
|
|
555
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
|
556
|
+
if (Yes == pi->options.trace) {
|
|
557
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, rval);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
static void
|
|
562
|
+
array_append_num(ParseInfo pi, NumInfo ni) {
|
|
563
|
+
volatile VALUE rval = Qnil;
|
|
564
|
+
|
|
565
|
+
if (ni->infinity || ni->nan) {
|
|
566
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
|
567
|
+
}
|
|
568
|
+
rval = oj_num_as_value(ni);
|
|
569
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
|
570
|
+
if (Yes == pi->options.trace) {
|
|
571
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
static void
|
|
576
|
+
array_append_value(ParseInfo pi, VALUE value) {
|
|
577
|
+
rb_ary_push(stack_peek(&pi->stack)->val, value);
|
|
578
|
+
if (Yes == pi->options.trace) {
|
|
579
|
+
oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
void
|
|
584
|
+
oj_set_wab_callbacks(ParseInfo pi) {
|
|
585
|
+
pi->start_hash = start_hash;
|
|
586
|
+
pi->end_hash = hash_end;
|
|
587
|
+
pi->hash_key = noop_hash_key;
|
|
588
|
+
pi->hash_set_cstr = hash_set_cstr;
|
|
589
|
+
pi->hash_set_num = hash_set_num;
|
|
590
|
+
pi->hash_set_value = hash_set_value;
|
|
591
|
+
pi->start_array = start_array;
|
|
592
|
+
pi->end_array = array_end;
|
|
593
|
+
pi->array_append_cstr = array_append_cstr;
|
|
594
|
+
pi->array_append_num = array_append_num;
|
|
595
|
+
pi->array_append_value = array_append_value;
|
|
596
|
+
pi->add_cstr = add_cstr;
|
|
597
|
+
pi->add_num = add_num;
|
|
598
|
+
pi->add_value = add_value;
|
|
599
|
+
pi->expect_value = 1;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
VALUE
|
|
603
|
+
oj_wab_parse(int argc, VALUE *argv, VALUE self) {
|
|
604
|
+
struct _parseInfo pi;
|
|
605
|
+
|
|
606
|
+
parse_info_init(&pi);
|
|
607
|
+
pi.options = oj_default_options;
|
|
608
|
+
pi.handler = Qnil;
|
|
609
|
+
pi.err_class = Qnil;
|
|
610
|
+
oj_set_wab_callbacks(&pi);
|
|
611
|
+
|
|
612
|
+
if (T_STRING == rb_type(*argv)) {
|
|
613
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, true);
|
|
614
|
+
} else {
|
|
615
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
VALUE
|
|
620
|
+
oj_wab_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
|
621
|
+
struct _parseInfo pi;
|
|
622
|
+
|
|
623
|
+
parse_info_init(&pi);
|
|
624
|
+
pi.options = oj_default_options;
|
|
625
|
+
pi.handler = Qnil;
|
|
626
|
+
pi.err_class = Qnil;
|
|
627
|
+
oj_set_wab_callbacks(&pi);
|
|
628
|
+
|
|
629
|
+
return oj_pi_parse(argc, argv, &pi, json, len, true);
|
|
630
|
+
}
|
|
631
|
+
|