oj 2.18.5 → 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 +5 -5
- data/CHANGELOG.md +1452 -0
- data/README.md +53 -221
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +54 -72
- data/ext/oj/cache.c +329 -0
- data/ext/oj/cache.h +22 -0
- data/ext/oj/cache8.c +61 -63
- data/ext/oj/cache8.h +12 -39
- data/ext/oj/circarray.c +38 -67
- data/ext/oj/circarray.h +16 -42
- data/ext/oj/code.c +214 -0
- data/ext/oj/code.h +40 -0
- data/ext/oj/compat.c +194 -110
- data/ext/oj/custom.c +1074 -0
- data/ext/oj/debug.c +126 -0
- data/ext/oj/dump.c +1276 -2494
- data/ext/oj/dump.h +110 -0
- data/ext/oj/dump_compat.c +897 -0
- data/ext/oj/dump_leaf.c +162 -0
- data/ext/oj/dump_object.c +710 -0
- data/ext/oj/dump_strict.c +399 -0
- data/ext/oj/encode.h +7 -42
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +28 -53
- data/ext/oj/err.h +49 -46
- data/ext/oj/extconf.rb +33 -32
- data/ext/oj/fast.c +1082 -1098
- 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 +919 -0
- data/ext/oj/object.c +545 -625
- data/ext/oj/odd.c +158 -168
- data/ext/oj/odd.h +32 -58
- data/ext/oj/oj.c +1727 -2080
- data/ext/oj/oj.h +334 -259
- data/ext/oj/parse.c +974 -753
- data/ext/oj/parse.h +97 -90
- data/ext/oj/parser.c +1600 -0
- data/ext/oj/parser.h +103 -0
- data/ext/oj/rails.c +1478 -0
- data/ext/oj/rails.h +18 -0
- data/ext/oj/reader.c +136 -163
- data/ext/oj/reader.h +76 -112
- data/ext/oj/resolve.c +45 -94
- data/ext/oj/resolve.h +7 -34
- data/ext/oj/rxclass.c +144 -0
- data/ext/oj/rxclass.h +26 -0
- data/ext/oj/saj.c +445 -511
- data/ext/oj/saj2.c +584 -0
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +82 -143
- data/ext/oj/simd.h +10 -0
- data/ext/oj/sparse.c +749 -644
- data/ext/oj/stream_writer.c +329 -0
- data/ext/oj/strict.c +114 -112
- data/ext/oj/string_writer.c +517 -0
- data/ext/oj/trace.c +72 -0
- data/ext/oj/trace.h +55 -0
- data/ext/oj/usual.c +1218 -0
- data/ext/oj/usual.h +69 -0
- data/ext/oj/util.c +136 -0
- data/ext/oj/util.h +20 -0
- data/ext/oj/val_stack.c +75 -72
- data/ext/oj/val_stack.h +94 -127
- data/ext/oj/validate.c +46 -0
- data/ext/oj/wab.c +586 -0
- data/lib/oj/active_support_helper.rb +1 -3
- data/lib/oj/bag.rb +8 -1
- data/lib/oj/easy_hash.rb +21 -13
- data/lib/oj/error.rb +10 -12
- data/lib/oj/json.rb +188 -0
- data/lib/oj/mimic.rb +165 -26
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/state.rb +135 -0
- data/lib/oj/version.rb +2 -3
- data/lib/oj.rb +3 -31
- data/pages/Advanced.md +22 -0
- data/pages/Compatibility.md +25 -0
- data/pages/Custom.md +23 -0
- data/pages/Encoding.md +65 -0
- data/pages/InstallOptions.md +20 -0
- data/pages/JsonGem.md +94 -0
- data/pages/Modes.md +161 -0
- data/pages/Options.md +337 -0
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +167 -0
- data/pages/Security.md +20 -0
- data/pages/WAB.md +13 -0
- metadata +126 -163
- 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/activesupport_datetime_test.rb +0 -23
- data/test/bug.rb +0 -51
- data/test/bug2.rb +0 -10
- data/test/bug3.rb +0 -46
- data/test/bug_fast.rb +0 -32
- data/test/bug_load.rb +0 -24
- data/test/crash.rb +0 -111
- data/test/curl/curl_oj.rb +0 -46
- data/test/curl/get_oj.rb +0 -24
- data/test/curl/just_curl.rb +0 -31
- data/test/curl/just_oj.rb +0 -51
- data/test/example.rb +0 -11
- data/test/files.rb +0 -29
- data/test/foo.rb +0 -24
- data/test/helper.rb +0 -27
- data/test/io.rb +0 -48
- data/test/isolated/shared.rb +0 -310
- 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_rails_datetime.rb +0 -27
- data/test/isolated/test_mimic_redefine.rb +0 -15
- data/test/mod.rb +0 -16
- data/test/perf.rb +0 -107
- data/test/perf_compat.rb +0 -128
- 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 -128
- data/test/rails.rb +0 -50
- data/test/russian.rb +0 -18
- 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 -55
- data/test/sample_json.rb +0 -37
- data/test/struct.rb +0 -29
- data/test/test_compat.rb +0 -398
- data/test/test_debian.rb +0 -53
- data/test/test_fast.rb +0 -458
- data/test/test_file.rb +0 -245
- data/test/test_gc.rb +0 -49
- data/test/test_hash.rb +0 -29
- data/test/test_object.rb +0 -745
- data/test/test_saj.rb +0 -186
- data/test/test_scp.rb +0 -396
- data/test/test_serializer.rb +0 -59
- data/test/test_strict.rb +0 -254
- data/test/test_various.rb +0 -1383
- data/test/test_writer.rb +0 -308
- data/test/write_timebars.rb +0 -31
@@ -0,0 +1,710 @@
|
|
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.
|
3
|
+
|
4
|
+
#include "dump.h"
|
5
|
+
#include "mem.h"
|
6
|
+
#include "odd.h"
|
7
|
+
#include "trace.h"
|
8
|
+
|
9
|
+
static const char hex_chars[17] = "0123456789abcdef";
|
10
|
+
|
11
|
+
static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out);
|
12
|
+
|
13
|
+
static void dump_time(VALUE obj, Out out) {
|
14
|
+
switch (out->opts->time_format) {
|
15
|
+
case RubyTime:
|
16
|
+
case XmlTime: oj_dump_xml_time(obj, out); break;
|
17
|
+
case UnixZTime: oj_dump_time(obj, out, 1); break;
|
18
|
+
case UnixTime:
|
19
|
+
default: oj_dump_time(obj, out, 0); break;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
static void dump_data(VALUE obj, int depth, Out out, bool as_ok) {
|
24
|
+
VALUE clas = rb_obj_class(obj);
|
25
|
+
|
26
|
+
if (rb_cTime == clas) {
|
27
|
+
assure_size(out, 6);
|
28
|
+
APPEND_CHARS(out->cur, "{\"^t\":", 6);
|
29
|
+
dump_time(obj, out);
|
30
|
+
*out->cur++ = '}';
|
31
|
+
*out->cur = '\0';
|
32
|
+
} else {
|
33
|
+
if (oj_bigdecimal_class == clas) {
|
34
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
35
|
+
const char *str = RSTRING_PTR(rstr);
|
36
|
+
size_t len = RSTRING_LEN(rstr);
|
37
|
+
|
38
|
+
if (No != out->opts->bigdec_as_num) {
|
39
|
+
oj_dump_raw(str, len, out);
|
40
|
+
} else if (0 == strcasecmp("Infinity", str)) {
|
41
|
+
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
|
42
|
+
oj_dump_raw(str, len, out);
|
43
|
+
} else if (0 == strcasecmp("-Infinity", str)) {
|
44
|
+
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
|
45
|
+
oj_dump_raw(str, len, out);
|
46
|
+
} else {
|
47
|
+
oj_dump_cstr(str, len, 0, 0, out);
|
48
|
+
}
|
49
|
+
} else {
|
50
|
+
long id = oj_check_circular(obj, out);
|
51
|
+
|
52
|
+
if (0 <= id) {
|
53
|
+
dump_obj_attrs(obj, clas, id, depth, out);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
60
|
+
VALUE clas = rb_obj_class(obj);
|
61
|
+
|
62
|
+
if (oj_bigdecimal_class == clas) {
|
63
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
64
|
+
const char *str = RSTRING_PTR(rstr);
|
65
|
+
size_t len = RSTRING_LEN(rstr);
|
66
|
+
|
67
|
+
if (0 == strcasecmp("Infinity", str)) {
|
68
|
+
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
|
69
|
+
oj_dump_raw(str, len, out);
|
70
|
+
} else if (0 == strcasecmp("-Infinity", str)) {
|
71
|
+
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
|
72
|
+
oj_dump_raw(str, len, out);
|
73
|
+
} else {
|
74
|
+
oj_dump_raw(str, len, out);
|
75
|
+
}
|
76
|
+
} else {
|
77
|
+
long id = oj_check_circular(obj, out);
|
78
|
+
|
79
|
+
if (0 <= id) {
|
80
|
+
dump_obj_attrs(obj, clas, id, depth, out);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
static void dump_class(VALUE obj, int depth, Out out, bool as_ok) {
|
86
|
+
const char *s = rb_class2name(obj);
|
87
|
+
size_t len = strlen(s);
|
88
|
+
|
89
|
+
assure_size(out, 6);
|
90
|
+
APPEND_CHARS(out->cur, "{\"^c\":", 6);
|
91
|
+
oj_dump_cstr(s, len, 0, 0, out);
|
92
|
+
*out->cur++ = '}';
|
93
|
+
*out->cur = '\0';
|
94
|
+
}
|
95
|
+
|
96
|
+
static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
|
97
|
+
size_t size;
|
98
|
+
size_t i;
|
99
|
+
size_t cnt;
|
100
|
+
int d2 = depth + 1;
|
101
|
+
long id = oj_check_circular(a, out);
|
102
|
+
|
103
|
+
if (id < 0) {
|
104
|
+
return;
|
105
|
+
}
|
106
|
+
if (Qundef != clas && rb_cArray != clas && ObjectMode == out->opts->mode) {
|
107
|
+
dump_obj_attrs(a, clas, 0, depth, out);
|
108
|
+
return;
|
109
|
+
}
|
110
|
+
cnt = RARRAY_LEN(a);
|
111
|
+
*out->cur++ = '[';
|
112
|
+
if (0 < id) {
|
113
|
+
assure_size(out, d2 * out->indent + 16);
|
114
|
+
fill_indent(out, d2);
|
115
|
+
APPEND_CHARS(out->cur, "\"^i", 3);
|
116
|
+
dump_ulong(id, out);
|
117
|
+
*out->cur++ = '"';
|
118
|
+
}
|
119
|
+
size = 2;
|
120
|
+
assure_size(out, 2);
|
121
|
+
if (0 == cnt) {
|
122
|
+
*out->cur++ = ']';
|
123
|
+
} else {
|
124
|
+
if (0 < id) {
|
125
|
+
*out->cur++ = ',';
|
126
|
+
}
|
127
|
+
if (out->opts->dump_opts.use) {
|
128
|
+
size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
|
129
|
+
} else {
|
130
|
+
size = d2 * out->indent + 2;
|
131
|
+
}
|
132
|
+
assure_size(out, size * cnt);
|
133
|
+
cnt--;
|
134
|
+
for (i = 0; i <= cnt; i++) {
|
135
|
+
if (out->opts->dump_opts.use) {
|
136
|
+
if (0 < out->opts->dump_opts.array_size) {
|
137
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
|
138
|
+
}
|
139
|
+
if (0 < out->opts->dump_opts.indent_size) {
|
140
|
+
int i;
|
141
|
+
for (i = d2; 0 < i; i--) {
|
142
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
|
143
|
+
}
|
144
|
+
}
|
145
|
+
} else {
|
146
|
+
fill_indent(out, d2);
|
147
|
+
}
|
148
|
+
oj_dump_obj_val(RARRAY_AREF(a, i), d2, out);
|
149
|
+
if (i < cnt) {
|
150
|
+
*out->cur++ = ',';
|
151
|
+
}
|
152
|
+
}
|
153
|
+
size = depth * out->indent + 1;
|
154
|
+
assure_size(out, size);
|
155
|
+
if (out->opts->dump_opts.use) {
|
156
|
+
// printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size,
|
157
|
+
// out->opts->dump_opts->indent);
|
158
|
+
if (0 < out->opts->dump_opts.array_size) {
|
159
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
|
160
|
+
}
|
161
|
+
if (0 < out->opts->dump_opts.indent_size) {
|
162
|
+
int i;
|
163
|
+
|
164
|
+
for (i = depth; 0 < i; i--) {
|
165
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
|
166
|
+
}
|
167
|
+
}
|
168
|
+
} else {
|
169
|
+
fill_indent(out, depth);
|
170
|
+
}
|
171
|
+
*out->cur++ = ']';
|
172
|
+
}
|
173
|
+
*out->cur = '\0';
|
174
|
+
}
|
175
|
+
|
176
|
+
static void dump_array(VALUE obj, int depth, Out out, bool as_ok) {
|
177
|
+
dump_array_class(obj, rb_obj_class(obj), depth, out);
|
178
|
+
}
|
179
|
+
|
180
|
+
static void dump_str_class(VALUE obj, VALUE clas, int depth, Out out) {
|
181
|
+
if (Qundef != clas && rb_cString != clas) {
|
182
|
+
dump_obj_attrs(obj, clas, 0, depth, out);
|
183
|
+
} else {
|
184
|
+
const char *s = RSTRING_PTR(obj);
|
185
|
+
size_t len = RSTRING_LEN(obj);
|
186
|
+
char s1 = s[1];
|
187
|
+
|
188
|
+
oj_dump_cstr(s, len, 0, (':' == *s || ('^' == *s && ('r' == s1 || 'i' == s1))), out);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
static void dump_str(VALUE obj, int depth, Out out, bool as_ok) {
|
193
|
+
dump_str_class(obj, rb_obj_class(obj), depth, out);
|
194
|
+
}
|
195
|
+
|
196
|
+
static void dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
|
197
|
+
volatile VALUE s = rb_sym2str(obj);
|
198
|
+
|
199
|
+
oj_dump_cstr(RSTRING_PTR(s), RSTRING_LEN(s), 1, 0, out);
|
200
|
+
}
|
201
|
+
|
202
|
+
static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
203
|
+
Out out = (Out)ov;
|
204
|
+
int depth = out->depth;
|
205
|
+
long size = depth * out->indent + 1;
|
206
|
+
|
207
|
+
if (dump_ignore(out->opts, value)) {
|
208
|
+
return ST_CONTINUE;
|
209
|
+
}
|
210
|
+
if (out->omit_nil && Qnil == value) {
|
211
|
+
return ST_CONTINUE;
|
212
|
+
}
|
213
|
+
assure_size(out, size);
|
214
|
+
fill_indent(out, depth);
|
215
|
+
switch (rb_type(key)) {
|
216
|
+
case T_STRING:
|
217
|
+
dump_str_class(key, Qundef, depth, out);
|
218
|
+
*out->cur++ = ':';
|
219
|
+
oj_dump_obj_val(value, depth, out);
|
220
|
+
break;
|
221
|
+
|
222
|
+
case T_SYMBOL:
|
223
|
+
dump_sym(key, 0, out, false);
|
224
|
+
*out->cur++ = ':';
|
225
|
+
oj_dump_obj_val(value, depth, out);
|
226
|
+
break;
|
227
|
+
|
228
|
+
default: {
|
229
|
+
int d2 = depth + 1;
|
230
|
+
long s2 = size + out->indent + 1;
|
231
|
+
int i;
|
232
|
+
int started = 0;
|
233
|
+
uint8_t b;
|
234
|
+
|
235
|
+
assure_size(out, s2 + 15);
|
236
|
+
APPEND_CHARS(out->cur, "\"^#", 3);
|
237
|
+
out->hash_cnt++;
|
238
|
+
for (i = 28; 0 <= i; i -= 4) {
|
239
|
+
b = (uint8_t)((out->hash_cnt >> i) & 0x0000000F);
|
240
|
+
if ('\0' != b) {
|
241
|
+
started = 1;
|
242
|
+
}
|
243
|
+
if (started) {
|
244
|
+
*out->cur++ = hex_chars[b];
|
245
|
+
}
|
246
|
+
}
|
247
|
+
APPEND_CHARS(out->cur, "\":[", 3);
|
248
|
+
fill_indent(out, d2);
|
249
|
+
oj_dump_obj_val(key, d2, out);
|
250
|
+
assure_size(out, s2);
|
251
|
+
*out->cur++ = ',';
|
252
|
+
fill_indent(out, d2);
|
253
|
+
oj_dump_obj_val(value, d2, out);
|
254
|
+
assure_size(out, size);
|
255
|
+
fill_indent(out, depth);
|
256
|
+
*out->cur++ = ']';
|
257
|
+
}
|
258
|
+
}
|
259
|
+
out->depth = depth;
|
260
|
+
*out->cur++ = ',';
|
261
|
+
|
262
|
+
return ST_CONTINUE;
|
263
|
+
}
|
264
|
+
|
265
|
+
static void dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
|
266
|
+
int cnt;
|
267
|
+
size_t size;
|
268
|
+
|
269
|
+
if (Qundef != clas && rb_cHash != clas) {
|
270
|
+
dump_obj_attrs(obj, clas, 0, depth, out);
|
271
|
+
return;
|
272
|
+
}
|
273
|
+
cnt = (int)RHASH_SIZE(obj);
|
274
|
+
size = depth * out->indent + 2;
|
275
|
+
assure_size(out, 2);
|
276
|
+
if (0 == cnt) {
|
277
|
+
APPEND_CHARS(out->cur, "{}", 2);
|
278
|
+
} else {
|
279
|
+
long id = oj_check_circular(obj, out);
|
280
|
+
|
281
|
+
if (0 > id) {
|
282
|
+
return;
|
283
|
+
}
|
284
|
+
*out->cur++ = '{';
|
285
|
+
if (0 < id) {
|
286
|
+
assure_size(out, size + 16);
|
287
|
+
fill_indent(out, depth + 1);
|
288
|
+
APPEND_CHARS(out->cur, "\"^i\":", 5);
|
289
|
+
dump_ulong(id, out);
|
290
|
+
*out->cur++ = ',';
|
291
|
+
}
|
292
|
+
out->depth = depth + 1;
|
293
|
+
rb_hash_foreach(obj, hash_cb, (VALUE)out);
|
294
|
+
if (',' == *(out->cur - 1)) {
|
295
|
+
out->cur--; // backup to overwrite last comma
|
296
|
+
}
|
297
|
+
if (!out->opts->dump_opts.use) {
|
298
|
+
assure_size(out, size);
|
299
|
+
fill_indent(out, depth);
|
300
|
+
} else {
|
301
|
+
size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
|
302
|
+
assure_size(out, size);
|
303
|
+
if (0 < out->opts->dump_opts.hash_size) {
|
304
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
|
305
|
+
}
|
306
|
+
if (0 < out->opts->dump_opts.indent_size) {
|
307
|
+
int i;
|
308
|
+
|
309
|
+
for (i = depth; 0 < i; i--) {
|
310
|
+
APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
|
311
|
+
}
|
312
|
+
}
|
313
|
+
}
|
314
|
+
*out->cur++ = '}';
|
315
|
+
}
|
316
|
+
*out->cur = '\0';
|
317
|
+
}
|
318
|
+
|
319
|
+
static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
|
320
|
+
Out out = (Out)ov;
|
321
|
+
int depth = out->depth;
|
322
|
+
size_t size = depth * out->indent + 1;
|
323
|
+
const char *attr = rb_id2name(key);
|
324
|
+
|
325
|
+
if (dump_ignore(out->opts, value)) {
|
326
|
+
return ST_CONTINUE;
|
327
|
+
}
|
328
|
+
if (out->omit_nil && Qnil == value) {
|
329
|
+
return ST_CONTINUE;
|
330
|
+
}
|
331
|
+
// Some exceptions such as NoMethodError have an invisible attribute where
|
332
|
+
// the key name is NULL. Not an empty string but NULL.
|
333
|
+
if (NULL == attr) {
|
334
|
+
attr = "";
|
335
|
+
} else if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) {
|
336
|
+
return ST_CONTINUE;
|
337
|
+
}
|
338
|
+
if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) {
|
339
|
+
return ST_CONTINUE;
|
340
|
+
}
|
341
|
+
assure_size(out, size);
|
342
|
+
fill_indent(out, depth);
|
343
|
+
if ('@' == *attr) {
|
344
|
+
attr++;
|
345
|
+
oj_dump_cstr(attr, strlen(attr), 0, 0, out);
|
346
|
+
} else {
|
347
|
+
char buf[32];
|
348
|
+
|
349
|
+
*buf = '~';
|
350
|
+
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
351
|
+
buf[sizeof(buf) - 1] = '\0';
|
352
|
+
oj_dump_cstr(buf, strlen(buf), 0, 0, out);
|
353
|
+
}
|
354
|
+
*out->cur++ = ':';
|
355
|
+
oj_dump_obj_val(value, depth, out);
|
356
|
+
out->depth = depth;
|
357
|
+
*out->cur++ = ',';
|
358
|
+
|
359
|
+
return ST_CONTINUE;
|
360
|
+
}
|
361
|
+
|
362
|
+
static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
363
|
+
dump_hash_class(obj, rb_obj_class(obj), depth, out);
|
364
|
+
}
|
365
|
+
|
366
|
+
static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
367
|
+
ID *idp;
|
368
|
+
AttrGetFunc *fp;
|
369
|
+
volatile VALUE v;
|
370
|
+
const char *name;
|
371
|
+
size_t size;
|
372
|
+
int d2 = depth + 1;
|
373
|
+
|
374
|
+
assure_size(out, 2);
|
375
|
+
*out->cur++ = '{';
|
376
|
+
if (Qundef != clas) {
|
377
|
+
const char *class_name = rb_class2name(clas);
|
378
|
+
int clen = (int)strlen(class_name);
|
379
|
+
|
380
|
+
size = d2 * out->indent + clen + 10;
|
381
|
+
assure_size(out, size);
|
382
|
+
fill_indent(out, d2);
|
383
|
+
APPEND_CHARS(out->cur, "\"^O\":", 5);
|
384
|
+
oj_dump_cstr(class_name, clen, 0, 0, out);
|
385
|
+
*out->cur++ = ',';
|
386
|
+
}
|
387
|
+
if (odd->raw) {
|
388
|
+
v = rb_funcall(obj, *odd->attrs, 0);
|
389
|
+
if (Qundef == v || T_STRING != rb_type(v)) {
|
390
|
+
rb_raise(rb_eEncodingError, "Invalid type for raw JSON.");
|
391
|
+
} else {
|
392
|
+
const char *s = RSTRING_PTR(v);
|
393
|
+
size_t len = RSTRING_LEN(v);
|
394
|
+
const char *name = rb_id2name(*odd->attrs);
|
395
|
+
size_t nlen = strlen(name);
|
396
|
+
|
397
|
+
size = len + d2 * out->indent + nlen + 10;
|
398
|
+
assure_size(out, size);
|
399
|
+
fill_indent(out, d2);
|
400
|
+
*out->cur++ = '"';
|
401
|
+
APPEND_CHARS(out->cur, name, nlen);
|
402
|
+
APPEND_CHARS(out->cur, "\":", 2);
|
403
|
+
APPEND_CHARS(out->cur, s, len);
|
404
|
+
*out->cur = '\0';
|
405
|
+
}
|
406
|
+
} else {
|
407
|
+
size = d2 * out->indent + 1;
|
408
|
+
for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) {
|
409
|
+
size_t nlen;
|
410
|
+
|
411
|
+
assure_size(out, size);
|
412
|
+
name = rb_id2name(*idp);
|
413
|
+
nlen = strlen(name);
|
414
|
+
if (NULL != *fp) {
|
415
|
+
v = (*fp)(obj);
|
416
|
+
} else if (0 == strchr(name, '.')) {
|
417
|
+
v = rb_funcall(obj, *idp, 0);
|
418
|
+
} else {
|
419
|
+
char nbuf[256];
|
420
|
+
char *n2 = nbuf;
|
421
|
+
char *n;
|
422
|
+
char *end;
|
423
|
+
ID i;
|
424
|
+
|
425
|
+
if (sizeof(nbuf) <= nlen) {
|
426
|
+
if (NULL == (n2 = OJ_STRDUP(name))) {
|
427
|
+
rb_raise(rb_eNoMemError, "for attribute name.");
|
428
|
+
}
|
429
|
+
} else {
|
430
|
+
strcpy(n2, name);
|
431
|
+
}
|
432
|
+
n = n2;
|
433
|
+
v = obj;
|
434
|
+
while (0 != (end = strchr(n, '.'))) {
|
435
|
+
*end = '\0';
|
436
|
+
i = rb_intern(n);
|
437
|
+
v = rb_funcall(v, i, 0);
|
438
|
+
n = end + 1;
|
439
|
+
}
|
440
|
+
i = rb_intern(n);
|
441
|
+
v = rb_funcall(v, i, 0);
|
442
|
+
if (nbuf != n2) {
|
443
|
+
OJ_FREE(n2);
|
444
|
+
}
|
445
|
+
}
|
446
|
+
fill_indent(out, d2);
|
447
|
+
oj_dump_cstr(name, nlen, 0, 0, out);
|
448
|
+
*out->cur++ = ':';
|
449
|
+
oj_dump_obj_val(v, d2, out);
|
450
|
+
assure_size(out, 2);
|
451
|
+
*out->cur++ = ',';
|
452
|
+
}
|
453
|
+
out->cur--;
|
454
|
+
}
|
455
|
+
*out->cur++ = '}';
|
456
|
+
*out->cur = '\0';
|
457
|
+
}
|
458
|
+
|
459
|
+
static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
|
460
|
+
size_t size = 0;
|
461
|
+
int d2 = depth + 1;
|
462
|
+
int type = rb_type(obj);
|
463
|
+
Odd odd;
|
464
|
+
|
465
|
+
if (0 != (odd = oj_get_odd(clas))) {
|
466
|
+
dump_odd(obj, odd, clas, depth + 1, out);
|
467
|
+
return;
|
468
|
+
}
|
469
|
+
assure_size(out, 2);
|
470
|
+
*out->cur++ = '{';
|
471
|
+
if (Qundef != clas) {
|
472
|
+
const char *class_name = rb_class2name(clas);
|
473
|
+
int clen = (int)strlen(class_name);
|
474
|
+
|
475
|
+
assure_size(out, d2 * out->indent + clen + 10);
|
476
|
+
fill_indent(out, d2);
|
477
|
+
APPEND_CHARS(out->cur, "\"^o\":", 5);
|
478
|
+
oj_dump_cstr(class_name, clen, 0, 0, out);
|
479
|
+
}
|
480
|
+
if (0 < id) {
|
481
|
+
assure_size(out, d2 * out->indent + 16);
|
482
|
+
*out->cur++ = ',';
|
483
|
+
fill_indent(out, d2);
|
484
|
+
APPEND_CHARS(out->cur, "\"^i\":", 5);
|
485
|
+
dump_ulong(id, out);
|
486
|
+
}
|
487
|
+
switch (type) {
|
488
|
+
case T_STRING:
|
489
|
+
assure_size(out, d2 * out->indent + 14);
|
490
|
+
*out->cur++ = ',';
|
491
|
+
fill_indent(out, d2);
|
492
|
+
APPEND_CHARS(out->cur, "\"self\":", 7);
|
493
|
+
oj_dump_cstr(RSTRING_PTR(obj), RSTRING_LEN(obj), 0, 0, out);
|
494
|
+
break;
|
495
|
+
case T_ARRAY:
|
496
|
+
assure_size(out, d2 * out->indent + 14);
|
497
|
+
*out->cur++ = ',';
|
498
|
+
fill_indent(out, d2);
|
499
|
+
APPEND_CHARS(out->cur, "\"self\":", 7);
|
500
|
+
dump_array_class(obj, Qundef, depth + 1, out);
|
501
|
+
break;
|
502
|
+
case T_HASH:
|
503
|
+
assure_size(out, d2 * out->indent + 14);
|
504
|
+
*out->cur++ = ',';
|
505
|
+
fill_indent(out, d2);
|
506
|
+
APPEND_CHARS(out->cur, "\"self\":", 7);
|
507
|
+
dump_hash_class(obj, Qundef, depth + 1, out);
|
508
|
+
break;
|
509
|
+
default: break;
|
510
|
+
}
|
511
|
+
{
|
512
|
+
int cnt = (int)rb_ivar_count(obj);
|
513
|
+
|
514
|
+
if (Qundef != clas && 0 < cnt) {
|
515
|
+
*out->cur++ = ',';
|
516
|
+
}
|
517
|
+
if (0 == cnt && Qundef == clas) {
|
518
|
+
// Might be something special like an Enumerable.
|
519
|
+
if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) {
|
520
|
+
out->cur--;
|
521
|
+
oj_dump_obj_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out);
|
522
|
+
return;
|
523
|
+
}
|
524
|
+
}
|
525
|
+
out->depth = depth + 1;
|
526
|
+
rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
|
527
|
+
if (',' == *(out->cur - 1)) {
|
528
|
+
out->cur--; // backup to overwrite last comma
|
529
|
+
}
|
530
|
+
if (rb_obj_is_kind_of(obj, rb_eException)) {
|
531
|
+
volatile VALUE rv;
|
532
|
+
|
533
|
+
if (',' != *(out->cur - 1)) {
|
534
|
+
*out->cur++ = ',';
|
535
|
+
}
|
536
|
+
// message
|
537
|
+
assure_size(out, size);
|
538
|
+
fill_indent(out, d2);
|
539
|
+
oj_dump_cstr("~mesg", 5, 0, 0, out);
|
540
|
+
*out->cur++ = ':';
|
541
|
+
rv = rb_funcall2(obj, rb_intern("message"), 0, 0);
|
542
|
+
oj_dump_obj_val(rv, d2, out);
|
543
|
+
assure_size(out, 2);
|
544
|
+
*out->cur++ = ',';
|
545
|
+
// backtrace
|
546
|
+
assure_size(out, size);
|
547
|
+
fill_indent(out, d2);
|
548
|
+
oj_dump_cstr("~bt", 3, 0, 0, out);
|
549
|
+
*out->cur++ = ':';
|
550
|
+
rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0);
|
551
|
+
oj_dump_obj_val(rv, d2, out);
|
552
|
+
assure_size(out, 2);
|
553
|
+
}
|
554
|
+
out->depth = depth;
|
555
|
+
}
|
556
|
+
fill_indent(out, depth);
|
557
|
+
*out->cur++ = '}';
|
558
|
+
*out->cur = '\0';
|
559
|
+
}
|
560
|
+
|
561
|
+
static void dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
|
562
|
+
dump_obj_attrs(obj, rb_obj_class(obj), 0, depth, out);
|
563
|
+
}
|
564
|
+
|
565
|
+
static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
566
|
+
VALUE clas = rb_obj_class(obj);
|
567
|
+
const char *class_name = rb_class2name(clas);
|
568
|
+
size_t i;
|
569
|
+
int d2 = depth + 1;
|
570
|
+
int d3 = d2 + 1;
|
571
|
+
size_t len = strlen(class_name);
|
572
|
+
size_t size = d2 * out->indent + d3 * out->indent + 10 + len;
|
573
|
+
char circular = out->opts->circular;
|
574
|
+
|
575
|
+
assure_size(out, size);
|
576
|
+
*out->cur++ = '{';
|
577
|
+
fill_indent(out, d2);
|
578
|
+
APPEND_CHARS(out->cur, "\"^u\":[", 6);
|
579
|
+
if ('#' == *class_name) {
|
580
|
+
VALUE ma = rb_struct_s_members(clas);
|
581
|
+
const char *name;
|
582
|
+
size_t cnt = RARRAY_LEN(ma);
|
583
|
+
|
584
|
+
*out->cur++ = '[';
|
585
|
+
for (i = 0; i < cnt; i++) {
|
586
|
+
volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
|
587
|
+
|
588
|
+
name = RSTRING_PTR(s);
|
589
|
+
len = RSTRING_LEN(s);
|
590
|
+
size = len + 3;
|
591
|
+
assure_size(out, size);
|
592
|
+
if (0 < i) {
|
593
|
+
*out->cur++ = ',';
|
594
|
+
}
|
595
|
+
*out->cur++ = '"';
|
596
|
+
APPEND_CHARS(out->cur, name, len);
|
597
|
+
*out->cur++ = '"';
|
598
|
+
}
|
599
|
+
*out->cur++ = ']';
|
600
|
+
} else {
|
601
|
+
fill_indent(out, d3);
|
602
|
+
*out->cur++ = '"';
|
603
|
+
APPEND_CHARS(out->cur, class_name, len);
|
604
|
+
*out->cur++ = '"';
|
605
|
+
}
|
606
|
+
*out->cur++ = ',';
|
607
|
+
size = d3 * out->indent + 2;
|
608
|
+
#ifdef RSTRUCT_LEN
|
609
|
+
{
|
610
|
+
VALUE v;
|
611
|
+
int cnt;
|
612
|
+
|
613
|
+
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
614
|
+
cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
|
615
|
+
#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
616
|
+
cnt = (int)RSTRUCT_LEN(obj);
|
617
|
+
#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
618
|
+
|
619
|
+
if (0 == strcmp(class_name, "Range")) {
|
620
|
+
out->opts->circular = 'n';
|
621
|
+
}
|
622
|
+
for (i = 0; i < (size_t)cnt; i++) {
|
623
|
+
v = RSTRUCT_GET(obj, (int)i);
|
624
|
+
if (dump_ignore(out->opts, v)) {
|
625
|
+
v = Qnil;
|
626
|
+
}
|
627
|
+
assure_size(out, size);
|
628
|
+
fill_indent(out, d3);
|
629
|
+
oj_dump_obj_val(v, d3, out);
|
630
|
+
*out->cur++ = ',';
|
631
|
+
}
|
632
|
+
}
|
633
|
+
#else
|
634
|
+
{
|
635
|
+
// This is a bit risky as a struct in C ruby is not the same as a Struct
|
636
|
+
// class in interpreted Ruby so length() may not be defined.
|
637
|
+
int slen = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
|
638
|
+
|
639
|
+
if (0 == strcmp(class_name, "Range")) {
|
640
|
+
out->opts->circular = 'n';
|
641
|
+
}
|
642
|
+
for (i = 0; i < slen; i++) {
|
643
|
+
assure_size(out, size);
|
644
|
+
fill_indent(out, d3);
|
645
|
+
if (dump_ignore(out->opts, v)) {
|
646
|
+
v = Qnil;
|
647
|
+
}
|
648
|
+
oj_dump_obj_val(rb_struct_aref(obj, INT2FIX(i)), d3, out, 0, 0, true);
|
649
|
+
*out->cur++ = ',';
|
650
|
+
}
|
651
|
+
}
|
652
|
+
#endif
|
653
|
+
out->opts->circular = circular;
|
654
|
+
out->cur--;
|
655
|
+
APPEND_CHARS(out->cur, "]}", 2);
|
656
|
+
*out->cur = '\0';
|
657
|
+
}
|
658
|
+
|
659
|
+
static void dump_complex(VALUE obj, int depth, Out out, bool as_ok) {
|
660
|
+
dump_obj_attrs(obj, rb_obj_class(obj), 0, depth, out);
|
661
|
+
}
|
662
|
+
|
663
|
+
static void dump_rational(VALUE obj, int depth, Out out, bool as_ok) {
|
664
|
+
dump_obj_attrs(obj, rb_obj_class(obj), 0, depth, out);
|
665
|
+
}
|
666
|
+
|
667
|
+
static DumpFunc obj_funcs[] = {
|
668
|
+
NULL, // RUBY_T_NONE = 0x00,
|
669
|
+
dump_obj, // RUBY_T_OBJECT = 0x01,
|
670
|
+
dump_class, // RUBY_T_CLASS = 0x02,
|
671
|
+
dump_class, // RUBY_T_MODULE = 0x03,
|
672
|
+
oj_dump_float, // RUBY_T_FLOAT = 0x04,
|
673
|
+
dump_str, // RUBY_T_STRING = 0x05,
|
674
|
+
dump_regexp, // RUBY_T_REGEXP = 0x06,
|
675
|
+
dump_array, // RUBY_T_ARRAY = 0x07,
|
676
|
+
dump_hash, // RUBY_T_HASH = 0x08,
|
677
|
+
dump_struct, // RUBY_T_STRUCT = 0x09,
|
678
|
+
oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
|
679
|
+
NULL, // RUBY_T_FILE = 0x0b,
|
680
|
+
dump_data, // RUBY_T_DATA = 0x0c,
|
681
|
+
NULL, // RUBY_T_MATCH = 0x0d,
|
682
|
+
dump_complex, // RUBY_T_COMPLEX = 0x0e,
|
683
|
+
dump_rational, // RUBY_T_RATIONAL = 0x0f,
|
684
|
+
NULL, // 0x10
|
685
|
+
oj_dump_nil, // RUBY_T_NIL = 0x11,
|
686
|
+
oj_dump_true, // RUBY_T_TRUE = 0x12,
|
687
|
+
oj_dump_false, // RUBY_T_FALSE = 0x13,
|
688
|
+
dump_sym, // RUBY_T_SYMBOL = 0x14,
|
689
|
+
oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
|
690
|
+
};
|
691
|
+
|
692
|
+
void oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
693
|
+
int type = rb_type(obj);
|
694
|
+
|
695
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
|
696
|
+
if (MAX_DEPTH < depth) {
|
697
|
+
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
698
|
+
}
|
699
|
+
if (0 < type && type <= RUBY_T_FIXNUM) {
|
700
|
+
DumpFunc f = obj_funcs[type];
|
701
|
+
|
702
|
+
if (NULL != f) {
|
703
|
+
f(obj, depth, out, false);
|
704
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
|
705
|
+
return;
|
706
|
+
}
|
707
|
+
}
|
708
|
+
oj_dump_nil(Qnil, depth, out, false);
|
709
|
+
TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
|
710
|
+
}
|