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