oj 2.18.5 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +33 -226
- data/ext/oj/circarray.c +0 -25
- data/ext/oj/circarray.h +0 -25
- data/ext/oj/code.c +227 -0
- data/ext/oj/code.h +40 -0
- data/ext/oj/compat.c +126 -38
- data/ext/oj/custom.c +1097 -0
- data/ext/oj/dump.c +658 -2376
- data/ext/oj/dump.h +92 -0
- data/ext/oj/dump_compat.c +937 -0
- data/ext/oj/dump_leaf.c +254 -0
- data/ext/oj/dump_object.c +810 -0
- data/ext/oj/dump_rails.c +329 -0
- data/ext/oj/dump_strict.c +416 -0
- data/ext/oj/err.c +0 -25
- data/ext/oj/err.h +8 -2
- data/ext/oj/fast.c +24 -24
- data/ext/oj/mimic_json.c +817 -0
- data/ext/oj/mimic_rails.c +806 -0
- data/ext/oj/mimic_rails.h +17 -0
- data/ext/oj/object.c +18 -72
- data/ext/oj/odd.c +0 -25
- data/ext/oj/odd.h +2 -27
- data/ext/oj/oj.c +655 -1503
- data/ext/oj/oj.h +93 -40
- data/ext/oj/parse.c +99 -46
- data/ext/oj/parse.h +12 -26
- data/ext/oj/reader.c +1 -25
- data/ext/oj/reader.h +3 -25
- data/ext/oj/resolve.c +9 -11
- data/ext/oj/resolve.h +2 -2
- data/ext/oj/rxclass.c +133 -0
- data/ext/oj/rxclass.h +27 -0
- data/ext/oj/saj.c +4 -25
- data/ext/oj/scp.c +3 -25
- data/ext/oj/sparse.c +89 -13
- data/ext/oj/stream_writer.c +301 -0
- data/ext/oj/strict.c +4 -27
- data/ext/oj/string_writer.c +480 -0
- data/ext/oj/val_stack.h +6 -2
- data/lib/oj.rb +1 -23
- data/lib/oj/easy_hash.rb +12 -4
- data/lib/oj/json.rb +172 -0
- data/lib/oj/mimic.rb +123 -18
- data/lib/oj/state.rb +131 -0
- data/lib/oj/version.rb +1 -1
- 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/JsonGem.md +79 -0
- data/pages/Modes.md +140 -0
- data/pages/Options.md +250 -0
- data/pages/Rails.md +60 -0
- data/pages/Security.md +20 -0
- data/test/activesupport4/decoding_test.rb +105 -0
- data/test/activesupport4/encoding_test.rb +531 -0
- data/test/activesupport4/test_helper.rb +41 -0
- data/test/activesupport5/decoding_test.rb +125 -0
- data/test/activesupport5/encoding_test.rb +483 -0
- data/test/activesupport5/encoding_test_cases.rb +90 -0
- data/test/activesupport5/test_helper.rb +50 -0
- data/test/activesupport5/time_zone_test_helpers.rb +24 -0
- data/test/json_gem/json_addition_test.rb +216 -0
- data/test/json_gem/json_common_interface_test.rb +143 -0
- data/test/json_gem/json_encoding_test.rb +109 -0
- data/test/json_gem/json_ext_parser_test.rb +20 -0
- data/test/json_gem/json_fixtures_test.rb +35 -0
- data/test/json_gem/json_generator_test.rb +383 -0
- data/test/json_gem/json_generic_object_test.rb +90 -0
- data/test/json_gem/json_parser_test.rb +470 -0
- data/test/json_gem/json_string_matching_test.rb +42 -0
- data/test/json_gem/test_helper.rb +18 -0
- data/test/perf_compat.rb +30 -28
- data/test/perf_object.rb +1 -1
- data/test/perf_strict.rb +18 -1
- data/test/sample.rb +0 -1
- data/test/test_compat.rb +169 -93
- data/test/test_custom.rb +355 -0
- data/test/test_file.rb +0 -8
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +268 -3
- data/test/test_scp.rb +22 -1
- data/test/test_strict.rb +160 -4
- data/test/test_various.rb +52 -620
- data/test/tests.rb +14 -0
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- metadata +89 -47
- 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/foo.rb +0 -24
- data/test/io.rb +0 -48
- data/test/isolated/test_mimic_rails_datetime.rb +0 -27
- data/test/mod.rb +0 -16
- data/test/rails.rb +0 -50
- data/test/russian.rb +0 -18
- data/test/struct.rb +0 -29
- data/test/test_serializer.rb +0 -59
- data/test/write_timebars.rb +0 -31
data/ext/oj/dump.c
CHANGED
@@ -1,31 +1,6 @@
|
|
1
1
|
/* dump.c
|
2
|
-
* Copyright (c) 2012, Peter Ohler
|
2
|
+
* Copyright (c) 2012, 2017, Peter Ohler
|
3
3
|
* All rights reserved.
|
4
|
-
*
|
5
|
-
* Redistribution and use in source and binary forms, with or without
|
6
|
-
* modification, are permitted provided that the following conditions are met:
|
7
|
-
*
|
8
|
-
* - Redistributions of source code must retain the above copyright notice, this
|
9
|
-
* list of conditions and the following disclaimer.
|
10
|
-
*
|
11
|
-
* - Redistributions in binary form must reproduce the above copyright notice,
|
12
|
-
* this list of conditions and the following disclaimer in the documentation
|
13
|
-
* and/or other materials provided with the distribution.
|
14
|
-
*
|
15
|
-
* - Neither the name of Peter Ohler nor the names of its contributors may be
|
16
|
-
* used to endorse or promote products derived from this software without
|
17
|
-
* specific prior written permission.
|
18
|
-
*
|
19
|
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
22
|
-
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
23
|
-
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
24
|
-
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
25
|
-
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
26
|
-
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
27
|
-
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
-
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
4
|
*/
|
30
5
|
|
31
6
|
#include <stdlib.h>
|
@@ -42,73 +17,24 @@
|
|
42
17
|
|
43
18
|
#include "oj.h"
|
44
19
|
#include "cache8.h"
|
20
|
+
#include "dump.h"
|
45
21
|
#include "odd.h"
|
46
22
|
|
47
|
-
#if !HAS_ENCODING_SUPPORT || defined(RUBINIUS_RUBY)
|
48
|
-
#define rb_eEncodingError rb_eException
|
49
|
-
#endif
|
50
|
-
|
51
23
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
52
24
|
#define OJ_INFINITY (1.0/0.0)
|
53
25
|
|
54
|
-
// Extra padding at end of buffer.
|
55
|
-
#define BUFFER_EXTRA 10
|
56
|
-
|
57
26
|
#define MAX_DEPTH 1000
|
58
27
|
|
59
|
-
|
28
|
+
static const char inf_val[] = INF_VAL;
|
29
|
+
static const char ninf_val[] = NINF_VAL;
|
30
|
+
static const char nan_val[] = NAN_VAL;
|
60
31
|
|
61
|
-
|
62
|
-
static void dump_val(VALUE obj, int depth, Out out, int argc, VALUE *argv, bool as_ok);
|
63
|
-
static void dump_nil(Out out);
|
64
|
-
static void dump_true(Out out);
|
65
|
-
static void dump_false(Out out);
|
66
|
-
static void dump_fixnum(VALUE obj, Out out);
|
67
|
-
static void dump_bignum(VALUE obj, Out out);
|
68
|
-
static void dump_float(VALUE obj, Out out);
|
69
|
-
static void dump_raw(const char *str, size_t cnt, Out out);
|
70
|
-
static void dump_cstr(const char *str, size_t cnt, int is_sym, int escape1, Out out);
|
71
|
-
static void dump_hex(uint8_t c, Out out);
|
72
|
-
static void dump_str_comp(VALUE obj, Out out);
|
73
|
-
static void dump_str_obj(VALUE obj, VALUE clas, int depth, Out out);
|
74
|
-
static void dump_sym_comp(VALUE obj, Out out);
|
75
|
-
static void dump_sym_obj(VALUE obj, Out out);
|
76
|
-
static void dump_class_comp(VALUE obj, Out out);
|
77
|
-
static void dump_class_obj(VALUE obj, Out out);
|
78
|
-
static void dump_array(VALUE obj, VALUE clas, int depth, Out out);
|
79
|
-
static int hash_cb_strict(VALUE key, VALUE value, Out out);
|
80
|
-
static int hash_cb_compat(VALUE key, VALUE value, Out out);
|
81
|
-
static int hash_cb_object(VALUE key, VALUE value, Out out);
|
82
|
-
static void dump_hash(VALUE obj, VALUE clas, int depth, int mode, Out out);
|
83
|
-
static void dump_time(VALUE obj, Out out, int withZone);
|
84
|
-
static void dump_ruby_time(VALUE obj, Out out);
|
85
|
-
static void dump_xml_time(VALUE obj, Out out);
|
86
|
-
static void dump_data_strict(VALUE obj, Out out);
|
87
|
-
static void dump_data_null(VALUE obj, Out out);
|
88
|
-
static void dump_data_comp(VALUE obj, int depth, Out out, int argc, VALUE *argv, bool as_ok);
|
89
|
-
static void dump_data_obj(VALUE obj, int depth, Out out);
|
90
|
-
static void dump_obj_comp(VALUE obj, int depth, Out out, int argc, VALUE *argv, bool as_ok);
|
91
|
-
static void dump_obj_obj(VALUE obj, int depth, Out out);
|
92
|
-
static void dump_struct_comp(VALUE obj, int depth, Out out, int argc, VALUE *argv, bool as_ok);
|
93
|
-
static void dump_struct_obj(VALUE obj, int depth, Out out);
|
94
|
-
#if HAS_IVAR_HELPERS
|
95
|
-
static int dump_attr_cb(ID key, VALUE value, Out out);
|
96
|
-
#endif
|
97
|
-
static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out);
|
98
|
-
static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out);
|
32
|
+
typedef unsigned long ulong;
|
99
33
|
|
100
|
-
static void grow(Out out, size_t len);
|
101
34
|
static size_t hibit_friendly_size(const uint8_t *str, size_t len);
|
102
35
|
static size_t xss_friendly_size(const uint8_t *str, size_t len);
|
103
36
|
static size_t ascii_friendly_size(const uint8_t *str, size_t len);
|
104
37
|
|
105
|
-
static void dump_leaf(Leaf leaf, int depth, Out out);
|
106
|
-
static void dump_leaf_str(Leaf leaf, Out out);
|
107
|
-
static void dump_leaf_fixnum(Leaf leaf, Out out);
|
108
|
-
static void dump_leaf_float(Leaf leaf, Out out);
|
109
|
-
static void dump_leaf_array(Leaf leaf, int depth, Out out);
|
110
|
-
static void dump_leaf_hash(Leaf leaf, int depth, Out out);
|
111
|
-
|
112
38
|
static const char hex_chars[17] = "0123456789abcdef";
|
113
39
|
|
114
40
|
// JSON standard except newlines are no escaped
|
@@ -156,11 +82,39 @@ static char xss_friendly_chars[256] = "\
|
|
156
82
|
33333333333333333333333333333333\
|
157
83
|
33333333333333333333333333333333";
|
158
84
|
|
85
|
+
// JSON XSS combo
|
86
|
+
static char hixss_friendly_chars[256] = "\
|
87
|
+
66666666222622666666666666666666\
|
88
|
+
11211161111111111111111111116161\
|
89
|
+
11111111111111111111111111112111\
|
90
|
+
11111111111111111111111111111111\
|
91
|
+
11111111111111111111111111111111\
|
92
|
+
11111111111111111111111111111111\
|
93
|
+
11111111111111111111111111111111\
|
94
|
+
11311111111111111111111111111111";
|
95
|
+
|
96
|
+
// Rails HTML non-escape
|
97
|
+
static char rails_friendly_chars[256] = "\
|
98
|
+
66666666222622666666666666666666\
|
99
|
+
11211111111111111111111111111111\
|
100
|
+
11111111111111111111111111112111\
|
101
|
+
11111111111111111111111111111111\
|
102
|
+
11111111111111111111111111111111\
|
103
|
+
11111111111111111111111111111111\
|
104
|
+
11111111111111111111111111111111\
|
105
|
+
11311111111111111111111111111111";
|
106
|
+
|
107
|
+
static void
|
108
|
+
raise_strict(VALUE obj) {
|
109
|
+
rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in strict mode.", rb_class2name(rb_obj_class(obj)));
|
110
|
+
}
|
111
|
+
|
159
112
|
inline static size_t
|
160
113
|
newline_friendly_size(const uint8_t *str, size_t len) {
|
161
114
|
size_t size = 0;
|
115
|
+
size_t i = len;
|
162
116
|
|
163
|
-
for (; 0 <
|
117
|
+
for (; 0 < i; str++, i--) {
|
164
118
|
size += newline_friendly_chars[*str];
|
165
119
|
}
|
166
120
|
return size - len * (size_t)'0';
|
@@ -169,8 +123,9 @@ newline_friendly_size(const uint8_t *str, size_t len) {
|
|
169
123
|
inline static size_t
|
170
124
|
hibit_friendly_size(const uint8_t *str, size_t len) {
|
171
125
|
size_t size = 0;
|
126
|
+
size_t i = len;
|
172
127
|
|
173
|
-
for (; 0 <
|
128
|
+
for (; 0 < i; str++, i--) {
|
174
129
|
size += hibit_friendly_chars[*str];
|
175
130
|
}
|
176
131
|
return size - len * (size_t)'0';
|
@@ -179,8 +134,9 @@ hibit_friendly_size(const uint8_t *str, size_t len) {
|
|
179
134
|
inline static size_t
|
180
135
|
ascii_friendly_size(const uint8_t *str, size_t len) {
|
181
136
|
size_t size = 0;
|
137
|
+
size_t i = len;
|
182
138
|
|
183
|
-
for (; 0 <
|
139
|
+
for (; 0 < i; str++, i--) {
|
184
140
|
size += ascii_friendly_chars[*str];
|
185
141
|
}
|
186
142
|
return size - len * (size_t)'0';
|
@@ -189,67 +145,76 @@ ascii_friendly_size(const uint8_t *str, size_t len) {
|
|
189
145
|
inline static size_t
|
190
146
|
xss_friendly_size(const uint8_t *str, size_t len) {
|
191
147
|
size_t size = 0;
|
148
|
+
size_t i = len;
|
192
149
|
|
193
|
-
for (; 0 <
|
150
|
+
for (; 0 < i; str++, i--) {
|
194
151
|
size += xss_friendly_chars[*str];
|
195
152
|
}
|
196
153
|
return size - len * (size_t)'0';
|
197
154
|
}
|
198
155
|
|
199
|
-
inline static
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
}
|
156
|
+
inline static size_t
|
157
|
+
hixss_friendly_size(const uint8_t *str, size_t len) {
|
158
|
+
size_t size = 0;
|
159
|
+
size_t i = len;
|
160
|
+
|
161
|
+
for (; 0 < i; str++, i--) {
|
162
|
+
size += hixss_friendly_chars[*str];
|
207
163
|
}
|
164
|
+
return size - len * (size_t)'0';
|
208
165
|
}
|
209
166
|
|
210
|
-
inline static
|
211
|
-
|
212
|
-
|
213
|
-
|
167
|
+
inline static size_t
|
168
|
+
rails_friendly_size(const uint8_t *str, size_t len) {
|
169
|
+
size_t size = 0;
|
170
|
+
size_t i = len;
|
214
171
|
|
215
|
-
|
216
|
-
|
217
|
-
for (; 0 < num; num /= 10, b--) {
|
218
|
-
*b = (num % 10) + '0';
|
219
|
-
}
|
220
|
-
b++;
|
221
|
-
} else {
|
222
|
-
*b = '0';
|
172
|
+
for (; 0 < i; str++, i--) {
|
173
|
+
size += rails_friendly_chars[*str];
|
223
174
|
}
|
224
|
-
|
225
|
-
*out->cur++ = *b;
|
226
|
-
}
|
227
|
-
*out->cur = '\0';
|
175
|
+
return size - len * (size_t)'0';
|
228
176
|
}
|
229
177
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
if (out->allocated) {
|
241
|
-
buf = REALLOC_N(out->buf, char, (size + BUFFER_EXTRA));
|
242
|
-
} else {
|
243
|
-
buf = ALLOC_N(char, (size + BUFFER_EXTRA));
|
244
|
-
out->allocated = 1;
|
245
|
-
memcpy(buf, out->buf, out->end - out->buf + BUFFER_EXTRA);
|
178
|
+
const char*
|
179
|
+
oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp) {
|
180
|
+
const char *str = NULL;
|
181
|
+
|
182
|
+
if (AutoNan == opt) {
|
183
|
+
switch (mode) {
|
184
|
+
case CompatMode: opt = WordNan; break;
|
185
|
+
case StrictMode: opt = RaiseNan; break;
|
186
|
+
default: break;
|
187
|
+
}
|
246
188
|
}
|
247
|
-
|
248
|
-
|
189
|
+
switch (opt) {
|
190
|
+
case RaiseNan:
|
191
|
+
raise_strict(obj);
|
192
|
+
break;
|
193
|
+
case WordNan:
|
194
|
+
if (plus) {
|
195
|
+
str = "Infinity";
|
196
|
+
*lenp = 8;
|
197
|
+
} else {
|
198
|
+
str = "-Infinity";
|
199
|
+
*lenp = 9;
|
200
|
+
}
|
201
|
+
break;
|
202
|
+
case NullNan:
|
203
|
+
str = "null";
|
204
|
+
*lenp = 4;
|
205
|
+
break;
|
206
|
+
case HugeNan:
|
207
|
+
default:
|
208
|
+
if (plus) {
|
209
|
+
str = inf_val;
|
210
|
+
*lenp = sizeof(inf_val) - 1;
|
211
|
+
} else {
|
212
|
+
str = ninf_val;
|
213
|
+
*lenp = sizeof(ninf_val) - 1;
|
214
|
+
}
|
215
|
+
break;
|
249
216
|
}
|
250
|
-
|
251
|
-
out->end = buf + size;
|
252
|
-
out->cur = out->buf + pos;
|
217
|
+
return str;
|
253
218
|
}
|
254
219
|
|
255
220
|
inline static void
|
@@ -261,17 +226,7 @@ dump_hex(uint8_t c, Out out) {
|
|
261
226
|
*out->cur++ = hex_chars[d];
|
262
227
|
}
|
263
228
|
|
264
|
-
static
|
265
|
-
dump_raw(const char *str, size_t cnt, Out out) {
|
266
|
-
if (out->end - out->cur <= (long)cnt + 10) {
|
267
|
-
grow(out, cnt + 10);
|
268
|
-
}
|
269
|
-
memcpy(out->cur, str, cnt);
|
270
|
-
out->cur += cnt;
|
271
|
-
*out->cur = '\0';
|
272
|
-
}
|
273
|
-
|
274
|
-
const char*
|
229
|
+
static const char*
|
275
230
|
dump_unicode(const char *str, const char *end, Out out) {
|
276
231
|
uint32_t code = 0;
|
277
232
|
uint8_t b = *(uint8_t*)str;
|
@@ -294,13 +249,13 @@ dump_unicode(const char *str, const char *end, Out out) {
|
|
294
249
|
code = b & 0x00000001;
|
295
250
|
} else {
|
296
251
|
cnt = 0;
|
297
|
-
rb_raise(
|
252
|
+
rb_raise(oj_json_generator_error_class, "Invalid Unicode");
|
298
253
|
}
|
299
254
|
str++;
|
300
255
|
for (; 0 < cnt; cnt--, str++) {
|
301
256
|
b = *(uint8_t*)str;
|
302
257
|
if (end <= str || 0x80 != (0xC0 & b)) {
|
303
|
-
rb_raise(
|
258
|
+
rb_raise(oj_json_generator_error_class, "Invalid Unicode");
|
304
259
|
}
|
305
260
|
code = (code << 6) | (b & 0x0000003F);
|
306
261
|
}
|
@@ -324,1912 +279,234 @@ dump_unicode(const char *str, const char *end, Out out) {
|
|
324
279
|
return str - 1;
|
325
280
|
}
|
326
281
|
|
327
|
-
//
|
328
|
-
// needed (duplicate), and a positive value if the object was added to the
|
329
|
-
|
330
|
-
|
282
|
+
// Returns 0 if not using circular references, -1 if no further writing is
|
283
|
+
// needed (duplicate), and a positive value if the object was added to the
|
284
|
+
// cache.
|
285
|
+
long
|
286
|
+
oj_check_circular(VALUE obj, Out out) {
|
331
287
|
slot_t id = 0;
|
332
288
|
slot_t *slot;
|
333
289
|
|
334
|
-
if (
|
290
|
+
if (Yes == out->opts->circular) {
|
335
291
|
if (0 == (id = oj_cache8_get(out->circ_cache, obj, &slot))) {
|
336
292
|
out->circ_cnt++;
|
337
293
|
id = out->circ_cnt;
|
338
294
|
*slot = id;
|
339
295
|
} else {
|
340
|
-
if (
|
341
|
-
|
296
|
+
if (ObjectMode == out->opts->mode) {
|
297
|
+
assure_size(out, 18);
|
298
|
+
*out->cur++ = '"';
|
299
|
+
*out->cur++ = '^';
|
300
|
+
*out->cur++ = 'r';
|
301
|
+
dump_ulong(id, out);
|
302
|
+
*out->cur++ = '"';
|
342
303
|
}
|
343
|
-
*out->cur++ = '"';
|
344
|
-
*out->cur++ = '^';
|
345
|
-
*out->cur++ = 'r';
|
346
|
-
dump_ulong(id, out);
|
347
|
-
*out->cur++ = '"';
|
348
|
-
|
349
304
|
return -1;
|
350
305
|
}
|
351
306
|
}
|
352
307
|
return (long)id;
|
353
308
|
}
|
354
309
|
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
*
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
*out->cur = '\0';
|
381
|
-
}
|
382
|
-
|
383
|
-
static void
|
384
|
-
dump_false(Out out) {
|
385
|
-
size_t size = 5;
|
310
|
+
void
|
311
|
+
oj_dump_time(VALUE obj, Out out, int withZone) {
|
312
|
+
char buf[64];
|
313
|
+
char *b = buf + sizeof(buf) - 1;
|
314
|
+
long size;
|
315
|
+
char *dot;
|
316
|
+
int neg = 0;
|
317
|
+
long one = 1000000000;
|
318
|
+
#if HAS_RB_TIME_TIMESPEC
|
319
|
+
struct timespec ts = rb_time_timespec(obj);
|
320
|
+
time_t sec = ts.tv_sec;
|
321
|
+
long nsec = ts.tv_nsec;
|
322
|
+
#else
|
323
|
+
time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
324
|
+
#if HAS_NANO_TIME
|
325
|
+
long long nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
326
|
+
#else
|
327
|
+
long long nsec = rb_num2ll(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
|
328
|
+
#endif
|
329
|
+
#endif
|
330
|
+
|
331
|
+
*b-- = '\0';
|
332
|
+
if (withZone) {
|
333
|
+
long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
|
334
|
+
int zneg = (0 > tzsecs);
|
386
335
|
|
387
|
-
|
388
|
-
|
336
|
+
if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
337
|
+
tzsecs = 86400;
|
338
|
+
}
|
339
|
+
if (zneg) {
|
340
|
+
tzsecs = -tzsecs;
|
341
|
+
}
|
342
|
+
if (0 == tzsecs) {
|
343
|
+
*b-- = '0';
|
344
|
+
} else {
|
345
|
+
for (; 0 < tzsecs; b--, tzsecs /= 10) {
|
346
|
+
*b = '0' + (tzsecs % 10);
|
347
|
+
}
|
348
|
+
if (zneg) {
|
349
|
+
*b-- = '-';
|
350
|
+
}
|
351
|
+
}
|
352
|
+
*b-- = 'e';
|
389
353
|
}
|
390
|
-
|
391
|
-
*out->cur++ = 'a';
|
392
|
-
*out->cur++ = 'l';
|
393
|
-
*out->cur++ = 's';
|
394
|
-
*out->cur++ = 'e';
|
395
|
-
*out->cur = '\0';
|
396
|
-
}
|
397
|
-
|
398
|
-
static void
|
399
|
-
dump_fixnum(VALUE obj, Out out) {
|
400
|
-
char buf[32];
|
401
|
-
char *b = buf + sizeof(buf) - 1;
|
402
|
-
long long num = rb_num2ll(obj);
|
403
|
-
int neg = 0;
|
404
|
-
|
405
|
-
if (0 > num) {
|
354
|
+
if (0 > sec) {
|
406
355
|
neg = 1;
|
407
|
-
|
356
|
+
sec = -sec;
|
357
|
+
if (0 < nsec) {
|
358
|
+
nsec = 1000000000 - nsec;
|
359
|
+
sec--;
|
360
|
+
}
|
408
361
|
}
|
409
|
-
|
410
|
-
if (0 <
|
411
|
-
|
412
|
-
|
362
|
+
dot = b - 9;
|
363
|
+
if (0 < out->opts->sec_prec) {
|
364
|
+
if (9 > out->opts->sec_prec) {
|
365
|
+
int i;
|
366
|
+
|
367
|
+
for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
|
368
|
+
dot++;
|
369
|
+
nsec = (nsec + 5) / 10;
|
370
|
+
one /= 10;
|
371
|
+
}
|
413
372
|
}
|
414
|
-
if (
|
415
|
-
|
416
|
-
|
417
|
-
b++;
|
373
|
+
if (one <= nsec) {
|
374
|
+
nsec -= one;
|
375
|
+
sec++;
|
418
376
|
}
|
419
|
-
|
420
|
-
|
377
|
+
for (; dot < b; b--, nsec /= 10) {
|
378
|
+
*b = '0' + (nsec % 10);
|
379
|
+
}
|
380
|
+
*b-- = '.';
|
421
381
|
}
|
422
|
-
if (
|
423
|
-
|
382
|
+
if (0 == sec) {
|
383
|
+
*b-- = '0';
|
384
|
+
} else {
|
385
|
+
for (; 0 < sec; b--, sec /= 10) {
|
386
|
+
*b = '0' + (sec % 10);
|
387
|
+
}
|
424
388
|
}
|
425
|
-
|
426
|
-
*
|
389
|
+
if (neg) {
|
390
|
+
*b-- = '-';
|
427
391
|
}
|
392
|
+
b++;
|
393
|
+
size = sizeof(buf) - (b - buf) - 1;
|
394
|
+
assure_size(out, size);
|
395
|
+
memcpy(out->cur, b, size);
|
396
|
+
out->cur += size;
|
428
397
|
*out->cur = '\0';
|
429
398
|
}
|
430
399
|
|
431
|
-
|
432
|
-
|
433
|
-
volatile VALUE
|
434
|
-
int cnt = (int)RSTRING_LEN(rs);
|
400
|
+
void
|
401
|
+
oj_dump_ruby_time(VALUE obj, Out out) {
|
402
|
+
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
435
403
|
|
436
|
-
|
437
|
-
grow(out, cnt);
|
438
|
-
}
|
439
|
-
memcpy(out->cur, rb_string_value_ptr((VALUE*)&rs), cnt);
|
440
|
-
out->cur += cnt;
|
441
|
-
*out->cur = '\0';
|
404
|
+
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
442
405
|
}
|
443
406
|
|
444
|
-
|
445
|
-
|
446
|
-
|
407
|
+
void
|
408
|
+
oj_dump_xml_time(VALUE obj, Out out) {
|
409
|
+
char buf[64];
|
410
|
+
struct tm *tm;
|
411
|
+
long one = 1000000000;
|
412
|
+
#if HAS_RB_TIME_TIMESPEC
|
413
|
+
struct timespec ts = rb_time_timespec(obj);
|
414
|
+
time_t sec = ts.tv_sec;
|
415
|
+
long nsec = ts.tv_nsec;
|
416
|
+
#else
|
417
|
+
time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
418
|
+
#if HAS_NANO_TIME
|
419
|
+
long long nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
420
|
+
#else
|
421
|
+
long long nsec = rb_num2ll(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
|
422
|
+
#endif
|
423
|
+
#endif
|
424
|
+
long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
|
425
|
+
int tzhour, tzmin;
|
426
|
+
char tzsign = '+';
|
447
427
|
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
cnt = 3;
|
463
|
-
} else if (OJ_INFINITY == d) {
|
464
|
-
if (ObjectMode == out->opts->mode) {
|
465
|
-
strcpy(buf, inf_val);
|
466
|
-
cnt = sizeof(inf_val) - 1;
|
467
|
-
} else {
|
468
|
-
NanDump nd = out->opts->dump_opts.nan_dump;
|
469
|
-
|
470
|
-
if (AutoNan == nd) {
|
471
|
-
switch (out->opts->mode) {
|
472
|
-
case CompatMode: nd = WordNan; break;
|
473
|
-
case StrictMode: nd = RaiseNan; break;
|
474
|
-
case NullMode: nd = NullNan; break;
|
475
|
-
default: break;
|
476
|
-
}
|
477
|
-
}
|
478
|
-
switch (nd) {
|
479
|
-
case RaiseNan:
|
480
|
-
raise_strict(obj);
|
481
|
-
break;
|
482
|
-
case WordNan:
|
483
|
-
strcpy(buf, "Infinity");
|
484
|
-
cnt = 8;
|
485
|
-
break;
|
486
|
-
case NullNan:
|
487
|
-
strcpy(buf, "null");
|
488
|
-
cnt = 4;
|
489
|
-
break;
|
490
|
-
case HugeNan:
|
491
|
-
default:
|
492
|
-
strcpy(buf, inf_val);
|
493
|
-
cnt = sizeof(inf_val) - 1;
|
494
|
-
break;
|
495
|
-
}
|
496
|
-
}
|
497
|
-
} else if (-OJ_INFINITY == d) {
|
498
|
-
if (ObjectMode == out->opts->mode) {
|
499
|
-
strcpy(buf, ninf_val);
|
500
|
-
cnt = sizeof(ninf_val) - 1;
|
501
|
-
} else {
|
502
|
-
NanDump nd = out->opts->dump_opts.nan_dump;
|
503
|
-
|
504
|
-
if (AutoNan == nd) {
|
505
|
-
switch (out->opts->mode) {
|
506
|
-
case CompatMode: nd = WordNan; break;
|
507
|
-
case StrictMode: nd = RaiseNan; break;
|
508
|
-
case NullMode: nd = NullNan; break;
|
509
|
-
default: break;
|
510
|
-
}
|
511
|
-
}
|
512
|
-
switch (nd) {
|
513
|
-
case RaiseNan:
|
514
|
-
raise_strict(obj);
|
515
|
-
break;
|
516
|
-
case WordNan:
|
517
|
-
strcpy(buf, "-Infinity");
|
518
|
-
cnt = 9;
|
519
|
-
break;
|
520
|
-
case NullNan:
|
521
|
-
strcpy(buf, "null");
|
522
|
-
cnt = 4;
|
523
|
-
break;
|
524
|
-
case HugeNan:
|
525
|
-
default:
|
526
|
-
strcpy(buf, ninf_val);
|
527
|
-
cnt = sizeof(ninf_val) - 1;
|
528
|
-
break;
|
529
|
-
}
|
530
|
-
}
|
531
|
-
} else if (isnan(d)) {
|
532
|
-
if (ObjectMode == out->opts->mode) {
|
533
|
-
strcpy(buf, nan_val);
|
534
|
-
cnt = sizeof(nan_val) - 1;
|
535
|
-
} else {
|
536
|
-
NanDump nd = out->opts->dump_opts.nan_dump;
|
537
|
-
|
538
|
-
if (AutoNan == nd) {
|
539
|
-
switch (out->opts->mode) {
|
540
|
-
case CompatMode: nd = WordNan; break;
|
541
|
-
case StrictMode: nd = RaiseNan; break;
|
542
|
-
case NullMode: nd = NullNan; break;
|
543
|
-
default: break;
|
544
|
-
}
|
545
|
-
}
|
546
|
-
switch (nd) {
|
547
|
-
case RaiseNan:
|
548
|
-
raise_strict(obj);
|
549
|
-
break;
|
550
|
-
case WordNan:
|
551
|
-
strcpy(buf, "NaN");
|
552
|
-
cnt = 3;
|
553
|
-
break;
|
554
|
-
case NullNan:
|
555
|
-
strcpy(buf, "null");
|
556
|
-
cnt = 4;
|
557
|
-
break;
|
558
|
-
case HugeNan:
|
559
|
-
default:
|
560
|
-
strcpy(buf, nan_val);
|
561
|
-
cnt = sizeof(nan_val) - 1;
|
562
|
-
break;
|
563
|
-
}
|
564
|
-
}
|
565
|
-
} else if (d == (double)(long long int)d) {
|
566
|
-
cnt = snprintf(buf, sizeof(buf), "%.1f", d);
|
567
|
-
} else if (0 == out->opts->float_prec) {
|
568
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
569
|
-
|
570
|
-
cnt = (int)RSTRING_LEN(rstr);
|
571
|
-
if ((int)sizeof(buf) <= cnt) {
|
572
|
-
cnt = sizeof(buf) - 1;
|
573
|
-
}
|
574
|
-
strncpy(buf, rb_string_value_ptr((VALUE*)&rstr), cnt);
|
575
|
-
buf[cnt] = '\0';
|
576
|
-
} else {
|
577
|
-
cnt = snprintf(buf, sizeof(buf), out->opts->float_fmt, d);
|
578
|
-
}
|
579
|
-
if (out->end - out->cur <= (long)cnt) {
|
580
|
-
grow(out, cnt);
|
581
|
-
}
|
582
|
-
for (b = buf; '\0' != *b; b++) {
|
583
|
-
*out->cur++ = *b;
|
584
|
-
}
|
585
|
-
*out->cur = '\0';
|
586
|
-
}
|
587
|
-
|
588
|
-
static void
|
589
|
-
dump_cstr(const char *str, size_t cnt, int is_sym, int escape1, Out out) {
|
590
|
-
size_t size;
|
591
|
-
char *cmap;
|
592
|
-
|
593
|
-
switch (out->opts->escape_mode) {
|
594
|
-
case NLEsc:
|
595
|
-
cmap = newline_friendly_chars;
|
596
|
-
size = newline_friendly_size((uint8_t*)str, cnt);
|
597
|
-
break;
|
598
|
-
case ASCIIEsc:
|
599
|
-
cmap = ascii_friendly_chars;
|
600
|
-
size = ascii_friendly_size((uint8_t*)str, cnt);
|
601
|
-
break;
|
602
|
-
case XSSEsc:
|
603
|
-
cmap = xss_friendly_chars;
|
604
|
-
size = xss_friendly_size((uint8_t*)str, cnt);
|
605
|
-
break;
|
606
|
-
case JSONEsc:
|
607
|
-
default:
|
608
|
-
cmap = hibit_friendly_chars;
|
609
|
-
size = hibit_friendly_size((uint8_t*)str, cnt);
|
610
|
-
}
|
611
|
-
if (out->end - out->cur <= (long)size + BUFFER_EXTRA) { // extra 10 for escaped first char, quotes, and sym
|
612
|
-
grow(out, size + BUFFER_EXTRA);
|
613
|
-
}
|
614
|
-
*out->cur++ = '"';
|
615
|
-
if (escape1) {
|
616
|
-
*out->cur++ = '\\';
|
617
|
-
*out->cur++ = 'u';
|
618
|
-
*out->cur++ = '0';
|
619
|
-
*out->cur++ = '0';
|
620
|
-
dump_hex((uint8_t)*str, out);
|
621
|
-
cnt--;
|
622
|
-
size--;
|
623
|
-
str++;
|
624
|
-
is_sym = 0; // just to make sure
|
625
|
-
}
|
626
|
-
if (cnt == size) {
|
627
|
-
if (is_sym) {
|
628
|
-
*out->cur++ = ':';
|
629
|
-
}
|
630
|
-
for (; '\0' != *str; str++) {
|
631
|
-
*out->cur++ = *str;
|
632
|
-
}
|
633
|
-
*out->cur++ = '"';
|
634
|
-
} else {
|
635
|
-
const char *end = str + cnt;
|
636
|
-
|
637
|
-
if (is_sym) {
|
638
|
-
*out->cur++ = ':';
|
639
|
-
}
|
640
|
-
for (; str < end; str++) {
|
641
|
-
switch (cmap[(uint8_t)*str]) {
|
642
|
-
case '1':
|
643
|
-
*out->cur++ = *str;
|
644
|
-
break;
|
645
|
-
case '2':
|
646
|
-
*out->cur++ = '\\';
|
647
|
-
switch (*str) {
|
648
|
-
case '\\': *out->cur++ = '\\'; break;
|
649
|
-
case '\b': *out->cur++ = 'b'; break;
|
650
|
-
case '\t': *out->cur++ = 't'; break;
|
651
|
-
case '\n': *out->cur++ = 'n'; break;
|
652
|
-
case '\f': *out->cur++ = 'f'; break;
|
653
|
-
case '\r': *out->cur++ = 'r'; break;
|
654
|
-
default: *out->cur++ = *str; break;
|
655
|
-
}
|
656
|
-
break;
|
657
|
-
case '3': // Unicode
|
658
|
-
str = dump_unicode(str, end, out);
|
659
|
-
break;
|
660
|
-
case '6': // control characters
|
661
|
-
*out->cur++ = '\\';
|
662
|
-
*out->cur++ = 'u';
|
663
|
-
*out->cur++ = '0';
|
664
|
-
*out->cur++ = '0';
|
665
|
-
dump_hex((uint8_t)*str, out);
|
666
|
-
break;
|
667
|
-
default:
|
668
|
-
break; // ignore, should never happen if the table is correct
|
669
|
-
}
|
670
|
-
}
|
671
|
-
*out->cur++ = '"';
|
672
|
-
}
|
673
|
-
*out->cur = '\0';
|
674
|
-
}
|
675
|
-
|
676
|
-
static void
|
677
|
-
dump_str_comp(VALUE obj, Out out) {
|
678
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&obj), (int)RSTRING_LEN(obj), 0, 0, out);
|
679
|
-
}
|
680
|
-
|
681
|
-
static void
|
682
|
-
dump_str_obj(VALUE obj, VALUE clas, int depth, Out out) {
|
683
|
-
if (Qundef != clas && rb_cString != clas) {
|
684
|
-
dump_obj_attrs(obj, clas, 0, depth, out);
|
685
|
-
} else {
|
686
|
-
const char *s = rb_string_value_ptr((VALUE*)&obj);
|
687
|
-
size_t len = (size_t)RSTRING_LEN(obj);
|
688
|
-
char s1 = s[1];
|
689
|
-
|
690
|
-
dump_cstr(s, len, 0, (':' == *s || ('^' == *s && ('r' == s1 || 'i' == s1))), out);
|
691
|
-
}
|
692
|
-
}
|
693
|
-
|
694
|
-
static void
|
695
|
-
dump_sym_comp(VALUE obj, Out out) {
|
696
|
-
const char *sym = rb_id2name(SYM2ID(obj));
|
697
|
-
|
698
|
-
dump_cstr(sym, strlen(sym), 0, 0, out);
|
699
|
-
}
|
700
|
-
|
701
|
-
static void
|
702
|
-
dump_sym_obj(VALUE obj, Out out) {
|
703
|
-
const char *sym = rb_id2name(SYM2ID(obj));
|
704
|
-
size_t len = strlen(sym);
|
705
|
-
|
706
|
-
dump_cstr(sym, len, 1, 0, out);
|
707
|
-
}
|
708
|
-
|
709
|
-
static void
|
710
|
-
dump_class_comp(VALUE obj, Out out) {
|
711
|
-
const char *s = rb_class2name(obj);
|
712
|
-
|
713
|
-
dump_cstr(s, strlen(s), 0, 0, out);
|
714
|
-
}
|
715
|
-
|
716
|
-
static void
|
717
|
-
dump_class_obj(VALUE obj, Out out) {
|
718
|
-
const char *s = rb_class2name(obj);
|
719
|
-
size_t len = strlen(s);
|
720
|
-
|
721
|
-
if (out->end - out->cur <= 6) {
|
722
|
-
grow(out, 6);
|
723
|
-
}
|
724
|
-
*out->cur++ = '{';
|
725
|
-
*out->cur++ = '"';
|
726
|
-
*out->cur++ = '^';
|
727
|
-
*out->cur++ = 'c';
|
728
|
-
*out->cur++ = '"';
|
729
|
-
*out->cur++ = ':';
|
730
|
-
dump_cstr(s, len, 0, 0, out);
|
731
|
-
*out->cur++ = '}';
|
732
|
-
*out->cur = '\0';
|
733
|
-
}
|
734
|
-
|
735
|
-
static void
|
736
|
-
dump_array(VALUE a, VALUE clas, int depth, Out out) {
|
737
|
-
size_t size;
|
738
|
-
int i, cnt;
|
739
|
-
int d2 = depth + 1;
|
740
|
-
long id = check_circular(a, out);
|
741
|
-
|
742
|
-
if (id < 0) {
|
743
|
-
return;
|
744
|
-
}
|
745
|
-
if (Qundef != clas && rb_cArray != clas && ObjectMode == out->opts->mode) {
|
746
|
-
dump_obj_attrs(a, clas, 0, depth, out);
|
747
|
-
return;
|
748
|
-
}
|
749
|
-
cnt = (int)RARRAY_LEN(a);
|
750
|
-
*out->cur++ = '[';
|
751
|
-
if (0 < id) {
|
752
|
-
size = d2 * out->indent + 16;
|
753
|
-
if (out->end - out->cur <= (long)size) {
|
754
|
-
grow(out, size);
|
755
|
-
}
|
756
|
-
fill_indent(out, d2);
|
757
|
-
*out->cur++ = '"';
|
758
|
-
*out->cur++ = '^';
|
759
|
-
*out->cur++ = 'i';
|
760
|
-
dump_ulong(id, out);
|
761
|
-
*out->cur++ = '"';
|
762
|
-
}
|
763
|
-
size = 2;
|
764
|
-
if (out->end - out->cur <= (long)size) {
|
765
|
-
grow(out, size);
|
766
|
-
}
|
767
|
-
if (0 == cnt) {
|
768
|
-
*out->cur++ = ']';
|
769
|
-
} else {
|
770
|
-
if (0 < id) {
|
771
|
-
*out->cur++ = ',';
|
772
|
-
}
|
773
|
-
if (out->opts->dump_opts.use) {
|
774
|
-
size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
|
775
|
-
} else {
|
776
|
-
size = d2 * out->indent + 2;
|
777
|
-
}
|
778
|
-
cnt--;
|
779
|
-
for (i = 0; i <= cnt; i++) {
|
780
|
-
if (out->end - out->cur <= (long)size) {
|
781
|
-
grow(out, size);
|
782
|
-
}
|
783
|
-
if (out->opts->dump_opts.use) {
|
784
|
-
if (0 < out->opts->dump_opts.array_size) {
|
785
|
-
strcpy(out->cur, out->opts->dump_opts.array_nl);
|
786
|
-
out->cur += out->opts->dump_opts.array_size;
|
787
|
-
}
|
788
|
-
if (0 < out->opts->dump_opts.indent_size) {
|
789
|
-
int i;
|
790
|
-
for (i = d2; 0 < i; i--) {
|
791
|
-
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
792
|
-
out->cur += out->opts->dump_opts.indent_size;
|
793
|
-
}
|
794
|
-
}
|
795
|
-
} else {
|
796
|
-
fill_indent(out, d2);
|
797
|
-
}
|
798
|
-
dump_val(rb_ary_entry(a, i), d2, out, 0, 0, true);
|
799
|
-
if (i < cnt) {
|
800
|
-
*out->cur++ = ',';
|
801
|
-
}
|
802
|
-
}
|
803
|
-
size = depth * out->indent + 1;
|
804
|
-
if (out->end - out->cur <= (long)size) {
|
805
|
-
grow(out, size);
|
806
|
-
}
|
807
|
-
if (out->opts->dump_opts.use) {
|
808
|
-
//printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size, out->opts->dump_opts->indent);
|
809
|
-
if (0 < out->opts->dump_opts.array_size) {
|
810
|
-
strcpy(out->cur, out->opts->dump_opts.array_nl);
|
811
|
-
out->cur += out->opts->dump_opts.array_size;
|
812
|
-
}
|
813
|
-
if (0 < out->opts->dump_opts.indent_size) {
|
814
|
-
int i;
|
815
|
-
|
816
|
-
for (i = depth; 0 < i; i--) {
|
817
|
-
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
818
|
-
out->cur += out->opts->dump_opts.indent_size;
|
819
|
-
}
|
820
|
-
}
|
821
|
-
} else {
|
822
|
-
fill_indent(out, depth);
|
823
|
-
}
|
824
|
-
*out->cur++ = ']';
|
825
|
-
}
|
826
|
-
*out->cur = '\0';
|
827
|
-
}
|
828
|
-
|
829
|
-
static int
|
830
|
-
hash_cb_strict(VALUE key, VALUE value, Out out) {
|
831
|
-
int depth = out->depth;
|
832
|
-
long size;
|
833
|
-
int rtype = rb_type(key);
|
834
|
-
|
835
|
-
if (rtype != T_STRING && rtype != T_SYMBOL) {
|
836
|
-
rb_raise(rb_eTypeError, "In :strict mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));
|
837
|
-
}
|
838
|
-
if (out->omit_nil && Qnil == value) {
|
839
|
-
return ST_CONTINUE;
|
840
|
-
}
|
841
|
-
if (!out->opts->dump_opts.use) {
|
842
|
-
size = depth * out->indent + 1;
|
843
|
-
if (out->end - out->cur <= size) {
|
844
|
-
grow(out, size);
|
845
|
-
}
|
846
|
-
fill_indent(out, depth);
|
847
|
-
if (rtype == T_STRING) {
|
848
|
-
dump_str_comp(key, out);
|
849
|
-
} else {
|
850
|
-
dump_sym_comp(key, out);
|
851
|
-
}
|
852
|
-
*out->cur++ = ':';
|
853
|
-
} else {
|
854
|
-
size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
|
855
|
-
if (out->end - out->cur <= size) {
|
856
|
-
grow(out, size);
|
857
|
-
}
|
858
|
-
if (0 < out->opts->dump_opts.hash_size) {
|
859
|
-
strcpy(out->cur, out->opts->dump_opts.hash_nl);
|
860
|
-
out->cur += out->opts->dump_opts.hash_size;
|
861
|
-
}
|
862
|
-
if (0 < out->opts->dump_opts.indent_size) {
|
863
|
-
int i;
|
864
|
-
for (i = depth; 0 < i; i--) {
|
865
|
-
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
866
|
-
out->cur += out->opts->dump_opts.indent_size;
|
867
|
-
}
|
868
|
-
}
|
869
|
-
if (rtype == T_STRING) {
|
870
|
-
dump_str_comp(key, out);
|
871
|
-
} else {
|
872
|
-
dump_sym_comp(key, out);
|
873
|
-
}
|
874
|
-
size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
875
|
-
if (out->end - out->cur <= size) {
|
876
|
-
grow(out, size);
|
877
|
-
}
|
878
|
-
if (0 < out->opts->dump_opts.before_size) {
|
879
|
-
strcpy(out->cur, out->opts->dump_opts.before_sep);
|
880
|
-
out->cur += out->opts->dump_opts.before_size;
|
881
|
-
}
|
882
|
-
*out->cur++ = ':';
|
883
|
-
if (0 < out->opts->dump_opts.after_size) {
|
884
|
-
strcpy(out->cur, out->opts->dump_opts.after_sep);
|
885
|
-
out->cur += out->opts->dump_opts.after_size;
|
886
|
-
}
|
887
|
-
}
|
888
|
-
dump_val(value, depth, out, 0, 0, false);
|
889
|
-
out->depth = depth;
|
890
|
-
*out->cur++ = ',';
|
891
|
-
|
892
|
-
return ST_CONTINUE;
|
893
|
-
}
|
894
|
-
|
895
|
-
static int
|
896
|
-
hash_cb_compat(VALUE key, VALUE value, Out out) {
|
897
|
-
int depth = out->depth;
|
898
|
-
long size;
|
899
|
-
|
900
|
-
if (out->omit_nil && Qnil == value) {
|
901
|
-
return ST_CONTINUE;
|
902
|
-
}
|
903
|
-
if (!out->opts->dump_opts.use) {
|
904
|
-
size = depth * out->indent + 1;
|
905
|
-
if (out->end - out->cur <= size) {
|
906
|
-
grow(out, size);
|
907
|
-
}
|
908
|
-
fill_indent(out, depth);
|
909
|
-
} else {
|
910
|
-
size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
|
911
|
-
if (out->end - out->cur <= size) {
|
912
|
-
grow(out, size);
|
913
|
-
}
|
914
|
-
if (0 < out->opts->dump_opts.hash_size) {
|
915
|
-
strcpy(out->cur, out->opts->dump_opts.hash_nl);
|
916
|
-
out->cur += out->opts->dump_opts.hash_size;
|
917
|
-
}
|
918
|
-
if (0 < out->opts->dump_opts.indent_size) {
|
919
|
-
int i;
|
920
|
-
for (i = depth; 0 < i; i--) {
|
921
|
-
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
922
|
-
out->cur += out->opts->dump_opts.indent_size;
|
923
|
-
}
|
924
|
-
}
|
925
|
-
}
|
926
|
-
switch (rb_type(key)) {
|
927
|
-
case T_STRING:
|
928
|
-
dump_str_comp(key, out);
|
929
|
-
break;
|
930
|
-
case T_SYMBOL:
|
931
|
-
dump_sym_comp(key, out);
|
932
|
-
break;
|
933
|
-
default:
|
934
|
-
/*rb_raise(rb_eTypeError, "In :compat mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));*/
|
935
|
-
dump_str_comp(rb_funcall(key, oj_to_s_id, 0), out);
|
936
|
-
break;
|
937
|
-
}
|
938
|
-
if (!out->opts->dump_opts.use) {
|
939
|
-
*out->cur++ = ':';
|
940
|
-
} else {
|
941
|
-
size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
942
|
-
if (out->end - out->cur <= size) {
|
943
|
-
grow(out, size);
|
944
|
-
}
|
945
|
-
if (0 < out->opts->dump_opts.before_size) {
|
946
|
-
strcpy(out->cur, out->opts->dump_opts.before_sep);
|
947
|
-
out->cur += out->opts->dump_opts.before_size;
|
948
|
-
}
|
949
|
-
*out->cur++ = ':';
|
950
|
-
if (0 < out->opts->dump_opts.after_size) {
|
951
|
-
strcpy(out->cur, out->opts->dump_opts.after_sep);
|
952
|
-
out->cur += out->opts->dump_opts.after_size;
|
953
|
-
}
|
954
|
-
}
|
955
|
-
dump_val(value, depth, out, 0, 0, true);
|
956
|
-
out->depth = depth;
|
957
|
-
*out->cur++ = ',';
|
958
|
-
|
959
|
-
return ST_CONTINUE;
|
960
|
-
}
|
961
|
-
|
962
|
-
static int
|
963
|
-
hash_cb_object(VALUE key, VALUE value, Out out) {
|
964
|
-
int depth = out->depth;
|
965
|
-
long size = depth * out->indent + 1;
|
966
|
-
|
967
|
-
if (out->omit_nil && Qnil == value) {
|
968
|
-
return ST_CONTINUE;
|
969
|
-
}
|
970
|
-
if (out->end - out->cur <= size) {
|
971
|
-
grow(out, size);
|
972
|
-
}
|
973
|
-
fill_indent(out, depth);
|
974
|
-
if (rb_type(key) == T_STRING) {
|
975
|
-
dump_str_obj(key, Qundef, depth, out);
|
976
|
-
*out->cur++ = ':';
|
977
|
-
dump_val(value, depth, out, 0, 0, true);
|
978
|
-
} else if (rb_type(key) == T_SYMBOL) {
|
979
|
-
dump_sym_obj(key, out);
|
980
|
-
*out->cur++ = ':';
|
981
|
-
dump_val(value, depth, out, 0, 0, true);
|
982
|
-
} else {
|
983
|
-
int d2 = depth + 1;
|
984
|
-
long s2 = size + out->indent + 1;
|
985
|
-
int i;
|
986
|
-
int started = 0;
|
987
|
-
uint8_t b;
|
988
|
-
|
989
|
-
if (out->end - out->cur <= s2 + 15) {
|
990
|
-
grow(out, s2 + 15);
|
991
|
-
}
|
992
|
-
*out->cur++ = '"';
|
993
|
-
*out->cur++ = '^';
|
994
|
-
*out->cur++ = '#';
|
995
|
-
out->hash_cnt++;
|
996
|
-
for (i = 28; 0 <= i; i -= 4) {
|
997
|
-
b = (uint8_t)((out->hash_cnt >> i) & 0x0000000F);
|
998
|
-
if ('\0' != b) {
|
999
|
-
started = 1;
|
1000
|
-
}
|
1001
|
-
if (started) {
|
1002
|
-
*out->cur++ = hex_chars[b];
|
1003
|
-
}
|
1004
|
-
}
|
1005
|
-
*out->cur++ = '"';
|
1006
|
-
*out->cur++ = ':';
|
1007
|
-
*out->cur++ = '[';
|
1008
|
-
fill_indent(out, d2);
|
1009
|
-
dump_val(key, d2, out, 0, 0, true);
|
1010
|
-
if (out->end - out->cur <= (long)s2) {
|
1011
|
-
grow(out, s2);
|
1012
|
-
}
|
1013
|
-
*out->cur++ = ',';
|
1014
|
-
fill_indent(out, d2);
|
1015
|
-
dump_val(value, d2, out, 0, 0, true);
|
1016
|
-
if (out->end - out->cur <= (long)size) {
|
1017
|
-
grow(out, size);
|
1018
|
-
}
|
1019
|
-
fill_indent(out, depth);
|
1020
|
-
*out->cur++ = ']';
|
1021
|
-
}
|
1022
|
-
out->depth = depth;
|
1023
|
-
*out->cur++ = ',';
|
1024
|
-
|
1025
|
-
return ST_CONTINUE;
|
1026
|
-
}
|
1027
|
-
|
1028
|
-
static void
|
1029
|
-
dump_hash(VALUE obj, VALUE clas, int depth, int mode, Out out) {
|
1030
|
-
int cnt;
|
1031
|
-
size_t size;
|
1032
|
-
|
1033
|
-
if (Qundef != clas && rb_cHash != clas && ObjectMode == mode) {
|
1034
|
-
dump_obj_attrs(obj, clas, 0, depth, out);
|
1035
|
-
return;
|
1036
|
-
}
|
1037
|
-
cnt = (int)RHASH_SIZE(obj);
|
1038
|
-
size = depth * out->indent + 2;
|
1039
|
-
if (out->end - out->cur <= 2) {
|
1040
|
-
grow(out, 2);
|
1041
|
-
}
|
1042
|
-
if (0 == cnt) {
|
1043
|
-
*out->cur++ = '{';
|
1044
|
-
*out->cur++ = '}';
|
1045
|
-
} else {
|
1046
|
-
long id = check_circular(obj, out);
|
1047
|
-
|
1048
|
-
if (0 > id) {
|
1049
|
-
return;
|
1050
|
-
}
|
1051
|
-
*out->cur++ = '{';
|
1052
|
-
if (0 < id) {
|
1053
|
-
if (out->end - out->cur <= (long)size + 16) {
|
1054
|
-
grow(out, size + 16);
|
1055
|
-
}
|
1056
|
-
fill_indent(out, depth + 1);
|
1057
|
-
*out->cur++ = '"';
|
1058
|
-
*out->cur++ = '^';
|
1059
|
-
*out->cur++ = 'i';
|
1060
|
-
*out->cur++ = '"';
|
1061
|
-
*out->cur++ = ':';
|
1062
|
-
dump_ulong(id, out);
|
1063
|
-
*out->cur++ = ',';
|
1064
|
-
}
|
1065
|
-
out->depth = depth + 1;
|
1066
|
-
if (ObjectMode == mode) {
|
1067
|
-
rb_hash_foreach(obj, hash_cb_object, (VALUE)out);
|
1068
|
-
} else if (CompatMode == mode) {
|
1069
|
-
rb_hash_foreach(obj, hash_cb_compat, (VALUE)out);
|
1070
|
-
} else {
|
1071
|
-
rb_hash_foreach(obj, hash_cb_strict, (VALUE)out);
|
1072
|
-
}
|
1073
|
-
if (',' == *(out->cur - 1)) {
|
1074
|
-
out->cur--; // backup to overwrite last comma
|
1075
|
-
}
|
1076
|
-
if (!out->opts->dump_opts.use) {
|
1077
|
-
if (out->end - out->cur <= (long)size) {
|
1078
|
-
grow(out, size);
|
1079
|
-
}
|
1080
|
-
fill_indent(out, depth);
|
1081
|
-
} else {
|
1082
|
-
size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
|
1083
|
-
if (out->end - out->cur <= (long)size) {
|
1084
|
-
grow(out, size);
|
1085
|
-
}
|
1086
|
-
if (0 < out->opts->dump_opts.hash_size) {
|
1087
|
-
strcpy(out->cur, out->opts->dump_opts.hash_nl);
|
1088
|
-
out->cur += out->opts->dump_opts.hash_size;
|
1089
|
-
}
|
1090
|
-
if (0 < out->opts->dump_opts.indent_size) {
|
1091
|
-
int i;
|
1092
|
-
|
1093
|
-
for (i = depth; 0 < i; i--) {
|
1094
|
-
strcpy(out->cur, out->opts->dump_opts.indent_str);
|
1095
|
-
out->cur += out->opts->dump_opts.indent_size;
|
1096
|
-
}
|
1097
|
-
}
|
1098
|
-
}
|
1099
|
-
*out->cur++ = '}';
|
1100
|
-
}
|
1101
|
-
*out->cur = '\0';
|
1102
|
-
}
|
1103
|
-
|
1104
|
-
static void
|
1105
|
-
dump_time(VALUE obj, Out out, int withZone) {
|
1106
|
-
char buf[64];
|
1107
|
-
char *b = buf + sizeof(buf) - 1;
|
1108
|
-
long size;
|
1109
|
-
char *dot;
|
1110
|
-
int neg = 0;
|
1111
|
-
long one = 1000000000;
|
1112
|
-
#if HAS_RB_TIME_TIMESPEC
|
1113
|
-
struct timespec ts = rb_time_timespec(obj);
|
1114
|
-
time_t sec = ts.tv_sec;
|
1115
|
-
long nsec = ts.tv_nsec;
|
1116
|
-
#else
|
1117
|
-
time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
1118
|
-
#if HAS_NANO_TIME
|
1119
|
-
long long nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
1120
|
-
#else
|
1121
|
-
long long nsec = rb_num2ll(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
|
1122
|
-
#endif
|
1123
|
-
#endif
|
1124
|
-
|
1125
|
-
*b-- = '\0';
|
1126
|
-
if (withZone) {
|
1127
|
-
long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
|
1128
|
-
int zneg = (0 > tzsecs);
|
1129
|
-
|
1130
|
-
if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
1131
|
-
tzsecs = 86400;
|
1132
|
-
}
|
1133
|
-
if (zneg) {
|
1134
|
-
tzsecs = -tzsecs;
|
1135
|
-
}
|
1136
|
-
if (0 == tzsecs) {
|
1137
|
-
*b-- = '0';
|
1138
|
-
} else {
|
1139
|
-
for (; 0 < tzsecs; b--, tzsecs /= 10) {
|
1140
|
-
*b = '0' + (tzsecs % 10);
|
1141
|
-
}
|
1142
|
-
if (zneg) {
|
1143
|
-
*b-- = '-';
|
1144
|
-
}
|
1145
|
-
}
|
1146
|
-
*b-- = 'e';
|
1147
|
-
}
|
1148
|
-
if (0 > sec) {
|
1149
|
-
neg = 1;
|
1150
|
-
sec = -sec;
|
1151
|
-
if (0 < nsec) {
|
1152
|
-
nsec = 1000000000 - nsec;
|
1153
|
-
sec--;
|
1154
|
-
}
|
1155
|
-
}
|
1156
|
-
dot = b - 9;
|
1157
|
-
if (0 < out->opts->sec_prec) {
|
1158
|
-
if (9 > out->opts->sec_prec) {
|
1159
|
-
int i;
|
1160
|
-
|
1161
|
-
for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
|
1162
|
-
dot++;
|
1163
|
-
nsec = (nsec + 5) / 10;
|
1164
|
-
one /= 10;
|
1165
|
-
}
|
1166
|
-
}
|
1167
|
-
if (one <= nsec) {
|
1168
|
-
nsec -= one;
|
1169
|
-
sec++;
|
1170
|
-
}
|
1171
|
-
for (; dot < b; b--, nsec /= 10) {
|
1172
|
-
*b = '0' + (nsec % 10);
|
1173
|
-
}
|
1174
|
-
*b-- = '.';
|
1175
|
-
}
|
1176
|
-
if (0 == sec) {
|
1177
|
-
*b-- = '0';
|
1178
|
-
} else {
|
1179
|
-
for (; 0 < sec; b--, sec /= 10) {
|
1180
|
-
*b = '0' + (sec % 10);
|
1181
|
-
}
|
1182
|
-
}
|
1183
|
-
if (neg) {
|
1184
|
-
*b-- = '-';
|
1185
|
-
}
|
1186
|
-
b++;
|
1187
|
-
size = sizeof(buf) - (b - buf) - 1;
|
1188
|
-
if (out->end - out->cur <= size) {
|
1189
|
-
grow(out, size);
|
1190
|
-
}
|
1191
|
-
memcpy(out->cur, b, size);
|
1192
|
-
out->cur += size;
|
1193
|
-
*out->cur = '\0';
|
1194
|
-
}
|
1195
|
-
|
1196
|
-
static void
|
1197
|
-
dump_ruby_time(VALUE obj, Out out) {
|
1198
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1199
|
-
|
1200
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
1201
|
-
}
|
1202
|
-
|
1203
|
-
static void
|
1204
|
-
dump_xml_time(VALUE obj, Out out) {
|
1205
|
-
char buf[64];
|
1206
|
-
struct tm *tm;
|
1207
|
-
long one = 1000000000;
|
1208
|
-
#if HAS_RB_TIME_TIMESPEC
|
1209
|
-
struct timespec ts = rb_time_timespec(obj);
|
1210
|
-
time_t sec = ts.tv_sec;
|
1211
|
-
long nsec = ts.tv_nsec;
|
1212
|
-
#else
|
1213
|
-
time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
1214
|
-
#if HAS_NANO_TIME
|
1215
|
-
long long nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
1216
|
-
#else
|
1217
|
-
long long nsec = rb_num2ll(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
|
1218
|
-
#endif
|
1219
|
-
#endif
|
1220
|
-
long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
|
1221
|
-
int tzhour, tzmin;
|
1222
|
-
char tzsign = '+';
|
1223
|
-
|
1224
|
-
if (out->end - out->cur <= 36) {
|
1225
|
-
grow(out, 36);
|
1226
|
-
}
|
1227
|
-
if (9 > out->opts->sec_prec) {
|
1228
|
-
int i;
|
1229
|
-
|
1230
|
-
for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
|
1231
|
-
nsec = (nsec + 5) / 10;
|
1232
|
-
one /= 10;
|
1233
|
-
}
|
1234
|
-
if (one <= nsec) {
|
1235
|
-
nsec -= one;
|
1236
|
-
sec++;
|
1237
|
-
}
|
1238
|
-
}
|
1239
|
-
// 2012-01-05T23:58:07.123456000+09:00
|
1240
|
-
//tm = localtime(&sec);
|
1241
|
-
sec += tzsecs;
|
1242
|
-
tm = gmtime(&sec);
|
1243
|
-
#if 1
|
1244
|
-
if (0 > tzsecs) {
|
1245
|
-
tzsign = '-';
|
1246
|
-
tzhour = (int)(tzsecs / -3600);
|
1247
|
-
tzmin = (int)(tzsecs / -60) - (tzhour * 60);
|
1248
|
-
} else {
|
1249
|
-
tzhour = (int)(tzsecs / 3600);
|
1250
|
-
tzmin = (int)(tzsecs / 60) - (tzhour * 60);
|
1251
|
-
}
|
1252
|
-
#else
|
1253
|
-
if (0 > tm->tm_gmtoff) {
|
1254
|
-
tzsign = '-';
|
1255
|
-
tzhour = (int)(tm->tm_gmtoff / -3600);
|
1256
|
-
tzmin = (int)(tm->tm_gmtoff / -60) - (tzhour * 60);
|
1257
|
-
} else {
|
1258
|
-
tzhour = (int)(tm->tm_gmtoff / 3600);
|
1259
|
-
tzmin = (int)(tm->tm_gmtoff / 60) - (tzhour * 60);
|
1260
|
-
}
|
1261
|
-
#endif
|
1262
|
-
if (0 == nsec || 0 == out->opts->sec_prec) {
|
1263
|
-
if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
1264
|
-
sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ",
|
1265
|
-
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
1266
|
-
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
1267
|
-
dump_cstr(buf, 20, 0, 0, out);
|
1268
|
-
} else {
|
1269
|
-
sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
|
1270
|
-
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
1271
|
-
tm->tm_hour, tm->tm_min, tm->tm_sec,
|
1272
|
-
tzsign, tzhour, tzmin);
|
1273
|
-
dump_cstr(buf, 25, 0, 0, out);
|
1274
|
-
}
|
1275
|
-
} else if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
1276
|
-
char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ";
|
1277
|
-
int len = 30;
|
1278
|
-
|
1279
|
-
if (9 > out->opts->sec_prec) {
|
1280
|
-
format[32] = '0' + out->opts->sec_prec;
|
1281
|
-
len -= 9 - out->opts->sec_prec;
|
1282
|
-
}
|
1283
|
-
sprintf(buf, format,
|
1284
|
-
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
1285
|
-
tm->tm_hour, tm->tm_min, tm->tm_sec, nsec);
|
1286
|
-
dump_cstr(buf, len, 0, 0, out);
|
1287
|
-
} else {
|
1288
|
-
char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
|
1289
|
-
int len = 35;
|
1290
|
-
|
1291
|
-
if (9 > out->opts->sec_prec) {
|
1292
|
-
format[32] = '0' + out->opts->sec_prec;
|
1293
|
-
len -= 9 - out->opts->sec_prec;
|
1294
|
-
}
|
1295
|
-
sprintf(buf, format,
|
1296
|
-
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
1297
|
-
tm->tm_hour, tm->tm_min, tm->tm_sec, nsec,
|
1298
|
-
tzsign, tzhour, tzmin);
|
1299
|
-
dump_cstr(buf, len, 0, 0, out);
|
1300
|
-
}
|
1301
|
-
}
|
1302
|
-
|
1303
|
-
static void
|
1304
|
-
dump_data_strict(VALUE obj, Out out) {
|
1305
|
-
VALUE clas = rb_obj_class(obj);
|
1306
|
-
|
1307
|
-
if (oj_bigdecimal_class == clas) {
|
1308
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1309
|
-
|
1310
|
-
dump_raw(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), out);
|
1311
|
-
} else {
|
1312
|
-
raise_strict(obj);
|
1313
|
-
}
|
1314
|
-
}
|
1315
|
-
|
1316
|
-
static void
|
1317
|
-
dump_data_null(VALUE obj, Out out) {
|
1318
|
-
VALUE clas = rb_obj_class(obj);
|
1319
|
-
|
1320
|
-
if (oj_bigdecimal_class == clas) {
|
1321
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1322
|
-
|
1323
|
-
dump_raw(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), out);
|
1324
|
-
} else {
|
1325
|
-
dump_nil(out);
|
1326
|
-
}
|
1327
|
-
}
|
1328
|
-
|
1329
|
-
static void
|
1330
|
-
dump_data_comp(VALUE obj, int depth, Out out, int argc, VALUE *argv, bool as_ok) {
|
1331
|
-
VALUE clas = rb_obj_class(obj);
|
1332
|
-
|
1333
|
-
if (as_ok && Yes == out->opts->to_json && rb_respond_to(obj, oj_to_hash_id)) {
|
1334
|
-
volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
1335
|
-
|
1336
|
-
if (T_HASH != rb_type(h)) {
|
1337
|
-
// It seems that ActiveRecord implemented to_hash so that it returns
|
1338
|
-
// an Array and not a Hash. To get around that any value returned
|
1339
|
-
// will be dumped.
|
1340
|
-
|
1341
|
-
//rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
1342
|
-
dump_val(h, depth, out, 0, 0, false);
|
1343
|
-
}
|
1344
|
-
dump_hash(h, Qundef, depth, out->opts->mode, out);
|
1345
|
-
} else if (Yes == out->opts->bigdec_as_num && oj_bigdecimal_class == clas) {
|
1346
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1347
|
-
|
1348
|
-
dump_raw(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), out);
|
1349
|
-
} else if (as_ok && Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
|
1350
|
-
volatile VALUE aj;
|
1351
|
-
|
1352
|
-
#if HAS_METHOD_ARITY
|
1353
|
-
// Some classes elect to not take an options argument so check the arity
|
1354
|
-
// of as_json.
|
1355
|
-
switch (rb_obj_method_arity(obj, oj_as_json_id)) {
|
1356
|
-
case 0:
|
1357
|
-
aj = rb_funcall2(obj, oj_as_json_id, 0, 0);
|
1358
|
-
break;
|
1359
|
-
case 1:
|
1360
|
-
if (1 <= argc) {
|
1361
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, argv);
|
1362
|
-
} else {
|
1363
|
-
VALUE nothing [1];
|
1364
|
-
|
1365
|
-
nothing[0] = Qnil;
|
1366
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, nothing);
|
1367
|
-
}
|
1368
|
-
break;
|
1369
|
-
default:
|
1370
|
-
aj = rb_funcall2(obj, oj_as_json_id, argc, argv);
|
1371
|
-
break;
|
1372
|
-
}
|
1373
|
-
#else
|
1374
|
-
aj = rb_funcall2(obj, oj_as_json_id, argc, argv);
|
1375
|
-
#endif
|
1376
|
-
// Catch the obvious brain damaged recursive dumping.
|
1377
|
-
if (aj == obj) {
|
1378
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1379
|
-
|
1380
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
1381
|
-
} else {
|
1382
|
-
dump_val(aj, depth, out, 0, 0, false);
|
1383
|
-
}
|
1384
|
-
} else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
|
1385
|
-
volatile VALUE rs;
|
1386
|
-
const char *s;
|
1387
|
-
int len;
|
1388
|
-
|
1389
|
-
rs = rb_funcall(obj, oj_to_json_id, 0);
|
1390
|
-
s = rb_string_value_ptr((VALUE*)&rs);
|
1391
|
-
len = (int)RSTRING_LEN(rs);
|
1392
|
-
|
1393
|
-
if (out->end - out->cur <= len + 1) {
|
1394
|
-
grow(out, len);
|
1395
|
-
}
|
1396
|
-
memcpy(out->cur, s, len);
|
1397
|
-
out->cur += len;
|
1398
|
-
*out->cur = '\0';
|
1399
|
-
} else {
|
1400
|
-
if (rb_cTime == clas) {
|
1401
|
-
switch (out->opts->time_format) {
|
1402
|
-
case RubyTime: dump_ruby_time(obj, out); break;
|
1403
|
-
case XmlTime: dump_xml_time(obj, out); break;
|
1404
|
-
case UnixZTime: dump_time(obj, out, 1); break;
|
1405
|
-
case UnixTime:
|
1406
|
-
default: dump_time(obj, out, 0); break;
|
1407
|
-
}
|
1408
|
-
} else if (oj_bigdecimal_class == clas) {
|
1409
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1410
|
-
|
1411
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
1412
|
-
} else {
|
1413
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1414
|
-
|
1415
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
1416
|
-
}
|
1417
|
-
}
|
1418
|
-
}
|
1419
|
-
|
1420
|
-
static void
|
1421
|
-
dump_data_obj(VALUE obj, int depth, Out out) {
|
1422
|
-
VALUE clas = rb_obj_class(obj);
|
1423
|
-
|
1424
|
-
if (rb_cTime == clas) {
|
1425
|
-
if (out->end - out->cur <= 6) {
|
1426
|
-
grow(out, 6);
|
1427
|
-
}
|
1428
|
-
*out->cur++ = '{';
|
1429
|
-
*out->cur++ = '"';
|
1430
|
-
*out->cur++ = '^';
|
1431
|
-
*out->cur++ = 't';
|
1432
|
-
*out->cur++ = '"';
|
1433
|
-
*out->cur++ = ':';
|
1434
|
-
switch (out->opts->time_format) {
|
1435
|
-
case RubyTime: // Does not output fractional seconds
|
1436
|
-
case XmlTime:
|
1437
|
-
dump_xml_time(obj, out);
|
1438
|
-
break;
|
1439
|
-
case UnixZTime:
|
1440
|
-
dump_time(obj, out, 1);
|
1441
|
-
break;
|
1442
|
-
case UnixTime:
|
1443
|
-
default:
|
1444
|
-
dump_time(obj, out, 0);
|
1445
|
-
break;
|
1446
|
-
}
|
1447
|
-
*out->cur++ = '}';
|
1448
|
-
*out->cur = '\0';
|
1449
|
-
} else {
|
1450
|
-
if (oj_bigdecimal_class == clas) {
|
1451
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1452
|
-
|
1453
|
-
if (Yes == out->opts->bigdec_as_num) {
|
1454
|
-
dump_raw(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), out);
|
1455
|
-
} else {
|
1456
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
1457
|
-
}
|
1458
|
-
} else {
|
1459
|
-
dump_nil(out);
|
1460
|
-
}
|
1461
|
-
}
|
1462
|
-
}
|
1463
|
-
|
1464
|
-
static void
|
1465
|
-
dump_obj_comp(VALUE obj, int depth, Out out, int argc, VALUE *argv, bool as_ok) {
|
1466
|
-
if (as_ok && Yes == out->opts->to_json && rb_respond_to(obj, oj_to_hash_id)) {
|
1467
|
-
volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
1468
|
-
|
1469
|
-
if (T_HASH != rb_type(h)) {
|
1470
|
-
// It seems that ActiveRecord implemented to_hash so that it returns
|
1471
|
-
// an Array and not a Hash. To get around that any value returned
|
1472
|
-
// will be dumped.
|
1473
|
-
|
1474
|
-
//rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
1475
|
-
dump_val(h, depth, out, 0, 0, false);
|
1476
|
-
} else {
|
1477
|
-
dump_hash(h, Qundef, depth, out->opts->mode, out);
|
1478
|
-
}
|
1479
|
-
} else if (as_ok && Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
|
1480
|
-
volatile VALUE aj;
|
1481
|
-
|
1482
|
-
#if HAS_METHOD_ARITY
|
1483
|
-
// Some classes elect to not take an options argument so check the arity
|
1484
|
-
// of as_json.
|
1485
|
-
switch (rb_obj_method_arity(obj, oj_as_json_id)) {
|
1486
|
-
case 0:
|
1487
|
-
aj = rb_funcall2(obj, oj_as_json_id, 0, 0);
|
1488
|
-
break;
|
1489
|
-
case 1:
|
1490
|
-
if (1 <= argc) {
|
1491
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, argv);
|
1492
|
-
} else {
|
1493
|
-
VALUE nothing [1];
|
1494
|
-
|
1495
|
-
nothing[0] = Qnil;
|
1496
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, nothing);
|
1497
|
-
}
|
1498
|
-
break;
|
1499
|
-
default:
|
1500
|
-
aj = rb_funcall2(obj, oj_as_json_id, argc, argv);
|
1501
|
-
break;
|
1502
|
-
}
|
1503
|
-
#else
|
1504
|
-
aj = rb_funcall2(obj, oj_as_json_id, argc, argv);
|
1505
|
-
#endif
|
1506
|
-
// Catch the obvious brain damaged recursive dumping.
|
1507
|
-
if (aj == obj) {
|
1508
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1509
|
-
|
1510
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
1511
|
-
} else {
|
1512
|
-
dump_val(aj, depth, out, 0, 0, false);
|
1513
|
-
}
|
1514
|
-
} else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
|
1515
|
-
volatile VALUE rs;
|
1516
|
-
const char *s;
|
1517
|
-
int len;
|
1518
|
-
|
1519
|
-
rs = rb_funcall(obj, oj_to_json_id, 0);
|
1520
|
-
s = rb_string_value_ptr((VALUE*)&rs);
|
1521
|
-
len = (int)RSTRING_LEN(rs);
|
1522
|
-
|
1523
|
-
if (out->end - out->cur <= len + 1) {
|
1524
|
-
grow(out, len);
|
1525
|
-
}
|
1526
|
-
memcpy(out->cur, s, len);
|
1527
|
-
out->cur += len;
|
1528
|
-
*out->cur = '\0';
|
1529
|
-
} else {
|
1530
|
-
VALUE clas = rb_obj_class(obj);
|
1531
|
-
|
1532
|
-
if (oj_bigdecimal_class == clas) {
|
1533
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1534
|
-
|
1535
|
-
if (Yes == out->opts->bigdec_as_num) {
|
1536
|
-
dump_raw(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), out);
|
1537
|
-
} else {
|
1538
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
1539
|
-
}
|
1540
|
-
#if (defined T_RATIONAL && defined RRATIONAL)
|
1541
|
-
} else if (oj_datetime_class == clas || oj_date_class == clas || rb_cRational == clas) {
|
1542
|
-
#else
|
1543
|
-
} else if (oj_datetime_class == clas || oj_date_class == clas) {
|
1544
|
-
#endif
|
1545
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1546
|
-
|
1547
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
1548
|
-
} else {
|
1549
|
-
dump_obj_attrs(obj, Qundef, 0, depth, out);
|
1550
|
-
}
|
1551
|
-
}
|
1552
|
-
*out->cur = '\0';
|
1553
|
-
}
|
1554
|
-
|
1555
|
-
inline static void
|
1556
|
-
dump_obj_obj(VALUE obj, int depth, Out out) {
|
1557
|
-
long id = check_circular(obj, out);
|
1558
|
-
|
1559
|
-
if (0 <= id) {
|
1560
|
-
VALUE clas = rb_obj_class(obj);
|
1561
|
-
|
1562
|
-
if (oj_bigdecimal_class == clas) {
|
1563
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1564
|
-
|
1565
|
-
dump_raw(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), out);
|
1566
|
-
} else {
|
1567
|
-
dump_obj_attrs(obj, clas, id, depth, out);
|
1568
|
-
}
|
1569
|
-
}
|
1570
|
-
}
|
1571
|
-
|
1572
|
-
#ifdef RUBINIUS_RUBY
|
1573
|
-
static int
|
1574
|
-
isRbxHashAttr(const char *attr) {
|
1575
|
-
const char *hashAttrs[] = {
|
1576
|
-
"@capacity",
|
1577
|
-
"@max_entries",
|
1578
|
-
"@state",
|
1579
|
-
"@mask",
|
1580
|
-
"@size",
|
1581
|
-
"@entries",
|
1582
|
-
"@default_proc",
|
1583
|
-
0 };
|
1584
|
-
const char **ap;
|
1585
|
-
|
1586
|
-
for (ap = hashAttrs; 0 != *ap; ap++) {
|
1587
|
-
if (0 == strcmp(attr, *ap)) {
|
1588
|
-
return 1;
|
1589
|
-
}
|
1590
|
-
}
|
1591
|
-
return 0;
|
1592
|
-
}
|
1593
|
-
#endif
|
1594
|
-
|
1595
|
-
#if HAS_IVAR_HELPERS
|
1596
|
-
static int
|
1597
|
-
dump_attr_cb(ID key, VALUE value, Out out) {
|
1598
|
-
int depth = out->depth;
|
1599
|
-
size_t size = depth * out->indent + 1;
|
1600
|
-
const char *attr = rb_id2name(key);
|
1601
|
-
|
1602
|
-
if (out->omit_nil && Qnil == value) {
|
1603
|
-
return ST_CONTINUE;
|
1604
|
-
}
|
1605
|
-
#if HAS_EXCEPTION_MAGIC
|
1606
|
-
if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) {
|
1607
|
-
return ST_CONTINUE;
|
1608
|
-
}
|
1609
|
-
#endif
|
1610
|
-
if (out->end - out->cur <= (long)size) {
|
1611
|
-
grow(out, size);
|
1612
|
-
}
|
1613
|
-
fill_indent(out, depth);
|
1614
|
-
if ('@' == *attr) {
|
1615
|
-
attr++;
|
1616
|
-
dump_cstr(attr, strlen(attr), 0, 0, out);
|
1617
|
-
} else {
|
1618
|
-
char buf[32];
|
1619
|
-
|
1620
|
-
*buf = '~';
|
1621
|
-
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
1622
|
-
buf[sizeof(buf) - 1] = '\0';
|
1623
|
-
dump_cstr(buf, strlen(buf), 0, 0, out);
|
1624
|
-
}
|
1625
|
-
*out->cur++ = ':';
|
1626
|
-
dump_val(value, depth, out, 0, 0, true);
|
1627
|
-
out->depth = depth;
|
1628
|
-
*out->cur++ = ',';
|
1629
|
-
|
1630
|
-
return ST_CONTINUE;
|
1631
|
-
}
|
1632
|
-
#endif
|
1633
|
-
|
1634
|
-
static void
|
1635
|
-
dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
|
1636
|
-
size_t size = 0;
|
1637
|
-
int d2 = depth + 1;
|
1638
|
-
int type = rb_type(obj);
|
1639
|
-
|
1640
|
-
if (out->end - out->cur <= 2) {
|
1641
|
-
grow(out, 2);
|
1642
|
-
}
|
1643
|
-
*out->cur++ = '{';
|
1644
|
-
if (Qundef != clas) {
|
1645
|
-
const char *class_name = rb_class2name(clas);
|
1646
|
-
int clen = (int)strlen(class_name);
|
1647
|
-
|
1648
|
-
size = d2 * out->indent + clen + 10;
|
1649
|
-
if (out->end - out->cur <= (long)size) {
|
1650
|
-
grow(out, size);
|
1651
|
-
}
|
1652
|
-
fill_indent(out, d2);
|
1653
|
-
*out->cur++ = '"';
|
1654
|
-
*out->cur++ = '^';
|
1655
|
-
*out->cur++ = 'o';
|
1656
|
-
*out->cur++ = '"';
|
1657
|
-
*out->cur++ = ':';
|
1658
|
-
dump_cstr(class_name, clen, 0, 0, out);
|
1659
|
-
}
|
1660
|
-
if (0 < id) {
|
1661
|
-
size = d2 * out->indent + 16;
|
1662
|
-
if (out->end - out->cur <= (long)size) {
|
1663
|
-
grow(out, size);
|
1664
|
-
}
|
1665
|
-
*out->cur++ = ',';
|
1666
|
-
fill_indent(out, d2);
|
1667
|
-
*out->cur++ = '"';
|
1668
|
-
*out->cur++ = '^';
|
1669
|
-
*out->cur++ = 'i';
|
1670
|
-
*out->cur++ = '"';
|
1671
|
-
*out->cur++ = ':';
|
1672
|
-
dump_ulong(id, out);
|
1673
|
-
}
|
1674
|
-
switch (type) {
|
1675
|
-
case T_STRING:
|
1676
|
-
size = d2 * out->indent + 14;
|
1677
|
-
if (out->end - out->cur <= (long)size) {
|
1678
|
-
grow(out, size);
|
1679
|
-
}
|
1680
|
-
*out->cur++ = ',';
|
1681
|
-
fill_indent(out, d2);
|
1682
|
-
*out->cur++ = '"';
|
1683
|
-
*out->cur++ = 's';
|
1684
|
-
*out->cur++ = 'e';
|
1685
|
-
*out->cur++ = 'l';
|
1686
|
-
*out->cur++ = 'f';
|
1687
|
-
*out->cur++ = '"';
|
1688
|
-
*out->cur++ = ':';
|
1689
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&obj), (int)RSTRING_LEN(obj), 0, 0, out);
|
1690
|
-
break;
|
1691
|
-
case T_ARRAY:
|
1692
|
-
size = d2 * out->indent + 14;
|
1693
|
-
if (out->end - out->cur <= (long)size) {
|
1694
|
-
grow(out, size);
|
1695
|
-
}
|
1696
|
-
*out->cur++ = ',';
|
1697
|
-
fill_indent(out, d2);
|
1698
|
-
*out->cur++ = '"';
|
1699
|
-
*out->cur++ = 's';
|
1700
|
-
*out->cur++ = 'e';
|
1701
|
-
*out->cur++ = 'l';
|
1702
|
-
*out->cur++ = 'f';
|
1703
|
-
*out->cur++ = '"';
|
1704
|
-
*out->cur++ = ':';
|
1705
|
-
dump_array(obj, Qundef, depth + 1, out);
|
1706
|
-
break;
|
1707
|
-
case T_HASH:
|
1708
|
-
size = d2 * out->indent + 14;
|
1709
|
-
if (out->end - out->cur <= (long)size) {
|
1710
|
-
grow(out, size);
|
1711
|
-
}
|
1712
|
-
*out->cur++ = ',';
|
1713
|
-
fill_indent(out, d2);
|
1714
|
-
*out->cur++ = '"';
|
1715
|
-
*out->cur++ = 's';
|
1716
|
-
*out->cur++ = 'e';
|
1717
|
-
*out->cur++ = 'l';
|
1718
|
-
*out->cur++ = 'f';
|
1719
|
-
*out->cur++ = '"';
|
1720
|
-
*out->cur++ = ':';
|
1721
|
-
dump_hash(obj, Qundef, depth + 1, out->opts->mode, out);
|
1722
|
-
break;
|
1723
|
-
default:
|
1724
|
-
break;
|
1725
|
-
}
|
1726
|
-
{
|
1727
|
-
int cnt;
|
1728
|
-
#if HAS_IVAR_HELPERS
|
1729
|
-
cnt = (int)rb_ivar_count(obj);
|
1730
|
-
#else
|
1731
|
-
volatile VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0);
|
1732
|
-
VALUE *np = RARRAY_PTR(vars);
|
1733
|
-
ID vid;
|
1734
|
-
const char *attr;
|
1735
|
-
int i;
|
1736
|
-
int first = 1;
|
1737
|
-
|
1738
|
-
cnt = (int)RARRAY_LEN(vars);
|
1739
|
-
#endif
|
1740
|
-
if (Qundef != clas && 0 < cnt) {
|
1741
|
-
*out->cur++ = ',';
|
1742
|
-
}
|
1743
|
-
out->depth = depth + 1;
|
1744
|
-
#if HAS_IVAR_HELPERS
|
1745
|
-
rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
|
1746
|
-
if (',' == *(out->cur - 1)) {
|
1747
|
-
out->cur--; // backup to overwrite last comma
|
1748
|
-
}
|
1749
|
-
#else
|
1750
|
-
size = d2 * out->indent + 1;
|
1751
|
-
for (i = cnt; 0 < i; i--, np++) {
|
1752
|
-
VALUE value;
|
1753
|
-
|
1754
|
-
vid = rb_to_id(*np);
|
1755
|
-
attr = rb_id2name(vid);
|
1756
|
-
#ifdef RUBINIUS_RUBY
|
1757
|
-
if (T_HASH == type && isRbxHashAttr(attr)) {
|
1758
|
-
continue;
|
1759
|
-
}
|
1760
|
-
#endif
|
1761
|
-
value = rb_ivar_get(obj, vid);
|
1762
|
-
if (out->omit_nil && Qnil == value) {
|
1763
|
-
continue;
|
1764
|
-
}
|
1765
|
-
if (first) {
|
1766
|
-
first = 0;
|
1767
|
-
} else {
|
1768
|
-
*out->cur++ = ',';
|
1769
|
-
}
|
1770
|
-
if (out->end - out->cur <= (long)size) {
|
1771
|
-
grow(out, size);
|
1772
|
-
}
|
1773
|
-
fill_indent(out, d2);
|
1774
|
-
if ('@' == *attr) {
|
1775
|
-
attr++;
|
1776
|
-
dump_cstr(attr, strlen(attr), 0, 0, out);
|
1777
|
-
} else {
|
1778
|
-
char buf[32];
|
1779
|
-
|
1780
|
-
*buf = '~';
|
1781
|
-
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
1782
|
-
buf[sizeof(buf) - 1] = '\0';
|
1783
|
-
dump_cstr(buf, strlen(attr) + 1, 0, 0, out);
|
1784
|
-
}
|
1785
|
-
*out->cur++ = ':';
|
1786
|
-
dump_val(value, d2, out, 0, 0, true);
|
1787
|
-
if (out->end - out->cur <= 2) {
|
1788
|
-
grow(out, 2);
|
1789
|
-
}
|
1790
|
-
}
|
1791
|
-
#endif
|
1792
|
-
#if HAS_EXCEPTION_MAGIC
|
1793
|
-
if (rb_obj_is_kind_of(obj, rb_eException)) {
|
1794
|
-
volatile VALUE rv;
|
1795
|
-
|
1796
|
-
if (',' != *(out->cur - 1)) {
|
1797
|
-
*out->cur++ = ',';
|
1798
|
-
}
|
1799
|
-
// message
|
1800
|
-
if (out->end - out->cur <= (long)size) {
|
1801
|
-
grow(out, size);
|
1802
|
-
}
|
1803
|
-
fill_indent(out, d2);
|
1804
|
-
dump_cstr("~mesg", 5, 0, 0, out);
|
1805
|
-
*out->cur++ = ':';
|
1806
|
-
rv = rb_funcall2(obj, rb_intern("message"), 0, 0);
|
1807
|
-
dump_val(rv, d2, out, 0, 0, true);
|
1808
|
-
if (out->end - out->cur <= 2) {
|
1809
|
-
grow(out, 2);
|
1810
|
-
}
|
1811
|
-
*out->cur++ = ',';
|
1812
|
-
// backtrace
|
1813
|
-
if (out->end - out->cur <= (long)size) {
|
1814
|
-
grow(out, size);
|
1815
|
-
}
|
1816
|
-
fill_indent(out, d2);
|
1817
|
-
dump_cstr("~bt", 3, 0, 0, out);
|
1818
|
-
*out->cur++ = ':';
|
1819
|
-
rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0);
|
1820
|
-
dump_val(rv, d2, out, 0, 0, true);
|
1821
|
-
if (out->end - out->cur <= 2) {
|
1822
|
-
grow(out, 2);
|
1823
|
-
}
|
1824
|
-
}
|
1825
|
-
#endif
|
1826
|
-
out->depth = depth;
|
1827
|
-
}
|
1828
|
-
fill_indent(out, depth);
|
1829
|
-
*out->cur++ = '}';
|
1830
|
-
*out->cur = '\0';
|
1831
|
-
}
|
1832
|
-
|
1833
|
-
static void
|
1834
|
-
dump_struct_comp(VALUE obj, int depth, Out out, int argc, VALUE *argv, bool as_ok) {
|
1835
|
-
if (as_ok && Yes == out->opts->to_json && rb_respond_to(obj, oj_to_hash_id)) {
|
1836
|
-
volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
1837
|
-
|
1838
|
-
if (T_HASH != rb_type(h)) {
|
1839
|
-
// It seems that ActiveRecord implemented to_hash so that it returns
|
1840
|
-
// an Array and not a Hash. To get around that any value returned
|
1841
|
-
// will be dumped.
|
1842
|
-
|
1843
|
-
//rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
1844
|
-
dump_val(h, depth, out, 0, 0, false);
|
1845
|
-
}
|
1846
|
-
dump_hash(h, Qundef, depth, out->opts->mode, out);
|
1847
|
-
} else if (as_ok && Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
|
1848
|
-
volatile VALUE aj;
|
1849
|
-
|
1850
|
-
#if HAS_METHOD_ARITY
|
1851
|
-
// Some classes elect to not take an options argument so check the arity
|
1852
|
-
// of as_json.
|
1853
|
-
switch (rb_obj_method_arity(obj, oj_as_json_id)) {
|
1854
|
-
case 0:
|
1855
|
-
aj = rb_funcall2(obj, oj_as_json_id, 0, 0);
|
1856
|
-
break;
|
1857
|
-
case 1:
|
1858
|
-
if (1 <= argc) {
|
1859
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, argv);
|
1860
|
-
} else {
|
1861
|
-
VALUE nothing [1];
|
1862
|
-
|
1863
|
-
nothing[0] = Qnil;
|
1864
|
-
aj = rb_funcall2(obj, oj_as_json_id, 1, nothing);
|
1865
|
-
}
|
1866
|
-
break;
|
1867
|
-
default:
|
1868
|
-
aj = rb_funcall2(obj, oj_as_json_id, argc, argv);
|
1869
|
-
break;
|
1870
|
-
}
|
1871
|
-
#else
|
1872
|
-
aj = rb_funcall2(obj, oj_as_json_id, argc, argv);
|
1873
|
-
#endif
|
1874
|
-
// Catch the obvious brain damaged recursive dumping.
|
1875
|
-
if (aj == obj) {
|
1876
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1877
|
-
|
1878
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
1879
|
-
} else {
|
1880
|
-
dump_val(aj, depth, out, 0, 0, false);
|
1881
|
-
}
|
1882
|
-
} else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
|
1883
|
-
volatile VALUE rs = rb_funcall(obj, oj_to_json_id, 0);
|
1884
|
-
const char *s;
|
1885
|
-
int len;
|
1886
|
-
|
1887
|
-
s = rb_string_value_ptr((VALUE*)&rs);
|
1888
|
-
len = (int)RSTRING_LEN(rs);
|
1889
|
-
if (out->end - out->cur <= len) {
|
1890
|
-
grow(out, len);
|
1891
|
-
}
|
1892
|
-
memcpy(out->cur, s, len);
|
1893
|
-
out->cur += len;
|
1894
|
-
} else {
|
1895
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1896
|
-
|
1897
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
1898
|
-
}
|
1899
|
-
}
|
1900
|
-
|
1901
|
-
static void
|
1902
|
-
dump_struct_obj(VALUE obj, int depth, Out out) {
|
1903
|
-
VALUE clas = rb_obj_class(obj);
|
1904
|
-
const char *class_name = rb_class2name(clas);
|
1905
|
-
int i;
|
1906
|
-
int d2 = depth + 1;
|
1907
|
-
int d3 = d2 + 1;
|
1908
|
-
size_t len = strlen(class_name);
|
1909
|
-
size_t size = d2 * out->indent + d3 * out->indent + 10 + len;
|
1910
|
-
|
1911
|
-
if (out->end - out->cur <= (long)size) {
|
1912
|
-
grow(out, size);
|
1913
|
-
}
|
1914
|
-
*out->cur++ = '{';
|
1915
|
-
fill_indent(out, d2);
|
1916
|
-
*out->cur++ = '"';
|
1917
|
-
*out->cur++ = '^';
|
1918
|
-
*out->cur++ = 'u';
|
1919
|
-
*out->cur++ = '"';
|
1920
|
-
*out->cur++ = ':';
|
1921
|
-
*out->cur++ = '[';
|
1922
|
-
#if HAS_STRUCT_MEMBERS
|
1923
|
-
if ('#' == *class_name) {
|
1924
|
-
VALUE ma = rb_struct_s_members(clas);
|
1925
|
-
const char *name;
|
1926
|
-
int cnt = (int)RARRAY_LEN(ma);
|
1927
|
-
|
1928
|
-
*out->cur++ = '[';
|
1929
|
-
for (i = 0; i < cnt; i++) {
|
1930
|
-
name = rb_id2name(SYM2ID(rb_ary_entry(ma, i)));
|
1931
|
-
len = strlen(name);
|
1932
|
-
size = len + 3;
|
1933
|
-
if (out->end - out->cur <= (long)size) {
|
1934
|
-
grow(out, size);
|
1935
|
-
}
|
1936
|
-
if (0 < i) {
|
1937
|
-
*out->cur++ = ',';
|
1938
|
-
}
|
1939
|
-
*out->cur++ = '"';
|
1940
|
-
memcpy(out->cur, name, len);
|
1941
|
-
out->cur += len;
|
1942
|
-
*out->cur++ = '"';
|
1943
|
-
}
|
1944
|
-
*out->cur++ = ']';
|
1945
|
-
} else {
|
1946
|
-
#else
|
1947
|
-
if (true) {
|
1948
|
-
#endif
|
1949
|
-
fill_indent(out, d3);
|
1950
|
-
*out->cur++ = '"';
|
1951
|
-
memcpy(out->cur, class_name, len);
|
1952
|
-
out->cur += len;
|
1953
|
-
*out->cur++ = '"';
|
1954
|
-
}
|
1955
|
-
*out->cur++ = ',';
|
1956
|
-
size = d3 * out->indent + 2;
|
1957
|
-
#ifdef RSTRUCT_LEN
|
1958
|
-
{
|
1959
|
-
VALUE v;
|
1960
|
-
int cnt;
|
1961
|
-
#if UNIFY_FIXNUM_AND_BIGNUM
|
1962
|
-
cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
|
1963
|
-
#else // UNIFY_FIXNUM_AND_INTEGER
|
1964
|
-
cnt = (int)RSTRUCT_LEN(obj);
|
1965
|
-
#endif // UNIFY_FIXNUM_AND_INTEGER
|
1966
|
-
|
1967
|
-
for (i = 0; i < cnt; i++) {
|
1968
|
-
v = RSTRUCT_GET(obj, i);
|
1969
|
-
if (out->end - out->cur <= (long)size) {
|
1970
|
-
grow(out, size);
|
1971
|
-
}
|
1972
|
-
fill_indent(out, d3);
|
1973
|
-
dump_val(v, d3, out, 0, 0, true);
|
1974
|
-
*out->cur++ = ',';
|
1975
|
-
}
|
1976
|
-
}
|
1977
|
-
#else
|
1978
|
-
{
|
1979
|
-
// This is a bit risky as a struct in C ruby is not the same as a Struct
|
1980
|
-
// class in interpreted Ruby so length() may not be defined.
|
1981
|
-
int slen = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
|
1982
|
-
|
1983
|
-
for (i = 0; i < slen; i++) {
|
1984
|
-
if (out->end - out->cur <= (long)size) {
|
1985
|
-
grow(out, size);
|
1986
|
-
}
|
1987
|
-
fill_indent(out, d3);
|
1988
|
-
dump_val(rb_struct_aref(obj, INT2FIX(i)), d3, out, 0, 0, true);
|
1989
|
-
*out->cur++ = ',';
|
1990
|
-
}
|
1991
|
-
}
|
1992
|
-
#endif
|
1993
|
-
out->cur--;
|
1994
|
-
*out->cur++ = ']';
|
1995
|
-
*out->cur++ = '}';
|
1996
|
-
*out->cur = '\0';
|
1997
|
-
}
|
1998
|
-
|
1999
|
-
static void
|
2000
|
-
dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
2001
|
-
ID *idp;
|
2002
|
-
AttrGetFunc *fp;
|
2003
|
-
volatile VALUE v;
|
2004
|
-
const char *name;
|
2005
|
-
size_t size;
|
2006
|
-
int d2 = depth + 1;
|
2007
|
-
|
2008
|
-
if (out->end - out->cur <= 2) {
|
2009
|
-
grow(out, 2);
|
2010
|
-
}
|
2011
|
-
*out->cur++ = '{';
|
2012
|
-
if (Qundef != clas) {
|
2013
|
-
const char *class_name = rb_class2name(clas);
|
2014
|
-
int clen = (int)strlen(class_name);
|
2015
|
-
|
2016
|
-
size = d2 * out->indent + clen + 10;
|
2017
|
-
if (out->end - out->cur <= (long)size) {
|
2018
|
-
grow(out, size);
|
2019
|
-
}
|
2020
|
-
fill_indent(out, d2);
|
2021
|
-
*out->cur++ = '"';
|
2022
|
-
*out->cur++ = '^';
|
2023
|
-
*out->cur++ = 'O';
|
2024
|
-
*out->cur++ = '"';
|
2025
|
-
*out->cur++ = ':';
|
2026
|
-
dump_cstr(class_name, clen, 0, 0, out);
|
2027
|
-
*out->cur++ = ',';
|
2028
|
-
}
|
2029
|
-
if (odd->raw) {
|
2030
|
-
v = rb_funcall(obj, *odd->attrs, 0);
|
2031
|
-
if (Qundef == v || T_STRING != rb_type(v)) {
|
2032
|
-
rb_raise(rb_eEncodingError, "Invalid type for raw JSON.\n");
|
2033
|
-
} else {
|
2034
|
-
const char *s = rb_string_value_ptr((VALUE*)&v);
|
2035
|
-
int len = (int)RSTRING_LEN(v);
|
2036
|
-
const char *name = rb_id2name(*odd->attrs);
|
2037
|
-
size_t nlen = strlen(name);
|
2038
|
-
|
2039
|
-
size = len + d2 * out->indent + nlen + 10;
|
2040
|
-
if (out->end - out->cur <= (long)size) {
|
2041
|
-
grow(out, size);
|
2042
|
-
}
|
2043
|
-
fill_indent(out, d2);
|
2044
|
-
*out->cur++ = '"';
|
2045
|
-
memcpy(out->cur, name, nlen);
|
2046
|
-
out->cur += nlen;
|
2047
|
-
*out->cur++ = '"';
|
2048
|
-
*out->cur++ = ':';
|
2049
|
-
memcpy(out->cur, s, len);
|
2050
|
-
out->cur += len;
|
2051
|
-
*out->cur = '\0';
|
2052
|
-
}
|
2053
|
-
} else {
|
2054
|
-
size = d2 * out->indent + 1;
|
2055
|
-
for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) {
|
2056
|
-
size_t nlen;
|
2057
|
-
|
2058
|
-
if (out->end - out->cur <= (long)size) {
|
2059
|
-
grow(out, size);
|
2060
|
-
}
|
2061
|
-
name = rb_id2name(*idp);
|
2062
|
-
nlen = strlen(name);
|
2063
|
-
if (0 != *fp) {
|
2064
|
-
v = (*fp)(obj);
|
2065
|
-
} else if (0 == strchr(name, '.')) {
|
2066
|
-
v = rb_funcall(obj, *idp, 0);
|
2067
|
-
} else {
|
2068
|
-
char nbuf[256];
|
2069
|
-
char *n2 = nbuf;
|
2070
|
-
char *n;
|
2071
|
-
char *end;
|
2072
|
-
ID i;
|
2073
|
-
|
2074
|
-
if (sizeof(nbuf) <= nlen) {
|
2075
|
-
n2 = strdup(name);
|
2076
|
-
} else {
|
2077
|
-
strcpy(n2, name);
|
2078
|
-
}
|
2079
|
-
n = n2;
|
2080
|
-
v = obj;
|
2081
|
-
while (0 != (end = strchr(n, '.'))) {
|
2082
|
-
*end = '\0';
|
2083
|
-
i = rb_intern(n);
|
2084
|
-
v = rb_funcall(v, i, 0);
|
2085
|
-
n = end + 1;
|
2086
|
-
}
|
2087
|
-
i = rb_intern(n);
|
2088
|
-
v = rb_funcall(v, i, 0);
|
2089
|
-
if (nbuf != n2) {
|
2090
|
-
free(n2);
|
2091
|
-
}
|
428
|
+
assure_size(out, 36);
|
429
|
+
if (9 > out->opts->sec_prec) {
|
430
|
+
int i;
|
431
|
+
|
432
|
+
// This is pretty lame but to be compatible with rails and active
|
433
|
+
// support rounding is not done but instead a floor is done when
|
434
|
+
// second precision is 3 just to be like rails. sigh.
|
435
|
+
if (3 == out->opts->sec_prec) {
|
436
|
+
nsec /= 1000000;
|
437
|
+
one = 1000;
|
438
|
+
} else {
|
439
|
+
for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
|
440
|
+
nsec = (nsec + 5) / 10;
|
441
|
+
one /= 10;
|
2092
442
|
}
|
2093
|
-
|
2094
|
-
|
2095
|
-
|
2096
|
-
dump_val(v, d2, out, 0, 0, true);
|
2097
|
-
if (out->end - out->cur <= 2) {
|
2098
|
-
grow(out, 2);
|
443
|
+
if (one <= nsec) {
|
444
|
+
nsec -= one;
|
445
|
+
sec++;
|
2099
446
|
}
|
2100
|
-
*out->cur++ = ',';
|
2101
447
|
}
|
2102
|
-
out->cur--;
|
2103
448
|
}
|
2104
|
-
|
2105
|
-
|
2106
|
-
|
2107
|
-
|
2108
|
-
|
2109
|
-
|
2110
|
-
|
2111
|
-
|
2112
|
-
|
2113
|
-
|
2114
|
-
|
2115
|
-
|
2116
|
-
|
2117
|
-
|
2118
|
-
|
449
|
+
// 2012-01-05T23:58:07.123456000+09:00
|
450
|
+
//tm = localtime(&sec);
|
451
|
+
sec += tzsecs;
|
452
|
+
tm = gmtime(&sec);
|
453
|
+
#if 1
|
454
|
+
if (0 > tzsecs) {
|
455
|
+
tzsign = '-';
|
456
|
+
tzhour = (int)(tzsecs / -3600);
|
457
|
+
tzmin = (int)(tzsecs / -60) - (tzhour * 60);
|
458
|
+
} else {
|
459
|
+
tzhour = (int)(tzsecs / 3600);
|
460
|
+
tzmin = (int)(tzsecs / 60) - (tzhour * 60);
|
461
|
+
}
|
462
|
+
#else
|
463
|
+
if (0 > tm->tm_gmtoff) {
|
464
|
+
tzsign = '-';
|
465
|
+
tzhour = (int)(tm->tm_gmtoff / -3600);
|
466
|
+
tzmin = (int)(tm->tm_gmtoff / -60) - (tzhour * 60);
|
467
|
+
} else {
|
468
|
+
tzhour = (int)(tm->tm_gmtoff / 3600);
|
469
|
+
tzmin = (int)(tm->tm_gmtoff / 60) - (tzhour * 60);
|
2119
470
|
}
|
2120
|
-
#ifdef OJ_DEBUG
|
2121
|
-
printf("Oj-debug: dump_val %s\n", rb_class2name(rb_obj_class(obj)));
|
2122
471
|
#endif
|
2123
|
-
|
2124
|
-
|
2125
|
-
|
2126
|
-
|
2127
|
-
|
2128
|
-
|
2129
|
-
|
2130
|
-
|
2131
|
-
|
2132
|
-
|
2133
|
-
|
2134
|
-
|
2135
|
-
case ObjectMode:
|
2136
|
-
default: dump_class_obj(obj, out); break;
|
2137
|
-
}
|
2138
|
-
break;
|
2139
|
-
case T_SYMBOL:
|
2140
|
-
switch (out->opts->mode) {
|
2141
|
-
case StrictMode: raise_strict(obj); break;
|
2142
|
-
case NullMode: dump_nil(out); break;
|
2143
|
-
case CompatMode: dump_sym_comp(obj, out); break;
|
2144
|
-
case ObjectMode:
|
2145
|
-
default: dump_sym_obj(obj, out); break;
|
472
|
+
if (0 == nsec || 0 == out->opts->sec_prec) {
|
473
|
+
if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
474
|
+
sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ",
|
475
|
+
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
476
|
+
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
477
|
+
oj_dump_cstr(buf, 20, 0, 0, out);
|
478
|
+
} else {
|
479
|
+
sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
|
480
|
+
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
481
|
+
tm->tm_hour, tm->tm_min, tm->tm_sec,
|
482
|
+
tzsign, tzhour, tzmin);
|
483
|
+
oj_dump_cstr(buf, 25, 0, 0, out);
|
2146
484
|
}
|
2147
|
-
|
2148
|
-
|
2149
|
-
|
2150
|
-
|
2151
|
-
|
2152
|
-
|
2153
|
-
|
2154
|
-
default: dump_struct_obj(obj, depth, out); break;
|
485
|
+
} else if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
486
|
+
char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ";
|
487
|
+
int len = 30;
|
488
|
+
|
489
|
+
if (9 > out->opts->sec_prec) {
|
490
|
+
format[32] = '0' + out->opts->sec_prec;
|
491
|
+
len -= 9 - out->opts->sec_prec;
|
2155
492
|
}
|
2156
|
-
|
2157
|
-
|
2158
|
-
|
2159
|
-
|
2160
|
-
|
2161
|
-
|
2162
|
-
|
2163
|
-
|
2164
|
-
|
2165
|
-
|
2166
|
-
|
2167
|
-
return;
|
2168
|
-
}
|
2169
|
-
switch (type) {
|
2170
|
-
case T_BIGNUM: dump_bignum(obj, out); break;
|
2171
|
-
case T_STRING:
|
2172
|
-
switch (out->opts->mode) {
|
2173
|
-
case StrictMode:
|
2174
|
-
case NullMode:
|
2175
|
-
case CompatMode: dump_str_comp(obj, out); break;
|
2176
|
-
case ObjectMode:
|
2177
|
-
default: dump_str_obj(obj, clas, depth, out); break;
|
2178
|
-
}
|
2179
|
-
break;
|
2180
|
-
case T_ARRAY: dump_array(obj, clas, depth, out); break;
|
2181
|
-
case T_HASH: dump_hash(obj, clas, depth, out->opts->mode, out); break;
|
2182
|
-
#if (defined T_RATIONAL && defined RRATIONAL)
|
2183
|
-
case T_RATIONAL:
|
2184
|
-
#endif
|
2185
|
-
case T_OBJECT:
|
2186
|
-
switch (out->opts->mode) {
|
2187
|
-
case StrictMode: dump_data_strict(obj, out); break;
|
2188
|
-
case NullMode: dump_data_null(obj, out); break;
|
2189
|
-
case CompatMode: dump_obj_comp(obj, depth, out, argc, argv, as_ok); break;
|
2190
|
-
case ObjectMode:
|
2191
|
-
default: dump_obj_obj(obj, depth, out); break;
|
2192
|
-
}
|
2193
|
-
break;
|
2194
|
-
case T_DATA:
|
2195
|
-
switch (out->opts->mode) {
|
2196
|
-
case StrictMode: dump_data_strict(obj, out); break;
|
2197
|
-
case NullMode: dump_data_null(obj, out); break;
|
2198
|
-
case CompatMode: dump_data_comp(obj, depth, out, argc, argv, as_ok);break;
|
2199
|
-
case ObjectMode:
|
2200
|
-
default: dump_data_obj(obj, depth, out); break;
|
2201
|
-
}
|
2202
|
-
break;
|
2203
|
-
#if (defined T_COMPLEX && defined RCOMPLEX)
|
2204
|
-
case T_COMPLEX:
|
2205
|
-
#endif
|
2206
|
-
case T_REGEXP:
|
2207
|
-
switch (out->opts->mode) {
|
2208
|
-
case StrictMode: raise_strict(obj); break;
|
2209
|
-
case NullMode: dump_nil(out); break;
|
2210
|
-
case CompatMode:
|
2211
|
-
case ObjectMode:
|
2212
|
-
default: dump_obj_comp(obj, depth, out, argc, argv, as_ok); break;
|
2213
|
-
}
|
2214
|
-
break;
|
2215
|
-
default:
|
2216
|
-
switch (out->opts->mode) {
|
2217
|
-
case StrictMode: raise_strict(obj); break;
|
2218
|
-
case NullMode: dump_nil(out); break;
|
2219
|
-
case CompatMode: {
|
2220
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
2221
|
-
dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
2222
|
-
break;
|
2223
|
-
}
|
2224
|
-
case ObjectMode:
|
2225
|
-
default:
|
2226
|
-
rb_raise(rb_eNotImpError, "Failed to dump '%s' Object (%02x)\n",
|
2227
|
-
rb_class2name(rb_obj_class(obj)), rb_type(obj));
|
2228
|
-
break;
|
2229
|
-
}
|
2230
|
-
break;
|
2231
|
-
}
|
493
|
+
sprintf(buf, format,
|
494
|
+
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
495
|
+
tm->tm_hour, tm->tm_min, tm->tm_sec, nsec);
|
496
|
+
oj_dump_cstr(buf, len, 0, 0, out);
|
497
|
+
} else {
|
498
|
+
char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
|
499
|
+
int len = 35;
|
500
|
+
|
501
|
+
if (9 > out->opts->sec_prec) {
|
502
|
+
format[32] = '0' + out->opts->sec_prec;
|
503
|
+
len -= 9 - out->opts->sec_prec;
|
2232
504
|
}
|
505
|
+
sprintf(buf, format,
|
506
|
+
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
507
|
+
tm->tm_hour, tm->tm_min, tm->tm_sec, nsec,
|
508
|
+
tzsign, tzhour, tzmin);
|
509
|
+
oj_dump_cstr(buf, len, 0, 0, out);
|
2233
510
|
}
|
2234
511
|
}
|
2235
512
|
|
@@ -2249,16 +526,26 @@ oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VA
|
|
2249
526
|
out->circ_cnt = 0;
|
2250
527
|
out->opts = copts;
|
2251
528
|
out->hash_cnt = 0;
|
529
|
+
out->indent = copts->indent;
|
530
|
+
out->argc = argc;
|
531
|
+
out->argv = argv;
|
2252
532
|
if (Yes == copts->circular) {
|
2253
533
|
oj_cache8_new(&out->circ_cache);
|
2254
534
|
}
|
2255
|
-
|
2256
|
-
|
535
|
+
switch (copts->mode) {
|
536
|
+
case StrictMode: oj_dump_strict_val(obj, 0, out); break;
|
537
|
+
case NullMode: oj_dump_null_val(obj, 0, out); break;
|
538
|
+
case ObjectMode: oj_dump_obj_val(obj, 0, out); break;
|
539
|
+
case CompatMode: oj_dump_compat_val(obj, 0, out, Yes == copts->to_json); break;
|
540
|
+
case RailsMode: oj_dump_rails_val(obj, 0, out, true); break;
|
541
|
+
case CustomMode: oj_dump_custom_val(obj, 0, out, true); break;
|
542
|
+
default: oj_dump_custom_val(obj, 0, out, true); break;
|
543
|
+
}
|
2257
544
|
if (0 < out->indent) {
|
2258
545
|
switch (*(out->cur - 1)) {
|
2259
546
|
case ']':
|
2260
547
|
case '}':
|
2261
|
-
|
548
|
+
assure_size(out, 1);
|
2262
549
|
*out->cur++ = '\n';
|
2263
550
|
default:
|
2264
551
|
break;
|
@@ -2288,7 +575,7 @@ oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
|
|
2288
575
|
if (out.allocated) {
|
2289
576
|
xfree(out.buf);
|
2290
577
|
}
|
2291
|
-
rb_raise(rb_eIOError, "%s
|
578
|
+
rb_raise(rb_eIOError, "%s", strerror(errno));
|
2292
579
|
}
|
2293
580
|
ok = (size == fwrite(out.buf, 1, size, f));
|
2294
581
|
if (out.allocated) {
|
@@ -2298,7 +585,7 @@ oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
|
|
2298
585
|
if (!ok) {
|
2299
586
|
int err = ferror(f);
|
2300
587
|
|
2301
|
-
rb_raise(rb_eIOError, "Write failed. [%d:%s]
|
588
|
+
rb_raise(rb_eIOError, "Write failed. [%d:%s]", err, strerror(err));
|
2302
589
|
}
|
2303
590
|
}
|
2304
591
|
|
@@ -2329,7 +616,7 @@ oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
|
2329
616
|
if (out.allocated) {
|
2330
617
|
xfree(out.buf);
|
2331
618
|
}
|
2332
|
-
rb_raise(rb_eIOError, "Write failed. [%d:%s]
|
619
|
+
rb_raise(rb_eIOError, "Write failed. [%d:%s]", errno, strerror(errno));
|
2333
620
|
}
|
2334
621
|
#endif
|
2335
622
|
} else if (rb_respond_to(stream, oj_write_id)) {
|
@@ -2345,427 +632,422 @@ oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
|
2345
632
|
}
|
2346
633
|
}
|
2347
634
|
|
2348
|
-
|
635
|
+
void
|
636
|
+
oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
|
637
|
+
#if HAS_ENCODING_SUPPORT
|
638
|
+
rb_encoding *enc = rb_to_encoding(rb_obj_encoding(obj));
|
2349
639
|
|
2350
|
-
|
2351
|
-
|
2352
|
-
if (out->end - out->cur <= (long)size) {
|
2353
|
-
grow(out, size);
|
640
|
+
if (rb_utf8_encoding() != enc) {
|
641
|
+
obj = rb_str_conv_enc(obj, enc, rb_utf8_encoding());
|
2354
642
|
}
|
2355
|
-
|
2356
|
-
|
2357
|
-
*out->cur = '\0';
|
643
|
+
#endif
|
644
|
+
oj_dump_cstr(rb_string_value_ptr((VALUE*)&obj), RSTRING_LEN(obj), 0, 0, out);
|
2358
645
|
}
|
2359
646
|
|
2360
|
-
|
2361
|
-
|
2362
|
-
|
2363
|
-
|
2364
|
-
|
2365
|
-
break;
|
2366
|
-
case RUBY_VAL:
|
2367
|
-
dump_cstr(rb_string_value_cstr(&leaf->value), (int)RSTRING_LEN(leaf->value), 0, 0, out);
|
2368
|
-
break;
|
2369
|
-
case COL_VAL:
|
2370
|
-
default:
|
2371
|
-
rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type);
|
2372
|
-
break;
|
2373
|
-
}
|
647
|
+
void
|
648
|
+
oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
|
649
|
+
const char *sym = rb_id2name(SYM2ID(obj));
|
650
|
+
|
651
|
+
oj_dump_cstr(sym, strlen(sym), 0, 0, out);
|
2374
652
|
}
|
2375
653
|
|
2376
|
-
|
2377
|
-
|
2378
|
-
|
2379
|
-
|
2380
|
-
|
654
|
+
void
|
655
|
+
oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
|
656
|
+
size_t size;
|
657
|
+
char *cmap;
|
658
|
+
|
659
|
+
switch (out->opts->escape_mode) {
|
660
|
+
case NLEsc:
|
661
|
+
cmap = newline_friendly_chars;
|
662
|
+
size = newline_friendly_size((uint8_t*)str, cnt);
|
2381
663
|
break;
|
2382
|
-
case
|
2383
|
-
|
2384
|
-
|
2385
|
-
} else {
|
2386
|
-
dump_fixnum(leaf->value, out);
|
2387
|
-
}
|
664
|
+
case ASCIIEsc:
|
665
|
+
cmap = ascii_friendly_chars;
|
666
|
+
size = ascii_friendly_size((uint8_t*)str, cnt);
|
2388
667
|
break;
|
2389
|
-
case
|
2390
|
-
|
2391
|
-
|
668
|
+
case XSSEsc:
|
669
|
+
cmap = xss_friendly_chars;
|
670
|
+
size = xss_friendly_size((uint8_t*)str, cnt);
|
2392
671
|
break;
|
2393
|
-
|
2394
|
-
|
2395
|
-
|
2396
|
-
static void
|
2397
|
-
dump_leaf_float(Leaf leaf, Out out) {
|
2398
|
-
switch (leaf->value_type) {
|
2399
|
-
case STR_VAL:
|
2400
|
-
dump_chars(leaf->str, strlen(leaf->str), out);
|
672
|
+
case JXEsc:
|
673
|
+
cmap = hixss_friendly_chars;
|
674
|
+
size = hixss_friendly_size((uint8_t*)str, cnt);
|
2401
675
|
break;
|
2402
|
-
case
|
2403
|
-
|
676
|
+
case RailsEsc:
|
677
|
+
cmap = rails_friendly_chars;
|
678
|
+
size = rails_friendly_size((uint8_t*)str, cnt);
|
2404
679
|
break;
|
2405
|
-
case
|
680
|
+
case JSONEsc:
|
2406
681
|
default:
|
2407
|
-
|
2408
|
-
|
682
|
+
cmap = hibit_friendly_chars;
|
683
|
+
size = hibit_friendly_size((uint8_t*)str, cnt);
|
2409
684
|
}
|
2410
|
-
|
2411
|
-
|
2412
|
-
static void
|
2413
|
-
dump_leaf_array(Leaf leaf, int depth, Out out) {
|
2414
|
-
size_t size;
|
2415
|
-
int d2 = depth + 1;
|
685
|
+
assure_size(out, size + BUFFER_EXTRA);
|
686
|
+
*out->cur++ = '"';
|
2416
687
|
|
2417
|
-
|
2418
|
-
|
2419
|
-
|
688
|
+
if (escape1) {
|
689
|
+
*out->cur++ = '\\';
|
690
|
+
*out->cur++ = 'u';
|
691
|
+
*out->cur++ = '0';
|
692
|
+
*out->cur++ = '0';
|
693
|
+
dump_hex((uint8_t)*str, out);
|
694
|
+
cnt--;
|
695
|
+
size--;
|
696
|
+
str++;
|
697
|
+
is_sym = 0; // just to make sure
|
2420
698
|
}
|
2421
|
-
|
2422
|
-
|
2423
|
-
|
2424
|
-
} else {
|
2425
|
-
Leaf first = leaf->elements->next;
|
2426
|
-
Leaf e = first;
|
2427
|
-
|
2428
|
-
size = d2 * out->indent + 2;
|
2429
|
-
do {
|
2430
|
-
if (out->end - out->cur <= (long)size) {
|
2431
|
-
grow(out, size);
|
2432
|
-
}
|
2433
|
-
fill_indent(out, d2);
|
2434
|
-
dump_leaf(e, d2, out);
|
2435
|
-
if (e->next != first) {
|
2436
|
-
*out->cur++ = ',';
|
2437
|
-
}
|
2438
|
-
e = e->next;
|
2439
|
-
} while (e != first);
|
2440
|
-
size = depth * out->indent + 1;
|
2441
|
-
if (out->end - out->cur <= (long)size) {
|
2442
|
-
grow(out, size);
|
699
|
+
if (cnt == size) {
|
700
|
+
if (is_sym) {
|
701
|
+
*out->cur++ = ':';
|
2443
702
|
}
|
2444
|
-
|
2445
|
-
|
2446
|
-
|
2447
|
-
|
2448
|
-
}
|
2449
|
-
|
2450
|
-
static void
|
2451
|
-
dump_leaf_hash(Leaf leaf, int depth, Out out) {
|
2452
|
-
size_t size;
|
2453
|
-
int d2 = depth + 1;
|
2454
|
-
|
2455
|
-
size = 2;
|
2456
|
-
if (out->end - out->cur <= (long)size) {
|
2457
|
-
grow(out, size);
|
2458
|
-
}
|
2459
|
-
*out->cur++ = '{';
|
2460
|
-
if (0 == leaf->elements) {
|
2461
|
-
*out->cur++ = '}';
|
703
|
+
for (; '\0' != *str; str++) {
|
704
|
+
*out->cur++ = *str;
|
705
|
+
}
|
706
|
+
*out->cur++ = '"';
|
2462
707
|
} else {
|
2463
|
-
|
2464
|
-
Leaf e = first;
|
708
|
+
const char *end = str + cnt;
|
2465
709
|
|
2466
|
-
|
2467
|
-
do {
|
2468
|
-
if (out->end - out->cur <= (long)size) {
|
2469
|
-
grow(out, size);
|
2470
|
-
}
|
2471
|
-
fill_indent(out, d2);
|
2472
|
-
dump_cstr(e->key, strlen(e->key), 0, 0, out);
|
710
|
+
if (is_sym) {
|
2473
711
|
*out->cur++ = ':';
|
2474
|
-
dump_leaf(e, d2, out);
|
2475
|
-
if (e->next != first) {
|
2476
|
-
*out->cur++ = ',';
|
2477
|
-
}
|
2478
|
-
e = e->next;
|
2479
|
-
} while (e != first);
|
2480
|
-
size = depth * out->indent + 1;
|
2481
|
-
if (out->end - out->cur <= (long)size) {
|
2482
|
-
grow(out, size);
|
2483
712
|
}
|
2484
|
-
|
2485
|
-
|
2486
|
-
|
2487
|
-
|
2488
|
-
|
2489
|
-
|
2490
|
-
|
2491
|
-
|
2492
|
-
|
2493
|
-
|
2494
|
-
|
2495
|
-
break;
|
2496
|
-
|
2497
|
-
|
2498
|
-
break;
|
2499
|
-
|
2500
|
-
|
2501
|
-
|
2502
|
-
|
2503
|
-
|
2504
|
-
|
2505
|
-
|
2506
|
-
|
2507
|
-
|
2508
|
-
|
2509
|
-
|
2510
|
-
|
2511
|
-
|
2512
|
-
|
2513
|
-
|
2514
|
-
|
2515
|
-
|
2516
|
-
|
2517
|
-
|
2518
|
-
|
2519
|
-
|
2520
|
-
|
2521
|
-
}
|
2522
|
-
|
2523
|
-
|
2524
|
-
oj_dump_leaf_to_json(Leaf leaf, Options copts, Out out) {
|
2525
|
-
if (0 == out->buf) {
|
2526
|
-
out->buf = ALLOC_N(char, 4096);
|
2527
|
-
out->end = out->buf + 4095 - BUFFER_EXTRA; // 1 less than end plus extra for possible errors
|
2528
|
-
out->allocated = 1;
|
2529
|
-
}
|
2530
|
-
out->cur = out->buf;
|
2531
|
-
out->circ_cnt = 0;
|
2532
|
-
out->opts = copts;
|
2533
|
-
out->hash_cnt = 0;
|
2534
|
-
out->indent = copts->indent;
|
2535
|
-
dump_leaf(leaf, 0, out);
|
2536
|
-
}
|
2537
|
-
|
2538
|
-
void
|
2539
|
-
oj_write_leaf_to_file(Leaf leaf, const char *path, Options copts) {
|
2540
|
-
char buf[4096];
|
2541
|
-
struct _Out out;
|
2542
|
-
size_t size;
|
2543
|
-
FILE *f;
|
2544
|
-
|
2545
|
-
out.buf = buf;
|
2546
|
-
out.end = buf + sizeof(buf) - BUFFER_EXTRA;
|
2547
|
-
out.allocated = 0;
|
2548
|
-
out.omit_nil = copts->dump_opts.omit_nil;
|
2549
|
-
oj_dump_leaf_to_json(leaf, copts, &out);
|
2550
|
-
size = out.cur - out.buf;
|
2551
|
-
if (0 == (f = fopen(path, "w"))) {
|
2552
|
-
rb_raise(rb_eIOError, "%s\n", strerror(errno));
|
2553
|
-
}
|
2554
|
-
if (size != fwrite(out.buf, 1, size, f)) {
|
2555
|
-
int err = ferror(f);
|
2556
|
-
|
2557
|
-
rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", err, strerror(err));
|
713
|
+
for (; str < end; str++) {
|
714
|
+
switch (cmap[(uint8_t)*str]) {
|
715
|
+
case '1':
|
716
|
+
*out->cur++ = *str;
|
717
|
+
break;
|
718
|
+
case '2':
|
719
|
+
*out->cur++ = '\\';
|
720
|
+
switch (*str) {
|
721
|
+
case '\\': *out->cur++ = '\\'; break;
|
722
|
+
case '\b': *out->cur++ = 'b'; break;
|
723
|
+
case '\t': *out->cur++ = 't'; break;
|
724
|
+
case '\n': *out->cur++ = 'n'; break;
|
725
|
+
case '\f': *out->cur++ = 'f'; break;
|
726
|
+
case '\r': *out->cur++ = 'r'; break;
|
727
|
+
default: *out->cur++ = *str; break;
|
728
|
+
}
|
729
|
+
break;
|
730
|
+
case '3': // Unicode
|
731
|
+
if (0xe2 == (uint8_t)*str && JXEsc == out->opts->escape_mode && 2 <= end - str) {
|
732
|
+
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
733
|
+
str = dump_unicode(str, end, out);
|
734
|
+
} else {
|
735
|
+
*out->cur++ = *str;
|
736
|
+
}
|
737
|
+
break;
|
738
|
+
}
|
739
|
+
str = dump_unicode(str, end, out);
|
740
|
+
break;
|
741
|
+
case '6': // control characters
|
742
|
+
*out->cur++ = '\\';
|
743
|
+
*out->cur++ = 'u';
|
744
|
+
*out->cur++ = '0';
|
745
|
+
*out->cur++ = '0';
|
746
|
+
dump_hex((uint8_t)*str, out);
|
747
|
+
break;
|
748
|
+
default:
|
749
|
+
break; // ignore, should never happen if the table is correct
|
750
|
+
}
|
751
|
+
}
|
752
|
+
*out->cur++ = '"';
|
2558
753
|
}
|
2559
|
-
if (out
|
2560
|
-
|
754
|
+
if (JXEsc == out->opts->escape_mode && 0 != (0x80 & *(str - 1))) {
|
755
|
+
uint8_t c = (uint8_t)*(str - 1);
|
756
|
+
int i;
|
757
|
+
|
758
|
+
// Last utf-8 characters must be 0x10xxxxxx. The start must be
|
759
|
+
// 0x110xxxxx for 2 characters, 0x1110xxxx for 3, and 0x11110xxx for
|
760
|
+
// 4.
|
761
|
+
if (0 != (0x40 & c)) {
|
762
|
+
rb_raise(oj_json_generator_error_class, "Partial character in string. 1");
|
763
|
+
}
|
764
|
+
for (i = 1; i < (int)cnt && i < 4; i++) {
|
765
|
+
c = str[-1 - i];
|
766
|
+
if (0x80 != (0xC0 & c)) {
|
767
|
+
switch (i) {
|
768
|
+
case 1:
|
769
|
+
if (0xC0 != (0xE0 & c)) {
|
770
|
+
rb_raise(oj_json_generator_error_class, "Partial character in string.");
|
771
|
+
}
|
772
|
+
break;
|
773
|
+
case 2:
|
774
|
+
if (0xE0 != (0xF0 & c)) {
|
775
|
+
rb_raise(oj_json_generator_error_class, "Partial character in string. 2");
|
776
|
+
}
|
777
|
+
break;
|
778
|
+
case 3:
|
779
|
+
if (0xF0 != (0xF8 & c)) {
|
780
|
+
rb_raise(oj_json_generator_error_class, "Partial character in string.");
|
781
|
+
}
|
782
|
+
break;
|
783
|
+
default: // can't get here
|
784
|
+
break;
|
785
|
+
}
|
786
|
+
break;
|
787
|
+
}
|
788
|
+
}
|
789
|
+
if (i == (int)cnt || 4 <= i) {
|
790
|
+
rb_raise(oj_json_generator_error_class, "Partial character in string.");
|
791
|
+
}
|
2561
792
|
}
|
2562
|
-
|
793
|
+
*out->cur = '\0';
|
2563
794
|
}
|
2564
795
|
|
2565
|
-
|
2566
|
-
|
2567
|
-
|
2568
|
-
key_check(StrWriter sw, const char *key) {
|
2569
|
-
DumpType type = sw->types[sw->depth];
|
796
|
+
void
|
797
|
+
oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) {
|
798
|
+
const char *s = rb_class2name(obj);
|
2570
799
|
|
2571
|
-
|
2572
|
-
rb_raise(rb_eStandardError, "Can not push onto an Object without a key.");
|
2573
|
-
}
|
800
|
+
oj_dump_cstr(s, strlen(s), 0, 0, out);
|
2574
801
|
}
|
2575
802
|
|
2576
|
-
|
2577
|
-
|
2578
|
-
|
2579
|
-
size_t size = (sw->types_end - sw->types) * 2;
|
803
|
+
void
|
804
|
+
oj_dump_obj_to_s(VALUE obj, Out out) {
|
805
|
+
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
2580
806
|
|
2581
|
-
|
2582
|
-
sw->types_end = sw->types + size;
|
2583
|
-
}
|
2584
|
-
sw->depth++;
|
2585
|
-
sw->types[sw->depth] = type;
|
807
|
+
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
2586
808
|
}
|
2587
809
|
|
2588
|
-
|
2589
|
-
|
2590
|
-
|
2591
|
-
|
2592
|
-
|
2593
|
-
|
2594
|
-
case ArrayNew:
|
2595
|
-
sw->types[sw->depth] = ArrayType;
|
2596
|
-
break;
|
2597
|
-
case ObjectType:
|
2598
|
-
case ArrayType:
|
2599
|
-
// Always have a few characters available in the out.buf.
|
2600
|
-
*sw->out.cur++ = ',';
|
2601
|
-
break;
|
2602
|
-
}
|
810
|
+
void
|
811
|
+
oj_dump_raw(const char *str, size_t cnt, Out out) {
|
812
|
+
assure_size(out, cnt + 10);
|
813
|
+
memcpy(out->cur, str, cnt);
|
814
|
+
out->cur += cnt;
|
815
|
+
*out->cur = '\0';
|
2603
816
|
}
|
2604
817
|
|
2605
818
|
void
|
2606
|
-
|
2607
|
-
|
2608
|
-
long
|
2609
|
-
|
2610
|
-
|
2611
|
-
|
2612
|
-
|
2613
|
-
|
2614
|
-
rb_raise(rb_eStandardError, "Can only push a key onto an Object.");
|
819
|
+
oj_grow_out(Out out, size_t len) {
|
820
|
+
size_t size = out->end - out->buf;
|
821
|
+
long pos = out->cur - out->buf;
|
822
|
+
char *buf;
|
823
|
+
|
824
|
+
size *= 2;
|
825
|
+
if (size <= len * 2 + pos) {
|
826
|
+
size += len;
|
2615
827
|
}
|
2616
|
-
|
2617
|
-
|
2618
|
-
|
828
|
+
if (out->allocated) {
|
829
|
+
buf = REALLOC_N(out->buf, char, (size + BUFFER_EXTRA));
|
830
|
+
} else {
|
831
|
+
buf = ALLOC_N(char, (size + BUFFER_EXTRA));
|
832
|
+
out->allocated = 1;
|
833
|
+
memcpy(buf, out->buf, out->end - out->buf + BUFFER_EXTRA);
|
2619
834
|
}
|
2620
|
-
|
2621
|
-
|
2622
|
-
fill_indent(&sw->out, sw->depth);
|
835
|
+
if (0 == buf) {
|
836
|
+
rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]", ENOSPC, strerror(ENOSPC));
|
2623
837
|
}
|
2624
|
-
|
2625
|
-
|
2626
|
-
|
838
|
+
out->buf = buf;
|
839
|
+
out->end = buf + size;
|
840
|
+
out->cur = out->buf + pos;
|
2627
841
|
}
|
2628
842
|
|
2629
843
|
void
|
2630
|
-
|
2631
|
-
|
2632
|
-
|
2633
|
-
|
2634
|
-
|
2635
|
-
|
2636
|
-
|
2637
|
-
|
844
|
+
oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok) {
|
845
|
+
assure_size(out, 4);
|
846
|
+
*out->cur++ = 'n';
|
847
|
+
*out->cur++ = 'u';
|
848
|
+
*out->cur++ = 'l';
|
849
|
+
*out->cur++ = 'l';
|
850
|
+
*out->cur = '\0';
|
851
|
+
}
|
2638
852
|
|
2639
|
-
|
2640
|
-
|
2641
|
-
|
2642
|
-
|
2643
|
-
|
2644
|
-
|
2645
|
-
|
2646
|
-
|
2647
|
-
}
|
2648
|
-
if (0 != key) {
|
2649
|
-
dump_cstr(key, strlen(key), 0, 0, &sw->out);
|
2650
|
-
*sw->out.cur++ = ':';
|
2651
|
-
}
|
2652
|
-
}
|
2653
|
-
*sw->out.cur++ = '{';
|
2654
|
-
push_type(sw, ObjectNew);
|
853
|
+
void
|
854
|
+
oj_dump_true(VALUE obj, int depth, Out out, bool as_ok) {
|
855
|
+
assure_size(out, 4);
|
856
|
+
*out->cur++ = 't';
|
857
|
+
*out->cur++ = 'r';
|
858
|
+
*out->cur++ = 'u';
|
859
|
+
*out->cur++ = 'e';
|
860
|
+
*out->cur = '\0';
|
2655
861
|
}
|
2656
862
|
|
2657
863
|
void
|
2658
|
-
|
2659
|
-
|
2660
|
-
|
2661
|
-
|
2662
|
-
|
2663
|
-
|
2664
|
-
|
2665
|
-
|
864
|
+
oj_dump_false(VALUE obj, int depth, Out out, bool as_ok) {
|
865
|
+
assure_size(out, 5);
|
866
|
+
*out->cur++ = 'f';
|
867
|
+
*out->cur++ = 'a';
|
868
|
+
*out->cur++ = 'l';
|
869
|
+
*out->cur++ = 's';
|
870
|
+
*out->cur++ = 'e';
|
871
|
+
*out->cur = '\0';
|
872
|
+
}
|
2666
873
|
|
2667
|
-
|
2668
|
-
|
2669
|
-
|
2670
|
-
|
2671
|
-
|
2672
|
-
|
2673
|
-
|
2674
|
-
|
874
|
+
void
|
875
|
+
oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
|
876
|
+
char buf[32];
|
877
|
+
char *b = buf + sizeof(buf) - 1;
|
878
|
+
long long num = rb_num2ll(obj);
|
879
|
+
int neg = 0;
|
880
|
+
|
881
|
+
if (0 > num) {
|
882
|
+
neg = 1;
|
883
|
+
num = -num;
|
884
|
+
}
|
885
|
+
*b-- = '\0';
|
886
|
+
if (0 < num) {
|
887
|
+
for (; 0 < num; num /= 10, b--) {
|
888
|
+
*b = (num % 10) + '0';
|
2675
889
|
}
|
2676
|
-
if (
|
2677
|
-
|
2678
|
-
|
890
|
+
if (neg) {
|
891
|
+
*b = '-';
|
892
|
+
} else {
|
893
|
+
b++;
|
2679
894
|
}
|
895
|
+
} else {
|
896
|
+
*b = '0';
|
2680
897
|
}
|
2681
|
-
|
2682
|
-
|
898
|
+
assure_size(out, (sizeof(buf) - (b - buf)));
|
899
|
+
for (; '\0' != *b; b++) {
|
900
|
+
*out->cur++ = *b;
|
901
|
+
}
|
902
|
+
*out->cur = '\0';
|
2683
903
|
}
|
2684
904
|
|
2685
905
|
void
|
2686
|
-
|
2687
|
-
|
2688
|
-
|
2689
|
-
} else {
|
2690
|
-
long size;
|
906
|
+
oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
907
|
+
volatile VALUE rs = rb_big2str(obj, 10);
|
908
|
+
int cnt = (int)RSTRING_LEN(rs);
|
2691
909
|
|
2692
|
-
|
2693
|
-
|
2694
|
-
|
2695
|
-
|
2696
|
-
}
|
2697
|
-
maybe_comma(sw);
|
2698
|
-
if (0 < sw->depth) {
|
2699
|
-
fill_indent(&sw->out, sw->depth);
|
2700
|
-
}
|
2701
|
-
if (0 != key) {
|
2702
|
-
dump_cstr(key, strlen(key), 0, 0, &sw->out);
|
2703
|
-
*sw->out.cur++ = ':';
|
2704
|
-
}
|
2705
|
-
}
|
2706
|
-
dump_val(val, sw->depth, &sw->out, 0, 0, true);
|
910
|
+
assure_size(out, cnt);
|
911
|
+
memcpy(out->cur, rb_string_value_ptr((VALUE*)&rs), cnt);
|
912
|
+
out->cur += cnt;
|
913
|
+
*out->cur = '\0';
|
2707
914
|
}
|
2708
915
|
|
916
|
+
// Removed dependencies on math due to problems with CentOS 5.4.
|
2709
917
|
void
|
2710
|
-
|
2711
|
-
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
918
|
+
oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
919
|
+
char buf[64];
|
920
|
+
char *b;
|
921
|
+
double d = rb_num2dbl(obj);
|
922
|
+
int cnt = 0;
|
2715
923
|
|
2716
|
-
|
2717
|
-
|
2718
|
-
|
2719
|
-
|
924
|
+
if (0.0 == d) {
|
925
|
+
b = buf;
|
926
|
+
*b++ = '0';
|
927
|
+
*b++ = '.';
|
928
|
+
*b++ = '0';
|
929
|
+
*b++ = '\0';
|
930
|
+
cnt = 3;
|
931
|
+
} else if (OJ_INFINITY == d) {
|
932
|
+
if (ObjectMode == out->opts->mode) {
|
933
|
+
strcpy(buf, inf_val);
|
934
|
+
cnt = sizeof(inf_val) - 1;
|
935
|
+
} else {
|
936
|
+
NanDump nd = out->opts->dump_opts.nan_dump;
|
937
|
+
|
938
|
+
if (AutoNan == nd) {
|
939
|
+
switch (out->opts->mode) {
|
940
|
+
case CompatMode: nd = WordNan; break;
|
941
|
+
case StrictMode: nd = RaiseNan; break;
|
942
|
+
case NullMode: nd = NullNan; break;
|
943
|
+
case CustomMode: nd = NullNan; break;
|
944
|
+
default: break;
|
945
|
+
}
|
946
|
+
}
|
947
|
+
switch (nd) {
|
948
|
+
case RaiseNan:
|
949
|
+
raise_strict(obj);
|
950
|
+
break;
|
951
|
+
case WordNan:
|
952
|
+
strcpy(buf, "Infinity");
|
953
|
+
cnt = 8;
|
954
|
+
break;
|
955
|
+
case NullNan:
|
956
|
+
strcpy(buf, "null");
|
957
|
+
cnt = 4;
|
958
|
+
break;
|
959
|
+
case HugeNan:
|
960
|
+
default:
|
961
|
+
strcpy(buf, inf_val);
|
962
|
+
cnt = sizeof(inf_val) - 1;
|
963
|
+
break;
|
964
|
+
}
|
2720
965
|
}
|
2721
|
-
|
2722
|
-
if (
|
2723
|
-
|
966
|
+
} else if (-OJ_INFINITY == d) {
|
967
|
+
if (ObjectMode == out->opts->mode) {
|
968
|
+
strcpy(buf, ninf_val);
|
969
|
+
cnt = sizeof(ninf_val) - 1;
|
970
|
+
} else {
|
971
|
+
NanDump nd = out->opts->dump_opts.nan_dump;
|
972
|
+
|
973
|
+
if (AutoNan == nd) {
|
974
|
+
switch (out->opts->mode) {
|
975
|
+
case CompatMode: nd = WordNan; break;
|
976
|
+
case StrictMode: nd = RaiseNan; break;
|
977
|
+
case NullMode: nd = NullNan; break;
|
978
|
+
default: break;
|
979
|
+
}
|
980
|
+
}
|
981
|
+
switch (nd) {
|
982
|
+
case RaiseNan:
|
983
|
+
raise_strict(obj);
|
984
|
+
break;
|
985
|
+
case WordNan:
|
986
|
+
strcpy(buf, "-Infinity");
|
987
|
+
cnt = 9;
|
988
|
+
break;
|
989
|
+
case NullNan:
|
990
|
+
strcpy(buf, "null");
|
991
|
+
cnt = 4;
|
992
|
+
break;
|
993
|
+
case HugeNan:
|
994
|
+
default:
|
995
|
+
strcpy(buf, ninf_val);
|
996
|
+
cnt = sizeof(ninf_val) - 1;
|
997
|
+
break;
|
998
|
+
}
|
2724
999
|
}
|
2725
|
-
|
2726
|
-
|
2727
|
-
|
1000
|
+
} else if (isnan(d)) {
|
1001
|
+
if (ObjectMode == out->opts->mode) {
|
1002
|
+
strcpy(buf, nan_val);
|
1003
|
+
cnt = sizeof(ninf_val) - 1;
|
1004
|
+
} else {
|
1005
|
+
NanDump nd = out->opts->dump_opts.nan_dump;
|
1006
|
+
|
1007
|
+
if (AutoNan == nd) {
|
1008
|
+
switch (out->opts->mode) {
|
1009
|
+
case ObjectMode: nd = HugeNan; break;
|
1010
|
+
case StrictMode: nd = RaiseNan; break;
|
1011
|
+
case NullMode: nd = NullNan; break;
|
1012
|
+
default: break;
|
1013
|
+
}
|
1014
|
+
}
|
1015
|
+
switch (nd) {
|
1016
|
+
case RaiseNan:
|
1017
|
+
raise_strict(obj);
|
1018
|
+
break;
|
1019
|
+
case WordNan:
|
1020
|
+
strcpy(buf, "NaN");
|
1021
|
+
cnt = 3;
|
1022
|
+
break;
|
1023
|
+
case NullNan:
|
1024
|
+
strcpy(buf, "null");
|
1025
|
+
cnt = 4;
|
1026
|
+
break;
|
1027
|
+
case HugeNan:
|
1028
|
+
default:
|
1029
|
+
strcpy(buf, nan_val);
|
1030
|
+
cnt = sizeof(nan_val) - 1;
|
1031
|
+
break;
|
1032
|
+
}
|
2728
1033
|
}
|
2729
|
-
}
|
2730
|
-
|
2731
|
-
}
|
2732
|
-
|
2733
|
-
void
|
2734
|
-
oj_str_writer_pop(StrWriter sw) {
|
2735
|
-
long size;
|
2736
|
-
DumpType type = sw->types[sw->depth];
|
1034
|
+
} else if (d == (double)(long long int)d) {
|
1035
|
+
cnt = snprintf(buf, sizeof(buf), "%.1f", d);
|
1036
|
+
} else if (0 == out->opts->float_prec) {
|
1037
|
+
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
2737
1038
|
|
2738
|
-
|
2739
|
-
|
2740
|
-
|
2741
|
-
|
2742
|
-
|
2743
|
-
|
2744
|
-
|
2745
|
-
|
2746
|
-
size = sw->depth * sw->out.indent + 2;
|
2747
|
-
if (sw->out.end - sw->out.cur <= size) {
|
2748
|
-
grow(&sw->out, size);
|
2749
|
-
}
|
2750
|
-
fill_indent(&sw->out, sw->depth);
|
2751
|
-
switch (type) {
|
2752
|
-
case ObjectNew:
|
2753
|
-
case ObjectType:
|
2754
|
-
*sw->out.cur++ = '}';
|
2755
|
-
break;
|
2756
|
-
case ArrayNew:
|
2757
|
-
case ArrayType:
|
2758
|
-
*sw->out.cur++ = ']';
|
2759
|
-
break;
|
2760
|
-
}
|
2761
|
-
if (0 == sw->depth && 0 <= sw->out.indent) {
|
2762
|
-
*sw->out.cur++ = '\n';
|
1039
|
+
cnt = RSTRING_LEN(rstr);
|
1040
|
+
if ((int)sizeof(buf) <= cnt) {
|
1041
|
+
cnt = sizeof(buf) - 1;
|
1042
|
+
}
|
1043
|
+
strncpy(buf, rb_string_value_ptr((VALUE*)&rstr), cnt);
|
1044
|
+
buf[cnt] = '\0';
|
1045
|
+
} else {
|
1046
|
+
cnt = snprintf(buf, sizeof(buf), out->opts->float_fmt, d);
|
2763
1047
|
}
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2767
|
-
oj_str_writer_pop_all(StrWriter sw) {
|
2768
|
-
while (0 < sw->depth) {
|
2769
|
-
oj_str_writer_pop(sw);
|
1048
|
+
assure_size(out, cnt);
|
1049
|
+
for (b = buf; '\0' != *b; b++) {
|
1050
|
+
*out->cur++ = *b;
|
2770
1051
|
}
|
1052
|
+
*out->cur = '\0';
|
2771
1053
|
}
|