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