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/custom.c
ADDED
|
@@ -0,0 +1,1188 @@
|
|
|
1
|
+
/* custom.c
|
|
2
|
+
* Copyright (c) 2012, 2017, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include <stdint.h>
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
|
|
9
|
+
#include "code.h"
|
|
10
|
+
#include "dump.h"
|
|
11
|
+
#include "encode.h"
|
|
12
|
+
#include "err.h"
|
|
13
|
+
#include "hash.h"
|
|
14
|
+
#include "odd.h"
|
|
15
|
+
#include "oj.h"
|
|
16
|
+
#include "parse.h"
|
|
17
|
+
#include "resolve.h"
|
|
18
|
+
#include "trace.h"
|
|
19
|
+
#include "util.h"
|
|
20
|
+
|
|
21
|
+
extern void oj_set_obj_ivar(Val parent, Val kval, VALUE value);
|
|
22
|
+
extern VALUE oj_parse_xml_time(const char *str, int len); // from object.c
|
|
23
|
+
|
|
24
|
+
static void
|
|
25
|
+
dump_obj_str(VALUE obj, int depth, Out out) {
|
|
26
|
+
struct _attr attrs[] = {
|
|
27
|
+
{ "s", 1, Qnil },
|
|
28
|
+
{ NULL, 0, Qnil },
|
|
29
|
+
};
|
|
30
|
+
attrs->value = rb_funcall(obj, oj_to_s_id, 0);
|
|
31
|
+
|
|
32
|
+
oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
static void
|
|
37
|
+
bigdecimal_dump(VALUE obj, int depth, Out out) {
|
|
38
|
+
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
39
|
+
const char *str = rb_string_value_ptr((VALUE*)&rstr);
|
|
40
|
+
int len = (int)RSTRING_LEN(rstr);
|
|
41
|
+
|
|
42
|
+
if (0 == strcasecmp("Infinity", str)) {
|
|
43
|
+
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
|
|
44
|
+
oj_dump_raw(str, len, out);
|
|
45
|
+
} else if (0 == strcasecmp("-Infinity", str)) {
|
|
46
|
+
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
|
|
47
|
+
oj_dump_raw(str, len, out);
|
|
48
|
+
} else if (No == out->opts->bigdec_as_num) {
|
|
49
|
+
oj_dump_cstr(str, len, 0, 0, out);
|
|
50
|
+
} else {
|
|
51
|
+
oj_dump_raw(str, len, out);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static ID real_id = 0;
|
|
56
|
+
static ID imag_id = 0;
|
|
57
|
+
|
|
58
|
+
static void
|
|
59
|
+
complex_dump(VALUE obj, int depth, Out out) {
|
|
60
|
+
struct _attr attrs[] = {
|
|
61
|
+
{ "real", 4, Qnil },
|
|
62
|
+
{ "imag", 4, Qnil },
|
|
63
|
+
{ NULL, 0, Qnil },
|
|
64
|
+
};
|
|
65
|
+
if (0 == real_id) {
|
|
66
|
+
real_id = rb_intern("real");
|
|
67
|
+
imag_id = rb_intern("imag");
|
|
68
|
+
}
|
|
69
|
+
attrs[0].value = rb_funcall(obj, real_id, 0);
|
|
70
|
+
attrs[1].value = rb_funcall(obj, imag_id, 0);
|
|
71
|
+
|
|
72
|
+
oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static VALUE
|
|
76
|
+
complex_load(VALUE clas, VALUE args) {
|
|
77
|
+
if (0 == real_id) {
|
|
78
|
+
real_id = rb_intern("real");
|
|
79
|
+
imag_id = rb_intern("imag");
|
|
80
|
+
}
|
|
81
|
+
return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)), rb_hash_aref(args, rb_id2str(imag_id)));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static void
|
|
85
|
+
time_dump(VALUE obj, int depth, Out out) {
|
|
86
|
+
if (Yes == out->opts->create_ok) {
|
|
87
|
+
struct _attr attrs[] = {
|
|
88
|
+
{ "time", 4, Qundef, 0, Qundef },
|
|
89
|
+
{ NULL, 0, Qnil },
|
|
90
|
+
};
|
|
91
|
+
attrs->time = obj;
|
|
92
|
+
|
|
93
|
+
oj_code_attrs(obj, attrs, depth, out, true);
|
|
94
|
+
} else {
|
|
95
|
+
switch (out->opts->time_format) {
|
|
96
|
+
case RubyTime: oj_dump_ruby_time(obj, out); break;
|
|
97
|
+
case XmlTime: oj_dump_xml_time(obj, out); break;
|
|
98
|
+
case UnixZTime: oj_dump_time(obj, out, true); break;
|
|
99
|
+
case UnixTime:
|
|
100
|
+
default: oj_dump_time(obj, out, false); break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static void
|
|
106
|
+
date_dump(VALUE obj, int depth, Out out) {
|
|
107
|
+
if (Yes == out->opts->create_ok) {
|
|
108
|
+
struct _attr attrs[] = {
|
|
109
|
+
{ "s", 1, Qnil },
|
|
110
|
+
{ NULL, 0, Qnil },
|
|
111
|
+
};
|
|
112
|
+
attrs->value = rb_funcall(obj, rb_intern("iso8601"), 0);
|
|
113
|
+
|
|
114
|
+
oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
|
|
115
|
+
} else {
|
|
116
|
+
volatile VALUE v;
|
|
117
|
+
volatile VALUE ov;
|
|
118
|
+
|
|
119
|
+
switch (out->opts->time_format) {
|
|
120
|
+
case RubyTime:
|
|
121
|
+
case XmlTime:
|
|
122
|
+
v = rb_funcall(obj, rb_intern("iso8601"), 0);
|
|
123
|
+
oj_dump_cstr(rb_string_value_ptr((VALUE*)&v), (int)RSTRING_LEN(v), 0, 0, out);
|
|
124
|
+
break;
|
|
125
|
+
case UnixZTime:
|
|
126
|
+
v = rb_funcall(obj, rb_intern("to_time"), 0);
|
|
127
|
+
if (oj_date_class == rb_obj_class(obj)) {
|
|
128
|
+
ov = rb_funcall(v, rb_intern("utc_offset"), 0);
|
|
129
|
+
v = rb_funcall(v, rb_intern("utc"), 0);
|
|
130
|
+
v = rb_funcall(v, rb_intern("+"), 1, ov);
|
|
131
|
+
oj_dump_time(v, out, false);
|
|
132
|
+
} else {
|
|
133
|
+
oj_dump_time(v, out, true);
|
|
134
|
+
}
|
|
135
|
+
break;
|
|
136
|
+
case UnixTime:
|
|
137
|
+
default:
|
|
138
|
+
v = rb_funcall(obj, rb_intern("to_time"), 0);
|
|
139
|
+
if (oj_date_class == rb_obj_class(obj)) {
|
|
140
|
+
ov = rb_funcall(v, rb_intern("utc_offset"), 0);
|
|
141
|
+
v = rb_funcall(v, rb_intern("utc"), 0);
|
|
142
|
+
v = rb_funcall(v, rb_intern("+"), 1, ov);
|
|
143
|
+
}
|
|
144
|
+
oj_dump_time(v, out, false);
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
static VALUE
|
|
151
|
+
date_load(VALUE clas, VALUE args) {
|
|
152
|
+
volatile VALUE v;
|
|
153
|
+
|
|
154
|
+
if (Qnil != (v = rb_hash_aref(args, rb_str_new2("s")))) {
|
|
155
|
+
return rb_funcall(oj_date_class, rb_intern("parse"), 1, v);
|
|
156
|
+
}
|
|
157
|
+
return Qnil;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static VALUE
|
|
161
|
+
datetime_load(VALUE clas, VALUE args) {
|
|
162
|
+
volatile VALUE v;
|
|
163
|
+
|
|
164
|
+
if (Qnil != (v = rb_hash_aref(args, rb_str_new2("s")))) {
|
|
165
|
+
return rb_funcall(oj_datetime_class, rb_intern("parse"), 1, v);
|
|
166
|
+
}
|
|
167
|
+
return Qnil;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
static ID table_id = 0;
|
|
171
|
+
|
|
172
|
+
static void
|
|
173
|
+
openstruct_dump(VALUE obj, int depth, Out out) {
|
|
174
|
+
struct _attr attrs[] = {
|
|
175
|
+
{ "table", 5, Qnil },
|
|
176
|
+
{ NULL, 0, Qnil },
|
|
177
|
+
};
|
|
178
|
+
if (0 == table_id) {
|
|
179
|
+
table_id = rb_intern("table");
|
|
180
|
+
}
|
|
181
|
+
attrs->value = rb_funcall(obj, table_id, 0);
|
|
182
|
+
|
|
183
|
+
oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
static VALUE
|
|
187
|
+
openstruct_load(VALUE clas, VALUE args) {
|
|
188
|
+
if (0 == table_id) {
|
|
189
|
+
table_id = rb_intern("table");
|
|
190
|
+
}
|
|
191
|
+
return rb_funcall(clas, oj_new_id, 1, rb_hash_aref(args, rb_id2str(table_id)));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
static void
|
|
195
|
+
range_dump(VALUE obj, int depth, Out out) {
|
|
196
|
+
struct _attr attrs[] = {
|
|
197
|
+
{ "begin", 5, Qnil },
|
|
198
|
+
{ "end", 3, Qnil },
|
|
199
|
+
{ "exclude", 7, Qnil },
|
|
200
|
+
{ NULL, 0, Qnil },
|
|
201
|
+
};
|
|
202
|
+
attrs[0].value = rb_funcall(obj, oj_begin_id, 0);
|
|
203
|
+
attrs[1].value = rb_funcall(obj, oj_end_id, 0);
|
|
204
|
+
attrs[2].value = rb_funcall(obj, oj_exclude_end_id, 0);
|
|
205
|
+
|
|
206
|
+
oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static VALUE
|
|
210
|
+
range_load(VALUE clas, VALUE args) {
|
|
211
|
+
VALUE nargs[3];
|
|
212
|
+
|
|
213
|
+
nargs[0] = rb_hash_aref(args, rb_id2str(oj_begin_id));
|
|
214
|
+
nargs[1] = rb_hash_aref(args, rb_id2str(oj_end_id));
|
|
215
|
+
nargs[2] = rb_hash_aref(args, rb_id2str(oj_exclude_end_id));
|
|
216
|
+
|
|
217
|
+
return rb_class_new_instance(3, nargs, rb_cRange);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
static ID numerator_id = 0;
|
|
221
|
+
static ID denominator_id = 0;
|
|
222
|
+
|
|
223
|
+
static void
|
|
224
|
+
rational_dump(VALUE obj, int depth, Out out) {
|
|
225
|
+
struct _attr attrs[] = {
|
|
226
|
+
{ "numerator", 9, Qnil },
|
|
227
|
+
{ "denominator", 11, Qnil },
|
|
228
|
+
{ NULL, 0, Qnil },
|
|
229
|
+
};
|
|
230
|
+
if (0 == numerator_id) {
|
|
231
|
+
numerator_id = rb_intern("numerator");
|
|
232
|
+
denominator_id = rb_intern("denominator");
|
|
233
|
+
}
|
|
234
|
+
attrs[0].value = rb_funcall(obj, numerator_id, 0);
|
|
235
|
+
attrs[1].value = rb_funcall(obj, denominator_id, 0);
|
|
236
|
+
|
|
237
|
+
oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
static VALUE
|
|
241
|
+
rational_load(VALUE clas, VALUE args) {
|
|
242
|
+
if (0 == numerator_id) {
|
|
243
|
+
numerator_id = rb_intern("numerator");
|
|
244
|
+
denominator_id = rb_intern("denominator");
|
|
245
|
+
}
|
|
246
|
+
return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)),
|
|
247
|
+
rb_hash_aref(args, rb_id2str(denominator_id)));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
static VALUE
|
|
251
|
+
regexp_load(VALUE clas, VALUE args) {
|
|
252
|
+
volatile VALUE v;
|
|
253
|
+
|
|
254
|
+
if (Qnil != (v = rb_hash_aref(args, rb_str_new2("s")))) {
|
|
255
|
+
return rb_funcall(rb_cRegexp, oj_new_id, 1, v);
|
|
256
|
+
}
|
|
257
|
+
return Qnil;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
static VALUE
|
|
261
|
+
time_load(VALUE clas, VALUE args) {
|
|
262
|
+
// Value should have already been replaced in one of the hash_set_xxx
|
|
263
|
+
// functions.
|
|
264
|
+
return args;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
static struct _code codes[] = {
|
|
268
|
+
{ "BigDecimal", Qnil, bigdecimal_dump, NULL, true },
|
|
269
|
+
{ "Complex", Qnil, complex_dump, complex_load, true },
|
|
270
|
+
{ "Date", Qnil, date_dump, date_load, true },
|
|
271
|
+
{ "DateTime", Qnil, date_dump, datetime_load, true },
|
|
272
|
+
{ "OpenStruct", Qnil, openstruct_dump, openstruct_load, true },
|
|
273
|
+
{ "Range", Qnil, range_dump, range_load, true },
|
|
274
|
+
{ "Rational", Qnil, rational_dump, rational_load, true },
|
|
275
|
+
{ "Regexp", Qnil, dump_obj_str, regexp_load, true },
|
|
276
|
+
{ "Time", Qnil, time_dump, time_load, true },
|
|
277
|
+
{ NULL, Qundef, NULL, NULL, false },
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
static int
|
|
281
|
+
hash_cb(VALUE key, VALUE value, Out out) {
|
|
282
|
+
int depth = out->depth;
|
|
283
|
+
|
|
284
|
+
if (oj_dump_ignore(out->opts, value)) {
|
|
285
|
+
return ST_CONTINUE;
|
|
286
|
+
}
|
|
287
|
+
if (out->omit_nil && Qnil == value) {
|
|
288
|
+
return ST_CONTINUE;
|
|
289
|
+
}
|
|
290
|
+
if (!out->opts->dump_opts.use) {
|
|
291
|
+
assure_size(out, depth * out->indent + 1);
|
|
292
|
+
fill_indent(out, depth);
|
|
293
|
+
} else {
|
|
294
|
+
assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
|
295
|
+
if (0 < out->opts->dump_opts.hash_size) {
|
|
296
|
+
strcpy(out->cur, out->opts->dump_opts.hash_nl);
|
|
297
|
+
out->cur += out->opts->dump_opts.hash_size;
|
|
298
|
+
}
|
|
299
|
+
if (0 < out->opts->dump_opts.indent_size) {
|
|
300
|
+
int i;
|
|
301
|
+
|
|
302
|
+
for (i = depth; 0 < i; i--) {
|
|
303
|
+
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
|
304
|
+
out->cur += out->opts->dump_opts.indent_size;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
switch (rb_type(key)) {
|
|
309
|
+
case T_STRING:
|
|
310
|
+
oj_dump_str(key, 0, out, false);
|
|
311
|
+
break;
|
|
312
|
+
case T_SYMBOL:
|
|
313
|
+
oj_dump_sym(key, 0, out, false);
|
|
314
|
+
break;
|
|
315
|
+
default:
|
|
316
|
+
oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false);
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
if (!out->opts->dump_opts.use) {
|
|
320
|
+
*out->cur++ = ':';
|
|
321
|
+
} else {
|
|
322
|
+
assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2);
|
|
323
|
+
if (0 < out->opts->dump_opts.before_size) {
|
|
324
|
+
strcpy(out->cur, out->opts->dump_opts.before_sep);
|
|
325
|
+
out->cur += out->opts->dump_opts.before_size;
|
|
326
|
+
}
|
|
327
|
+
*out->cur++ = ':';
|
|
328
|
+
if (0 < out->opts->dump_opts.after_size) {
|
|
329
|
+
strcpy(out->cur, out->opts->dump_opts.after_sep);
|
|
330
|
+
out->cur += out->opts->dump_opts.after_size;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
oj_dump_custom_val(value, depth, out, true);
|
|
334
|
+
out->depth = depth;
|
|
335
|
+
*out->cur++ = ',';
|
|
336
|
+
|
|
337
|
+
return ST_CONTINUE;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
static void
|
|
341
|
+
dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
342
|
+
int cnt;
|
|
343
|
+
long id = oj_check_circular(obj, out);
|
|
344
|
+
|
|
345
|
+
if (0 > id) {
|
|
346
|
+
oj_dump_nil(Qnil, depth, out, false);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
cnt = (int)RHASH_SIZE(obj);
|
|
350
|
+
assure_size(out, 2);
|
|
351
|
+
if (0 == cnt) {
|
|
352
|
+
*out->cur++ = '{';
|
|
353
|
+
*out->cur++ = '}';
|
|
354
|
+
} else {
|
|
355
|
+
*out->cur++ = '{';
|
|
356
|
+
out->depth = depth + 1;
|
|
357
|
+
rb_hash_foreach(obj, hash_cb, (VALUE)out);
|
|
358
|
+
if (',' == *(out->cur - 1)) {
|
|
359
|
+
out->cur--; // backup to overwrite last comma
|
|
360
|
+
}
|
|
361
|
+
if (!out->opts->dump_opts.use) {
|
|
362
|
+
assure_size(out, depth * out->indent + 2);
|
|
363
|
+
fill_indent(out, depth);
|
|
364
|
+
} else {
|
|
365
|
+
assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
|
366
|
+
if (0 < out->opts->dump_opts.hash_size) {
|
|
367
|
+
strcpy(out->cur, out->opts->dump_opts.hash_nl);
|
|
368
|
+
out->cur += out->opts->dump_opts.hash_size;
|
|
369
|
+
}
|
|
370
|
+
if (0 < out->opts->dump_opts.indent_size) {
|
|
371
|
+
int i;
|
|
372
|
+
|
|
373
|
+
for (i = depth; 0 < i; i--) {
|
|
374
|
+
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
|
375
|
+
out->cur += out->opts->dump_opts.indent_size;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
*out->cur++ = '}';
|
|
380
|
+
}
|
|
381
|
+
*out->cur = '\0';
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
static void
|
|
385
|
+
dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
386
|
+
ID *idp;
|
|
387
|
+
AttrGetFunc *fp;
|
|
388
|
+
volatile VALUE v;
|
|
389
|
+
const char *name;
|
|
390
|
+
size_t size;
|
|
391
|
+
int d2 = depth + 1;
|
|
392
|
+
|
|
393
|
+
assure_size(out, 2);
|
|
394
|
+
*out->cur++ = '{';
|
|
395
|
+
if (NULL != out->opts->create_id && Yes == out->opts->create_ok) {
|
|
396
|
+
const char *classname = rb_class2name(clas);
|
|
397
|
+
int clen = (int)strlen(classname);
|
|
398
|
+
size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
|
399
|
+
|
|
400
|
+
size = d2 * out->indent + 10 + clen + out->opts->create_id_len + sep_len;
|
|
401
|
+
assure_size(out, size);
|
|
402
|
+
fill_indent(out, d2);
|
|
403
|
+
*out->cur++ = '"';
|
|
404
|
+
memcpy(out->cur, out->opts->create_id, out->opts->create_id_len);
|
|
405
|
+
out->cur += out->opts->create_id_len;
|
|
406
|
+
*out->cur++ = '"';
|
|
407
|
+
if (0 < out->opts->dump_opts.before_size) {
|
|
408
|
+
strcpy(out->cur, out->opts->dump_opts.before_sep);
|
|
409
|
+
out->cur += out->opts->dump_opts.before_size;
|
|
410
|
+
}
|
|
411
|
+
*out->cur++ = ':';
|
|
412
|
+
if (0 < out->opts->dump_opts.after_size) {
|
|
413
|
+
strcpy(out->cur, out->opts->dump_opts.after_sep);
|
|
414
|
+
out->cur += out->opts->dump_opts.after_size;
|
|
415
|
+
}
|
|
416
|
+
*out->cur++ = '"';
|
|
417
|
+
memcpy(out->cur, classname, clen);
|
|
418
|
+
out->cur += clen;
|
|
419
|
+
*out->cur++ = '"';
|
|
420
|
+
*out->cur++ = ',';
|
|
421
|
+
}
|
|
422
|
+
if (odd->raw) {
|
|
423
|
+
v = rb_funcall(obj, *odd->attrs, 0);
|
|
424
|
+
if (Qundef == v || T_STRING != rb_type(v)) {
|
|
425
|
+
rb_raise(rb_eEncodingError, "Invalid type for raw JSON.\n");
|
|
426
|
+
} else {
|
|
427
|
+
const char *s = rb_string_value_ptr((VALUE*)&v);
|
|
428
|
+
int len = (int)RSTRING_LEN(v);
|
|
429
|
+
const char *name = rb_id2name(*odd->attrs);
|
|
430
|
+
size_t nlen = strlen(name);
|
|
431
|
+
|
|
432
|
+
size = len + d2 * out->indent + nlen + 10;
|
|
433
|
+
assure_size(out, size);
|
|
434
|
+
fill_indent(out, d2);
|
|
435
|
+
*out->cur++ = '"';
|
|
436
|
+
memcpy(out->cur, name, nlen);
|
|
437
|
+
out->cur += nlen;
|
|
438
|
+
*out->cur++ = '"';
|
|
439
|
+
*out->cur++ = ':';
|
|
440
|
+
memcpy(out->cur, s, len);
|
|
441
|
+
out->cur += len;
|
|
442
|
+
*out->cur = '\0';
|
|
443
|
+
}
|
|
444
|
+
} else {
|
|
445
|
+
size = d2 * out->indent + 1;
|
|
446
|
+
for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) {
|
|
447
|
+
size_t nlen;
|
|
448
|
+
|
|
449
|
+
assure_size(out, size);
|
|
450
|
+
name = rb_id2name(*idp);
|
|
451
|
+
nlen = strlen(name);
|
|
452
|
+
if (0 != *fp) {
|
|
453
|
+
v = (*fp)(obj);
|
|
454
|
+
} else if (0 == strchr(name, '.')) {
|
|
455
|
+
v = rb_funcall(obj, *idp, 0);
|
|
456
|
+
} else {
|
|
457
|
+
char nbuf[256];
|
|
458
|
+
char *n2 = nbuf;
|
|
459
|
+
char *n;
|
|
460
|
+
char *end;
|
|
461
|
+
ID i;
|
|
462
|
+
|
|
463
|
+
if (sizeof(nbuf) <= nlen) {
|
|
464
|
+
if (NULL == (n2 = strdup(name))) {
|
|
465
|
+
rb_raise(rb_eNoMemError, "for attribute name.");
|
|
466
|
+
}
|
|
467
|
+
} else {
|
|
468
|
+
strcpy(n2, name);
|
|
469
|
+
}
|
|
470
|
+
n = n2;
|
|
471
|
+
v = obj;
|
|
472
|
+
while (0 != (end = strchr(n, '.'))) {
|
|
473
|
+
*end = '\0';
|
|
474
|
+
i = rb_intern(n);
|
|
475
|
+
v = rb_funcall(v, i, 0);
|
|
476
|
+
n = end + 1;
|
|
477
|
+
}
|
|
478
|
+
i = rb_intern(n);
|
|
479
|
+
v = rb_funcall(v, i, 0);
|
|
480
|
+
if (nbuf != n2) {
|
|
481
|
+
free(n2);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
fill_indent(out, d2);
|
|
485
|
+
oj_dump_cstr(name, nlen, 0, 0, out);
|
|
486
|
+
*out->cur++ = ':';
|
|
487
|
+
oj_dump_custom_val(v, d2, out, true);
|
|
488
|
+
assure_size(out, 2);
|
|
489
|
+
*out->cur++ = ',';
|
|
490
|
+
}
|
|
491
|
+
out->cur--;
|
|
492
|
+
}
|
|
493
|
+
*out->cur++ = '}';
|
|
494
|
+
*out->cur = '\0';
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// Return class if still needs dumping.
|
|
498
|
+
static VALUE
|
|
499
|
+
dump_common(VALUE obj, int depth, Out out) {
|
|
500
|
+
if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
|
|
501
|
+
volatile VALUE rs;
|
|
502
|
+
const char *s;
|
|
503
|
+
int len;
|
|
504
|
+
|
|
505
|
+
if (Yes == out->opts->trace) {
|
|
506
|
+
oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
|
507
|
+
}
|
|
508
|
+
if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
|
|
509
|
+
rs = rb_funcall(obj, oj_to_json_id, 0);
|
|
510
|
+
} else {
|
|
511
|
+
rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
|
|
512
|
+
}
|
|
513
|
+
if (Yes == out->opts->trace) {
|
|
514
|
+
oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
|
515
|
+
}
|
|
516
|
+
s = rb_string_value_ptr((VALUE*)&rs);
|
|
517
|
+
len = (int)RSTRING_LEN(rs);
|
|
518
|
+
|
|
519
|
+
assure_size(out, len + 1);
|
|
520
|
+
memcpy(out->cur, s, len);
|
|
521
|
+
out->cur += len;
|
|
522
|
+
*out->cur = '\0';
|
|
523
|
+
} else if (Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
|
|
524
|
+
volatile VALUE aj;
|
|
525
|
+
|
|
526
|
+
if (Yes == out->opts->trace) {
|
|
527
|
+
oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
|
528
|
+
}
|
|
529
|
+
// Some classes elect to not take an options argument so check the arity
|
|
530
|
+
// of as_json.
|
|
531
|
+
if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
|
|
532
|
+
aj = rb_funcall(obj, oj_as_json_id, 0);
|
|
533
|
+
} else {
|
|
534
|
+
aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
|
535
|
+
}
|
|
536
|
+
if (Yes == out->opts->trace) {
|
|
537
|
+
oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
|
538
|
+
}
|
|
539
|
+
// Catch the obvious brain damaged recursive dumping.
|
|
540
|
+
if (aj == obj) {
|
|
541
|
+
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
542
|
+
|
|
543
|
+
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), false, false, out);
|
|
544
|
+
} else {
|
|
545
|
+
oj_dump_custom_val(aj, depth, out, true);
|
|
546
|
+
}
|
|
547
|
+
} else if (Yes == out->opts->to_hash && rb_respond_to(obj, oj_to_hash_id)) {
|
|
548
|
+
volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
|
549
|
+
|
|
550
|
+
if (T_HASH != rb_type(h)) {
|
|
551
|
+
// It seems that ActiveRecord implemented to_hash so that it returns
|
|
552
|
+
// an Array and not a Hash. To get around that any value returned
|
|
553
|
+
// will be dumped.
|
|
554
|
+
|
|
555
|
+
//rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
|
556
|
+
oj_dump_custom_val(h, depth, out, false);
|
|
557
|
+
} else {
|
|
558
|
+
dump_hash(h, depth, out, true);
|
|
559
|
+
}
|
|
560
|
+
} else if (!oj_code_dump(codes, obj, depth, out)) {
|
|
561
|
+
VALUE clas = rb_obj_class(obj);
|
|
562
|
+
Odd odd = oj_get_odd(clas);
|
|
563
|
+
|
|
564
|
+
if (NULL == odd) {
|
|
565
|
+
return clas;
|
|
566
|
+
}
|
|
567
|
+
dump_odd(obj, odd, clas, depth + 1, out);
|
|
568
|
+
}
|
|
569
|
+
return Qnil;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
static int
|
|
573
|
+
dump_attr_cb(ID key, VALUE value, Out out) {
|
|
574
|
+
int depth = out->depth;
|
|
575
|
+
size_t size;
|
|
576
|
+
const char *attr;
|
|
577
|
+
|
|
578
|
+
if (oj_dump_ignore(out->opts, value)) {
|
|
579
|
+
return ST_CONTINUE;
|
|
580
|
+
}
|
|
581
|
+
if (out->omit_nil && Qnil == value) {
|
|
582
|
+
return ST_CONTINUE;
|
|
583
|
+
}
|
|
584
|
+
size = depth * out->indent + 1;
|
|
585
|
+
attr = rb_id2name(key);
|
|
586
|
+
// Some exceptions such as NoMethodError have an invisible attribute where
|
|
587
|
+
// the key name is NULL. Not an empty string but NULL.
|
|
588
|
+
if (NULL == attr) {
|
|
589
|
+
attr = "";
|
|
590
|
+
}
|
|
591
|
+
if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) {
|
|
592
|
+
return ST_CONTINUE;
|
|
593
|
+
}
|
|
594
|
+
assure_size(out, size);
|
|
595
|
+
fill_indent(out, depth);
|
|
596
|
+
if ('@' == *attr) {
|
|
597
|
+
attr++;
|
|
598
|
+
oj_dump_cstr(attr, strlen(attr), 0, 0, out);
|
|
599
|
+
} else {
|
|
600
|
+
char buf[32];
|
|
601
|
+
|
|
602
|
+
*buf = '~';
|
|
603
|
+
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
|
604
|
+
buf[sizeof(buf) - 1] = '\0';
|
|
605
|
+
oj_dump_cstr(buf, strlen(buf), 0, 0, out);
|
|
606
|
+
}
|
|
607
|
+
*out->cur++ = ':';
|
|
608
|
+
oj_dump_custom_val(value, depth, out, true);
|
|
609
|
+
out->depth = depth;
|
|
610
|
+
*out->cur++ = ',';
|
|
611
|
+
|
|
612
|
+
return ST_CONTINUE;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
static void
|
|
616
|
+
dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
|
|
617
|
+
size_t size = 0;
|
|
618
|
+
int d2 = depth + 1;
|
|
619
|
+
int cnt;
|
|
620
|
+
bool class_written = false;
|
|
621
|
+
|
|
622
|
+
assure_size(out, 2);
|
|
623
|
+
*out->cur++ = '{';
|
|
624
|
+
if (Qundef != clas && NULL != out->opts->create_id && Yes == out->opts->create_ok) {
|
|
625
|
+
size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
|
626
|
+
const char *classname = rb_obj_classname(obj);
|
|
627
|
+
size_t len = strlen(classname);
|
|
628
|
+
|
|
629
|
+
size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len;
|
|
630
|
+
assure_size(out, size);
|
|
631
|
+
fill_indent(out, d2);
|
|
632
|
+
*out->cur++ = '"';
|
|
633
|
+
memcpy(out->cur, out->opts->create_id, out->opts->create_id_len);
|
|
634
|
+
out->cur += out->opts->create_id_len;
|
|
635
|
+
*out->cur++ = '"';
|
|
636
|
+
if (0 < out->opts->dump_opts.before_size) {
|
|
637
|
+
strcpy(out->cur, out->opts->dump_opts.before_sep);
|
|
638
|
+
out->cur += out->opts->dump_opts.before_size;
|
|
639
|
+
}
|
|
640
|
+
*out->cur++ = ':';
|
|
641
|
+
if (0 < out->opts->dump_opts.after_size) {
|
|
642
|
+
strcpy(out->cur, out->opts->dump_opts.after_sep);
|
|
643
|
+
out->cur += out->opts->dump_opts.after_size;
|
|
644
|
+
}
|
|
645
|
+
*out->cur++ = '"';
|
|
646
|
+
memcpy(out->cur, classname, len);
|
|
647
|
+
out->cur += len;
|
|
648
|
+
*out->cur++ = '"';
|
|
649
|
+
class_written = true;
|
|
650
|
+
}
|
|
651
|
+
cnt = (int)rb_ivar_count(obj);
|
|
652
|
+
if (class_written) {
|
|
653
|
+
*out->cur++ = ',';
|
|
654
|
+
}
|
|
655
|
+
if (0 == cnt && Qundef == clas) {
|
|
656
|
+
// Might be something special like an Enumerable.
|
|
657
|
+
if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) {
|
|
658
|
+
out->cur--;
|
|
659
|
+
oj_dump_custom_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out, false);
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
out->depth = depth + 1;
|
|
664
|
+
rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
|
|
665
|
+
if (',' == *(out->cur - 1)) {
|
|
666
|
+
out->cur--; // backup to overwrite last comma
|
|
667
|
+
}
|
|
668
|
+
if (rb_obj_is_kind_of(obj, rb_eException)) {
|
|
669
|
+
volatile VALUE rv;
|
|
670
|
+
|
|
671
|
+
if (',' != *(out->cur - 1)) {
|
|
672
|
+
*out->cur++ = ',';
|
|
673
|
+
}
|
|
674
|
+
// message
|
|
675
|
+
assure_size(out, 2);
|
|
676
|
+
fill_indent(out, d2);
|
|
677
|
+
oj_dump_cstr("~mesg", 5, 0, 0, out);
|
|
678
|
+
*out->cur++ = ':';
|
|
679
|
+
rv = rb_funcall2(obj, rb_intern("message"), 0, 0);
|
|
680
|
+
oj_dump_custom_val(rv, d2, out, true);
|
|
681
|
+
assure_size(out, size + 2);
|
|
682
|
+
*out->cur++ = ',';
|
|
683
|
+
// backtrace
|
|
684
|
+
fill_indent(out, d2);
|
|
685
|
+
oj_dump_cstr("~bt", 3, 0, 0, out);
|
|
686
|
+
*out->cur++ = ':';
|
|
687
|
+
rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0);
|
|
688
|
+
oj_dump_custom_val(rv, d2, out, true);
|
|
689
|
+
assure_size(out, 2);
|
|
690
|
+
}
|
|
691
|
+
out->depth = depth;
|
|
692
|
+
|
|
693
|
+
fill_indent(out, depth);
|
|
694
|
+
*out->cur++ = '}';
|
|
695
|
+
*out->cur = '\0';
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
static void
|
|
699
|
+
dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
700
|
+
long id = oj_check_circular(obj, out);
|
|
701
|
+
VALUE clas;
|
|
702
|
+
|
|
703
|
+
if (0 > id) {
|
|
704
|
+
oj_dump_nil(Qnil, depth, out, false);
|
|
705
|
+
} else if (Qnil != (clas = dump_common(obj, depth, out))) {
|
|
706
|
+
dump_obj_attrs(obj, clas, 0, depth, out);
|
|
707
|
+
}
|
|
708
|
+
*out->cur = '\0';
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
static void
|
|
712
|
+
dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
713
|
+
size_t size;
|
|
714
|
+
int i, cnt;
|
|
715
|
+
int d2 = depth + 1;
|
|
716
|
+
long id = oj_check_circular(a, out);
|
|
717
|
+
|
|
718
|
+
if (0 > id) {
|
|
719
|
+
oj_dump_nil(Qnil, depth, out, false);
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
cnt = (int)RARRAY_LEN(a);
|
|
723
|
+
*out->cur++ = '[';
|
|
724
|
+
assure_size(out, 2);
|
|
725
|
+
if (0 == cnt) {
|
|
726
|
+
*out->cur++ = ']';
|
|
727
|
+
} else {
|
|
728
|
+
if (out->opts->dump_opts.use) {
|
|
729
|
+
size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
|
|
730
|
+
} else {
|
|
731
|
+
size = d2 * out->indent + 2;
|
|
732
|
+
}
|
|
733
|
+
cnt--;
|
|
734
|
+
for (i = 0; i <= cnt; i++) {
|
|
735
|
+
assure_size(out, size);
|
|
736
|
+
if (out->opts->dump_opts.use) {
|
|
737
|
+
if (0 < out->opts->dump_opts.array_size) {
|
|
738
|
+
strcpy(out->cur, out->opts->dump_opts.array_nl);
|
|
739
|
+
out->cur += out->opts->dump_opts.array_size;
|
|
740
|
+
}
|
|
741
|
+
if (0 < out->opts->dump_opts.indent_size) {
|
|
742
|
+
int i;
|
|
743
|
+
for (i = d2; 0 < i; i--) {
|
|
744
|
+
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
|
745
|
+
out->cur += out->opts->dump_opts.indent_size;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
} else {
|
|
749
|
+
fill_indent(out, d2);
|
|
750
|
+
}
|
|
751
|
+
oj_dump_custom_val(rb_ary_entry(a, i), d2, out, true);
|
|
752
|
+
if (i < cnt) {
|
|
753
|
+
*out->cur++ = ',';
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
size = depth * out->indent + 1;
|
|
757
|
+
assure_size(out, size);
|
|
758
|
+
if (out->opts->dump_opts.use) {
|
|
759
|
+
if (0 < out->opts->dump_opts.array_size) {
|
|
760
|
+
strcpy(out->cur, out->opts->dump_opts.array_nl);
|
|
761
|
+
out->cur += out->opts->dump_opts.array_size;
|
|
762
|
+
}
|
|
763
|
+
if (0 < out->opts->dump_opts.indent_size) {
|
|
764
|
+
int i;
|
|
765
|
+
|
|
766
|
+
for (i = depth; 0 < i; i--) {
|
|
767
|
+
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
|
768
|
+
out->cur += out->opts->dump_opts.indent_size;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
} else {
|
|
772
|
+
fill_indent(out, depth);
|
|
773
|
+
}
|
|
774
|
+
*out->cur++ = ']';
|
|
775
|
+
}
|
|
776
|
+
*out->cur = '\0';
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
static void
|
|
780
|
+
dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
781
|
+
long id = oj_check_circular(obj, out);
|
|
782
|
+
VALUE clas;
|
|
783
|
+
|
|
784
|
+
if (0 > id) {
|
|
785
|
+
oj_dump_nil(Qnil, depth, out, false);
|
|
786
|
+
} else if (Qnil != (clas = dump_common(obj, depth, out))) {
|
|
787
|
+
VALUE ma = Qnil;
|
|
788
|
+
VALUE v;
|
|
789
|
+
char num_id[32];
|
|
790
|
+
int i;
|
|
791
|
+
int d2 = depth + 1;
|
|
792
|
+
int d3 = d2 + 1;
|
|
793
|
+
size_t size = d2 * out->indent + d3 * out->indent + 3;
|
|
794
|
+
const char *name;
|
|
795
|
+
int cnt;
|
|
796
|
+
size_t len;
|
|
797
|
+
|
|
798
|
+
assure_size(out, size);
|
|
799
|
+
if (clas == rb_cRange) {
|
|
800
|
+
*out->cur++ = '"';
|
|
801
|
+
oj_dump_custom_val(rb_funcall(obj, oj_begin_id, 0), d3, out, false);
|
|
802
|
+
assure_size(out, 3);
|
|
803
|
+
*out->cur++ = '.';
|
|
804
|
+
*out->cur++ = '.';
|
|
805
|
+
if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) {
|
|
806
|
+
*out->cur++ = '.';
|
|
807
|
+
}
|
|
808
|
+
oj_dump_custom_val(rb_funcall(obj, oj_end_id, 0), d3, out, false);
|
|
809
|
+
*out->cur++ = '"';
|
|
810
|
+
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
*out->cur++ = '{';
|
|
814
|
+
fill_indent(out, d2);
|
|
815
|
+
size = d3 * out->indent + 2;
|
|
816
|
+
ma = rb_struct_s_members(clas);
|
|
817
|
+
|
|
818
|
+
#ifdef RSTRUCT_LEN
|
|
819
|
+
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
820
|
+
cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
|
|
821
|
+
#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
822
|
+
cnt = (int)RSTRUCT_LEN(obj);
|
|
823
|
+
#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
824
|
+
#else
|
|
825
|
+
// This is a bit risky as a struct in C ruby is not the same as a Struct
|
|
826
|
+
// class in interpreted Ruby so length() may not be defined.
|
|
827
|
+
cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
|
|
828
|
+
#endif
|
|
829
|
+
for (i = 0; i < cnt; i++) {
|
|
830
|
+
#ifdef RSTRUCT_LEN
|
|
831
|
+
v = RSTRUCT_GET(obj, i);
|
|
832
|
+
#else
|
|
833
|
+
v = rb_struct_aref(obj, INT2FIX(i));
|
|
834
|
+
#endif
|
|
835
|
+
if (ma != Qnil) {
|
|
836
|
+
volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
|
|
837
|
+
|
|
838
|
+
name = rb_string_value_ptr((VALUE*)&s);
|
|
839
|
+
len = (int)RSTRING_LEN(s);
|
|
840
|
+
} else {
|
|
841
|
+
len = snprintf(num_id, sizeof(num_id), "%d", i);
|
|
842
|
+
name = num_id;
|
|
843
|
+
}
|
|
844
|
+
assure_size(out, size + len + 3);
|
|
845
|
+
fill_indent(out, d3);
|
|
846
|
+
*out->cur++ = '"';
|
|
847
|
+
memcpy(out->cur, name, len);
|
|
848
|
+
out->cur += len;
|
|
849
|
+
*out->cur++ = '"';
|
|
850
|
+
*out->cur++ = ':';
|
|
851
|
+
oj_dump_custom_val(v, d3, out, true);
|
|
852
|
+
*out->cur++ = ',';
|
|
853
|
+
}
|
|
854
|
+
out->cur--;
|
|
855
|
+
*out->cur++ = '}';
|
|
856
|
+
*out->cur = '\0';
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
static void
|
|
861
|
+
dump_data(VALUE obj, int depth, Out out, bool as_ok) {
|
|
862
|
+
long id = oj_check_circular(obj, out);
|
|
863
|
+
VALUE clas;
|
|
864
|
+
|
|
865
|
+
if (0 > id) {
|
|
866
|
+
oj_dump_nil(Qnil, depth, out, false);
|
|
867
|
+
} else if (Qnil != (clas = dump_common(obj, depth, out))) {
|
|
868
|
+
dump_obj_attrs(obj, clas, id, depth, out);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
static void
|
|
873
|
+
dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
|
|
874
|
+
dump_obj_str(obj, depth, out);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
static void
|
|
878
|
+
dump_complex(VALUE obj, int depth, Out out, bool as_ok) {
|
|
879
|
+
complex_dump(obj, depth, out);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
static void
|
|
883
|
+
dump_rational(VALUE obj, int depth, Out out, bool as_ok) {
|
|
884
|
+
rational_dump(obj, depth, out);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
static DumpFunc custom_funcs[] = {
|
|
888
|
+
NULL, // RUBY_T_NONE = 0x00,
|
|
889
|
+
dump_obj, // RUBY_T_OBJECT = 0x01,
|
|
890
|
+
oj_dump_class, // RUBY_T_CLASS = 0x02,
|
|
891
|
+
oj_dump_class, // RUBY_T_MODULE = 0x03,
|
|
892
|
+
oj_dump_float, // RUBY_T_FLOAT = 0x04,
|
|
893
|
+
oj_dump_str, // RUBY_T_STRING = 0x05,
|
|
894
|
+
dump_regexp, // RUBY_T_REGEXP = 0x06,
|
|
895
|
+
dump_array, // RUBY_T_ARRAY = 0x07,
|
|
896
|
+
dump_hash, // RUBY_T_HASH = 0x08,
|
|
897
|
+
dump_struct, // RUBY_T_STRUCT = 0x09,
|
|
898
|
+
oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
|
|
899
|
+
NULL, // RUBY_T_FILE = 0x0b,
|
|
900
|
+
dump_data, // RUBY_T_DATA = 0x0c,
|
|
901
|
+
NULL, // RUBY_T_MATCH = 0x0d,
|
|
902
|
+
dump_complex, // RUBY_T_COMPLEX = 0x0e,
|
|
903
|
+
dump_rational, // RUBY_T_RATIONAL = 0x0f,
|
|
904
|
+
NULL, // 0x10
|
|
905
|
+
oj_dump_nil, // RUBY_T_NIL = 0x11,
|
|
906
|
+
oj_dump_true, // RUBY_T_TRUE = 0x12,
|
|
907
|
+
oj_dump_false, // RUBY_T_FALSE = 0x13,
|
|
908
|
+
oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
|
|
909
|
+
oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
void
|
|
913
|
+
oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
914
|
+
int type = rb_type(obj);
|
|
915
|
+
|
|
916
|
+
if (Yes == out->opts->trace) {
|
|
917
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
|
918
|
+
}
|
|
919
|
+
if (MAX_DEPTH < depth) {
|
|
920
|
+
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
|
921
|
+
}
|
|
922
|
+
if (0 < type && type <= RUBY_T_FIXNUM) {
|
|
923
|
+
DumpFunc f = custom_funcs[type];
|
|
924
|
+
|
|
925
|
+
if (NULL != f) {
|
|
926
|
+
f(obj, depth, out, true);
|
|
927
|
+
if (Yes == out->opts->trace) {
|
|
928
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
|
929
|
+
}
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
oj_dump_nil(Qnil, depth, out, false);
|
|
934
|
+
if (Yes == out->opts->trace) {
|
|
935
|
+
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
///// load functions /////
|
|
940
|
+
|
|
941
|
+
static void
|
|
942
|
+
hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
|
943
|
+
const char *key = kval->key;
|
|
944
|
+
int klen = kval->klen;
|
|
945
|
+
Val parent = stack_peek(&pi->stack);
|
|
946
|
+
volatile VALUE rkey = kval->key_val;
|
|
947
|
+
|
|
948
|
+
if (Qundef == rkey &&
|
|
949
|
+
Yes == pi->options.create_ok &&
|
|
950
|
+
NULL != pi->options.create_id &&
|
|
951
|
+
*pi->options.create_id == *key &&
|
|
952
|
+
(int)pi->options.create_id_len == klen &&
|
|
953
|
+
0 == strncmp(pi->options.create_id, key, klen)) {
|
|
954
|
+
|
|
955
|
+
parent->clas = oj_name2class(pi, str, len, false, rb_eArgError);
|
|
956
|
+
if (2 == klen && '^' == *key && 'o' == key[1]) {
|
|
957
|
+
if (Qundef != parent->clas) {
|
|
958
|
+
if (!oj_code_has(codes, parent->clas, false)) {
|
|
959
|
+
parent->val = rb_obj_alloc(parent->clas);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
} else {
|
|
964
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
|
965
|
+
|
|
966
|
+
if (Qundef == rkey) {
|
|
967
|
+
rkey = rb_str_new(key, klen);
|
|
968
|
+
rstr = oj_encode(rstr);
|
|
969
|
+
rkey = oj_encode(rkey);
|
|
970
|
+
if (Yes == pi->options.sym_key) {
|
|
971
|
+
rkey = rb_str_intern(rkey);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
975
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
|
976
|
+
|
|
977
|
+
if (Qnil != clas) {
|
|
978
|
+
rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
switch (rb_type(parent->val)) {
|
|
982
|
+
case T_OBJECT:
|
|
983
|
+
oj_set_obj_ivar(parent, kval, rstr);
|
|
984
|
+
break;
|
|
985
|
+
case T_HASH:
|
|
986
|
+
if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 == strncmp("time", parent->key, 4)) {
|
|
987
|
+
if (Qnil == (parent->val = oj_parse_xml_time(str, (int)len))) {
|
|
988
|
+
parent->val = rb_funcall(rb_cTime, rb_intern("parse"), 1, rb_str_new(str, len));
|
|
989
|
+
}
|
|
990
|
+
} else {
|
|
991
|
+
rb_hash_aset(parent->val, rkey, rstr);
|
|
992
|
+
}
|
|
993
|
+
break;
|
|
994
|
+
default:
|
|
995
|
+
break;
|
|
996
|
+
}
|
|
997
|
+
if (Yes == pi->options.trace) {
|
|
998
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
static void
|
|
1004
|
+
end_hash(struct _parseInfo *pi) {
|
|
1005
|
+
Val parent = stack_peek(&pi->stack);
|
|
1006
|
+
|
|
1007
|
+
if (Qundef != parent->clas && parent->clas != rb_obj_class(parent->val)) {
|
|
1008
|
+
volatile VALUE obj = oj_code_load(codes, parent->clas, parent->val);
|
|
1009
|
+
|
|
1010
|
+
if (Qnil != obj) {
|
|
1011
|
+
parent->val = obj;
|
|
1012
|
+
} else {
|
|
1013
|
+
parent->val = rb_funcall(parent->clas, oj_json_create_id, 1, parent->val);
|
|
1014
|
+
}
|
|
1015
|
+
parent->clas = Qundef;
|
|
1016
|
+
}
|
|
1017
|
+
if (Yes == pi->options.trace) {
|
|
1018
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
static VALUE
|
|
1023
|
+
calc_hash_key(ParseInfo pi, Val parent) {
|
|
1024
|
+
volatile VALUE rkey = parent->key_val;
|
|
1025
|
+
|
|
1026
|
+
if (Qundef == rkey) {
|
|
1027
|
+
rkey = rb_str_new(parent->key, parent->klen);
|
|
1028
|
+
}
|
|
1029
|
+
rkey = oj_encode(rkey);
|
|
1030
|
+
if (Yes == pi->options.sym_key) {
|
|
1031
|
+
rkey = rb_str_intern(rkey);
|
|
1032
|
+
}
|
|
1033
|
+
return rkey;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
static void
|
|
1037
|
+
hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
|
|
1038
|
+
Val parent = stack_peek(&pi->stack);
|
|
1039
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
|
1040
|
+
|
|
1041
|
+
switch (rb_type(parent->val)) {
|
|
1042
|
+
case T_OBJECT:
|
|
1043
|
+
oj_set_obj_ivar(parent, kval, rval);
|
|
1044
|
+
break;
|
|
1045
|
+
case T_HASH:
|
|
1046
|
+
if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 == strncmp("time", parent->key, 4)) {
|
|
1047
|
+
int64_t nsec = ni->num * 1000000000LL / ni->div;
|
|
1048
|
+
|
|
1049
|
+
if (ni->neg) {
|
|
1050
|
+
ni->i = -ni->i;
|
|
1051
|
+
if (0 < nsec) {
|
|
1052
|
+
ni->i--;
|
|
1053
|
+
nsec = 1000000000LL - nsec;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
if (86400 == ni->exp) { // UTC time
|
|
1057
|
+
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
|
1058
|
+
// Since the ruby C routines alway create local time, the
|
|
1059
|
+
// offset and then a conversion to UTC keeps makes the time
|
|
1060
|
+
// match the expected value.
|
|
1061
|
+
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
|
1062
|
+
} else if (ni->hasExp) {
|
|
1063
|
+
int64_t t = (int64_t)(ni->i + ni->exp);
|
|
1064
|
+
struct _timeInfo ti;
|
|
1065
|
+
VALUE args[8];
|
|
1066
|
+
|
|
1067
|
+
sec_as_time(t, &ti);
|
|
1068
|
+
|
|
1069
|
+
args[0] = LONG2NUM(ti.year);
|
|
1070
|
+
args[1] = LONG2NUM(ti.mon);
|
|
1071
|
+
args[2] = LONG2NUM(ti.day);
|
|
1072
|
+
args[3] = LONG2NUM(ti.hour);
|
|
1073
|
+
args[4] = LONG2NUM(ti.min);
|
|
1074
|
+
args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
|
|
1075
|
+
args[6] = LONG2NUM(ni->exp);
|
|
1076
|
+
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
|
1077
|
+
} else {
|
|
1078
|
+
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
|
1079
|
+
}
|
|
1080
|
+
rval = parent->val;
|
|
1081
|
+
} else {
|
|
1082
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval), rval);
|
|
1083
|
+
}
|
|
1084
|
+
break;
|
|
1085
|
+
default:
|
|
1086
|
+
break;
|
|
1087
|
+
}
|
|
1088
|
+
if (Yes == pi->options.trace) {
|
|
1089
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
static void
|
|
1094
|
+
hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
|
1095
|
+
Val parent = stack_peek(&pi->stack);
|
|
1096
|
+
|
|
1097
|
+
switch (rb_type(parent->val)) {
|
|
1098
|
+
case T_OBJECT:
|
|
1099
|
+
oj_set_obj_ivar(parent, kval, value);
|
|
1100
|
+
break;
|
|
1101
|
+
case T_HASH:
|
|
1102
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval), value);
|
|
1103
|
+
break;
|
|
1104
|
+
default:
|
|
1105
|
+
break;
|
|
1106
|
+
}
|
|
1107
|
+
if (Yes == pi->options.trace) {
|
|
1108
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
static void
|
|
1113
|
+
array_append_num(ParseInfo pi, NumInfo ni) {
|
|
1114
|
+
Val parent = stack_peek(&pi->stack);
|
|
1115
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
|
1116
|
+
|
|
1117
|
+
rb_ary_push(parent->val, rval);
|
|
1118
|
+
if (Yes == pi->options.trace) {
|
|
1119
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
static void
|
|
1124
|
+
array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
1125
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
|
1126
|
+
|
|
1127
|
+
rstr = oj_encode(rstr);
|
|
1128
|
+
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
1129
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
|
1130
|
+
|
|
1131
|
+
if (Qnil != clas) {
|
|
1132
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rstr);
|
|
1137
|
+
if (Yes == pi->options.trace) {
|
|
1138
|
+
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
void
|
|
1143
|
+
oj_set_custom_callbacks(ParseInfo pi) {
|
|
1144
|
+
oj_set_compat_callbacks(pi);
|
|
1145
|
+
pi->hash_set_cstr = hash_set_cstr;
|
|
1146
|
+
pi->end_hash = end_hash;
|
|
1147
|
+
pi->hash_set_num = hash_set_num;
|
|
1148
|
+
pi->hash_set_value = hash_set_value;
|
|
1149
|
+
pi->array_append_cstr = array_append_cstr;
|
|
1150
|
+
pi->array_append_num = array_append_num;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
VALUE
|
|
1154
|
+
oj_custom_parse(int argc, VALUE *argv, VALUE self) {
|
|
1155
|
+
struct _parseInfo pi;
|
|
1156
|
+
|
|
1157
|
+
parse_info_init(&pi);
|
|
1158
|
+
pi.options = oj_default_options;
|
|
1159
|
+
pi.handler = Qnil;
|
|
1160
|
+
pi.err_class = Qnil;
|
|
1161
|
+
pi.max_depth = 0;
|
|
1162
|
+
pi.options.allow_nan = Yes;
|
|
1163
|
+
pi.options.nilnil = Yes;
|
|
1164
|
+
oj_set_custom_callbacks(&pi);
|
|
1165
|
+
|
|
1166
|
+
if (T_STRING == rb_type(*argv)) {
|
|
1167
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, false);
|
|
1168
|
+
} else {
|
|
1169
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
VALUE
|
|
1174
|
+
oj_custom_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
|
1175
|
+
struct _parseInfo pi;
|
|
1176
|
+
|
|
1177
|
+
parse_info_init(&pi);
|
|
1178
|
+
pi.options = oj_default_options;
|
|
1179
|
+
pi.handler = Qnil;
|
|
1180
|
+
pi.err_class = Qnil;
|
|
1181
|
+
pi.max_depth = 0;
|
|
1182
|
+
pi.options.allow_nan = Yes;
|
|
1183
|
+
pi.options.nilnil = Yes;
|
|
1184
|
+
oj_set_custom_callbacks(&pi);
|
|
1185
|
+
pi.end_hash = end_hash;
|
|
1186
|
+
|
|
1187
|
+
return oj_pi_parse(argc, argv, &pi, json, len, false);
|
|
1188
|
+
}
|