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