oj 2.0.0 → 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 +7 -0
- data/LICENSE +17 -23
- data/README.md +74 -425
- data/ext/oj/buf.h +103 -0
- data/ext/oj/cache8.c +4 -0
- data/ext/oj/circarray.c +68 -0
- data/ext/oj/circarray.h +23 -0
- data/ext/oj/code.c +227 -0
- data/ext/oj/code.h +40 -0
- data/ext/oj/compat.c +243 -0
- data/ext/oj/custom.c +1097 -0
- data/ext/oj/dump.c +766 -1534
- 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/encode.h +51 -0
- data/ext/oj/err.c +57 -0
- data/ext/oj/err.h +70 -0
- data/ext/oj/extconf.rb +17 -7
- data/ext/oj/fast.c +213 -180
- data/ext/oj/hash.c +163 -0
- data/ext/oj/hash.h +46 -0
- data/ext/oj/hash_test.c +512 -0
- 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 +752 -0
- data/ext/oj/odd.c +230 -0
- data/ext/oj/odd.h +44 -0
- data/ext/oj/oj.c +1288 -929
- data/ext/oj/oj.h +240 -69
- data/ext/oj/parse.c +1014 -0
- data/ext/oj/parse.h +92 -0
- data/ext/oj/reader.c +223 -0
- data/ext/oj/reader.h +151 -0
- data/ext/oj/resolve.c +127 -0
- data/ext/oj/{cache.h → resolve.h} +6 -13
- data/ext/oj/rxclass.c +133 -0
- data/ext/oj/rxclass.h +27 -0
- data/ext/oj/saj.c +77 -175
- data/ext/oj/scp.c +224 -0
- data/ext/oj/sparse.c +911 -0
- data/ext/oj/stream_writer.c +301 -0
- data/ext/oj/strict.c +162 -0
- data/ext/oj/string_writer.c +480 -0
- data/ext/oj/val_stack.c +98 -0
- data/ext/oj/val_stack.h +188 -0
- data/lib/oj/active_support_helper.rb +41 -0
- data/lib/oj/bag.rb +6 -10
- data/lib/oj/easy_hash.rb +52 -0
- data/lib/oj/json.rb +172 -0
- data/lib/oj/mimic.rb +260 -5
- data/lib/oj/saj.rb +13 -10
- data/lib/oj/schandler.rb +142 -0
- data/lib/oj/state.rb +131 -0
- data/lib/oj/version.rb +1 -1
- data/lib/oj.rb +11 -23
- 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/_test_active.rb +76 -0
- data/test/_test_active_mimic.rb +96 -0
- data/test/_test_mimic_rails.rb +126 -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/helper.rb +27 -0
- data/test/isolated/shared.rb +310 -0
- data/test/isolated/test_mimic_after.rb +13 -0
- data/test/isolated/test_mimic_alone.rb +12 -0
- data/test/isolated/test_mimic_as_json.rb +45 -0
- data/test/isolated/test_mimic_before.rb +13 -0
- data/test/isolated/test_mimic_define.rb +28 -0
- data/test/isolated/test_mimic_rails_after.rb +22 -0
- data/test/isolated/test_mimic_rails_before.rb +21 -0
- data/test/isolated/test_mimic_redefine.rb +15 -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 +130 -0
- data/test/perf_fast.rb +9 -9
- data/test/perf_file.rb +64 -0
- data/test/{perf_obj.rb → perf_object.rb} +24 -10
- data/test/perf_scp.rb +151 -0
- data/test/perf_strict.rb +32 -113
- data/test/sample.rb +2 -3
- data/test/test_compat.rb +474 -0
- data/test/test_custom.rb +355 -0
- data/test/test_debian.rb +53 -0
- data/test/test_fast.rb +66 -16
- data/test/test_file.rb +237 -0
- data/test/test_gc.rb +49 -0
- data/test/test_hash.rb +29 -0
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +1010 -0
- data/test/test_saj.rb +16 -16
- data/test/test_scp.rb +417 -0
- data/test/test_strict.rb +410 -0
- data/test/test_various.rb +815 -0
- data/test/test_writer.rb +308 -0
- data/test/tests.rb +9 -902
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- metadata +253 -38
- data/ext/oj/cache.c +0 -148
- data/ext/oj/foo.rb +0 -6
- data/ext/oj/load.c +0 -1049
- data/test/a.rb +0 -38
- data/test/perf1.rb +0 -64
- data/test/perf2.rb +0 -76
- data/test/perf_obj_old.rb +0 -213
- data/test/test_mimic.rb +0 -208
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>
|
|
@@ -37,91 +12,43 @@
|
|
|
37
12
|
#include <stdio.h>
|
|
38
13
|
#include <string.h>
|
|
39
14
|
#include <math.h>
|
|
15
|
+
#include <unistd.h>
|
|
16
|
+
#include <errno.h>
|
|
40
17
|
|
|
41
18
|
#include "oj.h"
|
|
42
19
|
#include "cache8.h"
|
|
20
|
+
#include "dump.h"
|
|
21
|
+
#include "odd.h"
|
|
43
22
|
|
|
44
|
-
|
|
45
|
-
#define
|
|
46
|
-
#endif
|
|
23
|
+
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
|
24
|
+
#define OJ_INFINITY (1.0/0.0)
|
|
47
25
|
|
|
48
|
-
|
|
49
|
-
#ifndef INFINITY
|
|
50
|
-
#define INFINITY (1.0/0.0)
|
|
51
|
-
#endif
|
|
52
|
-
|
|
26
|
+
#define MAX_DEPTH 1000
|
|
53
27
|
|
|
54
|
-
|
|
28
|
+
static const char inf_val[] = INF_VAL;
|
|
29
|
+
static const char ninf_val[] = NINF_VAL;
|
|
30
|
+
static const char nan_val[] = NAN_VAL;
|
|
55
31
|
|
|
56
|
-
typedef
|
|
57
|
-
char *buf;
|
|
58
|
-
char *end;
|
|
59
|
-
char *cur;
|
|
60
|
-
Cache8 circ_cache;
|
|
61
|
-
slot_t circ_cnt;
|
|
62
|
-
int indent;
|
|
63
|
-
int depth; // used by dump_hash
|
|
64
|
-
Options opts;
|
|
65
|
-
uint32_t hash_cnt;
|
|
66
|
-
} *Out;
|
|
67
|
-
|
|
68
|
-
static void dump_obj_to_json(VALUE obj, Options copts, Out out);
|
|
69
|
-
static void raise_strict(VALUE obj);
|
|
70
|
-
static void dump_val(VALUE obj, int depth, Out out);
|
|
71
|
-
static void dump_nil(Out out);
|
|
72
|
-
static void dump_true(Out out);
|
|
73
|
-
static void dump_false(Out out);
|
|
74
|
-
static void dump_fixnum(VALUE obj, Out out);
|
|
75
|
-
static void dump_bignum(VALUE obj, Out out);
|
|
76
|
-
static void dump_float(VALUE obj, Out out);
|
|
77
|
-
static void dump_raw(const char *str, size_t cnt, Out out);
|
|
78
|
-
static void dump_cstr(const char *str, size_t cnt, int is_sym, int escape1, Out out);
|
|
79
|
-
static void dump_hex(uint8_t c, Out out);
|
|
80
|
-
static void dump_str_comp(VALUE obj, Out out);
|
|
81
|
-
static void dump_str_obj(VALUE obj, Out out);
|
|
82
|
-
static void dump_sym_comp(VALUE obj, Out out);
|
|
83
|
-
static void dump_sym_obj(VALUE obj, Out out);
|
|
84
|
-
static void dump_class_comp(VALUE obj, Out out);
|
|
85
|
-
static void dump_class_obj(VALUE obj, Out out);
|
|
86
|
-
static void dump_array(VALUE obj, int depth, Out out);
|
|
87
|
-
static int hash_cb_strict(VALUE key, VALUE value, Out out);
|
|
88
|
-
static int hash_cb_compat(VALUE key, VALUE value, Out out);
|
|
89
|
-
static int hash_cb_object(VALUE key, VALUE value, Out out);
|
|
90
|
-
static void dump_hash(VALUE obj, int depth, int mode, Out out);
|
|
91
|
-
static void dump_time(VALUE obj, Out out);
|
|
92
|
-
static void dump_ruby_time(VALUE obj, Out out);
|
|
93
|
-
static void dump_xml_time(VALUE obj, Out out);
|
|
94
|
-
static void dump_data_strict(VALUE obj, Out out);
|
|
95
|
-
static void dump_data_null(VALUE obj, Out out);
|
|
96
|
-
static void dump_data_comp(VALUE obj, Out out);
|
|
97
|
-
static void dump_data_obj(VALUE obj, int depth, Out out);
|
|
98
|
-
static void dump_obj_comp(VALUE obj, int depth, Out out);
|
|
99
|
-
static void dump_obj_obj(VALUE obj, int depth, Out out);
|
|
100
|
-
#if HAS_RSTRUCT
|
|
101
|
-
static void dump_struct_comp(VALUE obj, int depth, Out out);
|
|
102
|
-
static void dump_struct_obj(VALUE obj, int depth, Out out);
|
|
103
|
-
#endif
|
|
104
|
-
#if HAS_IVAR_HELPERS
|
|
105
|
-
static int dump_attr_cb(ID key, VALUE value, Out out);
|
|
106
|
-
#endif
|
|
107
|
-
static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out);
|
|
108
|
-
static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out);
|
|
32
|
+
typedef unsigned long ulong;
|
|
109
33
|
|
|
110
|
-
static void grow(Out out, size_t len);
|
|
111
34
|
static size_t hibit_friendly_size(const uint8_t *str, size_t len);
|
|
35
|
+
static size_t xss_friendly_size(const uint8_t *str, size_t len);
|
|
112
36
|
static size_t ascii_friendly_size(const uint8_t *str, size_t len);
|
|
113
37
|
|
|
114
|
-
static void dump_leaf_to_json(Leaf leaf, Options copts, Out out);
|
|
115
|
-
static void dump_leaf(Leaf leaf, int depth, Out out);
|
|
116
|
-
static void dump_leaf_str(Leaf leaf, Out out);
|
|
117
|
-
static void dump_leaf_fixnum(Leaf leaf, Out out);
|
|
118
|
-
static void dump_leaf_float(Leaf leaf, Out out);
|
|
119
|
-
static void dump_leaf_array(Leaf leaf, int depth, Out out);
|
|
120
|
-
static void dump_leaf_hash(Leaf leaf, int depth, Out out);
|
|
121
|
-
|
|
122
|
-
|
|
123
38
|
static const char hex_chars[17] = "0123456789abcdef";
|
|
124
39
|
|
|
40
|
+
// JSON standard except newlines are no escaped
|
|
41
|
+
static char newline_friendly_chars[256] = "\
|
|
42
|
+
66666666221622666666666666666666\
|
|
43
|
+
11211111111111111111111111111111\
|
|
44
|
+
11111111111111111111111111112111\
|
|
45
|
+
11111111111111111111111111111111\
|
|
46
|
+
11111111111111111111111111111111\
|
|
47
|
+
11111111111111111111111111111111\
|
|
48
|
+
11111111111111111111111111111111\
|
|
49
|
+
11111111111111111111111111111111";
|
|
50
|
+
|
|
51
|
+
// JSON standard
|
|
125
52
|
static char hibit_friendly_chars[256] = "\
|
|
126
53
|
66666666222622666666666666666666\
|
|
127
54
|
11211111111111111111111111111111\
|
|
@@ -136,7 +63,18 @@ static char hibit_friendly_chars[256] = "\
|
|
|
136
63
|
// bytes per character in the output. That makes this conservative.
|
|
137
64
|
static char ascii_friendly_chars[256] = "\
|
|
138
65
|
66666666222622666666666666666666\
|
|
139
|
-
|
|
66
|
+
11211111111111111111111111111111\
|
|
67
|
+
11111111111111111111111111112111\
|
|
68
|
+
11111111111111111111111111111116\
|
|
69
|
+
33333333333333333333333333333333\
|
|
70
|
+
33333333333333333333333333333333\
|
|
71
|
+
33333333333333333333333333333333\
|
|
72
|
+
33333333333333333333333333333333";
|
|
73
|
+
|
|
74
|
+
// XSS safe mode
|
|
75
|
+
static char xss_friendly_chars[256] = "\
|
|
76
|
+
66666666222622666666666666666666\
|
|
77
|
+
11211161111111121111111111116161\
|
|
140
78
|
11111111111111111111111111112111\
|
|
141
79
|
11111111111111111111111111111116\
|
|
142
80
|
33333333333333333333333333333333\
|
|
@@ -144,11 +82,50 @@ static char ascii_friendly_chars[256] = "\
|
|
|
144
82
|
33333333333333333333333333333333\
|
|
145
83
|
33333333333333333333333333333333";
|
|
146
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
|
+
|
|
112
|
+
inline static size_t
|
|
113
|
+
newline_friendly_size(const uint8_t *str, size_t len) {
|
|
114
|
+
size_t size = 0;
|
|
115
|
+
size_t i = len;
|
|
116
|
+
|
|
117
|
+
for (; 0 < i; str++, i--) {
|
|
118
|
+
size += newline_friendly_chars[*str];
|
|
119
|
+
}
|
|
120
|
+
return size - len * (size_t)'0';
|
|
121
|
+
}
|
|
122
|
+
|
|
147
123
|
inline static size_t
|
|
148
124
|
hibit_friendly_size(const uint8_t *str, size_t len) {
|
|
149
125
|
size_t size = 0;
|
|
126
|
+
size_t i = len;
|
|
150
127
|
|
|
151
|
-
for (; 0 <
|
|
128
|
+
for (; 0 < i; str++, i--) {
|
|
152
129
|
size += hibit_friendly_chars[*str];
|
|
153
130
|
}
|
|
154
131
|
return size - len * (size_t)'0';
|
|
@@ -157,74 +134,87 @@ hibit_friendly_size(const uint8_t *str, size_t len) {
|
|
|
157
134
|
inline static size_t
|
|
158
135
|
ascii_friendly_size(const uint8_t *str, size_t len) {
|
|
159
136
|
size_t size = 0;
|
|
137
|
+
size_t i = len;
|
|
160
138
|
|
|
161
|
-
for (; 0 <
|
|
139
|
+
for (; 0 < i; str++, i--) {
|
|
162
140
|
size += ascii_friendly_chars[*str];
|
|
163
141
|
}
|
|
164
142
|
return size - len * (size_t)'0';
|
|
165
143
|
}
|
|
166
144
|
|
|
167
|
-
inline static
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
145
|
+
inline static size_t
|
|
146
|
+
xss_friendly_size(const uint8_t *str, size_t len) {
|
|
147
|
+
size_t size = 0;
|
|
148
|
+
size_t i = len;
|
|
149
|
+
|
|
150
|
+
for (; 0 < i; str++, i--) {
|
|
151
|
+
size += xss_friendly_chars[*str];
|
|
175
152
|
}
|
|
153
|
+
return size - len * (size_t)'0';
|
|
176
154
|
}
|
|
177
155
|
|
|
178
|
-
inline static
|
|
179
|
-
|
|
180
|
-
|
|
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;
|
|
181
160
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
*b = (num % 10) + '0';
|
|
161
|
+
for (; 0 < i; str++, i--) {
|
|
162
|
+
size += hixss_friendly_chars[*str];
|
|
185
163
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return b;
|
|
164
|
+
return size - len * (size_t)'0';
|
|
189
165
|
}
|
|
190
166
|
|
|
191
|
-
inline static
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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;
|
|
195
171
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
for (; 0 < num; num /= 10, b--) {
|
|
199
|
-
*b = (num % 10) + '0';
|
|
200
|
-
}
|
|
201
|
-
b++;
|
|
202
|
-
} else {
|
|
203
|
-
*b = '0';
|
|
172
|
+
for (; 0 < i; str++, i--) {
|
|
173
|
+
size += rails_friendly_chars[*str];
|
|
204
174
|
}
|
|
205
|
-
|
|
206
|
-
*out->cur++ = *b;
|
|
207
|
-
}
|
|
208
|
-
*out->cur = '\0';
|
|
175
|
+
return size - len * (size_t)'0';
|
|
209
176
|
}
|
|
210
177
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
+
}
|
|
220
188
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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;
|
|
224
216
|
}
|
|
225
|
-
|
|
226
|
-
out->end = buf + size;
|
|
227
|
-
out->cur = out->buf + pos;
|
|
217
|
+
return str;
|
|
228
218
|
}
|
|
229
219
|
|
|
230
220
|
inline static void
|
|
@@ -236,17 +226,7 @@ dump_hex(uint8_t c, Out out) {
|
|
|
236
226
|
*out->cur++ = hex_chars[d];
|
|
237
227
|
}
|
|
238
228
|
|
|
239
|
-
static
|
|
240
|
-
dump_raw(const char *str, size_t cnt, Out out) {
|
|
241
|
-
if (out->end - out->cur <= (long)cnt + 10) {
|
|
242
|
-
grow(out, cnt + 10);
|
|
243
|
-
}
|
|
244
|
-
memcpy(out->cur, str, cnt);
|
|
245
|
-
out->cur += cnt;
|
|
246
|
-
*out->cur = '\0';
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const char*
|
|
229
|
+
static const char*
|
|
250
230
|
dump_unicode(const char *str, const char *end, Out out) {
|
|
251
231
|
uint32_t code = 0;
|
|
252
232
|
uint8_t b = *(uint8_t*)str;
|
|
@@ -268,13 +248,14 @@ dump_unicode(const char *str, const char *end, Out out) {
|
|
|
268
248
|
cnt = 5;
|
|
269
249
|
code = b & 0x00000001;
|
|
270
250
|
} else {
|
|
271
|
-
|
|
251
|
+
cnt = 0;
|
|
252
|
+
rb_raise(oj_json_generator_error_class, "Invalid Unicode");
|
|
272
253
|
}
|
|
273
254
|
str++;
|
|
274
255
|
for (; 0 < cnt; cnt--, str++) {
|
|
275
256
|
b = *(uint8_t*)str;
|
|
276
257
|
if (end <= str || 0x80 != (0xC0 & b)) {
|
|
277
|
-
rb_raise(
|
|
258
|
+
rb_raise(oj_json_generator_error_class, "Invalid Unicode");
|
|
278
259
|
}
|
|
279
260
|
code = (code << 6) | (b & 0x0000003F);
|
|
280
261
|
}
|
|
@@ -298,174 +279,412 @@ dump_unicode(const char *str, const char *end, Out out) {
|
|
|
298
279
|
return str - 1;
|
|
299
280
|
}
|
|
300
281
|
|
|
301
|
-
//
|
|
302
|
-
// needed (duplicate), and a positive value if the object was added to the
|
|
303
|
-
|
|
304
|
-
|
|
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) {
|
|
305
287
|
slot_t id = 0;
|
|
306
288
|
slot_t *slot;
|
|
307
289
|
|
|
308
|
-
if (
|
|
290
|
+
if (Yes == out->opts->circular) {
|
|
309
291
|
if (0 == (id = oj_cache8_get(out->circ_cache, obj, &slot))) {
|
|
310
292
|
out->circ_cnt++;
|
|
311
293
|
id = out->circ_cnt;
|
|
312
294
|
*slot = id;
|
|
313
295
|
} else {
|
|
314
|
-
if (
|
|
315
|
-
|
|
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++ = '"';
|
|
316
303
|
}
|
|
317
|
-
*out->cur++ = '"';
|
|
318
|
-
*out->cur++ = '^';
|
|
319
|
-
*out->cur++ = 'r';
|
|
320
|
-
dump_ulong(id, out);
|
|
321
|
-
*out->cur++ = '"';
|
|
322
|
-
|
|
323
304
|
return -1;
|
|
324
305
|
}
|
|
325
306
|
}
|
|
326
307
|
return (long)id;
|
|
327
308
|
}
|
|
328
309
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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);
|
|
332
335
|
|
|
333
|
-
|
|
334
|
-
|
|
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';
|
|
335
353
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
354
|
+
if (0 > sec) {
|
|
355
|
+
neg = 1;
|
|
356
|
+
sec = -sec;
|
|
357
|
+
if (0 < nsec) {
|
|
358
|
+
nsec = 1000000000 - nsec;
|
|
359
|
+
sec--;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
dot = b - 9;
|
|
363
|
+
if (0 < out->opts->sec_prec) {
|
|
364
|
+
if (9 > out->opts->sec_prec) {
|
|
365
|
+
int i;
|
|
346
366
|
|
|
347
|
-
|
|
348
|
-
|
|
367
|
+
for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
|
|
368
|
+
dot++;
|
|
369
|
+
nsec = (nsec + 5) / 10;
|
|
370
|
+
one /= 10;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (one <= nsec) {
|
|
374
|
+
nsec -= one;
|
|
375
|
+
sec++;
|
|
376
|
+
}
|
|
377
|
+
for (; dot < b; b--, nsec /= 10) {
|
|
378
|
+
*b = '0' + (nsec % 10);
|
|
379
|
+
}
|
|
380
|
+
*b-- = '.';
|
|
349
381
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
382
|
+
if (0 == sec) {
|
|
383
|
+
*b-- = '0';
|
|
384
|
+
} else {
|
|
385
|
+
for (; 0 < sec; b--, sec /= 10) {
|
|
386
|
+
*b = '0' + (sec % 10);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (neg) {
|
|
390
|
+
*b-- = '-';
|
|
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;
|
|
354
397
|
*out->cur = '\0';
|
|
355
398
|
}
|
|
356
399
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
400
|
+
void
|
|
401
|
+
oj_dump_ruby_time(VALUE obj, Out out) {
|
|
402
|
+
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
360
403
|
|
|
361
|
-
|
|
362
|
-
grow(out, size);
|
|
363
|
-
}
|
|
364
|
-
*out->cur++ = 'f';
|
|
365
|
-
*out->cur++ = 'a';
|
|
366
|
-
*out->cur++ = 'l';
|
|
367
|
-
*out->cur++ = 's';
|
|
368
|
-
*out->cur++ = 'e';
|
|
369
|
-
*out->cur = '\0';
|
|
404
|
+
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
|
370
405
|
}
|
|
371
406
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
char
|
|
375
|
-
|
|
376
|
-
long
|
|
377
|
-
|
|
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 = '+';
|
|
378
427
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
*b = '-';
|
|
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;
|
|
390
438
|
} else {
|
|
391
|
-
|
|
439
|
+
for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
|
|
440
|
+
nsec = (nsec + 5) / 10;
|
|
441
|
+
one /= 10;
|
|
442
|
+
}
|
|
443
|
+
if (one <= nsec) {
|
|
444
|
+
nsec -= one;
|
|
445
|
+
sec++;
|
|
446
|
+
}
|
|
392
447
|
}
|
|
393
|
-
} else {
|
|
394
|
-
*b = '0';
|
|
395
448
|
}
|
|
396
|
-
|
|
397
|
-
|
|
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);
|
|
398
461
|
}
|
|
399
|
-
|
|
400
|
-
|
|
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);
|
|
401
470
|
}
|
|
402
|
-
|
|
403
|
-
|
|
471
|
+
#endif
|
|
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);
|
|
484
|
+
}
|
|
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;
|
|
404
488
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
489
|
+
if (9 > out->opts->sec_prec) {
|
|
490
|
+
format[32] = '0' + out->opts->sec_prec;
|
|
491
|
+
len -= 9 - out->opts->sec_prec;
|
|
492
|
+
}
|
|
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;
|
|
409
500
|
|
|
410
|
-
|
|
411
|
-
|
|
501
|
+
if (9 > out->opts->sec_prec) {
|
|
502
|
+
format[32] = '0' + out->opts->sec_prec;
|
|
503
|
+
len -= 9 - out->opts->sec_prec;
|
|
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);
|
|
412
510
|
}
|
|
413
|
-
memcpy(out->cur, StringValuePtr(rs), cnt);
|
|
414
|
-
out->cur += cnt;
|
|
415
|
-
*out->cur = '\0';
|
|
416
511
|
}
|
|
417
512
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
char *b;
|
|
423
|
-
double d = rb_num2dbl(obj);
|
|
424
|
-
int cnt;
|
|
513
|
+
void
|
|
514
|
+
oj_dump_obj_to_json(VALUE obj, Options copts, Out out) {
|
|
515
|
+
oj_dump_obj_to_json_using_params(obj, copts, out, 0, 0);
|
|
516
|
+
}
|
|
425
517
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
cnt = 3;
|
|
433
|
-
} else if (INFINITY == d) {
|
|
434
|
-
strcpy(buf, "Infinity");
|
|
435
|
-
cnt = 8;
|
|
436
|
-
} else if (-INFINITY == d) {
|
|
437
|
-
strcpy(buf, "-Infinity");
|
|
438
|
-
cnt = 9;
|
|
439
|
-
} else if (d == (double)(long long int)d) {
|
|
440
|
-
cnt = sprintf(buf, "%.1f", d); // used sprintf due to bug in snprintf
|
|
441
|
-
} else {
|
|
442
|
-
cnt = sprintf(buf, "%0.16g", d); // used sprintf due to bug in snprintf
|
|
518
|
+
void
|
|
519
|
+
oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VALUE *argv) {
|
|
520
|
+
if (0 == out->buf) {
|
|
521
|
+
out->buf = ALLOC_N(char, 4096);
|
|
522
|
+
out->end = out->buf + 4095 - BUFFER_EXTRA; // 1 less than end plus extra for possible errors
|
|
523
|
+
out->allocated = 1;
|
|
443
524
|
}
|
|
444
|
-
|
|
445
|
-
|
|
525
|
+
out->cur = out->buf;
|
|
526
|
+
out->circ_cnt = 0;
|
|
527
|
+
out->opts = copts;
|
|
528
|
+
out->hash_cnt = 0;
|
|
529
|
+
out->indent = copts->indent;
|
|
530
|
+
out->argc = argc;
|
|
531
|
+
out->argv = argv;
|
|
532
|
+
if (Yes == copts->circular) {
|
|
533
|
+
oj_cache8_new(&out->circ_cache);
|
|
446
534
|
}
|
|
447
|
-
|
|
448
|
-
|
|
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
|
+
}
|
|
544
|
+
if (0 < out->indent) {
|
|
545
|
+
switch (*(out->cur - 1)) {
|
|
546
|
+
case ']':
|
|
547
|
+
case '}':
|
|
548
|
+
assure_size(out, 1);
|
|
549
|
+
*out->cur++ = '\n';
|
|
550
|
+
default:
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
449
553
|
}
|
|
450
554
|
*out->cur = '\0';
|
|
555
|
+
if (Yes == copts->circular) {
|
|
556
|
+
oj_cache8_delete(out->circ_cache);
|
|
557
|
+
}
|
|
451
558
|
}
|
|
452
559
|
|
|
453
|
-
|
|
454
|
-
|
|
560
|
+
void
|
|
561
|
+
oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
|
|
562
|
+
char buf[4096];
|
|
563
|
+
struct _Out out;
|
|
564
|
+
size_t size;
|
|
565
|
+
FILE *f;
|
|
566
|
+
int ok;
|
|
567
|
+
|
|
568
|
+
out.buf = buf;
|
|
569
|
+
out.end = buf + sizeof(buf) - BUFFER_EXTRA;
|
|
570
|
+
out.allocated = 0;
|
|
571
|
+
out.omit_nil = copts->dump_opts.omit_nil;
|
|
572
|
+
oj_dump_obj_to_json(obj, copts, &out);
|
|
573
|
+
size = out.cur - out.buf;
|
|
574
|
+
if (0 == (f = fopen(path, "w"))) {
|
|
575
|
+
if (out.allocated) {
|
|
576
|
+
xfree(out.buf);
|
|
577
|
+
}
|
|
578
|
+
rb_raise(rb_eIOError, "%s", strerror(errno));
|
|
579
|
+
}
|
|
580
|
+
ok = (size == fwrite(out.buf, 1, size, f));
|
|
581
|
+
if (out.allocated) {
|
|
582
|
+
xfree(out.buf);
|
|
583
|
+
}
|
|
584
|
+
fclose(f);
|
|
585
|
+
if (!ok) {
|
|
586
|
+
int err = ferror(f);
|
|
587
|
+
|
|
588
|
+
rb_raise(rb_eIOError, "Write failed. [%d:%s]", err, strerror(err));
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
void
|
|
593
|
+
oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
|
594
|
+
char buf[4096];
|
|
595
|
+
struct _Out out;
|
|
596
|
+
ssize_t size;
|
|
597
|
+
VALUE clas = rb_obj_class(stream);
|
|
598
|
+
#if !IS_WINDOWS
|
|
599
|
+
int fd;
|
|
600
|
+
VALUE s;
|
|
601
|
+
#endif
|
|
602
|
+
|
|
603
|
+
out.buf = buf;
|
|
604
|
+
out.end = buf + sizeof(buf) - BUFFER_EXTRA;
|
|
605
|
+
out.allocated = 0;
|
|
606
|
+
out.omit_nil = copts->dump_opts.omit_nil;
|
|
607
|
+
oj_dump_obj_to_json(obj, copts, &out);
|
|
608
|
+
size = out.cur - out.buf;
|
|
609
|
+
if (oj_stringio_class == clas) {
|
|
610
|
+
rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
|
|
611
|
+
#if !IS_WINDOWS
|
|
612
|
+
} else if (rb_respond_to(stream, oj_fileno_id) &&
|
|
613
|
+
Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) &&
|
|
614
|
+
0 != (fd = FIX2INT(s))) {
|
|
615
|
+
if (size != write(fd, out.buf, size)) {
|
|
616
|
+
if (out.allocated) {
|
|
617
|
+
xfree(out.buf);
|
|
618
|
+
}
|
|
619
|
+
rb_raise(rb_eIOError, "Write failed. [%d:%s]", errno, strerror(errno));
|
|
620
|
+
}
|
|
621
|
+
#endif
|
|
622
|
+
} else if (rb_respond_to(stream, oj_write_id)) {
|
|
623
|
+
rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
|
|
624
|
+
} else {
|
|
625
|
+
if (out.allocated) {
|
|
626
|
+
xfree(out.buf);
|
|
627
|
+
}
|
|
628
|
+
rb_raise(rb_eArgError, "to_stream() expected an IO Object.");
|
|
629
|
+
}
|
|
630
|
+
if (out.allocated) {
|
|
631
|
+
xfree(out.buf);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
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));
|
|
639
|
+
|
|
640
|
+
if (rb_utf8_encoding() != enc) {
|
|
641
|
+
obj = rb_str_conv_enc(obj, enc, rb_utf8_encoding());
|
|
642
|
+
}
|
|
643
|
+
#endif
|
|
644
|
+
oj_dump_cstr(rb_string_value_ptr((VALUE*)&obj), RSTRING_LEN(obj), 0, 0, out);
|
|
645
|
+
}
|
|
646
|
+
|
|
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);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
void
|
|
655
|
+
oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
|
|
455
656
|
size_t size;
|
|
456
657
|
char *cmap;
|
|
457
658
|
|
|
458
|
-
|
|
659
|
+
switch (out->opts->escape_mode) {
|
|
660
|
+
case NLEsc:
|
|
661
|
+
cmap = newline_friendly_chars;
|
|
662
|
+
size = newline_friendly_size((uint8_t*)str, cnt);
|
|
663
|
+
break;
|
|
664
|
+
case ASCIIEsc:
|
|
459
665
|
cmap = ascii_friendly_chars;
|
|
460
666
|
size = ascii_friendly_size((uint8_t*)str, cnt);
|
|
461
|
-
|
|
667
|
+
break;
|
|
668
|
+
case XSSEsc:
|
|
669
|
+
cmap = xss_friendly_chars;
|
|
670
|
+
size = xss_friendly_size((uint8_t*)str, cnt);
|
|
671
|
+
break;
|
|
672
|
+
case JXEsc:
|
|
673
|
+
cmap = hixss_friendly_chars;
|
|
674
|
+
size = hixss_friendly_size((uint8_t*)str, cnt);
|
|
675
|
+
break;
|
|
676
|
+
case RailsEsc:
|
|
677
|
+
cmap = rails_friendly_chars;
|
|
678
|
+
size = rails_friendly_size((uint8_t*)str, cnt);
|
|
679
|
+
break;
|
|
680
|
+
case JSONEsc:
|
|
681
|
+
default:
|
|
462
682
|
cmap = hibit_friendly_chars;
|
|
463
683
|
size = hibit_friendly_size((uint8_t*)str, cnt);
|
|
464
684
|
}
|
|
465
|
-
|
|
466
|
-
grow(out, size + 10);
|
|
467
|
-
}
|
|
685
|
+
assure_size(out, size + BUFFER_EXTRA);
|
|
468
686
|
*out->cur++ = '"';
|
|
687
|
+
|
|
469
688
|
if (escape1) {
|
|
470
689
|
*out->cur++ = '\\';
|
|
471
690
|
*out->cur++ = 'u';
|
|
@@ -499,6 +718,7 @@ dump_cstr(const char *str, size_t cnt, int is_sym, int escape1, Out out) {
|
|
|
499
718
|
case '2':
|
|
500
719
|
*out->cur++ = '\\';
|
|
501
720
|
switch (*str) {
|
|
721
|
+
case '\\': *out->cur++ = '\\'; break;
|
|
502
722
|
case '\b': *out->cur++ = 'b'; break;
|
|
503
723
|
case '\t': *out->cur++ = 't'; break;
|
|
504
724
|
case '\n': *out->cur++ = 'n'; break;
|
|
@@ -508,6 +728,14 @@ dump_cstr(const char *str, size_t cnt, int is_sym, int escape1, Out out) {
|
|
|
508
728
|
}
|
|
509
729
|
break;
|
|
510
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
|
+
}
|
|
511
739
|
str = dump_unicode(str, end, out);
|
|
512
740
|
break;
|
|
513
741
|
case '6': // control characters
|
|
@@ -521,1301 +749,305 @@ dump_cstr(const char *str, size_t cnt, int is_sym, int escape1, Out out) {
|
|
|
521
749
|
break; // ignore, should never happen if the table is correct
|
|
522
750
|
}
|
|
523
751
|
}
|
|
524
|
-
*out->cur++ = '"';
|
|
752
|
+
*out->cur++ = '"';
|
|
753
|
+
}
|
|
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
|
+
}
|
|
525
792
|
}
|
|
526
793
|
*out->cur = '\0';
|
|
527
794
|
}
|
|
528
795
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
796
|
+
void
|
|
797
|
+
oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) {
|
|
798
|
+
const char *s = rb_class2name(obj);
|
|
799
|
+
|
|
800
|
+
oj_dump_cstr(s, strlen(s), 0, 0, out);
|
|
532
801
|
}
|
|
533
802
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
size_t len = RSTRING_LEN(obj);
|
|
538
|
-
char s1 = s[1];
|
|
803
|
+
void
|
|
804
|
+
oj_dump_obj_to_s(VALUE obj, Out out) {
|
|
805
|
+
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
539
806
|
|
|
540
|
-
|
|
807
|
+
oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
|
|
541
808
|
}
|
|
542
809
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
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';
|
|
548
816
|
}
|
|
549
817
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
818
|
+
void
|
|
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;
|
|
827
|
+
}
|
|
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);
|
|
834
|
+
}
|
|
835
|
+
if (0 == buf) {
|
|
836
|
+
rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]", ENOSPC, strerror(ENOSPC));
|
|
837
|
+
}
|
|
838
|
+
out->buf = buf;
|
|
839
|
+
out->end = buf + size;
|
|
840
|
+
out->cur = out->buf + pos;
|
|
556
841
|
}
|
|
557
842
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
843
|
+
void
|
|
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';
|
|
563
851
|
}
|
|
564
852
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
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';
|
|
861
|
+
}
|
|
569
862
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
*out->cur++ = '
|
|
574
|
-
*out->cur++ = '
|
|
575
|
-
*out->cur++ = '
|
|
576
|
-
*out->cur++ = '
|
|
577
|
-
*out->cur++ = '
|
|
578
|
-
*out->cur++ = ':';
|
|
579
|
-
dump_cstr(s, len, 0, 0, out);
|
|
580
|
-
*out->cur++ = '}';
|
|
863
|
+
void
|
|
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';
|
|
581
871
|
*out->cur = '\0';
|
|
582
872
|
}
|
|
583
873
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
int
|
|
590
|
-
long id = check_circular(a, out);
|
|
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;
|
|
591
880
|
|
|
592
|
-
if (
|
|
593
|
-
|
|
881
|
+
if (0 > num) {
|
|
882
|
+
neg = 1;
|
|
883
|
+
num = -num;
|
|
594
884
|
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
size = d2 * out->indent + 16;
|
|
600
|
-
if (out->end - out->cur <= (long)size) {
|
|
601
|
-
grow(out, size);
|
|
885
|
+
*b-- = '\0';
|
|
886
|
+
if (0 < num) {
|
|
887
|
+
for (; 0 < num; num /= 10, b--) {
|
|
888
|
+
*b = (num % 10) + '0';
|
|
602
889
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
890
|
+
if (neg) {
|
|
891
|
+
*b = '-';
|
|
892
|
+
} else {
|
|
893
|
+
b++;
|
|
894
|
+
}
|
|
895
|
+
} else {
|
|
896
|
+
*b = '0';
|
|
609
897
|
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
898
|
+
assure_size(out, (sizeof(buf) - (b - buf)));
|
|
899
|
+
for (; '\0' != *b; b++) {
|
|
900
|
+
*out->cur++ = *b;
|
|
613
901
|
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
902
|
+
*out->cur = '\0';
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
void
|
|
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);
|
|
909
|
+
|
|
910
|
+
assure_size(out, cnt);
|
|
911
|
+
memcpy(out->cur, rb_string_value_ptr((VALUE*)&rs), cnt);
|
|
912
|
+
out->cur += cnt;
|
|
913
|
+
*out->cur = '\0';
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// Removed dependencies on math due to problems with CentOS 5.4.
|
|
917
|
+
void
|
|
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;
|
|
923
|
+
|
|
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;
|
|
622
935
|
} else {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
if (0 < out->opts->dump_opts->array_size) {
|
|
633
|
-
strcpy(out->cur, out->opts->dump_opts->array_nl);
|
|
634
|
-
out->cur += out->opts->dump_opts->array_size;
|
|
635
|
-
}
|
|
636
|
-
if (0 < out->opts->dump_opts->indent_size) {
|
|
637
|
-
int i;
|
|
638
|
-
for (i = d2; 0 < i; i--) {
|
|
639
|
-
strcpy(out->cur, out->opts->dump_opts->indent);
|
|
640
|
-
out->cur += out->opts->dump_opts->indent_size;
|
|
641
|
-
}
|
|
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;
|
|
642
945
|
}
|
|
643
946
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
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;
|
|
647
964
|
}
|
|
648
965
|
}
|
|
649
|
-
|
|
650
|
-
if (
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
if (0 == out->opts->dump_opts) {
|
|
654
|
-
fill_indent(out, depth);
|
|
966
|
+
} else if (-OJ_INFINITY == d) {
|
|
967
|
+
if (ObjectMode == out->opts->mode) {
|
|
968
|
+
strcpy(buf, ninf_val);
|
|
969
|
+
cnt = sizeof(ninf_val) - 1;
|
|
655
970
|
} else {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
for (i = depth; 0 < i; i--) {
|
|
665
|
-
strcpy(out->cur, out->opts->dump_opts->indent);
|
|
666
|
-
out->cur += out->opts->dump_opts->indent_size;
|
|
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;
|
|
667
979
|
}
|
|
668
980
|
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
grow(out, size);
|
|
687
|
-
}
|
|
688
|
-
fill_indent(out, depth);
|
|
689
|
-
dump_str_comp(key, out);
|
|
690
|
-
*out->cur++ = ':';
|
|
691
|
-
} else {
|
|
692
|
-
size = depth * out->opts->dump_opts->indent_size + out->opts->dump_opts->hash_size + 1;
|
|
693
|
-
if (out->end - out->cur <= size) {
|
|
694
|
-
grow(out, size);
|
|
695
|
-
}
|
|
696
|
-
if (0 < out->opts->dump_opts->hash_size) {
|
|
697
|
-
strcpy(out->cur, out->opts->dump_opts->hash_nl);
|
|
698
|
-
out->cur += out->opts->dump_opts->hash_size;
|
|
699
|
-
}
|
|
700
|
-
if (0 < out->opts->dump_opts->indent_size) {
|
|
701
|
-
int i;
|
|
702
|
-
for (i = depth; 0 < i; i--) {
|
|
703
|
-
strcpy(out->cur, out->opts->dump_opts->indent);
|
|
704
|
-
out->cur += out->opts->dump_opts->indent_size;
|
|
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;
|
|
705
998
|
}
|
|
706
999
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
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
|
+
}
|
|
720
1033
|
}
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
out->
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
return ST_CONTINUE;
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
static int
|
|
730
|
-
hash_cb_compat(VALUE key, VALUE value, Out out) {
|
|
731
|
-
int depth = out->depth;
|
|
732
|
-
long size;
|
|
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);
|
|
733
1038
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
grow(out, size);
|
|
1039
|
+
cnt = RSTRING_LEN(rstr);
|
|
1040
|
+
if ((int)sizeof(buf) <= cnt) {
|
|
1041
|
+
cnt = sizeof(buf) - 1;
|
|
738
1042
|
}
|
|
739
|
-
|
|
1043
|
+
strncpy(buf, rb_string_value_ptr((VALUE*)&rstr), cnt);
|
|
1044
|
+
buf[cnt] = '\0';
|
|
740
1045
|
} else {
|
|
741
|
-
|
|
742
|
-
if (out->end - out->cur <= size) {
|
|
743
|
-
grow(out, size);
|
|
744
|
-
}
|
|
745
|
-
if (0 < out->opts->dump_opts->hash_size) {
|
|
746
|
-
strcpy(out->cur, out->opts->dump_opts->hash_nl);
|
|
747
|
-
out->cur += out->opts->dump_opts->hash_size;
|
|
748
|
-
}
|
|
749
|
-
if (0 < out->opts->dump_opts->indent_size) {
|
|
750
|
-
int i;
|
|
751
|
-
for (i = depth; 0 < i; i--) {
|
|
752
|
-
strcpy(out->cur, out->opts->dump_opts->indent);
|
|
753
|
-
out->cur += out->opts->dump_opts->indent_size;
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
switch (rb_type(key)) {
|
|
758
|
-
case T_STRING:
|
|
759
|
-
dump_str_comp(key, out);
|
|
760
|
-
break;
|
|
761
|
-
case T_SYMBOL:
|
|
762
|
-
dump_sym_comp(key, out);
|
|
763
|
-
break;
|
|
764
|
-
default:
|
|
765
|
-
/*rb_raise(rb_eTypeError, "In :compat mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));*/
|
|
766
|
-
dump_str_comp(rb_funcall(key, oj_to_s_id, 0), out);
|
|
767
|
-
break;
|
|
1046
|
+
cnt = snprintf(buf, sizeof(buf), out->opts->float_fmt, d);
|
|
768
1047
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
size = out->opts->dump_opts->before_size + out->opts->dump_opts->after_size + 2;
|
|
773
|
-
if (out->end - out->cur <= size) {
|
|
774
|
-
grow(out, size);
|
|
775
|
-
}
|
|
776
|
-
if (0 < out->opts->dump_opts->before_size) {
|
|
777
|
-
strcpy(out->cur, out->opts->dump_opts->before_sep);
|
|
778
|
-
out->cur += out->opts->dump_opts->before_size;
|
|
779
|
-
}
|
|
780
|
-
*out->cur++ = ':';
|
|
781
|
-
if (0 < out->opts->dump_opts->after_size) {
|
|
782
|
-
strcpy(out->cur, out->opts->dump_opts->after_sep);
|
|
783
|
-
out->cur += out->opts->dump_opts->after_size;
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
dump_val(value, depth, out);
|
|
787
|
-
out->depth = depth;
|
|
788
|
-
*out->cur++ = ',';
|
|
789
|
-
|
|
790
|
-
return ST_CONTINUE;
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
static int
|
|
794
|
-
hash_cb_object(VALUE key, VALUE value, Out out) {
|
|
795
|
-
int depth = out->depth;
|
|
796
|
-
long size = depth * out->indent + 1;
|
|
797
|
-
|
|
798
|
-
if (out->end - out->cur <= size) {
|
|
799
|
-
grow(out, size);
|
|
800
|
-
}
|
|
801
|
-
fill_indent(out, depth);
|
|
802
|
-
if (rb_type(key) == T_STRING) {
|
|
803
|
-
dump_str_obj(key, out);
|
|
804
|
-
*out->cur++ = ':';
|
|
805
|
-
dump_val(value, depth, out);
|
|
806
|
-
} else if (rb_type(key) == T_SYMBOL) {
|
|
807
|
-
dump_sym_obj(key, out);
|
|
808
|
-
*out->cur++ = ':';
|
|
809
|
-
dump_val(value, depth, out);
|
|
810
|
-
} else {
|
|
811
|
-
int d2 = depth + 1;
|
|
812
|
-
long s2 = size + out->indent + 1;
|
|
813
|
-
int i;
|
|
814
|
-
int started = 0;
|
|
815
|
-
uint8_t b;
|
|
816
|
-
|
|
817
|
-
if (out->end - out->cur <= s2 + 15) {
|
|
818
|
-
grow(out, s2 + 15);
|
|
819
|
-
}
|
|
820
|
-
*out->cur++ = '"';
|
|
821
|
-
*out->cur++ = '^';
|
|
822
|
-
*out->cur++ = '#';
|
|
823
|
-
out->hash_cnt++;
|
|
824
|
-
for (i = 28; 0 <= i; i -= 4) {
|
|
825
|
-
b = (uint8_t)((out->hash_cnt >> i) & 0x0000000F);
|
|
826
|
-
if ('\0' != b) {
|
|
827
|
-
started = 1;
|
|
828
|
-
}
|
|
829
|
-
if (started) {
|
|
830
|
-
*out->cur++ = hex_chars[b];
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
*out->cur++ = '"';
|
|
834
|
-
*out->cur++ = ':';
|
|
835
|
-
*out->cur++ = '[';
|
|
836
|
-
fill_indent(out, d2);
|
|
837
|
-
dump_val(key, d2, out);
|
|
838
|
-
if (out->end - out->cur <= (long)s2) {
|
|
839
|
-
grow(out, s2);
|
|
840
|
-
}
|
|
841
|
-
*out->cur++ = ',';
|
|
842
|
-
fill_indent(out, d2);
|
|
843
|
-
dump_val(value, d2, out);
|
|
844
|
-
if (out->end - out->cur <= (long)size) {
|
|
845
|
-
grow(out, size);
|
|
846
|
-
}
|
|
847
|
-
fill_indent(out, depth);
|
|
848
|
-
*out->cur++ = ']';
|
|
849
|
-
}
|
|
850
|
-
out->depth = depth;
|
|
851
|
-
*out->cur++ = ',';
|
|
852
|
-
|
|
853
|
-
return ST_CONTINUE;
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
static void
|
|
857
|
-
dump_hash(VALUE obj, int depth, int mode, Out out) {
|
|
858
|
-
int cnt = (int)RHASH_SIZE(obj);
|
|
859
|
-
size_t size = depth * out->indent + 2;
|
|
860
|
-
|
|
861
|
-
if (out->end - out->cur <= 2) {
|
|
862
|
-
grow(out, 2);
|
|
863
|
-
}
|
|
864
|
-
if (0 == cnt) {
|
|
865
|
-
*out->cur++ = '{';
|
|
866
|
-
*out->cur++ = '}';
|
|
867
|
-
} else {
|
|
868
|
-
long id = check_circular(obj, out);
|
|
869
|
-
|
|
870
|
-
if (0 > id) {
|
|
871
|
-
return;
|
|
872
|
-
}
|
|
873
|
-
*out->cur++ = '{';
|
|
874
|
-
if (0 < id) {
|
|
875
|
-
if (out->end - out->cur <= (long)size + 16) {
|
|
876
|
-
grow(out, size + 16);
|
|
877
|
-
}
|
|
878
|
-
fill_indent(out, depth + 1);
|
|
879
|
-
*out->cur++ = '"';
|
|
880
|
-
*out->cur++ = '^';
|
|
881
|
-
*out->cur++ = 'i';
|
|
882
|
-
*out->cur++ = '"';
|
|
883
|
-
*out->cur++ = ':';
|
|
884
|
-
dump_ulong(id, out);
|
|
885
|
-
*out->cur++ = ',';
|
|
886
|
-
}
|
|
887
|
-
out->depth = depth + 1;
|
|
888
|
-
if (ObjectMode == mode) {
|
|
889
|
-
rb_hash_foreach(obj, hash_cb_object, (VALUE)out);
|
|
890
|
-
} else if (CompatMode == mode) {
|
|
891
|
-
rb_hash_foreach(obj, hash_cb_compat, (VALUE)out);
|
|
892
|
-
} else {
|
|
893
|
-
rb_hash_foreach(obj, hash_cb_strict, (VALUE)out);
|
|
894
|
-
}
|
|
895
|
-
if (',' == *(out->cur - 1)) {
|
|
896
|
-
out->cur--; // backup to overwrite last comma
|
|
897
|
-
}
|
|
898
|
-
if (0 == out->opts->dump_opts) {
|
|
899
|
-
if (out->end - out->cur <= (long)size) {
|
|
900
|
-
grow(out, size);
|
|
901
|
-
}
|
|
902
|
-
fill_indent(out, depth);
|
|
903
|
-
} else {
|
|
904
|
-
size = depth * out->opts->dump_opts->indent_size + out->opts->dump_opts->hash_size + 1;
|
|
905
|
-
if (out->end - out->cur <= (long)size) {
|
|
906
|
-
grow(out, size);
|
|
907
|
-
}
|
|
908
|
-
if (0 < out->opts->dump_opts->hash_size) {
|
|
909
|
-
strcpy(out->cur, out->opts->dump_opts->hash_nl);
|
|
910
|
-
out->cur += out->opts->dump_opts->hash_size;
|
|
911
|
-
}
|
|
912
|
-
if (0 < out->opts->dump_opts->indent_size) {
|
|
913
|
-
int i;
|
|
914
|
-
for (i = depth; 0 < i; i--) {
|
|
915
|
-
strcpy(out->cur, out->opts->dump_opts->indent);
|
|
916
|
-
out->cur += out->opts->dump_opts->indent_size;
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
|
-
*out->cur++ = '}';
|
|
921
|
-
}
|
|
922
|
-
*out->cur = '\0';
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
static void
|
|
926
|
-
dump_time(VALUE obj, Out out) {
|
|
927
|
-
char buf[64];
|
|
928
|
-
char *b = buf + sizeof(buf) - 1;
|
|
929
|
-
long size;
|
|
930
|
-
char *dot = b - 10;
|
|
931
|
-
#if HAS_RB_TIME_TIMESPEC
|
|
932
|
-
struct timespec ts = rb_time_timespec(obj);
|
|
933
|
-
time_t sec = ts.tv_sec;
|
|
934
|
-
long nsec = ts.tv_nsec;
|
|
935
|
-
#else
|
|
936
|
-
time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
|
937
|
-
#if HAS_NANO_TIME
|
|
938
|
-
long nsec = NUM2LONG(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
|
939
|
-
#else
|
|
940
|
-
long nsec = NUM2LONG(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
|
|
941
|
-
#endif
|
|
942
|
-
#endif
|
|
943
|
-
|
|
944
|
-
*b-- = '\0';
|
|
945
|
-
for (; dot < b; b--, nsec /= 10) {
|
|
946
|
-
*b = '0' + (nsec % 10);
|
|
947
|
-
}
|
|
948
|
-
*b-- = '.';
|
|
949
|
-
for (; 0 < sec; b--, sec /= 10) {
|
|
950
|
-
*b = '0' + (sec % 10);
|
|
951
|
-
}
|
|
952
|
-
b++;
|
|
953
|
-
size = sizeof(buf) - (b - buf) - 1;
|
|
954
|
-
if (out->end - out->cur <= size) {
|
|
955
|
-
grow(out, size);
|
|
956
|
-
}
|
|
957
|
-
memcpy(out->cur, b, size);
|
|
958
|
-
out->cur += size;
|
|
959
|
-
*out->cur = '\0';
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
static void
|
|
963
|
-
dump_ruby_time(VALUE obj, Out out) {
|
|
964
|
-
VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
965
|
-
|
|
966
|
-
dump_cstr(StringValuePtr(rstr), RSTRING_LEN(rstr), 0, 0, out);
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
static void
|
|
970
|
-
dump_xml_time(VALUE obj, Out out) {
|
|
971
|
-
char buf[64];
|
|
972
|
-
struct tm *tm;
|
|
973
|
-
#if HAS_RB_TIME_TIMESPEC
|
|
974
|
-
struct timespec ts = rb_time_timespec(obj);
|
|
975
|
-
time_t sec = ts.tv_sec;
|
|
976
|
-
long nsec = ts.tv_nsec;
|
|
977
|
-
#else
|
|
978
|
-
time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
|
979
|
-
#if HAS_NANO_TIME
|
|
980
|
-
long nsec = NUM2LONG(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
|
981
|
-
#else
|
|
982
|
-
long nsec = NUM2LONG(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
|
|
983
|
-
#endif
|
|
984
|
-
#endif
|
|
985
|
-
long tz_secs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
|
|
986
|
-
int tzhour, tzmin;
|
|
987
|
-
char tzsign = '+';
|
|
988
|
-
|
|
989
|
-
if (out->end - out->cur <= 36) {
|
|
990
|
-
grow(out, 36);
|
|
991
|
-
}
|
|
992
|
-
// 2012-01-05T23:58:07.123456000+09:00
|
|
993
|
-
//tm = localtime(&sec);
|
|
994
|
-
sec += tz_secs;
|
|
995
|
-
tm = gmtime(&sec);
|
|
996
|
-
#if 1
|
|
997
|
-
if (0 > tz_secs) {
|
|
998
|
-
tzsign = '-';
|
|
999
|
-
tzhour = (int)(tz_secs / -3600);
|
|
1000
|
-
tzmin = (int)(tz_secs / -60) - (tzhour * 60);
|
|
1001
|
-
} else {
|
|
1002
|
-
tzhour = (int)(tz_secs / 3600);
|
|
1003
|
-
tzmin = (int)(tz_secs / 60) - (tzhour * 60);
|
|
1004
|
-
}
|
|
1005
|
-
#else
|
|
1006
|
-
if (0 > tm->tm_gmtoff) {
|
|
1007
|
-
tzsign = '-';
|
|
1008
|
-
tzhour = (int)(tm->tm_gmtoff / -3600);
|
|
1009
|
-
tzmin = (int)(tm->tm_gmtoff / -60) - (tzhour * 60);
|
|
1010
|
-
} else {
|
|
1011
|
-
tzhour = (int)(tm->tm_gmtoff / 3600);
|
|
1012
|
-
tzmin = (int)(tm->tm_gmtoff / 60) - (tzhour * 60);
|
|
1013
|
-
}
|
|
1014
|
-
#endif
|
|
1015
|
-
if (0 == nsec) {
|
|
1016
|
-
if (0 == tzhour && 0 == tzmin) {
|
|
1017
|
-
sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ",
|
|
1018
|
-
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
|
1019
|
-
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
|
1020
|
-
dump_cstr(buf, 20, 0, 0, out);
|
|
1021
|
-
} else {
|
|
1022
|
-
sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
|
|
1023
|
-
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
|
1024
|
-
tm->tm_hour, tm->tm_min, tm->tm_sec,
|
|
1025
|
-
tzsign, tzhour, tzmin);
|
|
1026
|
-
dump_cstr(buf, 25, 0, 0, out);
|
|
1027
|
-
}
|
|
1028
|
-
} else {
|
|
1029
|
-
sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d",
|
|
1030
|
-
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
|
|
1031
|
-
tm->tm_hour, tm->tm_min, tm->tm_sec, nsec,
|
|
1032
|
-
tzsign, tzhour, tzmin);
|
|
1033
|
-
dump_cstr(buf, 35, 0, 0, out);
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
static void
|
|
1038
|
-
dump_data_strict(VALUE obj, Out out) {
|
|
1039
|
-
VALUE clas = rb_obj_class(obj);
|
|
1040
|
-
|
|
1041
|
-
if (oj_bigdecimal_class == clas) {
|
|
1042
|
-
VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
1043
|
-
|
|
1044
|
-
dump_raw(StringValuePtr(rstr), RSTRING_LEN(rstr), out);
|
|
1045
|
-
} else {
|
|
1046
|
-
raise_strict(obj);
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
static void
|
|
1051
|
-
dump_data_null(VALUE obj, Out out) {
|
|
1052
|
-
VALUE clas = rb_obj_class(obj);
|
|
1053
|
-
|
|
1054
|
-
if (oj_bigdecimal_class == clas) {
|
|
1055
|
-
VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
1056
|
-
|
|
1057
|
-
dump_raw(StringValuePtr(rstr), RSTRING_LEN(rstr), out);
|
|
1058
|
-
} else {
|
|
1059
|
-
dump_nil(out);
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
static void
|
|
1064
|
-
dump_data_comp(VALUE obj, Out out) {
|
|
1065
|
-
VALUE clas = rb_obj_class(obj);
|
|
1066
|
-
|
|
1067
|
-
if (rb_cTime == clas) {
|
|
1068
|
-
switch (out->opts->time_format) {
|
|
1069
|
-
case RubyTime: dump_ruby_time(obj, out); break;
|
|
1070
|
-
case XmlTime: dump_xml_time(obj, out); break;
|
|
1071
|
-
case UnixTime:
|
|
1072
|
-
default: dump_time(obj, out); break;
|
|
1073
|
-
}
|
|
1074
|
-
} else {
|
|
1075
|
-
VALUE rstr;
|
|
1076
|
-
|
|
1077
|
-
if (oj_bigdecimal_class == clas) {
|
|
1078
|
-
//rstr = rb_funcall(obj, oj_to_s_id, 1, rb_intern("E"));
|
|
1079
|
-
rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
1080
|
-
dump_raw(StringValuePtr(rstr), RSTRING_LEN(rstr), out);
|
|
1081
|
-
} else {
|
|
1082
|
-
rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
1083
|
-
dump_cstr(StringValuePtr(rstr), RSTRING_LEN(rstr), 0, 0, out);
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
static void
|
|
1089
|
-
dump_data_obj(VALUE obj, int depth, Out out) {
|
|
1090
|
-
VALUE clas = rb_obj_class(obj);
|
|
1091
|
-
|
|
1092
|
-
if (rb_cTime == clas) {
|
|
1093
|
-
if (out->end - out->cur <= 6) {
|
|
1094
|
-
grow(out, 6);
|
|
1095
|
-
}
|
|
1096
|
-
*out->cur++ = '{';
|
|
1097
|
-
*out->cur++ = '"';
|
|
1098
|
-
*out->cur++ = '^';
|
|
1099
|
-
*out->cur++ = 't';
|
|
1100
|
-
*out->cur++ = '"';
|
|
1101
|
-
*out->cur++ = ':';
|
|
1102
|
-
dump_time(obj, out);
|
|
1103
|
-
*out->cur++ = '}';
|
|
1104
|
-
*out->cur = '\0';
|
|
1105
|
-
} else {
|
|
1106
|
-
Odd odd = oj_get_odd(clas);
|
|
1107
|
-
|
|
1108
|
-
if (0 == odd) {
|
|
1109
|
-
if (oj_bigdecimal_class == clas) {
|
|
1110
|
-
VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
1111
|
-
|
|
1112
|
-
dump_raw(StringValuePtr(rstr), RSTRING_LEN(rstr), out);
|
|
1113
|
-
} else {
|
|
1114
|
-
dump_nil(out);
|
|
1115
|
-
}
|
|
1116
|
-
} else {
|
|
1117
|
-
dump_odd(obj, odd, clas, depth + 1, out);
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
static void
|
|
1123
|
-
dump_obj_comp(VALUE obj, int depth, Out out) {
|
|
1124
|
-
if (rb_respond_to(obj, oj_to_hash_id)) {
|
|
1125
|
-
VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
|
1126
|
-
|
|
1127
|
-
if (T_HASH != rb_type(h)) {
|
|
1128
|
-
rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
|
1129
|
-
}
|
|
1130
|
-
dump_hash(h, depth, out->opts->mode, out);
|
|
1131
|
-
} else if (rb_respond_to(obj, oj_as_json_id)) {
|
|
1132
|
-
dump_val(rb_funcall(obj, oj_as_json_id, 0), depth, out);
|
|
1133
|
-
} else if (rb_respond_to(obj, oj_to_json_id)) {
|
|
1134
|
-
VALUE rs = rb_funcall(obj, oj_to_json_id, 0);
|
|
1135
|
-
const char *s = StringValuePtr(rs);
|
|
1136
|
-
int len = (int)RSTRING_LEN(rs);
|
|
1137
|
-
|
|
1138
|
-
if (out->end - out->cur <= len) {
|
|
1139
|
-
grow(out, len);
|
|
1140
|
-
}
|
|
1141
|
-
memcpy(out->cur, s, len);
|
|
1142
|
-
out->cur += len;
|
|
1143
|
-
} else {
|
|
1144
|
-
VALUE clas = rb_obj_class(obj);
|
|
1145
|
-
|
|
1146
|
-
if (oj_bigdecimal_class == clas) {
|
|
1147
|
-
VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
1148
|
-
|
|
1149
|
-
dump_raw(StringValuePtr(rstr), RSTRING_LEN(rstr), out);
|
|
1150
|
-
} else {
|
|
1151
|
-
Odd odd = oj_get_odd(clas);
|
|
1152
|
-
|
|
1153
|
-
if (0 == odd) {
|
|
1154
|
-
dump_obj_attrs(obj, 0, 0, depth, out);
|
|
1155
|
-
} else {
|
|
1156
|
-
dump_odd(obj, odd, 0, depth + 1, out);
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
*out->cur = '\0';
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
inline static void
|
|
1164
|
-
dump_obj_obj(VALUE obj, int depth, Out out) {
|
|
1165
|
-
long id = check_circular(obj, out);
|
|
1166
|
-
|
|
1167
|
-
if (0 <= id) {
|
|
1168
|
-
VALUE clas = rb_obj_class(obj);
|
|
1169
|
-
Odd odd = oj_get_odd(clas);
|
|
1170
|
-
|
|
1171
|
-
if (0 == odd) {
|
|
1172
|
-
if (oj_bigdecimal_class == clas) {
|
|
1173
|
-
VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
|
1174
|
-
|
|
1175
|
-
dump_raw(StringValuePtr(rstr), RSTRING_LEN(rstr), out);
|
|
1176
|
-
} else {
|
|
1177
|
-
dump_obj_attrs(obj, clas, id, depth, out);
|
|
1178
|
-
}
|
|
1179
|
-
} else {
|
|
1180
|
-
dump_odd(obj, odd, clas, depth + 1, out);
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
#if HAS_IVAR_HELPERS
|
|
1186
|
-
static int
|
|
1187
|
-
dump_attr_cb(ID key, VALUE value, Out out) {
|
|
1188
|
-
int depth = out->depth;
|
|
1189
|
-
size_t size = depth * out->indent + 1;
|
|
1190
|
-
const char *attr = rb_id2name(key);
|
|
1191
|
-
|
|
1192
|
-
if (out->end - out->cur <= (long)size) {
|
|
1193
|
-
grow(out, size);
|
|
1194
|
-
}
|
|
1195
|
-
fill_indent(out, depth);
|
|
1196
|
-
if ('@' == *attr) {
|
|
1197
|
-
attr++;
|
|
1198
|
-
dump_cstr(attr, strlen(attr), 0, 0, out);
|
|
1199
|
-
} else {
|
|
1200
|
-
char buf[32];
|
|
1201
|
-
|
|
1202
|
-
*buf = '~';
|
|
1203
|
-
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
|
1204
|
-
buf[sizeof(buf) - 1] = '\0';
|
|
1205
|
-
dump_cstr(buf, strlen(buf), 0, 0, out);
|
|
1206
|
-
}
|
|
1207
|
-
*out->cur++ = ':';
|
|
1208
|
-
dump_val(value, depth, out);
|
|
1209
|
-
out->depth = depth;
|
|
1210
|
-
*out->cur++ = ',';
|
|
1211
|
-
|
|
1212
|
-
return ST_CONTINUE;
|
|
1213
|
-
}
|
|
1214
|
-
#endif
|
|
1215
|
-
|
|
1216
|
-
static void
|
|
1217
|
-
dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
|
|
1218
|
-
size_t size;
|
|
1219
|
-
int d2 = depth + 1;
|
|
1220
|
-
|
|
1221
|
-
if (out->end - out->cur <= 2) {
|
|
1222
|
-
grow(out, 2);
|
|
1223
|
-
}
|
|
1224
|
-
*out->cur++ = '{';
|
|
1225
|
-
if (0 != clas) {
|
|
1226
|
-
const char *class_name = rb_class2name(clas);
|
|
1227
|
-
int clen = (int)strlen(class_name);
|
|
1228
|
-
|
|
1229
|
-
size = d2 * out->indent + clen + 10;
|
|
1230
|
-
if (out->end - out->cur <= (long)size) {
|
|
1231
|
-
grow(out, size);
|
|
1232
|
-
}
|
|
1233
|
-
fill_indent(out, d2);
|
|
1234
|
-
*out->cur++ = '"';
|
|
1235
|
-
*out->cur++ = '^';
|
|
1236
|
-
*out->cur++ = 'o';
|
|
1237
|
-
*out->cur++ = '"';
|
|
1238
|
-
*out->cur++ = ':';
|
|
1239
|
-
dump_cstr(class_name, clen, 0, 0, out);
|
|
1240
|
-
}
|
|
1241
|
-
if (0 < id) {
|
|
1242
|
-
size = d2 * out->indent + 16;
|
|
1243
|
-
if (out->end - out->cur <= (long)size) {
|
|
1244
|
-
grow(out, size);
|
|
1245
|
-
}
|
|
1246
|
-
*out->cur++ = ',';
|
|
1247
|
-
fill_indent(out, d2);
|
|
1248
|
-
*out->cur++ = '"';
|
|
1249
|
-
*out->cur++ = '^';
|
|
1250
|
-
*out->cur++ = 'i';
|
|
1251
|
-
*out->cur++ = '"';
|
|
1252
|
-
*out->cur++ = ':';
|
|
1253
|
-
dump_ulong(id, out);
|
|
1254
|
-
}
|
|
1255
|
-
{
|
|
1256
|
-
int cnt;
|
|
1257
|
-
// use encoding as the indicator for Ruby 1.8.7 or 1.9.x
|
|
1258
|
-
#if HAS_IVAR_HELPERS
|
|
1259
|
-
cnt = (int)rb_ivar_count(obj);
|
|
1260
|
-
#else
|
|
1261
|
-
VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0);
|
|
1262
|
-
VALUE *np = RARRAY_PTR(vars);
|
|
1263
|
-
ID vid;
|
|
1264
|
-
const char *attr;
|
|
1265
|
-
int i;
|
|
1266
|
-
|
|
1267
|
-
cnt = (int)RARRAY_LEN(vars);
|
|
1268
|
-
#endif
|
|
1269
|
-
if (0 != clas && 0 < cnt) {
|
|
1270
|
-
*out->cur++ = ',';
|
|
1271
|
-
}
|
|
1272
|
-
out->depth = depth + 1;
|
|
1273
|
-
#if HAS_IVAR_HELPERS
|
|
1274
|
-
rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
|
|
1275
|
-
if (',' == *(out->cur - 1)) {
|
|
1276
|
-
out->cur--; // backup to overwrite last comma
|
|
1277
|
-
}
|
|
1278
|
-
#else
|
|
1279
|
-
size = d2 * out->indent + 1;
|
|
1280
|
-
#if HAS_EXCEPTION_MAGIC
|
|
1281
|
-
if (Qtrue == rb_obj_is_kind_of(obj, rb_eException)) {
|
|
1282
|
-
if (',' != *(out->cur - 1)) {
|
|
1283
|
-
*out->cur++ = ',';
|
|
1284
|
-
}
|
|
1285
|
-
// message
|
|
1286
|
-
if (out->end - out->cur <= (long)size) {
|
|
1287
|
-
grow(out, size);
|
|
1288
|
-
}
|
|
1289
|
-
fill_indent(out, d2);
|
|
1290
|
-
dump_cstr("~mesg", 5, 0, 0, out);
|
|
1291
|
-
*out->cur++ = ':';
|
|
1292
|
-
dump_val(rb_funcall2(obj, rb_intern("message"), 0, 0), d2, out);
|
|
1293
|
-
if (out->end - out->cur <= 2) {
|
|
1294
|
-
grow(out, 2);
|
|
1295
|
-
}
|
|
1296
|
-
*out->cur++ = ',';
|
|
1297
|
-
// backtrace
|
|
1298
|
-
if (out->end - out->cur <= (long)size) {
|
|
1299
|
-
grow(out, size);
|
|
1300
|
-
}
|
|
1301
|
-
fill_indent(out, d2);
|
|
1302
|
-
dump_cstr("~bt", 3, 0, 0, out);
|
|
1303
|
-
*out->cur++ = ':';
|
|
1304
|
-
dump_val(rb_funcall2(obj, rb_intern("backtrace"), 0, 0), d2, out);
|
|
1305
|
-
if (out->end - out->cur <= 2) {
|
|
1306
|
-
grow(out, 2);
|
|
1307
|
-
}
|
|
1308
|
-
if (0 < cnt) {
|
|
1309
|
-
*out->cur++ = ',';
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
#endif
|
|
1313
|
-
for (i = cnt; 0 < i; i--, np++) {
|
|
1314
|
-
if (out->end - out->cur <= (long)size) {
|
|
1315
|
-
grow(out, size);
|
|
1316
|
-
}
|
|
1317
|
-
vid = rb_to_id(*np);
|
|
1318
|
-
fill_indent(out, d2);
|
|
1319
|
-
attr = rb_id2name(vid);
|
|
1320
|
-
if ('@' == *attr) {
|
|
1321
|
-
attr++;
|
|
1322
|
-
dump_cstr(attr, strlen(attr), 0, 0, out);
|
|
1323
|
-
} else {
|
|
1324
|
-
char buf[32];
|
|
1325
|
-
|
|
1326
|
-
*buf = '~';
|
|
1327
|
-
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
|
1328
|
-
buf[sizeof(buf) - 1] = '\0';
|
|
1329
|
-
dump_cstr(buf, strlen(attr) + 1, 0, 0, out);
|
|
1330
|
-
}
|
|
1331
|
-
*out->cur++ = ':';
|
|
1332
|
-
dump_val(rb_ivar_get(obj, vid), d2, out);
|
|
1333
|
-
if (out->end - out->cur <= 2) {
|
|
1334
|
-
grow(out, 2);
|
|
1335
|
-
}
|
|
1336
|
-
if (1 < i) {
|
|
1337
|
-
*out->cur++ = ',';
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
#endif
|
|
1341
|
-
out->depth = depth;
|
|
1342
|
-
}
|
|
1343
|
-
*out->cur++ = '}';
|
|
1344
|
-
*out->cur = '\0';
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
#if HAS_RSTRUCT
|
|
1348
|
-
static void
|
|
1349
|
-
dump_struct_comp(VALUE obj, int depth, Out out) {
|
|
1350
|
-
if (rb_respond_to(obj, oj_to_hash_id)) {
|
|
1351
|
-
VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
|
|
1352
|
-
|
|
1353
|
-
if (T_HASH != rb_type(h)) {
|
|
1354
|
-
rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
|
1355
|
-
}
|
|
1356
|
-
dump_hash(h, depth, out->opts->mode, out);
|
|
1357
|
-
} else if (rb_respond_to(obj, oj_to_json_id)) {
|
|
1358
|
-
VALUE rs = rb_funcall(obj, oj_to_json_id, 0);
|
|
1359
|
-
const char *s = StringValuePtr(rs);
|
|
1360
|
-
int len = (int)RSTRING_LEN(rs);
|
|
1361
|
-
|
|
1362
|
-
if (out->end - out->cur <= len) {
|
|
1363
|
-
grow(out, len);
|
|
1364
|
-
}
|
|
1365
|
-
memcpy(out->cur, s, len);
|
|
1366
|
-
out->cur += len;
|
|
1367
|
-
} else {
|
|
1368
|
-
dump_struct_obj(obj, depth, out);
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
static void
|
|
1373
|
-
dump_struct_obj(VALUE obj, int depth, Out out) {
|
|
1374
|
-
VALUE clas = rb_obj_class(obj);
|
|
1375
|
-
const char *class_name = rb_class2name(clas);
|
|
1376
|
-
VALUE *vp;
|
|
1377
|
-
int i;
|
|
1378
|
-
int d2 = depth + 1;
|
|
1379
|
-
int d3 = d2 + 1;
|
|
1380
|
-
size_t len = strlen(class_name);
|
|
1381
|
-
size_t size = d2 * out->indent + d3 * out->indent + 10 + len;
|
|
1382
|
-
|
|
1383
|
-
if (out->end - out->cur <= (long)size) {
|
|
1384
|
-
grow(out, size);
|
|
1385
|
-
}
|
|
1386
|
-
*out->cur++ = '{';
|
|
1387
|
-
fill_indent(out, d2);
|
|
1388
|
-
*out->cur++ = '"';
|
|
1389
|
-
*out->cur++ = '^';
|
|
1390
|
-
*out->cur++ = 'u';
|
|
1391
|
-
*out->cur++ = '"';
|
|
1392
|
-
*out->cur++ = ':';
|
|
1393
|
-
*out->cur++ = '[';
|
|
1394
|
-
fill_indent(out, d3);
|
|
1395
|
-
*out->cur++ = '"';
|
|
1396
|
-
memcpy(out->cur, class_name, len);
|
|
1397
|
-
out->cur += len;
|
|
1398
|
-
*out->cur++ = '"';
|
|
1399
|
-
*out->cur++ = ',';
|
|
1400
|
-
size = d3 * out->indent + 2;
|
|
1401
|
-
for (i = (int)RSTRUCT_LEN(obj), vp = RSTRUCT_PTR(obj); 0 < i; i--, vp++) {
|
|
1402
|
-
if (out->end - out->cur <= (long)size) {
|
|
1403
|
-
grow(out, size);
|
|
1404
|
-
}
|
|
1405
|
-
fill_indent(out, d3);
|
|
1406
|
-
dump_val(*vp, d3, out);
|
|
1407
|
-
*out->cur++ = ',';
|
|
1408
|
-
}
|
|
1409
|
-
out->cur--;
|
|
1410
|
-
*out->cur++ = ']';
|
|
1411
|
-
*out->cur++ = '}';
|
|
1412
|
-
*out->cur = '\0';
|
|
1413
|
-
}
|
|
1414
|
-
#endif
|
|
1415
|
-
|
|
1416
|
-
static void
|
|
1417
|
-
dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
1418
|
-
ID *idp;
|
|
1419
|
-
VALUE v;
|
|
1420
|
-
const char *name;
|
|
1421
|
-
size_t size;
|
|
1422
|
-
int d2 = depth + 1;
|
|
1423
|
-
|
|
1424
|
-
if (out->end - out->cur <= 2) {
|
|
1425
|
-
grow(out, 2);
|
|
1426
|
-
}
|
|
1427
|
-
*out->cur++ = '{';
|
|
1428
|
-
if (0 != clas) {
|
|
1429
|
-
const char *class_name = rb_class2name(clas);
|
|
1430
|
-
int clen = (int)strlen(class_name);
|
|
1431
|
-
|
|
1432
|
-
size = d2 * out->indent + clen + 10;
|
|
1433
|
-
if (out->end - out->cur <= (long)size) {
|
|
1434
|
-
grow(out, size);
|
|
1435
|
-
}
|
|
1436
|
-
fill_indent(out, d2);
|
|
1437
|
-
*out->cur++ = '"';
|
|
1438
|
-
*out->cur++ = '^';
|
|
1439
|
-
*out->cur++ = 'O';
|
|
1440
|
-
*out->cur++ = '"';
|
|
1441
|
-
*out->cur++ = ':';
|
|
1442
|
-
dump_cstr(class_name, clen, 0, 0, out);
|
|
1443
|
-
*out->cur++ = ',';
|
|
1444
|
-
}
|
|
1445
|
-
size = d2 * out->indent + 1;
|
|
1446
|
-
for (idp = odd->attrs; 0 != *idp; idp++) {
|
|
1447
|
-
if (out->end - out->cur <= (long)size) {
|
|
1448
|
-
grow(out, size);
|
|
1449
|
-
}
|
|
1450
|
-
name = rb_id2name(*idp);
|
|
1451
|
-
v = rb_funcall(obj, *idp, 0);
|
|
1452
|
-
fill_indent(out, d2);
|
|
1453
|
-
dump_cstr(name, strlen(name), 0, 0, out);
|
|
1454
|
-
*out->cur++ = ':';
|
|
1455
|
-
dump_val(v, d2, out);
|
|
1456
|
-
if (out->end - out->cur <= 2) {
|
|
1457
|
-
grow(out, 2);
|
|
1458
|
-
}
|
|
1459
|
-
*out->cur++ = ',';
|
|
1460
|
-
}
|
|
1461
|
-
out->cur--;
|
|
1462
|
-
*out->cur++ = '}';
|
|
1463
|
-
*out->cur = '\0';
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
static void
|
|
1467
|
-
raise_strict(VALUE obj) {
|
|
1468
|
-
rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in strict mode.\n", rb_class2name(rb_obj_class(obj)));
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
static void
|
|
1472
|
-
dump_val(VALUE obj, int depth, Out out) {
|
|
1473
|
-
switch (rb_type(obj)) {
|
|
1474
|
-
case T_NIL: dump_nil(out); break;
|
|
1475
|
-
case T_TRUE: dump_true(out); break;
|
|
1476
|
-
case T_FALSE: dump_false(out); break;
|
|
1477
|
-
case T_FIXNUM: dump_fixnum(obj, out); break;
|
|
1478
|
-
case T_FLOAT: dump_float(obj, out); break;
|
|
1479
|
-
case T_BIGNUM: dump_bignum(obj, out); break;
|
|
1480
|
-
case T_STRING:
|
|
1481
|
-
switch (out->opts->mode) {
|
|
1482
|
-
case StrictMode:
|
|
1483
|
-
case NullMode:
|
|
1484
|
-
case CompatMode: dump_str_comp(obj, out); break;
|
|
1485
|
-
case ObjectMode:
|
|
1486
|
-
default: dump_str_obj(obj, out); break;
|
|
1487
|
-
}
|
|
1488
|
-
break;
|
|
1489
|
-
case T_SYMBOL:
|
|
1490
|
-
switch (out->opts->mode) {
|
|
1491
|
-
case StrictMode: raise_strict(obj); break;
|
|
1492
|
-
case NullMode: dump_nil(out); break;
|
|
1493
|
-
case CompatMode: dump_sym_comp(obj, out); break;
|
|
1494
|
-
case ObjectMode:
|
|
1495
|
-
default: dump_sym_obj(obj, out); break;
|
|
1496
|
-
}
|
|
1497
|
-
break;
|
|
1498
|
-
case T_ARRAY: dump_array(obj, depth, out); break;
|
|
1499
|
-
case T_HASH: dump_hash(obj, depth, out->opts->mode, out); break;
|
|
1500
|
-
case T_CLASS:
|
|
1501
|
-
switch (out->opts->mode) {
|
|
1502
|
-
case StrictMode: raise_strict(obj); break;
|
|
1503
|
-
case NullMode: dump_nil(out); break;
|
|
1504
|
-
case CompatMode: dump_class_comp(obj, out); break;
|
|
1505
|
-
case ObjectMode:
|
|
1506
|
-
default: dump_class_obj(obj, out); break;
|
|
1507
|
-
}
|
|
1508
|
-
break;
|
|
1509
|
-
#if (defined T_RATIONAL && defined RRATIONAL)
|
|
1510
|
-
case T_RATIONAL:
|
|
1511
|
-
#endif
|
|
1512
|
-
case T_OBJECT:
|
|
1513
|
-
switch (out->opts->mode) {
|
|
1514
|
-
case StrictMode: dump_data_strict(obj, out); break;
|
|
1515
|
-
case NullMode: dump_data_null(obj, out); break;
|
|
1516
|
-
case CompatMode: dump_obj_comp(obj, depth, out); break;
|
|
1517
|
-
case ObjectMode:
|
|
1518
|
-
default: dump_obj_obj(obj, depth, out); break;
|
|
1519
|
-
}
|
|
1520
|
-
break;
|
|
1521
|
-
case T_DATA:
|
|
1522
|
-
switch (out->opts->mode) {
|
|
1523
|
-
case StrictMode: dump_data_strict(obj, out); break;
|
|
1524
|
-
case NullMode: dump_data_null(obj, out); break;
|
|
1525
|
-
case CompatMode: dump_data_comp(obj, out); break;
|
|
1526
|
-
case ObjectMode:
|
|
1527
|
-
default: dump_data_obj(obj, depth, out); break;
|
|
1528
|
-
}
|
|
1529
|
-
break;
|
|
1530
|
-
#if HAS_RSTRUCT
|
|
1531
|
-
case T_STRUCT: // for Range
|
|
1532
|
-
switch (out->opts->mode) {
|
|
1533
|
-
case StrictMode: raise_strict(obj); break;
|
|
1534
|
-
case NullMode: dump_nil(out); break;
|
|
1535
|
-
case CompatMode: dump_struct_comp(obj, depth, out); break;
|
|
1536
|
-
case ObjectMode:
|
|
1537
|
-
default: dump_struct_obj(obj, depth, out); break;
|
|
1538
|
-
}
|
|
1539
|
-
break;
|
|
1540
|
-
#endif
|
|
1541
|
-
#if (defined T_COMPLEX && defined RCOMPLEX)
|
|
1542
|
-
case T_COMPLEX:
|
|
1543
|
-
#endif
|
|
1544
|
-
case T_REGEXP:
|
|
1545
|
-
switch (out->opts->mode) {
|
|
1546
|
-
case StrictMode: raise_strict(obj); break;
|
|
1547
|
-
case NullMode: dump_nil(out); break;
|
|
1548
|
-
case CompatMode:
|
|
1549
|
-
case ObjectMode:
|
|
1550
|
-
default: dump_obj_comp(obj, depth, out); break;
|
|
1551
|
-
}
|
|
1552
|
-
break;
|
|
1553
|
-
default:
|
|
1554
|
-
rb_raise(rb_eNotImpError, "Failed to dump '%s' Object (%02x)\n",
|
|
1555
|
-
rb_class2name(rb_obj_class(obj)), rb_type(obj));
|
|
1556
|
-
break;
|
|
1557
|
-
}
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
static void
|
|
1561
|
-
dump_obj_to_json(VALUE obj, Options copts, Out out) {
|
|
1562
|
-
out->buf = ALLOC_N(char, 65336);
|
|
1563
|
-
out->end = out->buf + 65325; // 1 less than end plus extra for possible errors
|
|
1564
|
-
out->cur = out->buf;
|
|
1565
|
-
out->circ_cnt = 0;
|
|
1566
|
-
out->opts = copts;
|
|
1567
|
-
out->hash_cnt = 0;
|
|
1568
|
-
if (Yes == copts->circular) {
|
|
1569
|
-
oj_cache8_new(&out->circ_cache);
|
|
1570
|
-
}
|
|
1571
|
-
out->indent = copts->indent;
|
|
1572
|
-
dump_val(obj, 0, out);
|
|
1573
|
-
if (Yes == copts->circular) {
|
|
1574
|
-
oj_cache8_delete(out->circ_cache);
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
char*
|
|
1579
|
-
oj_write_obj_to_str(VALUE obj, Options copts) {
|
|
1580
|
-
struct _Out out;
|
|
1581
|
-
|
|
1582
|
-
dump_obj_to_json(obj, copts, &out);
|
|
1583
|
-
|
|
1584
|
-
return out.buf;
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
void
|
|
1588
|
-
oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
|
|
1589
|
-
struct _Out out;
|
|
1590
|
-
size_t size;
|
|
1591
|
-
FILE *f;
|
|
1592
|
-
|
|
1593
|
-
dump_obj_to_json(obj, copts, &out);
|
|
1594
|
-
size = out.cur - out.buf;
|
|
1595
|
-
if (0 == (f = fopen(path, "w"))) {
|
|
1596
|
-
rb_raise(rb_eIOError, "%s\n", strerror(errno));
|
|
1597
|
-
}
|
|
1598
|
-
if (size != fwrite(out.buf, 1, size, f)) {
|
|
1599
|
-
int err = ferror(f);
|
|
1600
|
-
|
|
1601
|
-
rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", err, strerror(err));
|
|
1602
|
-
}
|
|
1603
|
-
xfree(out.buf);
|
|
1604
|
-
fclose(f);
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
// dump leaf functions
|
|
1608
|
-
|
|
1609
|
-
inline static void
|
|
1610
|
-
dump_chars(const char *s, size_t size, Out out) {
|
|
1611
|
-
if (out->end - out->cur <= (long)size) {
|
|
1612
|
-
grow(out, size);
|
|
1613
|
-
}
|
|
1614
|
-
memcpy(out->cur, s, size);
|
|
1615
|
-
out->cur += size;
|
|
1616
|
-
*out->cur = '\0';
|
|
1617
|
-
}
|
|
1618
|
-
|
|
1619
|
-
static void
|
|
1620
|
-
dump_leaf_str(Leaf leaf, Out out) {
|
|
1621
|
-
switch (leaf->value_type) {
|
|
1622
|
-
case STR_VAL:
|
|
1623
|
-
dump_cstr(leaf->str, strlen(leaf->str), 0, 0, out);
|
|
1624
|
-
break;
|
|
1625
|
-
case RUBY_VAL:
|
|
1626
|
-
dump_cstr(StringValuePtr(leaf->value), RSTRING_LEN(leaf->value), 0, 0, out);
|
|
1627
|
-
break;
|
|
1628
|
-
case COL_VAL:
|
|
1629
|
-
default:
|
|
1630
|
-
rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type);
|
|
1631
|
-
break;
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
|
-
static void
|
|
1636
|
-
dump_leaf_fixnum(Leaf leaf, Out out) {
|
|
1637
|
-
switch (leaf->value_type) {
|
|
1638
|
-
case STR_VAL:
|
|
1639
|
-
dump_chars(leaf->str, strlen(leaf->str), out);
|
|
1640
|
-
break;
|
|
1641
|
-
case RUBY_VAL:
|
|
1642
|
-
if (T_BIGNUM == rb_type(leaf->value)) {
|
|
1643
|
-
dump_bignum(leaf->value, out);
|
|
1644
|
-
} else {
|
|
1645
|
-
dump_fixnum(leaf->value, out);
|
|
1646
|
-
}
|
|
1647
|
-
break;
|
|
1648
|
-
case COL_VAL:
|
|
1649
|
-
default:
|
|
1650
|
-
rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type);
|
|
1651
|
-
break;
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1655
|
-
static void
|
|
1656
|
-
dump_leaf_float(Leaf leaf, Out out) {
|
|
1657
|
-
switch (leaf->value_type) {
|
|
1658
|
-
case STR_VAL:
|
|
1659
|
-
dump_chars(leaf->str, strlen(leaf->str), out);
|
|
1660
|
-
break;
|
|
1661
|
-
case RUBY_VAL:
|
|
1662
|
-
dump_float(leaf->value, out);
|
|
1663
|
-
break;
|
|
1664
|
-
case COL_VAL:
|
|
1665
|
-
default:
|
|
1666
|
-
rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type);
|
|
1667
|
-
break;
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
|
-
|
|
1671
|
-
static void
|
|
1672
|
-
dump_leaf_array(Leaf leaf, int depth, Out out) {
|
|
1673
|
-
size_t size;
|
|
1674
|
-
int d2 = depth + 1;
|
|
1675
|
-
|
|
1676
|
-
size = 2;
|
|
1677
|
-
if (out->end - out->cur <= (long)size) {
|
|
1678
|
-
grow(out, size);
|
|
1679
|
-
}
|
|
1680
|
-
*out->cur++ = '[';
|
|
1681
|
-
if (0 == leaf->elements) {
|
|
1682
|
-
*out->cur++ = ']';
|
|
1683
|
-
} else {
|
|
1684
|
-
Leaf first = leaf->elements->next;
|
|
1685
|
-
Leaf e = first;
|
|
1686
|
-
|
|
1687
|
-
size = d2 * out->indent + 2;
|
|
1688
|
-
do {
|
|
1689
|
-
if (out->end - out->cur <= (long)size) {
|
|
1690
|
-
grow(out, size);
|
|
1691
|
-
}
|
|
1692
|
-
fill_indent(out, d2);
|
|
1693
|
-
dump_leaf(e, d2, out);
|
|
1694
|
-
if (e->next != first) {
|
|
1695
|
-
*out->cur++ = ',';
|
|
1696
|
-
}
|
|
1697
|
-
e = e->next;
|
|
1698
|
-
} while (e != first);
|
|
1699
|
-
size = depth * out->indent + 1;
|
|
1700
|
-
if (out->end - out->cur <= (long)size) {
|
|
1701
|
-
grow(out, size);
|
|
1702
|
-
}
|
|
1703
|
-
fill_indent(out, depth);
|
|
1704
|
-
*out->cur++ = ']';
|
|
1705
|
-
}
|
|
1706
|
-
*out->cur = '\0';
|
|
1707
|
-
}
|
|
1708
|
-
|
|
1709
|
-
static void
|
|
1710
|
-
dump_leaf_hash(Leaf leaf, int depth, Out out) {
|
|
1711
|
-
size_t size;
|
|
1712
|
-
int d2 = depth + 1;
|
|
1713
|
-
|
|
1714
|
-
size = 2;
|
|
1715
|
-
if (out->end - out->cur <= (long)size) {
|
|
1716
|
-
grow(out, size);
|
|
1717
|
-
}
|
|
1718
|
-
*out->cur++ = '{';
|
|
1719
|
-
if (0 == leaf->elements) {
|
|
1720
|
-
*out->cur++ = '}';
|
|
1721
|
-
} else {
|
|
1722
|
-
Leaf first = leaf->elements->next;
|
|
1723
|
-
Leaf e = first;
|
|
1724
|
-
|
|
1725
|
-
size = d2 * out->indent + 2;
|
|
1726
|
-
do {
|
|
1727
|
-
if (out->end - out->cur <= (long)size) {
|
|
1728
|
-
grow(out, size);
|
|
1729
|
-
}
|
|
1730
|
-
fill_indent(out, d2);
|
|
1731
|
-
dump_cstr(e->key, strlen(e->key), 0, 0, out);
|
|
1732
|
-
*out->cur++ = ':';
|
|
1733
|
-
dump_leaf(e, d2, out);
|
|
1734
|
-
if (e->next != first) {
|
|
1735
|
-
*out->cur++ = ',';
|
|
1736
|
-
}
|
|
1737
|
-
e = e->next;
|
|
1738
|
-
} while (e != first);
|
|
1739
|
-
size = depth * out->indent + 1;
|
|
1740
|
-
if (out->end - out->cur <= (long)size) {
|
|
1741
|
-
grow(out, size);
|
|
1742
|
-
}
|
|
1743
|
-
fill_indent(out, depth);
|
|
1744
|
-
*out->cur++ = '}';
|
|
1048
|
+
assure_size(out, cnt);
|
|
1049
|
+
for (b = buf; '\0' != *b; b++) {
|
|
1050
|
+
*out->cur++ = *b;
|
|
1745
1051
|
}
|
|
1746
1052
|
*out->cur = '\0';
|
|
1747
1053
|
}
|
|
1748
|
-
|
|
1749
|
-
static void
|
|
1750
|
-
dump_leaf(Leaf leaf, int depth, Out out) {
|
|
1751
|
-
switch (leaf->type) {
|
|
1752
|
-
case T_NIL:
|
|
1753
|
-
dump_nil(out);
|
|
1754
|
-
break;
|
|
1755
|
-
case T_TRUE:
|
|
1756
|
-
dump_true(out);
|
|
1757
|
-
break;
|
|
1758
|
-
case T_FALSE:
|
|
1759
|
-
dump_false(out);
|
|
1760
|
-
break;
|
|
1761
|
-
case T_STRING:
|
|
1762
|
-
dump_leaf_str(leaf, out);
|
|
1763
|
-
break;
|
|
1764
|
-
case T_FIXNUM:
|
|
1765
|
-
dump_leaf_fixnum(leaf, out);
|
|
1766
|
-
break;
|
|
1767
|
-
case T_FLOAT:
|
|
1768
|
-
dump_leaf_float(leaf, out);
|
|
1769
|
-
break;
|
|
1770
|
-
case T_ARRAY:
|
|
1771
|
-
dump_leaf_array(leaf, depth, out);
|
|
1772
|
-
break;
|
|
1773
|
-
case T_HASH:
|
|
1774
|
-
dump_leaf_hash(leaf, depth, out);
|
|
1775
|
-
break;
|
|
1776
|
-
default:
|
|
1777
|
-
rb_raise(rb_eTypeError, "Unexpected type %02x.\n", leaf->type);
|
|
1778
|
-
break;
|
|
1779
|
-
}
|
|
1780
|
-
}
|
|
1781
|
-
|
|
1782
|
-
static void
|
|
1783
|
-
dump_leaf_to_json(Leaf leaf, Options copts, Out out) {
|
|
1784
|
-
out->buf = ALLOC_N(char, 65336);
|
|
1785
|
-
out->end = out->buf + 65325; // 10 less than end plus extra for possible errors
|
|
1786
|
-
out->cur = out->buf;
|
|
1787
|
-
out->circ_cnt = 0;
|
|
1788
|
-
out->opts = copts;
|
|
1789
|
-
out->hash_cnt = 0;
|
|
1790
|
-
out->indent = copts->indent;
|
|
1791
|
-
dump_leaf(leaf, 0, out);
|
|
1792
|
-
}
|
|
1793
|
-
|
|
1794
|
-
char*
|
|
1795
|
-
oj_write_leaf_to_str(Leaf leaf, Options copts) {
|
|
1796
|
-
struct _Out out;
|
|
1797
|
-
|
|
1798
|
-
dump_leaf_to_json(leaf, copts, &out);
|
|
1799
|
-
|
|
1800
|
-
return out.buf;
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
void
|
|
1804
|
-
oj_write_leaf_to_file(Leaf leaf, const char *path, Options copts) {
|
|
1805
|
-
struct _Out out;
|
|
1806
|
-
size_t size;
|
|
1807
|
-
FILE *f;
|
|
1808
|
-
|
|
1809
|
-
dump_leaf_to_json(leaf, copts, &out);
|
|
1810
|
-
size = out.cur - out.buf;
|
|
1811
|
-
if (0 == (f = fopen(path, "w"))) {
|
|
1812
|
-
rb_raise(rb_eIOError, "%s\n", strerror(errno));
|
|
1813
|
-
}
|
|
1814
|
-
if (size != fwrite(out.buf, 1, size, f)) {
|
|
1815
|
-
int err = ferror(f);
|
|
1816
|
-
|
|
1817
|
-
rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", err, strerror(err));
|
|
1818
|
-
}
|
|
1819
|
-
xfree(out.buf);
|
|
1820
|
-
fclose(f);
|
|
1821
|
-
}
|