oj 3.11.0 → 3.16.5
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/CHANGELOG.md +1421 -0
- data/README.md +20 -5
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +48 -38
- data/ext/oj/cache.c +329 -0
- data/ext/oj/cache.h +22 -0
- data/ext/oj/cache8.c +60 -62
- data/ext/oj/cache8.h +8 -7
- data/ext/oj/circarray.c +35 -35
- data/ext/oj/circarray.h +11 -9
- data/ext/oj/code.c +156 -174
- data/ext/oj/code.h +19 -18
- data/ext/oj/compat.c +140 -197
- data/ext/oj/custom.c +737 -879
- data/ext/oj/debug.c +126 -0
- data/ext/oj/dump.c +830 -835
- data/ext/oj/dump.h +65 -53
- data/ext/oj/dump_compat.c +566 -642
- data/ext/oj/dump_leaf.c +95 -182
- data/ext/oj/dump_object.c +518 -659
- data/ext/oj/dump_strict.c +301 -334
- data/ext/oj/encode.h +3 -4
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +27 -24
- data/ext/oj/err.h +38 -13
- data/ext/oj/extconf.rb +23 -7
- data/ext/oj/fast.c +1043 -1073
- data/ext/oj/intern.c +313 -0
- data/ext/oj/intern.h +22 -0
- data/ext/oj/mem.c +318 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +449 -423
- data/ext/oj/object.c +530 -576
- data/ext/oj/odd.c +155 -138
- data/ext/oj/odd.h +24 -22
- data/ext/oj/oj.c +1331 -993
- data/ext/oj/oj.h +306 -292
- data/ext/oj/parse.c +934 -938
- data/ext/oj/parse.h +73 -70
- data/ext/oj/parser.c +1600 -0
- data/ext/oj/parser.h +101 -0
- data/ext/oj/rails.c +795 -845
- data/ext/oj/rails.h +7 -7
- data/ext/oj/reader.c +132 -140
- data/ext/oj/reader.h +67 -78
- data/ext/oj/resolve.c +40 -59
- data/ext/oj/resolve.h +3 -2
- data/ext/oj/rxclass.c +67 -67
- data/ext/oj/rxclass.h +11 -9
- data/ext/oj/saj.c +441 -480
- data/ext/oj/saj2.c +584 -0
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +78 -111
- data/ext/oj/sparse.c +726 -730
- data/ext/oj/stream_writer.c +146 -165
- data/ext/oj/strict.c +103 -123
- data/ext/oj/string_writer.c +241 -253
- data/ext/oj/trace.c +29 -33
- data/ext/oj/trace.h +41 -11
- data/ext/oj/usual.c +1218 -0
- data/ext/oj/usual.h +69 -0
- data/ext/oj/util.c +103 -103
- data/ext/oj/util.h +3 -2
- data/ext/oj/val_stack.c +60 -49
- data/ext/oj/val_stack.h +79 -85
- data/ext/oj/validate.c +46 -0
- data/ext/oj/wab.c +307 -350
- data/lib/oj/active_support_helper.rb +1 -3
- data/lib/oj/bag.rb +8 -1
- data/lib/oj/easy_hash.rb +9 -9
- data/lib/oj/error.rb +1 -2
- data/lib/oj/json.rb +162 -150
- data/lib/oj/mimic.rb +9 -19
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/state.rb +12 -8
- data/lib/oj/version.rb +1 -2
- data/lib/oj.rb +2 -0
- data/pages/Compatibility.md +1 -1
- data/pages/InstallOptions.md +20 -0
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +8 -3
- data/pages/Options.md +43 -5
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +14 -2
- data/test/_test_active.rb +8 -9
- data/test/_test_active_mimic.rb +7 -8
- data/test/_test_mimic_rails.rb +17 -20
- data/test/activerecord/result_test.rb +12 -8
- data/test/activesupport6/encoding_test.rb +63 -28
- data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
- data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
- data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
- data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
- data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
- data/test/files.rb +15 -15
- data/test/foo.rb +17 -43
- data/test/helper.rb +16 -3
- data/test/isolated/shared.rb +3 -2
- data/test/json_gem/json_addition_test.rb +2 -2
- data/test/json_gem/json_common_interface_test.rb +8 -6
- data/test/json_gem/json_encoding_test.rb +0 -0
- data/test/json_gem/json_ext_parser_test.rb +1 -0
- data/test/json_gem/json_fixtures_test.rb +3 -2
- data/test/json_gem/json_generator_test.rb +71 -41
- data/test/json_gem/json_generic_object_test.rb +11 -11
- data/test/json_gem/json_parser_test.rb +54 -47
- data/test/json_gem/json_string_matching_test.rb +9 -9
- data/test/json_gem/test_helper.rb +12 -0
- data/test/mem.rb +34 -0
- data/test/perf.rb +22 -27
- data/test/perf_compat.rb +31 -33
- data/test/perf_dump.rb +50 -0
- data/test/perf_fast.rb +80 -82
- data/test/perf_file.rb +27 -29
- data/test/perf_object.rb +65 -69
- data/test/perf_once.rb +59 -0
- data/test/perf_parser.rb +183 -0
- data/test/perf_saj.rb +46 -54
- data/test/perf_scp.rb +58 -69
- data/test/perf_simple.rb +41 -39
- data/test/perf_strict.rb +74 -82
- data/test/perf_wab.rb +67 -69
- data/test/prec.rb +5 -5
- data/test/sample/change.rb +0 -1
- data/test/sample/dir.rb +0 -1
- data/test/sample/doc.rb +0 -1
- data/test/sample/file.rb +0 -1
- data/test/sample/group.rb +0 -1
- data/test/sample/hasprops.rb +0 -1
- data/test/sample/layer.rb +0 -1
- data/test/sample/rect.rb +0 -1
- data/test/sample/shape.rb +0 -1
- data/test/sample/text.rb +0 -1
- data/test/sample.rb +16 -16
- data/test/sample_json.rb +8 -8
- data/test/test_compat.rb +97 -45
- data/test/test_custom.rb +73 -51
- data/test/test_debian.rb +7 -10
- data/test/test_fast.rb +135 -79
- data/test/test_file.rb +41 -30
- data/test/test_gc.rb +16 -5
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +15 -5
- data/test/test_integer_range.rb +9 -9
- data/test/test_null.rb +20 -20
- data/test/test_object.rb +99 -96
- data/test/test_parser.rb +11 -0
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +337 -0
- data/test/test_parser_usual.rb +251 -0
- data/test/test_rails.rb +2 -2
- data/test/test_saj.rb +10 -8
- data/test/test_scp.rb +38 -40
- data/test/test_strict.rb +40 -32
- data/test/test_various.rb +165 -84
- data/test/test_wab.rb +48 -44
- data/test/test_writer.rb +47 -47
- data/test/tests.rb +13 -5
- data/test/tests_mimic.rb +12 -3
- data/test/tests_mimic_addition.rb +12 -3
- metadata +75 -127
- data/ext/oj/hash.c +0 -135
- data/ext/oj/hash.h +0 -18
- data/ext/oj/hash_test.c +0 -484
- data/test/activesupport4/decoding_test.rb +0 -108
- data/test/activesupport4/encoding_test.rb +0 -531
- data/test/activesupport4/test_helper.rb +0 -41
- data/test/activesupport5/test_helper.rb +0 -72
- data/test/bar.rb +0 -35
- data/test/baz.rb +0 -16
- data/test/zoo.rb +0 -13
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>
|
@@ -7,7 +8,8 @@
|
|
7
8
|
#include "dump.h"
|
8
9
|
#include "encode.h"
|
9
10
|
#include "err.h"
|
10
|
-
#include "
|
11
|
+
#include "intern.h"
|
12
|
+
#include "mem.h"
|
11
13
|
#include "odd.h"
|
12
14
|
#include "oj.h"
|
13
15
|
#include "parse.h"
|
@@ -15,212 +17,199 @@
|
|
15
17
|
#include "trace.h"
|
16
18
|
#include "util.h"
|
17
19
|
|
18
|
-
extern void
|
19
|
-
extern VALUE
|
20
|
+
extern void oj_set_obj_ivar(Val parent, Val kval, VALUE value);
|
21
|
+
extern VALUE oj_parse_xml_time(const char *str, int len); // from object.c
|
20
22
|
|
21
|
-
static void
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
{ NULL, 0, Qnil },
|
23
|
+
static void dump_obj_str(VALUE obj, int depth, Out out) {
|
24
|
+
struct _attr attrs[] = {
|
25
|
+
{"s", 1, Qnil},
|
26
|
+
{NULL, 0, Qnil},
|
26
27
|
};
|
27
|
-
attrs->value =
|
28
|
+
attrs->value = oj_safe_string_convert(obj);
|
28
29
|
|
29
30
|
oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
|
30
31
|
}
|
31
32
|
|
32
|
-
static void
|
33
|
-
|
34
|
-
|
35
|
-
const char *str = rb_string_value_ptr((VALUE*)&rstr);
|
33
|
+
static void dump_obj_as_str(VALUE obj, int depth, Out out) {
|
34
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
35
|
+
const char *str = RSTRING_PTR(rstr);
|
36
36
|
|
37
37
|
oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
|
38
38
|
}
|
39
39
|
|
40
|
-
static void
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
int len = (int)RSTRING_LEN(rstr);
|
40
|
+
static void bigdecimal_dump(VALUE obj, int depth, Out out) {
|
41
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
42
|
+
const char *str = RSTRING_PTR(rstr);
|
43
|
+
int len = (int)RSTRING_LEN(rstr);
|
45
44
|
|
46
45
|
if (0 == strcasecmp("Infinity", str)) {
|
47
|
-
|
48
|
-
|
46
|
+
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
|
47
|
+
oj_dump_raw(str, len, out);
|
49
48
|
} else if (0 == strcasecmp("-Infinity", str)) {
|
50
|
-
|
51
|
-
|
49
|
+
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
|
50
|
+
oj_dump_raw(str, len, out);
|
52
51
|
} else if (No == out->opts->bigdec_as_num) {
|
53
|
-
|
52
|
+
oj_dump_cstr(str, len, 0, 0, out);
|
54
53
|
} else {
|
55
|
-
|
54
|
+
oj_dump_raw(str, len, out);
|
56
55
|
}
|
57
56
|
}
|
58
57
|
|
59
|
-
static ID
|
60
|
-
static ID
|
58
|
+
static ID real_id = 0;
|
59
|
+
static ID imag_id = 0;
|
61
60
|
|
62
|
-
static void
|
63
|
-
complex_dump(VALUE obj, int depth, Out out) {
|
61
|
+
static void complex_dump(VALUE obj, int depth, Out out) {
|
64
62
|
if (NULL != out->opts->create_id) {
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
63
|
+
struct _attr attrs[] = {
|
64
|
+
{"real", 4, Qnil},
|
65
|
+
{"imag", 4, Qnil},
|
66
|
+
{NULL, 0, Qnil},
|
67
|
+
};
|
68
|
+
if (0 == real_id) {
|
69
|
+
real_id = rb_intern("real");
|
70
|
+
imag_id = rb_intern("imag");
|
71
|
+
}
|
72
|
+
attrs[0].value = rb_funcall(obj, real_id, 0);
|
73
|
+
attrs[1].value = rb_funcall(obj, imag_id, 0);
|
74
|
+
|
75
|
+
oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
|
78
76
|
} else {
|
79
|
-
|
77
|
+
dump_obj_as_str(obj, depth, out);
|
80
78
|
}
|
81
79
|
}
|
82
80
|
|
83
|
-
static VALUE
|
84
|
-
complex_load(VALUE clas, VALUE args) {
|
81
|
+
static VALUE complex_load(VALUE clas, VALUE args) {
|
85
82
|
if (0 == real_id) {
|
86
|
-
|
87
|
-
|
83
|
+
real_id = rb_intern("real");
|
84
|
+
imag_id = rb_intern("imag");
|
88
85
|
}
|
89
86
|
return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)), 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(RSTRING_PTR(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,854 @@ 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
|
-
return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)),
|
263
|
-
rb_hash_aref(args, rb_id2str(denominator_id)));
|
249
|
+
return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)), rb_hash_aref(args, rb_id2str(denominator_id)));
|
264
250
|
}
|
265
251
|
|
266
|
-
static VALUE
|
267
|
-
|
268
|
-
volatile VALUE v;
|
252
|
+
static VALUE regexp_load(VALUE clas, VALUE args) {
|
253
|
+
volatile VALUE v;
|
269
254
|
|
270
255
|
if (Qnil != (v = rb_hash_aref(args, rb_str_new2("s")))) {
|
271
|
-
|
256
|
+
return rb_funcall(rb_cRegexp, oj_new_id, 1, v);
|
272
257
|
}
|
273
258
|
return Qnil;
|
274
259
|
}
|
275
260
|
|
276
|
-
static VALUE
|
277
|
-
time_load(VALUE clas, VALUE args) {
|
261
|
+
static VALUE time_load(VALUE clas, VALUE args) {
|
278
262
|
// Value should have already been replaced in one of the hash_set_xxx
|
279
263
|
// functions.
|
280
264
|
return args;
|
281
265
|
}
|
282
266
|
|
283
|
-
static struct _code
|
284
|
-
{
|
285
|
-
{
|
286
|
-
{
|
287
|
-
{
|
288
|
-
{
|
289
|
-
{
|
290
|
-
{
|
291
|
-
{
|
292
|
-
{
|
293
|
-
{
|
267
|
+
static struct _code codes[] = {
|
268
|
+
{"BigDecimal", Qnil, bigdecimal_dump, NULL, true},
|
269
|
+
{"Complex", Qnil, complex_dump, complex_load, true},
|
270
|
+
{"Date", Qnil, date_dump, date_load, true},
|
271
|
+
{"DateTime", Qnil, date_dump, datetime_load, true},
|
272
|
+
{"OpenStruct", Qnil, openstruct_dump, openstruct_load, true},
|
273
|
+
{"Range", Qnil, range_dump, range_load, true},
|
274
|
+
{"Rational", Qnil, rational_dump, rational_load, true},
|
275
|
+
{"Regexp", Qnil, dump_obj_str, regexp_load, true},
|
276
|
+
{"Time", Qnil, time_dump, time_load, true},
|
277
|
+
{NULL, Qundef, NULL, NULL, false},
|
294
278
|
};
|
295
279
|
|
296
|
-
static int
|
297
|
-
|
298
|
-
|
299
|
-
int depth = out->depth;
|
280
|
+
static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
281
|
+
Out out = (Out)ov;
|
282
|
+
int depth = out->depth;
|
300
283
|
|
301
|
-
if (
|
302
|
-
|
284
|
+
if (dump_ignore(out->opts, value)) {
|
285
|
+
return ST_CONTINUE;
|
303
286
|
}
|
304
287
|
if (out->omit_nil && Qnil == value) {
|
305
|
-
|
288
|
+
return ST_CONTINUE;
|
306
289
|
}
|
307
290
|
if (!out->opts->dump_opts.use) {
|
308
|
-
|
309
|
-
|
291
|
+
assure_size(out, depth * out->indent + 1);
|
292
|
+
fill_indent(out, depth);
|
310
293
|
} else {
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
}
|
323
|
-
}
|
294
|
+
assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
295
|
+
if (0 < out->opts->dump_opts.hash_size) {
|
296
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
|
297
|
+
}
|
298
|
+
if (0 < out->opts->dump_opts.indent_size) {
|
299
|
+
int i;
|
300
|
+
|
301
|
+
for (i = depth; 0 < i; i--) {
|
302
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
|
303
|
+
}
|
304
|
+
}
|
324
305
|
}
|
325
306
|
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;
|
307
|
+
case T_STRING: oj_dump_str(key, 0, out, false); break;
|
308
|
+
case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
|
309
|
+
default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
|
335
310
|
}
|
336
311
|
if (!out->opts->dump_opts.use) {
|
337
|
-
|
312
|
+
*out->cur++ = ':';
|
338
313
|
} else {
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
out->cur += out->opts->dump_opts.after_size;
|
348
|
-
}
|
314
|
+
assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2);
|
315
|
+
if (0 < out->opts->dump_opts.before_size) {
|
316
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
|
317
|
+
}
|
318
|
+
*out->cur++ = ':';
|
319
|
+
if (0 < out->opts->dump_opts.after_size) {
|
320
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
|
321
|
+
}
|
349
322
|
}
|
350
323
|
oj_dump_custom_val(value, depth, out, true);
|
351
|
-
out->depth
|
324
|
+
out->depth = depth;
|
352
325
|
*out->cur++ = ',';
|
353
326
|
|
354
327
|
return ST_CONTINUE;
|
355
328
|
}
|
356
329
|
|
357
|
-
static void
|
358
|
-
|
359
|
-
|
360
|
-
long id = oj_check_circular(obj, out);
|
330
|
+
static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
331
|
+
int cnt;
|
332
|
+
long id = oj_check_circular(obj, out);
|
361
333
|
|
362
334
|
if (0 > id) {
|
363
|
-
|
364
|
-
|
335
|
+
oj_dump_nil(Qnil, depth, out, false);
|
336
|
+
return;
|
365
337
|
}
|
366
338
|
cnt = (int)RHASH_SIZE(obj);
|
367
339
|
assure_size(out, 2);
|
368
340
|
if (0 == cnt) {
|
369
|
-
|
370
|
-
*out->cur++ = '}';
|
341
|
+
APPEND_CHARS(out->cur, "{}", 2);
|
371
342
|
} 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
|
-
*out->cur++ = '}';
|
343
|
+
*out->cur++ = '{';
|
344
|
+
out->depth = depth + 1;
|
345
|
+
rb_hash_foreach(obj, hash_cb, (VALUE)out);
|
346
|
+
if (',' == *(out->cur - 1)) {
|
347
|
+
out->cur--; // backup to overwrite last comma
|
348
|
+
}
|
349
|
+
if (!out->opts->dump_opts.use) {
|
350
|
+
assure_size(out, depth * out->indent + 2);
|
351
|
+
fill_indent(out, depth);
|
352
|
+
} else {
|
353
|
+
assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
|
354
|
+
if (0 < out->opts->dump_opts.hash_size) {
|
355
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
|
356
|
+
}
|
357
|
+
if (0 < out->opts->dump_opts.indent_size) {
|
358
|
+
int i;
|
359
|
+
|
360
|
+
for (i = depth; 0 < i; i--) {
|
361
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
|
362
|
+
}
|
363
|
+
}
|
364
|
+
}
|
365
|
+
*out->cur++ = '}';
|
397
366
|
}
|
398
367
|
*out->cur = '\0';
|
399
368
|
}
|
400
369
|
|
401
|
-
static void
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
int d2 = depth + 1;
|
370
|
+
static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
371
|
+
ID *idp;
|
372
|
+
AttrGetFunc *fp;
|
373
|
+
volatile VALUE v;
|
374
|
+
const char *name;
|
375
|
+
size_t size;
|
376
|
+
int d2 = depth + 1;
|
409
377
|
|
410
378
|
assure_size(out, 2);
|
411
379
|
*out->cur++ = '{';
|
412
380
|
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
|
-
*out->cur++ = '"';
|
434
|
-
memcpy(out->cur, classname, clen);
|
435
|
-
out->cur += clen;
|
436
|
-
*out->cur++ = '"';
|
437
|
-
*out->cur++ = ',';
|
381
|
+
const char *classname = rb_class2name(clas);
|
382
|
+
int clen = (int)strlen(classname);
|
383
|
+
size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
384
|
+
|
385
|
+
size = d2 * out->indent + 10 + clen + out->opts->create_id_len + sep_len;
|
386
|
+
assure_size(out, size);
|
387
|
+
fill_indent(out, d2);
|
388
|
+
*out->cur++ = '"';
|
389
|
+
APPEND_CHARS(out->cur, out->opts->create_id, out->opts->create_id_len);
|
390
|
+
*out->cur++ = '"';
|
391
|
+
if (0 < out->opts->dump_opts.before_size) {
|
392
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
|
393
|
+
}
|
394
|
+
*out->cur++ = ':';
|
395
|
+
if (0 < out->opts->dump_opts.after_size) {
|
396
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
|
397
|
+
}
|
398
|
+
*out->cur++ = '"';
|
399
|
+
APPEND_CHARS(out->cur, classname, clen);
|
400
|
+
APPEND_CHARS(out->cur, "\",", 2);
|
438
401
|
}
|
439
402
|
if (odd->raw) {
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
out->cur += len;
|
459
|
-
*out->cur = '\0';
|
460
|
-
}
|
403
|
+
v = rb_funcall(obj, *odd->attrs, 0);
|
404
|
+
if (Qundef == v || T_STRING != rb_type(v)) {
|
405
|
+
rb_raise(rb_eEncodingError, "Invalid type for raw JSON.\n");
|
406
|
+
} else {
|
407
|
+
const char *s = RSTRING_PTR(v);
|
408
|
+
int len = (int)RSTRING_LEN(v);
|
409
|
+
const char *name = rb_id2name(*odd->attrs);
|
410
|
+
size_t nlen = strlen(name);
|
411
|
+
|
412
|
+
size = len + d2 * out->indent + nlen + 10;
|
413
|
+
assure_size(out, size);
|
414
|
+
fill_indent(out, d2);
|
415
|
+
*out->cur++ = '"';
|
416
|
+
APPEND_CHARS(out->cur, name, nlen);
|
417
|
+
APPEND_CHARS(out->cur, "\":", 2);
|
418
|
+
APPEND_CHARS(out->cur, s, len);
|
419
|
+
*out->cur = '\0';
|
420
|
+
}
|
461
421
|
} 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
|
-
|
422
|
+
size = d2 * out->indent + 1;
|
423
|
+
for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) {
|
424
|
+
size_t nlen;
|
425
|
+
|
426
|
+
assure_size(out, size);
|
427
|
+
name = rb_id2name(*idp);
|
428
|
+
nlen = strlen(name);
|
429
|
+
if (0 != *fp) {
|
430
|
+
v = (*fp)(obj);
|
431
|
+
} else if (0 == strchr(name, '.')) {
|
432
|
+
v = rb_funcall(obj, *idp, 0);
|
433
|
+
} else {
|
434
|
+
char nbuf[256];
|
435
|
+
char *n2 = nbuf;
|
436
|
+
char *n;
|
437
|
+
char *end;
|
438
|
+
ID i;
|
439
|
+
|
440
|
+
if (sizeof(nbuf) <= nlen) {
|
441
|
+
if (NULL == (n2 = OJ_STRDUP(name))) {
|
442
|
+
rb_raise(rb_eNoMemError, "for attribute name.");
|
443
|
+
}
|
444
|
+
} else {
|
445
|
+
strcpy(n2, name);
|
446
|
+
}
|
447
|
+
n = n2;
|
448
|
+
v = obj;
|
449
|
+
while (0 != (end = strchr(n, '.'))) {
|
450
|
+
*end = '\0';
|
451
|
+
i = rb_intern(n);
|
452
|
+
v = rb_funcall(v, i, 0);
|
453
|
+
n = end + 1;
|
454
|
+
}
|
455
|
+
i = rb_intern(n);
|
456
|
+
v = rb_funcall(v, i, 0);
|
457
|
+
if (nbuf != n2) {
|
458
|
+
OJ_FREE(n2);
|
459
|
+
}
|
460
|
+
}
|
461
|
+
fill_indent(out, d2);
|
462
|
+
oj_dump_cstr(name, nlen, 0, 0, out);
|
463
|
+
*out->cur++ = ':';
|
464
|
+
oj_dump_custom_val(v, d2, out, true);
|
465
|
+
assure_size(out, 2);
|
466
|
+
*out->cur++ = ',';
|
467
|
+
}
|
468
|
+
out->cur--;
|
509
469
|
}
|
510
470
|
*out->cur++ = '}';
|
511
|
-
*out->cur
|
471
|
+
*out->cur = '\0';
|
512
472
|
}
|
513
473
|
|
514
474
|
// Return class if still needs dumping.
|
515
|
-
static VALUE
|
516
|
-
dump_common(VALUE obj, int depth, Out out) {
|
517
|
-
|
475
|
+
static VALUE dump_common(VALUE obj, int depth, Out out) {
|
518
476
|
if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
|
519
|
-
|
477
|
+
oj_dump_raw_json(obj, depth, out);
|
520
478
|
} 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
|
-
assure_size(out, len + 1);
|
540
|
-
memcpy(out->cur, s, len);
|
541
|
-
out->cur += len;
|
542
|
-
*out->cur = '\0';
|
479
|
+
volatile VALUE rs;
|
480
|
+
const char *s;
|
481
|
+
int len;
|
482
|
+
|
483
|
+
TRACE(out->opts->trace, "to_json", obj, depth + 1, TraceRubyIn);
|
484
|
+
if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
|
485
|
+
rs = rb_funcall(obj, oj_to_json_id, 0);
|
486
|
+
} else {
|
487
|
+
rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
|
488
|
+
}
|
489
|
+
TRACE(out->opts->trace, "to_json", obj, depth + 1, TraceRubyOut);
|
490
|
+
s = RSTRING_PTR(rs);
|
491
|
+
len = (int)RSTRING_LEN(rs);
|
492
|
+
|
493
|
+
assure_size(out, len + 1);
|
494
|
+
APPEND_CHARS(out->cur, s, len);
|
495
|
+
*out->cur = '\0';
|
543
496
|
} 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
|
-
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), false, false, out);
|
564
|
-
} else {
|
565
|
-
oj_dump_custom_val(aj, depth, out, true);
|
566
|
-
}
|
497
|
+
volatile VALUE aj;
|
498
|
+
|
499
|
+
TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyIn);
|
500
|
+
// Some classes elect to not take an options argument so check the arity
|
501
|
+
// of as_json.
|
502
|
+
if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
|
503
|
+
aj = rb_funcall(obj, oj_as_json_id, 0);
|
504
|
+
} else {
|
505
|
+
aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
506
|
+
}
|
507
|
+
TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyOut);
|
508
|
+
// Catch the obvious brain damaged recursive dumping.
|
509
|
+
if (aj == obj) {
|
510
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
511
|
+
|
512
|
+
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), false, false, out);
|
513
|
+
} else {
|
514
|
+
oj_dump_custom_val(aj, depth, out, true);
|
515
|
+
}
|
567
516
|
} 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
|
-
|
517
|
+
volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
518
|
+
|
519
|
+
if (T_HASH != rb_type(h)) {
|
520
|
+
// It seems that ActiveRecord implemented to_hash so that it returns
|
521
|
+
// an Array and not a Hash. To get around that any value returned
|
522
|
+
// will be dumped.
|
523
|
+
|
524
|
+
// rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n",
|
525
|
+
// rb_class2name(rb_obj_class(obj)));
|
526
|
+
oj_dump_custom_val(h, depth, out, false);
|
527
|
+
} else {
|
528
|
+
dump_hash(h, depth, out, true);
|
529
|
+
}
|
580
530
|
} else if (!oj_code_dump(codes, obj, depth, out)) {
|
581
|
-
|
582
|
-
|
531
|
+
VALUE clas = rb_obj_class(obj);
|
532
|
+
Odd odd = oj_get_odd(clas);
|
583
533
|
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
534
|
+
if (NULL == odd) {
|
535
|
+
return clas;
|
536
|
+
}
|
537
|
+
dump_odd(obj, odd, clas, depth + 1, out);
|
588
538
|
}
|
589
539
|
return Qnil;
|
590
540
|
}
|
591
541
|
|
592
|
-
static int
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
const char *attr;
|
542
|
+
static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
|
543
|
+
Out out = (Out)ov;
|
544
|
+
int depth = out->depth;
|
545
|
+
size_t size;
|
546
|
+
const char *attr;
|
598
547
|
|
599
|
-
if (
|
600
|
-
|
548
|
+
if (dump_ignore(out->opts, value)) {
|
549
|
+
return ST_CONTINUE;
|
601
550
|
}
|
602
551
|
if (out->omit_nil && Qnil == value) {
|
603
|
-
|
552
|
+
return ST_CONTINUE;
|
604
553
|
}
|
605
554
|
size = depth * out->indent + 1;
|
606
555
|
attr = rb_id2name(key);
|
607
556
|
// Some exceptions such as NoMethodError have an invisible attribute where
|
608
557
|
// the key name is NULL. Not an empty string but NULL.
|
609
558
|
if (NULL == attr) {
|
610
|
-
|
559
|
+
attr = "";
|
611
560
|
} else if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) {
|
612
|
-
|
561
|
+
return ST_CONTINUE;
|
613
562
|
}
|
614
563
|
if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) {
|
615
|
-
|
564
|
+
return ST_CONTINUE;
|
616
565
|
}
|
617
566
|
assure_size(out, size);
|
618
567
|
fill_indent(out, depth);
|
619
568
|
if ('@' == *attr) {
|
620
|
-
|
621
|
-
|
569
|
+
attr++;
|
570
|
+
oj_dump_cstr(attr, strlen(attr), 0, 0, out);
|
622
571
|
} else {
|
623
|
-
|
572
|
+
char buf[32];
|
624
573
|
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
574
|
+
*buf = '~';
|
575
|
+
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
576
|
+
buf[sizeof(buf) - 1] = '\0';
|
577
|
+
oj_dump_cstr(buf, strlen(buf), 0, 0, out);
|
629
578
|
}
|
630
579
|
*out->cur++ = ':';
|
631
580
|
oj_dump_custom_val(value, depth, out, true);
|
632
|
-
out->depth
|
581
|
+
out->depth = depth;
|
633
582
|
*out->cur++ = ',';
|
634
583
|
|
635
584
|
return ST_CONTINUE;
|
636
585
|
}
|
637
586
|
|
638
|
-
static void
|
639
|
-
|
640
|
-
|
641
|
-
int
|
642
|
-
|
643
|
-
bool class_written = false;
|
587
|
+
static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
|
588
|
+
size_t size = 0;
|
589
|
+
int d2 = depth + 1;
|
590
|
+
int cnt;
|
591
|
+
bool class_written = false;
|
644
592
|
|
645
593
|
assure_size(out, 2);
|
646
594
|
*out->cur++ = '{';
|
647
595
|
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
|
-
memcpy(out->cur, classname, len);
|
670
|
-
out->cur += len;
|
671
|
-
*out->cur++ = '"';
|
672
|
-
class_written = true;
|
596
|
+
size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
597
|
+
const char *classname = rb_obj_classname(obj);
|
598
|
+
size_t len = strlen(classname);
|
599
|
+
|
600
|
+
size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len;
|
601
|
+
assure_size(out, size);
|
602
|
+
fill_indent(out, d2);
|
603
|
+
*out->cur++ = '"';
|
604
|
+
APPEND_CHARS(out->cur, out->opts->create_id, out->opts->create_id_len);
|
605
|
+
*out->cur++ = '"';
|
606
|
+
if (0 < out->opts->dump_opts.before_size) {
|
607
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
|
608
|
+
}
|
609
|
+
*out->cur++ = ':';
|
610
|
+
if (0 < out->opts->dump_opts.after_size) {
|
611
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
|
612
|
+
}
|
613
|
+
*out->cur++ = '"';
|
614
|
+
APPEND_CHARS(out->cur, classname, len);
|
615
|
+
*out->cur++ = '"';
|
616
|
+
class_written = true;
|
673
617
|
}
|
674
618
|
cnt = (int)rb_ivar_count(obj);
|
675
619
|
if (class_written) {
|
676
|
-
|
620
|
+
*out->cur++ = ',';
|
677
621
|
}
|
678
622
|
if (0 == cnt && Qundef == clas) {
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
623
|
+
// Might be something special like an Enumerable.
|
624
|
+
if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) {
|
625
|
+
out->cur--;
|
626
|
+
oj_dump_custom_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out, false);
|
627
|
+
return;
|
628
|
+
}
|
685
629
|
}
|
686
630
|
out->depth = depth + 1;
|
687
631
|
rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
|
688
632
|
if (',' == *(out->cur - 1)) {
|
689
|
-
|
633
|
+
out->cur--; // backup to overwrite last comma
|
690
634
|
}
|
691
635
|
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
|
-
|
636
|
+
volatile VALUE rv;
|
637
|
+
|
638
|
+
if (',' != *(out->cur - 1)) {
|
639
|
+
*out->cur++ = ',';
|
640
|
+
}
|
641
|
+
// message
|
642
|
+
assure_size(out, 2);
|
643
|
+
fill_indent(out, d2);
|
644
|
+
oj_dump_cstr("~mesg", 5, 0, 0, out);
|
645
|
+
*out->cur++ = ':';
|
646
|
+
rv = rb_funcall2(obj, rb_intern("message"), 0, 0);
|
647
|
+
oj_dump_custom_val(rv, d2, out, true);
|
648
|
+
assure_size(out, size + 2);
|
649
|
+
*out->cur++ = ',';
|
650
|
+
// backtrace
|
651
|
+
fill_indent(out, d2);
|
652
|
+
oj_dump_cstr("~bt", 3, 0, 0, out);
|
653
|
+
*out->cur++ = ':';
|
654
|
+
rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0);
|
655
|
+
oj_dump_custom_val(rv, d2, out, true);
|
656
|
+
assure_size(out, 2);
|
713
657
|
}
|
714
658
|
out->depth = depth;
|
715
659
|
|
716
660
|
fill_indent(out, depth);
|
717
661
|
*out->cur++ = '}';
|
718
|
-
*out->cur
|
662
|
+
*out->cur = '\0';
|
719
663
|
}
|
720
664
|
|
721
|
-
static void
|
722
|
-
|
723
|
-
|
724
|
-
VALUE clas;
|
665
|
+
static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
666
|
+
long id = oj_check_circular(obj, out);
|
667
|
+
VALUE clas;
|
725
668
|
|
726
669
|
if (0 > id) {
|
727
|
-
|
670
|
+
oj_dump_nil(Qnil, depth, out, false);
|
728
671
|
} else if (Qnil != (clas = dump_common(obj, depth, out))) {
|
729
|
-
|
672
|
+
dump_obj_attrs(obj, clas, 0, depth, out);
|
730
673
|
}
|
731
674
|
*out->cur = '\0';
|
732
675
|
}
|
733
676
|
|
734
|
-
static void
|
735
|
-
|
736
|
-
|
737
|
-
int
|
738
|
-
|
739
|
-
long id = oj_check_circular(a, out);
|
677
|
+
static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
678
|
+
size_t size;
|
679
|
+
int i, cnt;
|
680
|
+
int d2 = depth + 1;
|
681
|
+
long id = oj_check_circular(a, out);
|
740
682
|
|
741
683
|
if (0 > id) {
|
742
|
-
|
743
|
-
|
684
|
+
oj_dump_nil(Qnil, depth, out, false);
|
685
|
+
return;
|
744
686
|
}
|
745
|
-
cnt
|
687
|
+
cnt = (int)RARRAY_LEN(a);
|
746
688
|
*out->cur++ = '[';
|
747
689
|
assure_size(out, 2);
|
748
690
|
if (0 == cnt) {
|
749
|
-
|
691
|
+
*out->cur++ = ']';
|
750
692
|
} 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
|
-
} else {
|
795
|
-
fill_indent(out, depth);
|
796
|
-
}
|
797
|
-
*out->cur++ = ']';
|
693
|
+
if (out->opts->dump_opts.use) {
|
694
|
+
size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
|
695
|
+
} else {
|
696
|
+
size = d2 * out->indent + 2;
|
697
|
+
}
|
698
|
+
assure_size(out, size * cnt);
|
699
|
+
cnt--;
|
700
|
+
for (i = 0; i <= cnt; i++) {
|
701
|
+
if (out->opts->dump_opts.use) {
|
702
|
+
if (0 < out->opts->dump_opts.array_size) {
|
703
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
|
704
|
+
}
|
705
|
+
if (0 < out->opts->dump_opts.indent_size) {
|
706
|
+
int i;
|
707
|
+
for (i = d2; 0 < i; i--) {
|
708
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
|
709
|
+
}
|
710
|
+
}
|
711
|
+
} else {
|
712
|
+
fill_indent(out, d2);
|
713
|
+
}
|
714
|
+
oj_dump_custom_val(RARRAY_AREF(a, i), d2, out, true);
|
715
|
+
if (i < cnt) {
|
716
|
+
*out->cur++ = ',';
|
717
|
+
}
|
718
|
+
}
|
719
|
+
size = depth * out->indent + 1;
|
720
|
+
assure_size(out, size);
|
721
|
+
if (out->opts->dump_opts.use) {
|
722
|
+
if (0 < out->opts->dump_opts.array_size) {
|
723
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
|
724
|
+
}
|
725
|
+
if (0 < out->opts->dump_opts.indent_size) {
|
726
|
+
int i;
|
727
|
+
|
728
|
+
for (i = depth; 0 < i; i--) {
|
729
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
|
730
|
+
}
|
731
|
+
}
|
732
|
+
} else {
|
733
|
+
fill_indent(out, depth);
|
734
|
+
}
|
735
|
+
*out->cur++ = ']';
|
798
736
|
}
|
799
737
|
*out->cur = '\0';
|
800
738
|
}
|
801
739
|
|
802
|
-
static void
|
803
|
-
|
804
|
-
|
805
|
-
VALUE clas;
|
740
|
+
static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
741
|
+
long id = oj_check_circular(obj, out);
|
742
|
+
VALUE clas;
|
806
743
|
|
807
744
|
if (0 > id) {
|
808
|
-
|
745
|
+
oj_dump_nil(Qnil, depth, out, false);
|
809
746
|
} 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
|
-
ma = rb_struct_s_members(clas);
|
747
|
+
VALUE ma = Qnil;
|
748
|
+
VALUE v;
|
749
|
+
char num_id[32];
|
750
|
+
int i;
|
751
|
+
int d2 = depth + 1;
|
752
|
+
int d3 = d2 + 1;
|
753
|
+
size_t size = d2 * out->indent + d3 * out->indent + 3;
|
754
|
+
const char *name;
|
755
|
+
int cnt;
|
756
|
+
size_t len;
|
757
|
+
|
758
|
+
assure_size(out, size);
|
759
|
+
if (clas == rb_cRange) {
|
760
|
+
*out->cur++ = '"';
|
761
|
+
oj_dump_custom_val(rb_funcall(obj, oj_begin_id, 0), d3, out, false);
|
762
|
+
assure_size(out, 3);
|
763
|
+
APPEND_CHARS(out->cur, "..", 2);
|
764
|
+
if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) {
|
765
|
+
*out->cur++ = '.';
|
766
|
+
}
|
767
|
+
oj_dump_custom_val(rb_funcall(obj, oj_end_id, 0), d3, out, false);
|
768
|
+
*out->cur++ = '"';
|
769
|
+
|
770
|
+
return;
|
771
|
+
}
|
772
|
+
*out->cur++ = '{';
|
773
|
+
fill_indent(out, d2);
|
774
|
+
size = d3 * out->indent + 2;
|
775
|
+
ma = rb_struct_s_members(clas);
|
840
776
|
|
841
777
|
#ifdef RSTRUCT_LEN
|
842
778
|
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
843
|
-
|
844
|
-
#else
|
845
|
-
|
846
|
-
#endif
|
779
|
+
cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
|
780
|
+
#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
781
|
+
cnt = (int)RSTRUCT_LEN(obj);
|
782
|
+
#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
847
783
|
#else
|
848
|
-
|
849
|
-
|
850
|
-
|
784
|
+
// This is a bit risky as a struct in C ruby is not the same as a Struct
|
785
|
+
// class in interpreted Ruby so length() may not be defined.
|
786
|
+
cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
|
851
787
|
#endif
|
852
|
-
|
788
|
+
for (i = 0; i < cnt; i++) {
|
853
789
|
#ifdef RSTRUCT_LEN
|
854
|
-
|
790
|
+
v = RSTRUCT_GET(obj, i);
|
855
791
|
#else
|
856
|
-
|
792
|
+
v = rb_struct_aref(obj, INT2FIX(i));
|
857
793
|
#endif
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
*out->cur++ = '}';
|
879
|
-
*out->cur = '\0';
|
794
|
+
if (ma != Qnil) {
|
795
|
+
volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
|
796
|
+
|
797
|
+
name = RSTRING_PTR(s);
|
798
|
+
len = (int)RSTRING_LEN(s);
|
799
|
+
} else {
|
800
|
+
len = snprintf(num_id, sizeof(num_id), "%d", i);
|
801
|
+
name = num_id;
|
802
|
+
}
|
803
|
+
assure_size(out, size + len + 3);
|
804
|
+
fill_indent(out, d3);
|
805
|
+
*out->cur++ = '"';
|
806
|
+
APPEND_CHARS(out->cur, name, len);
|
807
|
+
APPEND_CHARS(out->cur, "\":", 2);
|
808
|
+
oj_dump_custom_val(v, d3, out, true);
|
809
|
+
*out->cur++ = ',';
|
810
|
+
}
|
811
|
+
out->cur--;
|
812
|
+
*out->cur++ = '}';
|
813
|
+
*out->cur = '\0';
|
880
814
|
}
|
881
815
|
}
|
882
816
|
|
883
|
-
static void
|
884
|
-
|
885
|
-
|
886
|
-
VALUE clas;
|
817
|
+
static void dump_data(VALUE obj, int depth, Out out, bool as_ok) {
|
818
|
+
long id = oj_check_circular(obj, out);
|
819
|
+
VALUE clas;
|
887
820
|
|
888
821
|
if (0 > id) {
|
889
|
-
|
822
|
+
oj_dump_nil(Qnil, depth, out, false);
|
890
823
|
} else if (Qnil != (clas = dump_common(obj, depth, out))) {
|
891
|
-
|
824
|
+
dump_obj_attrs(obj, clas, id, depth, out);
|
892
825
|
}
|
893
826
|
}
|
894
827
|
|
895
|
-
static void
|
896
|
-
dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
|
828
|
+
static void dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
|
897
829
|
if (NULL != out->opts->create_id) {
|
898
|
-
|
830
|
+
dump_obj_str(obj, depth, out);
|
899
831
|
} else {
|
900
|
-
|
832
|
+
dump_obj_as_str(obj, depth, out);
|
901
833
|
}
|
902
834
|
}
|
903
835
|
|
904
|
-
static void
|
905
|
-
dump_complex(VALUE obj, int depth, Out out, bool as_ok) {
|
836
|
+
static void dump_complex(VALUE obj, int depth, Out out, bool as_ok) {
|
906
837
|
complex_dump(obj, depth, out);
|
907
838
|
}
|
908
839
|
|
909
|
-
static void
|
910
|
-
dump_rational(VALUE obj, int depth, Out out, bool as_ok) {
|
840
|
+
static void dump_rational(VALUE obj, int depth, Out out, bool as_ok) {
|
911
841
|
rational_dump(obj, depth, out);
|
912
842
|
}
|
913
843
|
|
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,
|
844
|
+
static DumpFunc custom_funcs[] = {
|
845
|
+
NULL, // RUBY_T_NONE = 0x00,
|
846
|
+
dump_obj, // RUBY_T_OBJECT = 0x01,
|
847
|
+
oj_dump_class, // RUBY_T_CLASS = 0x02,
|
848
|
+
oj_dump_class, // RUBY_T_MODULE = 0x03,
|
849
|
+
oj_dump_float, // RUBY_T_FLOAT = 0x04,
|
850
|
+
oj_dump_str, // RUBY_T_STRING = 0x05,
|
851
|
+
dump_regexp, // RUBY_T_REGEXP = 0x06,
|
852
|
+
dump_array, // RUBY_T_ARRAY = 0x07,
|
853
|
+
dump_hash, // RUBY_T_HASH = 0x08,
|
854
|
+
dump_struct, // RUBY_T_STRUCT = 0x09,
|
855
|
+
oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
|
856
|
+
NULL, // RUBY_T_FILE = 0x0b,
|
857
|
+
dump_data, // RUBY_T_DATA = 0x0c,
|
858
|
+
NULL, // RUBY_T_MATCH = 0x0d,
|
859
|
+
dump_complex, // RUBY_T_COMPLEX = 0x0e,
|
860
|
+
dump_rational, // RUBY_T_RATIONAL = 0x0f,
|
861
|
+
NULL, // 0x10
|
862
|
+
oj_dump_nil, // RUBY_T_NIL = 0x11,
|
863
|
+
oj_dump_true, // RUBY_T_TRUE = 0x12,
|
864
|
+
oj_dump_false, // RUBY_T_FALSE = 0x13,
|
865
|
+
oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
|
866
|
+
oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
|
937
867
|
};
|
938
868
|
|
939
|
-
void
|
940
|
-
|
941
|
-
int type = rb_type(obj);
|
869
|
+
void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
870
|
+
int type = rb_type(obj);
|
942
871
|
|
943
|
-
|
944
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
945
|
-
}
|
872
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
|
946
873
|
if (MAX_DEPTH < depth) {
|
947
|
-
|
874
|
+
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
948
875
|
}
|
949
876
|
if (0 < type && type <= RUBY_T_FIXNUM) {
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
return;
|
958
|
-
}
|
877
|
+
DumpFunc f = custom_funcs[type];
|
878
|
+
|
879
|
+
if (NULL != f) {
|
880
|
+
f(obj, depth, out, true);
|
881
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
|
882
|
+
return;
|
883
|
+
}
|
959
884
|
}
|
960
885
|
oj_dump_nil(Qnil, depth, out, false);
|
961
|
-
|
962
|
-
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
963
|
-
}
|
886
|
+
TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
|
964
887
|
}
|
965
888
|
|
966
889
|
///// load functions /////
|
967
890
|
|
968
|
-
static void
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
if (Qundef != parent->clas) {
|
985
|
-
if (!oj_code_has(codes, parent->clas, false)) {
|
986
|
-
parent->val = rb_obj_alloc(parent->clas);
|
987
|
-
}
|
988
|
-
}
|
989
|
-
}
|
891
|
+
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
892
|
+
const char *key = kval->key;
|
893
|
+
int klen = kval->klen;
|
894
|
+
Val parent = stack_peek(&pi->stack);
|
895
|
+
|
896
|
+
if (Qundef == kval->key_val && Yes == pi->options.create_ok && NULL != pi->options.create_id &&
|
897
|
+
*pi->options.create_id == *key && (int)pi->options.create_id_len == klen &&
|
898
|
+
0 == strncmp(pi->options.create_id, key, klen)) {
|
899
|
+
parent->clas = oj_name2class(pi, str, len, false, rb_eArgError);
|
900
|
+
if (2 == klen && '^' == *key && 'o' == key[1]) {
|
901
|
+
if (Qundef != parent->clas) {
|
902
|
+
if (!oj_code_has(codes, parent->clas, false)) {
|
903
|
+
parent->val = rb_obj_alloc(parent->clas);
|
904
|
+
}
|
905
|
+
}
|
906
|
+
}
|
990
907
|
} 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
|
-
} else {
|
1018
|
-
rb_hash_aset(parent->val, rkey, rstr);
|
1019
|
-
}
|
1020
|
-
break;
|
1021
|
-
default:
|
1022
|
-
break;
|
1023
|
-
}
|
1024
|
-
if (Yes == pi->options.trace) {
|
1025
|
-
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
|
1026
|
-
}
|
908
|
+
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
909
|
+
volatile VALUE rkey = oj_calc_hash_key(pi, kval);
|
910
|
+
|
911
|
+
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
912
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
913
|
+
|
914
|
+
if (Qnil != clas) {
|
915
|
+
rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
916
|
+
}
|
917
|
+
}
|
918
|
+
switch (rb_type(parent->val)) {
|
919
|
+
case T_OBJECT: oj_set_obj_ivar(parent, kval, rstr); break;
|
920
|
+
case T_HASH:
|
921
|
+
if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas &&
|
922
|
+
0 == strncmp("time", parent->key, 4)) {
|
923
|
+
if (Qnil == (parent->val = oj_parse_xml_time(str, (int)len))) {
|
924
|
+
parent->val = rb_funcall(rb_cTime, rb_intern("parse"), 1, rb_str_new(str, len));
|
925
|
+
}
|
926
|
+
} else {
|
927
|
+
rb_hash_aset(parent->val, rkey, rstr);
|
928
|
+
}
|
929
|
+
break;
|
930
|
+
default: break;
|
931
|
+
}
|
932
|
+
TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rstr);
|
1027
933
|
}
|
1028
934
|
}
|
1029
935
|
|
1030
|
-
static void
|
1031
|
-
|
1032
|
-
Val parent = stack_peek(&pi->stack);
|
936
|
+
static void end_hash(struct _parseInfo *pi) {
|
937
|
+
Val parent = stack_peek(&pi->stack);
|
1033
938
|
|
1034
939
|
if (Qundef != parent->clas && parent->clas != rb_obj_class(parent->val)) {
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
}
|
1044
|
-
if (Yes == pi->options.trace) {
|
1045
|
-
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
940
|
+
volatile VALUE obj = oj_code_load(codes, parent->clas, parent->val);
|
941
|
+
|
942
|
+
if (Qnil != obj) {
|
943
|
+
parent->val = obj;
|
944
|
+
} else {
|
945
|
+
parent->val = rb_funcall(parent->clas, oj_json_create_id, 1, parent->val);
|
946
|
+
}
|
947
|
+
parent->clas = Qundef;
|
1046
948
|
}
|
949
|
+
TRACE_PARSE_HASH_END(pi->options.trace, pi);
|
1047
950
|
}
|
1048
951
|
|
1049
|
-
static
|
1050
|
-
|
1051
|
-
volatile VALUE
|
1052
|
-
|
1053
|
-
if (Qundef == rkey) {
|
1054
|
-
rkey = rb_str_new(parent->key, parent->klen);
|
1055
|
-
}
|
1056
|
-
rkey = oj_encode(rkey);
|
1057
|
-
if (Yes == pi->options.sym_key) {
|
1058
|
-
rkey = rb_str_intern(rkey);
|
1059
|
-
}
|
1060
|
-
return rkey;
|
1061
|
-
}
|
1062
|
-
|
1063
|
-
static void
|
1064
|
-
hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
|
1065
|
-
Val parent = stack_peek(&pi->stack);
|
1066
|
-
volatile VALUE rval = oj_num_as_value(ni);
|
952
|
+
static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
|
953
|
+
Val parent = stack_peek(&pi->stack);
|
954
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
1067
955
|
|
1068
956
|
switch (rb_type(parent->val)) {
|
1069
|
-
case T_OBJECT:
|
1070
|
-
oj_set_obj_ivar(parent, kval, rval);
|
1071
|
-
break;
|
957
|
+
case T_OBJECT: oj_set_obj_ivar(parent, kval, rval); break;
|
1072
958
|
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
|
-
} else {
|
1105
|
-
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
1106
|
-
}
|
1107
|
-
rval = parent->val;
|
1108
|
-
} else {
|
1109
|
-
rb_hash_aset(parent->val, calc_hash_key(pi, kval), rval);
|
1110
|
-
}
|
1111
|
-
break;
|
1112
|
-
default:
|
1113
|
-
break;
|
1114
|
-
}
|
1115
|
-
if (Yes == pi->options.trace) {
|
1116
|
-
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
|
959
|
+
if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 != ni->div &&
|
960
|
+
0 == strncmp("time", parent->key, 4)) {
|
961
|
+
int64_t nsec = ni->num * 1000000000LL / ni->div;
|
962
|
+
|
963
|
+
if (ni->neg) {
|
964
|
+
ni->i = -ni->i;
|
965
|
+
if (0 < nsec) {
|
966
|
+
ni->i--;
|
967
|
+
nsec = 1000000000LL - nsec;
|
968
|
+
}
|
969
|
+
}
|
970
|
+
if (86400 == ni->exp) { // UTC time
|
971
|
+
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
972
|
+
// Since the ruby C routines always create local time, the
|
973
|
+
// offset and then a conversion to UTC keeps makes the time
|
974
|
+
// match the expected value.
|
975
|
+
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
976
|
+
} else if (ni->has_exp) {
|
977
|
+
struct timespec ts;
|
978
|
+
ts.tv_sec = ni->i;
|
979
|
+
ts.tv_nsec = nsec;
|
980
|
+
parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
|
981
|
+
} else {
|
982
|
+
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
983
|
+
}
|
984
|
+
rval = parent->val;
|
985
|
+
} else {
|
986
|
+
rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), rval);
|
987
|
+
}
|
988
|
+
break;
|
989
|
+
default: break;
|
1117
990
|
}
|
991
|
+
TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rval);
|
1118
992
|
}
|
1119
993
|
|
1120
|
-
static void
|
1121
|
-
|
1122
|
-
Val parent = stack_peek(&pi->stack);
|
994
|
+
static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
995
|
+
Val parent = stack_peek(&pi->stack);
|
1123
996
|
|
1124
997
|
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;
|
1133
|
-
}
|
1134
|
-
if (Yes == pi->options.trace) {
|
1135
|
-
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
998
|
+
case T_OBJECT: oj_set_obj_ivar(parent, kval, value); break;
|
999
|
+
case T_HASH: rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), value); break;
|
1000
|
+
default: break;
|
1136
1001
|
}
|
1002
|
+
TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
|
1137
1003
|
}
|
1138
1004
|
|
1139
|
-
static void
|
1140
|
-
|
1141
|
-
|
1142
|
-
volatile VALUE rval = oj_num_as_value(ni);
|
1005
|
+
static void array_append_num(ParseInfo pi, NumInfo ni) {
|
1006
|
+
Val parent = stack_peek(&pi->stack);
|
1007
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
1143
1008
|
|
1144
1009
|
rb_ary_push(parent->val, rval);
|
1145
|
-
|
1146
|
-
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
1147
|
-
}
|
1010
|
+
TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
|
1148
1011
|
}
|
1149
1012
|
|
1150
|
-
static void
|
1151
|
-
|
1152
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
1013
|
+
static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
1014
|
+
volatile VALUE rstr = rb_utf8_str_new(str, len);
|
1153
1015
|
|
1154
|
-
rstr = oj_encode(rstr);
|
1155
1016
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
1156
|
-
|
1017
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
1157
1018
|
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1019
|
+
if (Qnil != clas) {
|
1020
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
|
1021
|
+
return;
|
1022
|
+
}
|
1162
1023
|
}
|
1163
1024
|
rb_ary_push(stack_peek(&pi->stack)->val, rstr);
|
1164
|
-
|
1165
|
-
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
|
1166
|
-
}
|
1025
|
+
TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rstr);
|
1167
1026
|
}
|
1168
1027
|
|
1169
|
-
void
|
1170
|
-
oj_set_custom_callbacks(ParseInfo pi) {
|
1028
|
+
void oj_set_custom_callbacks(ParseInfo pi) {
|
1171
1029
|
oj_set_compat_callbacks(pi);
|
1172
|
-
pi->hash_set_cstr
|
1173
|
-
pi->end_hash
|
1174
|
-
pi->hash_set_num
|
1175
|
-
pi->hash_set_value
|
1030
|
+
pi->hash_set_cstr = hash_set_cstr;
|
1031
|
+
pi->end_hash = end_hash;
|
1032
|
+
pi->hash_set_num = hash_set_num;
|
1033
|
+
pi->hash_set_value = hash_set_value;
|
1176
1034
|
pi->array_append_cstr = array_append_cstr;
|
1177
|
-
pi->array_append_num
|
1035
|
+
pi->array_append_num = array_append_num;
|
1178
1036
|
}
|
1179
1037
|
|
1180
1038
|
VALUE
|
1181
1039
|
oj_custom_parse(int argc, VALUE *argv, VALUE self) {
|
1182
|
-
struct _parseInfo
|
1040
|
+
struct _parseInfo pi;
|
1183
1041
|
|
1184
1042
|
parse_info_init(&pi);
|
1185
|
-
pi.options
|
1186
|
-
pi.handler
|
1187
|
-
pi.err_class
|
1188
|
-
pi.max_depth
|
1043
|
+
pi.options = oj_default_options;
|
1044
|
+
pi.handler = Qnil;
|
1045
|
+
pi.err_class = Qnil;
|
1046
|
+
pi.max_depth = 0;
|
1189
1047
|
pi.options.allow_nan = Yes;
|
1190
|
-
pi.options.nilnil
|
1048
|
+
pi.options.nilnil = Yes;
|
1191
1049
|
oj_set_custom_callbacks(&pi);
|
1192
1050
|
|
1193
1051
|
if (T_STRING == rb_type(*argv)) {
|
1194
|
-
|
1052
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, false);
|
1195
1053
|
} else {
|
1196
|
-
|
1054
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
1197
1055
|
}
|
1198
1056
|
}
|
1199
1057
|
|
1200
1058
|
VALUE
|
1201
1059
|
oj_custom_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
1202
|
-
struct _parseInfo
|
1060
|
+
struct _parseInfo pi;
|
1203
1061
|
|
1204
1062
|
parse_info_init(&pi);
|
1205
|
-
pi.options
|
1206
|
-
pi.handler
|
1207
|
-
pi.err_class
|
1208
|
-
pi.max_depth
|
1063
|
+
pi.options = oj_default_options;
|
1064
|
+
pi.handler = Qnil;
|
1065
|
+
pi.err_class = Qnil;
|
1066
|
+
pi.max_depth = 0;
|
1209
1067
|
pi.options.allow_nan = Yes;
|
1210
|
-
pi.options.nilnil
|
1068
|
+
pi.options.nilnil = Yes;
|
1211
1069
|
oj_set_custom_callbacks(&pi);
|
1212
1070
|
pi.end_hash = end_hash;
|
1213
1071
|
|