oj 3.11.0 → 3.16.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1421 -0
- data/README.md +20 -5
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +48 -38
- data/ext/oj/cache.c +329 -0
- data/ext/oj/cache.h +22 -0
- data/ext/oj/cache8.c +60 -62
- data/ext/oj/cache8.h +8 -7
- data/ext/oj/circarray.c +35 -35
- data/ext/oj/circarray.h +11 -9
- data/ext/oj/code.c +156 -174
- data/ext/oj/code.h +19 -18
- data/ext/oj/compat.c +140 -197
- data/ext/oj/custom.c +737 -879
- data/ext/oj/debug.c +126 -0
- data/ext/oj/dump.c +830 -835
- data/ext/oj/dump.h +65 -53
- data/ext/oj/dump_compat.c +566 -642
- data/ext/oj/dump_leaf.c +95 -182
- data/ext/oj/dump_object.c +518 -659
- data/ext/oj/dump_strict.c +301 -334
- data/ext/oj/encode.h +3 -4
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +27 -24
- data/ext/oj/err.h +38 -13
- data/ext/oj/extconf.rb +23 -7
- data/ext/oj/fast.c +1043 -1073
- data/ext/oj/intern.c +313 -0
- data/ext/oj/intern.h +22 -0
- data/ext/oj/mem.c +318 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +449 -423
- data/ext/oj/object.c +530 -576
- data/ext/oj/odd.c +155 -138
- data/ext/oj/odd.h +24 -22
- data/ext/oj/oj.c +1331 -993
- data/ext/oj/oj.h +306 -292
- data/ext/oj/parse.c +934 -938
- data/ext/oj/parse.h +73 -70
- data/ext/oj/parser.c +1600 -0
- data/ext/oj/parser.h +101 -0
- data/ext/oj/rails.c +795 -845
- data/ext/oj/rails.h +7 -7
- data/ext/oj/reader.c +132 -140
- data/ext/oj/reader.h +67 -78
- data/ext/oj/resolve.c +40 -59
- data/ext/oj/resolve.h +3 -2
- data/ext/oj/rxclass.c +67 -67
- data/ext/oj/rxclass.h +11 -9
- data/ext/oj/saj.c +441 -480
- data/ext/oj/saj2.c +584 -0
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +78 -111
- data/ext/oj/sparse.c +726 -730
- data/ext/oj/stream_writer.c +146 -165
- data/ext/oj/strict.c +103 -123
- data/ext/oj/string_writer.c +241 -253
- data/ext/oj/trace.c +29 -33
- data/ext/oj/trace.h +41 -11
- data/ext/oj/usual.c +1218 -0
- data/ext/oj/usual.h +69 -0
- data/ext/oj/util.c +103 -103
- data/ext/oj/util.h +3 -2
- data/ext/oj/val_stack.c +60 -49
- data/ext/oj/val_stack.h +79 -85
- data/ext/oj/validate.c +46 -0
- data/ext/oj/wab.c +307 -350
- data/lib/oj/active_support_helper.rb +1 -3
- data/lib/oj/bag.rb +8 -1
- data/lib/oj/easy_hash.rb +9 -9
- data/lib/oj/error.rb +1 -2
- data/lib/oj/json.rb +162 -150
- data/lib/oj/mimic.rb +9 -19
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/state.rb +12 -8
- data/lib/oj/version.rb +1 -2
- data/lib/oj.rb +2 -0
- data/pages/Compatibility.md +1 -1
- data/pages/InstallOptions.md +20 -0
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +8 -3
- data/pages/Options.md +43 -5
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +14 -2
- data/test/_test_active.rb +8 -9
- data/test/_test_active_mimic.rb +7 -8
- data/test/_test_mimic_rails.rb +17 -20
- data/test/activerecord/result_test.rb +12 -8
- data/test/activesupport6/encoding_test.rb +63 -28
- data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
- data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
- data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
- data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
- data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
- data/test/files.rb +15 -15
- data/test/foo.rb +17 -43
- data/test/helper.rb +16 -3
- data/test/isolated/shared.rb +3 -2
- data/test/json_gem/json_addition_test.rb +2 -2
- data/test/json_gem/json_common_interface_test.rb +8 -6
- data/test/json_gem/json_encoding_test.rb +0 -0
- data/test/json_gem/json_ext_parser_test.rb +1 -0
- data/test/json_gem/json_fixtures_test.rb +3 -2
- data/test/json_gem/json_generator_test.rb +71 -41
- data/test/json_gem/json_generic_object_test.rb +11 -11
- data/test/json_gem/json_parser_test.rb +54 -47
- data/test/json_gem/json_string_matching_test.rb +9 -9
- data/test/json_gem/test_helper.rb +12 -0
- data/test/mem.rb +34 -0
- data/test/perf.rb +22 -27
- data/test/perf_compat.rb +31 -33
- data/test/perf_dump.rb +50 -0
- data/test/perf_fast.rb +80 -82
- data/test/perf_file.rb +27 -29
- data/test/perf_object.rb +65 -69
- data/test/perf_once.rb +59 -0
- data/test/perf_parser.rb +183 -0
- data/test/perf_saj.rb +46 -54
- data/test/perf_scp.rb +58 -69
- data/test/perf_simple.rb +41 -39
- data/test/perf_strict.rb +74 -82
- data/test/perf_wab.rb +67 -69
- data/test/prec.rb +5 -5
- data/test/sample/change.rb +0 -1
- data/test/sample/dir.rb +0 -1
- data/test/sample/doc.rb +0 -1
- data/test/sample/file.rb +0 -1
- data/test/sample/group.rb +0 -1
- data/test/sample/hasprops.rb +0 -1
- data/test/sample/layer.rb +0 -1
- data/test/sample/rect.rb +0 -1
- data/test/sample/shape.rb +0 -1
- data/test/sample/text.rb +0 -1
- data/test/sample.rb +16 -16
- data/test/sample_json.rb +8 -8
- data/test/test_compat.rb +97 -45
- data/test/test_custom.rb +73 -51
- data/test/test_debian.rb +7 -10
- data/test/test_fast.rb +135 -79
- data/test/test_file.rb +41 -30
- data/test/test_gc.rb +16 -5
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +15 -5
- data/test/test_integer_range.rb +9 -9
- data/test/test_null.rb +20 -20
- data/test/test_object.rb +99 -96
- data/test/test_parser.rb +11 -0
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +337 -0
- data/test/test_parser_usual.rb +251 -0
- data/test/test_rails.rb +2 -2
- data/test/test_saj.rb +10 -8
- data/test/test_scp.rb +38 -40
- data/test/test_strict.rb +40 -32
- data/test/test_various.rb +165 -84
- data/test/test_wab.rb +48 -44
- data/test/test_writer.rb +47 -47
- data/test/tests.rb +13 -5
- data/test/tests_mimic.rb +12 -3
- data/test/tests_mimic_addition.rb +12 -3
- metadata +75 -127
- data/ext/oj/hash.c +0 -135
- data/ext/oj/hash.h +0 -18
- data/ext/oj/hash_test.c +0 -484
- data/test/activesupport4/decoding_test.rb +0 -108
- data/test/activesupport4/encoding_test.rb +0 -531
- data/test/activesupport4/test_helper.rb +0 -41
- data/test/activesupport5/test_helper.rb +0 -72
- data/test/bar.rb +0 -35
- data/test/baz.rb +0 -16
- data/test/zoo.rb +0 -13
data/ext/oj/dump.c
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
// Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
3
|
+
|
4
|
+
#include "dump.h"
|
2
5
|
|
3
6
|
#include <errno.h>
|
4
7
|
#include <math.h>
|
@@ -7,33 +10,37 @@
|
|
7
10
|
#include <stdlib.h>
|
8
11
|
#include <string.h>
|
9
12
|
#include <unistd.h>
|
13
|
+
#if !IS_WINDOWS
|
14
|
+
#include <poll.h>
|
15
|
+
#endif
|
10
16
|
|
11
|
-
#include "oj.h"
|
12
17
|
#include "cache8.h"
|
13
|
-
#include "
|
18
|
+
#include "mem.h"
|
14
19
|
#include "odd.h"
|
20
|
+
#include "oj.h"
|
15
21
|
#include "trace.h"
|
16
22
|
#include "util.h"
|
17
23
|
|
18
24
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
19
|
-
#define OJ_INFINITY (1.0/0.0)
|
25
|
+
#define OJ_INFINITY (1.0 / 0.0)
|
20
26
|
|
21
27
|
#define MAX_DEPTH 1000
|
22
28
|
|
23
|
-
static const char
|
24
|
-
static const char
|
25
|
-
static const char
|
29
|
+
static const char inf_val[] = INF_VAL;
|
30
|
+
static const char ninf_val[] = NINF_VAL;
|
31
|
+
static const char nan_val[] = NAN_VAL;
|
26
32
|
|
27
|
-
typedef unsigned long
|
33
|
+
typedef unsigned long ulong;
|
28
34
|
|
29
|
-
static size_t
|
30
|
-
static size_t
|
31
|
-
static size_t
|
35
|
+
static size_t hibit_friendly_size(const uint8_t *str, size_t len);
|
36
|
+
static size_t slash_friendly_size(const uint8_t *str, size_t len);
|
37
|
+
static size_t xss_friendly_size(const uint8_t *str, size_t len);
|
38
|
+
static size_t ascii_friendly_size(const uint8_t *str, size_t len);
|
32
39
|
|
33
|
-
static const char
|
40
|
+
static const char hex_chars[17] = "0123456789abcdef";
|
34
41
|
|
35
42
|
// JSON standard except newlines are no escaped
|
36
|
-
static char
|
43
|
+
static char newline_friendly_chars[256] = "\
|
37
44
|
66666666221622666666666666666666\
|
38
45
|
11211111111111111111111111111111\
|
39
46
|
11111111111111111111111111112111\
|
@@ -44,7 +51,7 @@ static char newline_friendly_chars[256] = "\
|
|
44
51
|
11111111111111111111111111111111";
|
45
52
|
|
46
53
|
// JSON standard
|
47
|
-
static char
|
54
|
+
static char hibit_friendly_chars[256] = "\
|
48
55
|
66666666222622666666666666666666\
|
49
56
|
11211111111111111111111111111111\
|
50
57
|
11111111111111111111111111112111\
|
@@ -54,9 +61,20 @@ static char hibit_friendly_chars[256] = "\
|
|
54
61
|
11111111111111111111111111111111\
|
55
62
|
11111111111111111111111111111111";
|
56
63
|
|
64
|
+
// JSON standard but escape forward slashes `/`
|
65
|
+
static char slash_friendly_chars[256] = "\
|
66
|
+
66666666222622666666666666666666\
|
67
|
+
11211111111111121111111111111111\
|
68
|
+
11111111111111111111111111112111\
|
69
|
+
11111111111111111111111111111111\
|
70
|
+
11111111111111111111111111111111\
|
71
|
+
11111111111111111111111111111111\
|
72
|
+
11111111111111111111111111111111\
|
73
|
+
11111111111111111111111111111111";
|
74
|
+
|
57
75
|
// High bit set characters are always encoded as unicode. Worse case is 3
|
58
76
|
// bytes per character in the output. That makes this conservative.
|
59
|
-
static char
|
77
|
+
static char ascii_friendly_chars[256] = "\
|
60
78
|
66666666222622666666666666666666\
|
61
79
|
11211111111111111111111111111111\
|
62
80
|
11111111111111111111111111112111\
|
@@ -67,7 +85,7 @@ static char ascii_friendly_chars[256] = "\
|
|
67
85
|
33333333333333333333333333333333";
|
68
86
|
|
69
87
|
// XSS safe mode
|
70
|
-
static char
|
88
|
+
static char xss_friendly_chars[256] = "\
|
71
89
|
66666666222622666666666666666666\
|
72
90
|
11211161111111121111111111116161\
|
73
91
|
11111111111111111111111111112111\
|
@@ -78,7 +96,7 @@ static char xss_friendly_chars[256] = "\
|
|
78
96
|
33333333333333333333333333333333";
|
79
97
|
|
80
98
|
// JSON XSS combo
|
81
|
-
static char
|
99
|
+
static char hixss_friendly_chars[256] = "\
|
82
100
|
66666666222622666666666666666666\
|
83
101
|
11211111111111111111111111111111\
|
84
102
|
11111111111111111111111111112111\
|
@@ -89,7 +107,7 @@ static char hixss_friendly_chars[256] = "\
|
|
89
107
|
11611111111111111111111111111111";
|
90
108
|
|
91
109
|
// Rails XSS combo
|
92
|
-
static char
|
110
|
+
static char rails_xss_friendly_chars[256] = "\
|
93
111
|
66666666222622666666666666666666\
|
94
112
|
11211161111111111111111111116161\
|
95
113
|
11111111111111111111111111112111\
|
@@ -100,7 +118,7 @@ static char rails_xss_friendly_chars[256] = "\
|
|
100
118
|
11611111111111111111111111111111";
|
101
119
|
|
102
120
|
// Rails HTML non-escape
|
103
|
-
static char
|
121
|
+
static char rails_friendly_chars[256] = "\
|
104
122
|
66666666222622666666666666666666\
|
105
123
|
11211111111111111111111111111111\
|
106
124
|
11111111111111111111111111112111\
|
@@ -110,248 +128,232 @@ static char rails_friendly_chars[256] = "\
|
|
110
128
|
11111111111111111111111111111111\
|
111
129
|
11111111111111111111111111111111";
|
112
130
|
|
113
|
-
static void
|
114
|
-
raise_strict(VALUE obj) {
|
131
|
+
static void raise_strict(VALUE obj) {
|
115
132
|
rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in strict mode.", rb_class2name(rb_obj_class(obj)));
|
116
133
|
}
|
117
134
|
|
118
|
-
inline static size_t
|
119
|
-
|
120
|
-
size_t
|
121
|
-
size_t i = len;
|
135
|
+
inline static size_t calculate_string_size(const uint8_t *str, size_t len, const char *table) {
|
136
|
+
size_t size = 0;
|
137
|
+
size_t i = len;
|
122
138
|
|
123
|
-
for (;
|
124
|
-
|
139
|
+
for (; 3 < i; i -= 4) {
|
140
|
+
size += table[*str++];
|
141
|
+
size += table[*str++];
|
142
|
+
size += table[*str++];
|
143
|
+
size += table[*str++];
|
144
|
+
}
|
145
|
+
for (; 0 < i; i--) {
|
146
|
+
size += table[*str++];
|
125
147
|
}
|
126
148
|
return size - len * (size_t)'0';
|
127
149
|
}
|
128
150
|
|
129
|
-
inline static size_t
|
130
|
-
|
131
|
-
size_t size = 0;
|
132
|
-
size_t i = len;
|
133
|
-
|
134
|
-
for (; 0 < i; str++, i--) {
|
135
|
-
size += hibit_friendly_chars[*str];
|
136
|
-
}
|
137
|
-
return size - len * (size_t)'0';
|
151
|
+
inline static size_t newline_friendly_size(const uint8_t *str, size_t len) {
|
152
|
+
return calculate_string_size(str, len, newline_friendly_chars);
|
138
153
|
}
|
139
154
|
|
140
|
-
inline static size_t
|
141
|
-
|
142
|
-
|
143
|
-
size_t i = len;
|
155
|
+
inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
|
156
|
+
return calculate_string_size(str, len, hibit_friendly_chars);
|
157
|
+
}
|
144
158
|
|
145
|
-
|
146
|
-
|
147
|
-
}
|
148
|
-
return size - len * (size_t)'0';
|
159
|
+
inline static size_t slash_friendly_size(const uint8_t *str, size_t len) {
|
160
|
+
return calculate_string_size(str, len, slash_friendly_chars);
|
149
161
|
}
|
150
162
|
|
151
|
-
inline static size_t
|
152
|
-
|
153
|
-
|
154
|
-
size_t i = len;
|
163
|
+
inline static size_t ascii_friendly_size(const uint8_t *str, size_t len) {
|
164
|
+
return calculate_string_size(str, len, ascii_friendly_chars);
|
165
|
+
}
|
155
166
|
|
156
|
-
|
157
|
-
|
158
|
-
}
|
159
|
-
return size - len * (size_t)'0';
|
167
|
+
inline static size_t xss_friendly_size(const uint8_t *str, size_t len) {
|
168
|
+
return calculate_string_size(str, len, xss_friendly_chars);
|
160
169
|
}
|
161
170
|
|
162
|
-
inline static size_t
|
163
|
-
|
164
|
-
size_t
|
165
|
-
|
166
|
-
bool check = false;
|
171
|
+
inline static size_t hixss_friendly_size(const uint8_t *str, size_t len) {
|
172
|
+
size_t size = 0;
|
173
|
+
size_t i = len;
|
174
|
+
bool check = false;
|
167
175
|
|
168
176
|
for (; 0 < i; str++, i--) {
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
177
|
+
size += hixss_friendly_chars[*str];
|
178
|
+
if (0 != (0x80 & *str)) {
|
179
|
+
check = true;
|
180
|
+
}
|
173
181
|
}
|
174
182
|
return size - len * (size_t)'0' + check;
|
175
183
|
}
|
176
184
|
|
177
|
-
inline static long
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
uint8_t hi = 0;
|
185
|
+
inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) {
|
186
|
+
long size = 0;
|
187
|
+
size_t i = len;
|
188
|
+
uint8_t hi = 0;
|
182
189
|
|
183
190
|
for (; 0 < i; str++, i--) {
|
184
|
-
|
185
|
-
|
191
|
+
size += rails_xss_friendly_chars[*str];
|
192
|
+
hi |= *str & 0x80;
|
186
193
|
}
|
187
194
|
if (0 == hi) {
|
188
|
-
|
195
|
+
return size - len * (size_t)'0';
|
189
196
|
}
|
190
197
|
return -(size - len * (size_t)'0');
|
191
198
|
}
|
192
199
|
|
193
|
-
inline static size_t
|
194
|
-
|
195
|
-
size_t
|
196
|
-
|
200
|
+
inline static size_t rails_friendly_size(const uint8_t *str, size_t len) {
|
201
|
+
long size = 0;
|
202
|
+
size_t i = len;
|
203
|
+
uint8_t hi = 0;
|
197
204
|
|
198
205
|
for (; 0 < i; str++, i--) {
|
199
|
-
|
206
|
+
size += rails_friendly_chars[*str];
|
207
|
+
hi |= *str & 0x80;
|
200
208
|
}
|
201
|
-
|
209
|
+
if (0 == hi) {
|
210
|
+
return size - len * (size_t)'0';
|
211
|
+
}
|
212
|
+
return -(size - len * (size_t)'0');
|
202
213
|
}
|
203
214
|
|
204
|
-
const char*
|
205
|
-
|
206
|
-
const char *str = NULL;
|
215
|
+
const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp) {
|
216
|
+
const char *str = NULL;
|
207
217
|
|
208
218
|
if (AutoNan == opt) {
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
219
|
+
switch (mode) {
|
220
|
+
case CompatMode: opt = WordNan; break;
|
221
|
+
case StrictMode: opt = RaiseNan; break;
|
222
|
+
default: break;
|
223
|
+
}
|
214
224
|
}
|
215
225
|
switch (opt) {
|
216
|
-
case RaiseNan:
|
217
|
-
raise_strict(obj);
|
218
|
-
break;
|
226
|
+
case RaiseNan: raise_strict(obj); break;
|
219
227
|
case WordNan:
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
+
if (plus) {
|
229
|
+
str = "Infinity";
|
230
|
+
*lenp = 8;
|
231
|
+
} else {
|
232
|
+
str = "-Infinity";
|
233
|
+
*lenp = 9;
|
234
|
+
}
|
235
|
+
break;
|
228
236
|
case NullNan:
|
229
|
-
|
230
|
-
|
231
|
-
|
237
|
+
str = "null";
|
238
|
+
*lenp = 4;
|
239
|
+
break;
|
232
240
|
case HugeNan:
|
233
241
|
default:
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
+
if (plus) {
|
243
|
+
str = inf_val;
|
244
|
+
*lenp = sizeof(inf_val) - 1;
|
245
|
+
} else {
|
246
|
+
str = ninf_val;
|
247
|
+
*lenp = sizeof(ninf_val) - 1;
|
248
|
+
}
|
249
|
+
break;
|
242
250
|
}
|
243
251
|
return str;
|
244
252
|
}
|
245
253
|
|
246
|
-
inline static void
|
247
|
-
|
248
|
-
uint8_t d = (c >> 4) & 0x0F;
|
254
|
+
inline static void dump_hex(uint8_t c, Out out) {
|
255
|
+
uint8_t d = (c >> 4) & 0x0F;
|
249
256
|
|
250
257
|
*out->cur++ = hex_chars[d];
|
251
|
-
d
|
258
|
+
d = c & 0x0F;
|
252
259
|
*out->cur++ = hex_chars[d];
|
253
260
|
}
|
254
261
|
|
255
|
-
static void
|
256
|
-
|
257
|
-
char
|
258
|
-
char
|
259
|
-
|
260
|
-
|
261
|
-
uint8_t d;
|
262
|
+
static void raise_invalid_unicode(const char *str, int len, int pos) {
|
263
|
+
char c;
|
264
|
+
char code[32];
|
265
|
+
char *cp = code;
|
266
|
+
int i;
|
267
|
+
uint8_t d;
|
262
268
|
|
263
269
|
*cp++ = '[';
|
264
270
|
for (i = pos; i < len && i - pos < 5; i++) {
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
+
c = str[i];
|
272
|
+
d = (c >> 4) & 0x0F;
|
273
|
+
*cp++ = hex_chars[d];
|
274
|
+
d = c & 0x0F;
|
275
|
+
*cp++ = hex_chars[d];
|
276
|
+
*cp++ = ' ';
|
271
277
|
}
|
272
278
|
cp--;
|
273
279
|
*cp++ = ']';
|
274
|
-
*cp
|
280
|
+
*cp = '\0';
|
275
281
|
rb_raise(oj_json_generator_error_class, "Invalid Unicode %s at %d", code, pos);
|
276
282
|
}
|
277
283
|
|
278
|
-
static const char*
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
int i, cnt;
|
284
|
+
static const char *dump_unicode(const char *str, const char *end, Out out, const char *orig) {
|
285
|
+
uint32_t code = 0;
|
286
|
+
uint8_t b = *(uint8_t *)str;
|
287
|
+
int i, cnt;
|
283
288
|
|
284
289
|
if (0xC0 == (0xE0 & b)) {
|
285
|
-
|
286
|
-
|
290
|
+
cnt = 1;
|
291
|
+
code = b & 0x0000001F;
|
287
292
|
} else if (0xE0 == (0xF0 & b)) {
|
288
|
-
|
289
|
-
|
293
|
+
cnt = 2;
|
294
|
+
code = b & 0x0000000F;
|
290
295
|
} else if (0xF0 == (0xF8 & b)) {
|
291
|
-
|
292
|
-
|
296
|
+
cnt = 3;
|
297
|
+
code = b & 0x00000007;
|
293
298
|
} else if (0xF8 == (0xFC & b)) {
|
294
|
-
|
295
|
-
|
299
|
+
cnt = 4;
|
300
|
+
code = b & 0x00000003;
|
296
301
|
} else if (0xFC == (0xFE & b)) {
|
297
|
-
|
298
|
-
|
302
|
+
cnt = 5;
|
303
|
+
code = b & 0x00000001;
|
299
304
|
} else {
|
300
|
-
|
301
|
-
|
305
|
+
cnt = 0;
|
306
|
+
raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig));
|
302
307
|
}
|
303
308
|
str++;
|
304
309
|
for (; 0 < cnt; cnt--, str++) {
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
+
b = *(uint8_t *)str;
|
311
|
+
if (end <= str || 0x80 != (0xC0 & b)) {
|
312
|
+
raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig));
|
313
|
+
}
|
314
|
+
code = (code << 6) | (b & 0x0000003F);
|
310
315
|
}
|
311
316
|
if (0x0000FFFF < code) {
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
}
|
317
|
+
uint32_t c1;
|
318
|
+
|
319
|
+
code -= 0x00010000;
|
320
|
+
c1 = ((code >> 10) & 0x000003FF) + 0x0000D800;
|
321
|
+
code = (code & 0x000003FF) + 0x0000DC00;
|
322
|
+
APPEND_CHARS(out->cur, "\\u", 2);
|
323
|
+
for (i = 3; 0 <= i; i--) {
|
324
|
+
*out->cur++ = hex_chars[(uint8_t)(c1 >> (i * 4)) & 0x0F];
|
325
|
+
}
|
322
326
|
}
|
323
|
-
|
324
|
-
*out->cur++ = 'u';
|
327
|
+
APPEND_CHARS(out->cur, "\\u", 2);
|
325
328
|
for (i = 3; 0 <= i; i--) {
|
326
|
-
|
329
|
+
*out->cur++ = hex_chars[(uint8_t)(code >> (i * 4)) & 0x0F];
|
327
330
|
}
|
328
331
|
return str - 1;
|
329
332
|
}
|
330
333
|
|
331
|
-
static const char*
|
332
|
-
|
333
|
-
|
334
|
-
int cnt = 0;
|
334
|
+
static const char *check_unicode(const char *str, const char *end, const char *orig) {
|
335
|
+
uint8_t b = *(uint8_t *)str;
|
336
|
+
int cnt = 0;
|
335
337
|
|
336
338
|
if (0xC0 == (0xE0 & b)) {
|
337
|
-
|
339
|
+
cnt = 1;
|
338
340
|
} else if (0xE0 == (0xF0 & b)) {
|
339
|
-
|
341
|
+
cnt = 2;
|
340
342
|
} else if (0xF0 == (0xF8 & b)) {
|
341
|
-
|
343
|
+
cnt = 3;
|
342
344
|
} else if (0xF8 == (0xFC & b)) {
|
343
|
-
|
345
|
+
cnt = 4;
|
344
346
|
} else if (0xFC == (0xFE & b)) {
|
345
|
-
|
347
|
+
cnt = 5;
|
346
348
|
} else {
|
347
|
-
|
349
|
+
raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig));
|
348
350
|
}
|
349
351
|
str++;
|
350
352
|
for (; 0 < cnt; cnt--, str++) {
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
353
|
+
b = *(uint8_t *)str;
|
354
|
+
if (end <= str || 0x80 != (0xC0 & b)) {
|
355
|
+
raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig));
|
356
|
+
}
|
355
357
|
}
|
356
358
|
return str;
|
357
359
|
}
|
@@ -359,901 +361,894 @@ check_unicode(const char *str, const char *end, const char *orig) {
|
|
359
361
|
// Returns 0 if not using circular references, -1 if no further writing is
|
360
362
|
// needed (duplicate), and a positive value if the object was added to the
|
361
363
|
// cache.
|
362
|
-
long
|
363
|
-
|
364
|
-
slot_t
|
365
|
-
slot_t *slot;
|
364
|
+
long oj_check_circular(VALUE obj, Out out) {
|
365
|
+
slot_t id = 0;
|
366
|
+
slot_t *slot;
|
366
367
|
|
367
368
|
if (Yes == out->opts->circular) {
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
return -1;
|
382
|
-
}
|
369
|
+
if (0 == (id = oj_cache8_get(out->circ_cache, obj, &slot))) {
|
370
|
+
out->circ_cnt++;
|
371
|
+
id = out->circ_cnt;
|
372
|
+
*slot = id;
|
373
|
+
} else {
|
374
|
+
if (ObjectMode == out->opts->mode) {
|
375
|
+
assure_size(out, 18);
|
376
|
+
APPEND_CHARS(out->cur, "\"^r", 3);
|
377
|
+
dump_ulong(id, out);
|
378
|
+
*out->cur++ = '"';
|
379
|
+
}
|
380
|
+
return -1;
|
381
|
+
}
|
383
382
|
}
|
384
383
|
return (long)id;
|
385
384
|
}
|
386
385
|
|
387
|
-
void
|
388
|
-
|
389
|
-
char
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
long
|
395
|
-
long long
|
396
|
-
|
397
|
-
|
398
|
-
#ifdef HAVE_RB_TIME_TIMESPEC
|
386
|
+
void oj_dump_time(VALUE obj, Out out, int withZone) {
|
387
|
+
char buf[64];
|
388
|
+
char *b = buf + sizeof(buf) - 1;
|
389
|
+
long size;
|
390
|
+
char *dot;
|
391
|
+
int neg = 0;
|
392
|
+
long one = 1000000000;
|
393
|
+
long long sec;
|
394
|
+
long long nsec;
|
395
|
+
|
399
396
|
// rb_time_timespec as well as rb_time_timeeval have a bug that causes an
|
400
397
|
// exception to be raised if a time is before 1970 on 32 bit systems so
|
401
398
|
// check the timespec size and use the ruby calls if a 32 bit system.
|
402
399
|
if (16 <= sizeof(struct timespec)) {
|
403
|
-
|
400
|
+
struct timespec ts = rb_time_timespec(obj);
|
404
401
|
|
405
|
-
|
406
|
-
|
402
|
+
sec = (long long)ts.tv_sec;
|
403
|
+
nsec = ts.tv_nsec;
|
407
404
|
} else {
|
408
|
-
|
409
|
-
|
405
|
+
sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
406
|
+
nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
410
407
|
}
|
411
|
-
#else
|
412
|
-
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
413
|
-
nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
414
|
-
#endif
|
415
408
|
|
416
409
|
*b-- = '\0';
|
417
410
|
if (withZone) {
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
411
|
+
long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
|
412
|
+
int zneg = (0 > tzsecs);
|
413
|
+
|
414
|
+
if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
415
|
+
tzsecs = 86400;
|
416
|
+
}
|
417
|
+
if (zneg) {
|
418
|
+
tzsecs = -tzsecs;
|
419
|
+
}
|
420
|
+
if (0 == tzsecs) {
|
421
|
+
*b-- = '0';
|
422
|
+
} else {
|
423
|
+
for (; 0 < tzsecs; b--, tzsecs /= 10) {
|
424
|
+
*b = '0' + (tzsecs % 10);
|
425
|
+
}
|
426
|
+
if (zneg) {
|
427
|
+
*b-- = '-';
|
428
|
+
}
|
429
|
+
}
|
430
|
+
*b-- = 'e';
|
438
431
|
}
|
439
432
|
if (0 > sec) {
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
433
|
+
neg = 1;
|
434
|
+
sec = -sec;
|
435
|
+
if (0 < nsec) {
|
436
|
+
nsec = 1000000000 - nsec;
|
437
|
+
sec--;
|
438
|
+
}
|
446
439
|
}
|
447
440
|
dot = b - 9;
|
448
441
|
if (0 < out->opts->sec_prec) {
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
442
|
+
if (9 > out->opts->sec_prec) {
|
443
|
+
int i;
|
444
|
+
|
445
|
+
for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
|
446
|
+
dot++;
|
447
|
+
nsec = (nsec + 5) / 10;
|
448
|
+
one /= 10;
|
449
|
+
}
|
450
|
+
}
|
451
|
+
if (one <= nsec) {
|
452
|
+
nsec -= one;
|
453
|
+
sec++;
|
454
|
+
}
|
455
|
+
for (; dot < b; b--, nsec /= 10) {
|
456
|
+
*b = '0' + (nsec % 10);
|
457
|
+
}
|
458
|
+
*b-- = '.';
|
466
459
|
}
|
467
460
|
if (0 == sec) {
|
468
|
-
|
461
|
+
*b-- = '0';
|
469
462
|
} else {
|
470
|
-
|
471
|
-
|
472
|
-
|
463
|
+
for (; 0 < sec; b--, sec /= 10) {
|
464
|
+
*b = '0' + (sec % 10);
|
465
|
+
}
|
473
466
|
}
|
474
467
|
if (neg) {
|
475
|
-
|
468
|
+
*b-- = '-';
|
476
469
|
}
|
477
470
|
b++;
|
478
471
|
size = sizeof(buf) - (b - buf) - 1;
|
479
472
|
assure_size(out, size);
|
480
|
-
|
481
|
-
out->cur += size;
|
473
|
+
APPEND_CHARS(out->cur, b, size);
|
482
474
|
*out->cur = '\0';
|
483
475
|
}
|
484
476
|
|
485
|
-
void
|
486
|
-
|
487
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
477
|
+
void oj_dump_ruby_time(VALUE obj, Out out) {
|
478
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
488
479
|
|
489
|
-
oj_dump_cstr(
|
480
|
+
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
490
481
|
}
|
491
482
|
|
492
|
-
void
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
long
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
#ifdef HAVE_RB_TIME_TIMESPEC
|
483
|
+
void oj_dump_xml_time(VALUE obj, Out out) {
|
484
|
+
char buf[64];
|
485
|
+
struct _timeInfo ti;
|
486
|
+
long one = 1000000000;
|
487
|
+
int64_t sec;
|
488
|
+
long long nsec;
|
489
|
+
long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
|
490
|
+
int tzhour, tzmin;
|
491
|
+
char tzsign = '+';
|
492
|
+
|
504
493
|
if (16 <= sizeof(struct timespec)) {
|
505
|
-
|
494
|
+
struct timespec ts = rb_time_timespec(obj);
|
506
495
|
|
507
|
-
|
508
|
-
|
496
|
+
sec = ts.tv_sec;
|
497
|
+
nsec = ts.tv_nsec;
|
509
498
|
} else {
|
510
|
-
|
511
|
-
|
499
|
+
sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
500
|
+
nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
512
501
|
}
|
513
|
-
#else
|
514
|
-
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
515
|
-
nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
516
|
-
#endif
|
517
502
|
|
518
503
|
assure_size(out, 36);
|
519
504
|
if (9 > out->opts->sec_prec) {
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
505
|
+
int i;
|
506
|
+
|
507
|
+
// This is pretty lame but to be compatible with rails and active
|
508
|
+
// support rounding is not done but instead a floor is done when
|
509
|
+
// second precision is 3 just to be like rails. sigh.
|
510
|
+
if (3 == out->opts->sec_prec) {
|
511
|
+
nsec /= 1000000;
|
512
|
+
one = 1000;
|
513
|
+
} else {
|
514
|
+
for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
|
515
|
+
nsec = (nsec + 5) / 10;
|
516
|
+
one /= 10;
|
517
|
+
}
|
518
|
+
if (one <= nsec) {
|
519
|
+
nsec -= one;
|
520
|
+
sec++;
|
521
|
+
}
|
522
|
+
}
|
538
523
|
}
|
539
524
|
// 2012-01-05T23:58:07.123456000+09:00
|
540
|
-
//tm = localtime(&sec);
|
525
|
+
// tm = localtime(&sec);
|
541
526
|
sec += tzsecs;
|
542
527
|
sec_as_time((int64_t)sec, &ti);
|
543
528
|
if (0 > tzsecs) {
|
544
529
|
tzsign = '-';
|
545
530
|
tzhour = (int)(tzsecs / -3600);
|
546
|
-
tzmin
|
531
|
+
tzmin = (int)(tzsecs / -60) - (tzhour * 60);
|
547
532
|
} else {
|
548
533
|
tzhour = (int)(tzsecs / 3600);
|
549
|
-
tzmin
|
534
|
+
tzmin = (int)(tzsecs / 60) - (tzhour * 60);
|
550
535
|
}
|
551
536
|
if ((0 == nsec && !out->opts->sec_prec_set) || 0 == out->opts->sec_prec) {
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
537
|
+
if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
538
|
+
int len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec);
|
539
|
+
oj_dump_cstr(buf, len, 0, 0, out);
|
540
|
+
} else {
|
541
|
+
int len = sprintf(buf,
|
542
|
+
"%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
|
543
|
+
ti.year,
|
544
|
+
ti.mon,
|
545
|
+
ti.day,
|
546
|
+
ti.hour,
|
547
|
+
ti.min,
|
548
|
+
ti.sec,
|
549
|
+
tzsign,
|
550
|
+
tzhour,
|
551
|
+
tzmin);
|
552
|
+
oj_dump_cstr(buf, len, 0, 0, out);
|
553
|
+
}
|
560
554
|
} else if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
oj_dump_cstr(buf, len, 0, 0, out);
|
555
|
+
char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ";
|
556
|
+
int len;
|
557
|
+
|
558
|
+
if (9 > out->opts->sec_prec) {
|
559
|
+
format[32] = '0' + out->opts->sec_prec;
|
560
|
+
}
|
561
|
+
len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec);
|
562
|
+
oj_dump_cstr(buf, len, 0, 0, out);
|
570
563
|
} else {
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
oj_dump_cstr(buf, len, 0, 0, out);
|
564
|
+
char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
|
565
|
+
int len;
|
566
|
+
|
567
|
+
if (9 > out->opts->sec_prec) {
|
568
|
+
format[32] = '0' + out->opts->sec_prec;
|
569
|
+
}
|
570
|
+
len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec, tzsign, tzhour, tzmin);
|
571
|
+
oj_dump_cstr(buf, len, 0, 0, out);
|
580
572
|
}
|
581
573
|
}
|
582
574
|
|
583
|
-
void
|
584
|
-
oj_dump_obj_to_json(VALUE obj, Options copts, Out out) {
|
575
|
+
void oj_dump_obj_to_json(VALUE obj, Options copts, Out out) {
|
585
576
|
oj_dump_obj_to_json_using_params(obj, copts, out, 0, 0);
|
586
577
|
}
|
587
578
|
|
588
|
-
void
|
589
|
-
oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VALUE *argv) {
|
579
|
+
void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VALUE *argv) {
|
590
580
|
if (0 == out->buf) {
|
591
|
-
|
592
|
-
out->end = out->buf + 4095 - BUFFER_EXTRA; // 1 less than end plus extra for possible errors
|
593
|
-
out->allocated = true;
|
581
|
+
oj_out_init(out);
|
594
582
|
}
|
595
|
-
out->cur = out->buf;
|
596
583
|
out->circ_cnt = 0;
|
597
|
-
out->opts
|
584
|
+
out->opts = copts;
|
598
585
|
out->hash_cnt = 0;
|
599
|
-
out->indent
|
600
|
-
out->argc
|
601
|
-
out->argv
|
602
|
-
out->ropts
|
586
|
+
out->indent = copts->indent;
|
587
|
+
out->argc = argc;
|
588
|
+
out->argv = argv;
|
589
|
+
out->ropts = NULL;
|
603
590
|
if (Yes == copts->circular) {
|
604
|
-
|
591
|
+
oj_cache8_new(&out->circ_cache);
|
605
592
|
}
|
606
593
|
switch (copts->mode) {
|
607
|
-
case StrictMode:
|
608
|
-
case NullMode:
|
609
|
-
case ObjectMode:
|
610
|
-
case CompatMode:
|
611
|
-
case RailsMode:
|
612
|
-
case CustomMode:
|
613
|
-
case WabMode:
|
614
|
-
default:
|
594
|
+
case StrictMode: oj_dump_strict_val(obj, 0, out); break;
|
595
|
+
case NullMode: oj_dump_null_val(obj, 0, out); break;
|
596
|
+
case ObjectMode: oj_dump_obj_val(obj, 0, out); break;
|
597
|
+
case CompatMode: oj_dump_compat_val(obj, 0, out, Yes == copts->to_json); break;
|
598
|
+
case RailsMode: oj_dump_rails_val(obj, 0, out); break;
|
599
|
+
case CustomMode: oj_dump_custom_val(obj, 0, out, true); break;
|
600
|
+
case WabMode: oj_dump_wab_val(obj, 0, out); break;
|
601
|
+
default: oj_dump_custom_val(obj, 0, out, true); break;
|
615
602
|
}
|
616
603
|
if (0 < out->indent) {
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
default:
|
623
|
-
break;
|
624
|
-
}
|
604
|
+
switch (*(out->cur - 1)) {
|
605
|
+
case ']':
|
606
|
+
case '}': assure_size(out, 1); *out->cur++ = '\n';
|
607
|
+
default: break;
|
608
|
+
}
|
625
609
|
}
|
626
610
|
*out->cur = '\0';
|
627
611
|
if (Yes == copts->circular) {
|
628
|
-
|
612
|
+
oj_cache8_delete(out->circ_cache);
|
629
613
|
}
|
630
614
|
}
|
631
615
|
|
632
|
-
void
|
633
|
-
oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
|
634
|
-
char buf[4096];
|
616
|
+
void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
|
635
617
|
struct _out out;
|
636
|
-
size_t
|
637
|
-
FILE
|
638
|
-
int
|
618
|
+
size_t size;
|
619
|
+
FILE *f;
|
620
|
+
int ok;
|
621
|
+
|
622
|
+
oj_out_init(&out);
|
639
623
|
|
640
|
-
out.buf = buf;
|
641
|
-
out.end = buf + sizeof(buf) - BUFFER_EXTRA;
|
642
|
-
out.allocated = false;
|
643
624
|
out.omit_nil = copts->dump_opts.omit_nil;
|
644
625
|
oj_dump_obj_to_json(obj, copts, &out);
|
645
626
|
size = out.cur - out.buf;
|
646
627
|
if (0 == (f = fopen(path, "w"))) {
|
647
|
-
|
648
|
-
|
649
|
-
}
|
650
|
-
rb_raise(rb_eIOError, "%s", strerror(errno));
|
628
|
+
oj_out_free(&out);
|
629
|
+
rb_raise(rb_eIOError, "%s", strerror(errno));
|
651
630
|
}
|
652
631
|
ok = (size == fwrite(out.buf, 1, size, f));
|
653
|
-
|
654
|
-
|
632
|
+
|
633
|
+
oj_out_free(&out);
|
634
|
+
|
635
|
+
if (!ok) {
|
636
|
+
int err = ferror(f);
|
637
|
+
fclose(f);
|
638
|
+
|
639
|
+
rb_raise(rb_eIOError, "Write failed. [%d:%s]", err, strerror(err));
|
655
640
|
}
|
656
641
|
fclose(f);
|
657
|
-
|
658
|
-
int err = ferror(f);
|
642
|
+
}
|
659
643
|
|
660
|
-
|
644
|
+
#if !IS_WINDOWS
|
645
|
+
static void write_ready(int fd) {
|
646
|
+
struct pollfd pp;
|
647
|
+
int i;
|
648
|
+
|
649
|
+
pp.fd = fd;
|
650
|
+
pp.events = POLLERR | POLLOUT;
|
651
|
+
pp.revents = 0;
|
652
|
+
if (0 >= (i = poll(&pp, 1, 5000))) {
|
653
|
+
if (0 == i || EAGAIN == errno) {
|
654
|
+
rb_raise(rb_eIOError, "write timed out");
|
655
|
+
}
|
656
|
+
rb_raise(rb_eIOError, "write failed. %d %s.", errno, strerror(errno));
|
661
657
|
}
|
662
658
|
}
|
659
|
+
#endif
|
663
660
|
|
664
|
-
void
|
665
|
-
oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
666
|
-
char buf[4096];
|
661
|
+
void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
667
662
|
struct _out out;
|
668
|
-
ssize_t
|
669
|
-
VALUE
|
663
|
+
ssize_t size;
|
664
|
+
VALUE clas = rb_obj_class(stream);
|
670
665
|
#if !IS_WINDOWS
|
671
|
-
int
|
672
|
-
VALUE
|
666
|
+
int fd;
|
667
|
+
VALUE s;
|
673
668
|
#endif
|
674
669
|
|
675
|
-
out
|
676
|
-
|
677
|
-
out.allocated = false;
|
670
|
+
oj_out_init(&out);
|
671
|
+
|
678
672
|
out.omit_nil = copts->dump_opts.omit_nil;
|
679
673
|
oj_dump_obj_to_json(obj, copts, &out);
|
680
674
|
size = out.cur - out.buf;
|
681
675
|
if (oj_stringio_class == clas) {
|
682
|
-
|
676
|
+
rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
|
683
677
|
#if !IS_WINDOWS
|
684
|
-
} else if (rb_respond_to(stream, oj_fileno_id) &&
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
678
|
+
} else if (rb_respond_to(stream, oj_fileno_id) && Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) &&
|
679
|
+
0 != (fd = FIX2INT(s))) {
|
680
|
+
ssize_t cnt;
|
681
|
+
ssize_t total = 0;
|
682
|
+
|
683
|
+
while (true) {
|
684
|
+
if (0 > (cnt = write(fd, out.buf + total, size - total))) {
|
685
|
+
if (EAGAIN != errno) {
|
686
|
+
rb_raise(rb_eIOError, "write failed. %d %s.", errno, strerror(errno));
|
687
|
+
break;
|
688
|
+
}
|
689
|
+
}
|
690
|
+
total += cnt;
|
691
|
+
if (size <= total) {
|
692
|
+
// Completed
|
693
|
+
break;
|
694
|
+
}
|
695
|
+
write_ready(fd);
|
696
|
+
}
|
693
697
|
#endif
|
694
698
|
} else if (rb_respond_to(stream, oj_write_id)) {
|
695
|
-
|
699
|
+
rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
|
696
700
|
} else {
|
697
|
-
|
698
|
-
|
699
|
-
}
|
700
|
-
rb_raise(rb_eArgError, "to_stream() expected an IO Object.");
|
701
|
-
}
|
702
|
-
if (out.allocated) {
|
703
|
-
xfree(out.buf);
|
701
|
+
oj_out_free(&out);
|
702
|
+
rb_raise(rb_eArgError, "to_stream() expected an IO Object.");
|
704
703
|
}
|
704
|
+
oj_out_free(&out);
|
705
705
|
}
|
706
706
|
|
707
|
-
void
|
708
|
-
|
709
|
-
rb_encoding *enc = rb_to_encoding(rb_obj_encoding(obj));
|
707
|
+
void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
|
708
|
+
int idx = RB_ENCODING_GET(obj);
|
710
709
|
|
711
|
-
if (
|
712
|
-
|
710
|
+
if (oj_utf8_encoding_index != idx) {
|
711
|
+
rb_encoding *enc = rb_enc_from_index(idx);
|
712
|
+
obj = rb_str_conv_enc(obj, enc, oj_utf8_encoding);
|
713
713
|
}
|
714
|
-
oj_dump_cstr(
|
714
|
+
oj_dump_cstr(RSTRING_PTR(obj), (int)RSTRING_LEN(obj), 0, 0, out);
|
715
715
|
}
|
716
716
|
|
717
|
-
void
|
718
|
-
|
719
|
-
// This causes a memory leak in 2.5.1. Maybe in other versions as well.
|
720
|
-
//const char *sym = rb_id2name(SYM2ID(obj));
|
721
|
-
|
722
|
-
volatile VALUE s = rb_sym_to_s(obj);
|
717
|
+
void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
|
718
|
+
volatile VALUE s = rb_sym2str(obj);
|
723
719
|
|
724
|
-
oj_dump_cstr(
|
720
|
+
oj_dump_cstr(RSTRING_PTR(s), (int)RSTRING_LEN(s), 0, 0, out);
|
725
721
|
}
|
726
722
|
|
727
|
-
static void
|
728
|
-
|
729
|
-
char
|
730
|
-
char
|
731
|
-
const char
|
732
|
-
const char *s_end = s + cnt;
|
723
|
+
static void debug_raise(const char *orig, size_t cnt, int line) {
|
724
|
+
char buf[1024];
|
725
|
+
char *b = buf;
|
726
|
+
const char *s = orig;
|
727
|
+
const char *s_end = s + cnt;
|
733
728
|
|
734
729
|
if (32 < s_end - s) {
|
735
|
-
|
730
|
+
s_end = s + 32;
|
736
731
|
}
|
737
732
|
for (; s < s_end; s++) {
|
738
|
-
|
733
|
+
b += sprintf(b, " %02x", *s);
|
739
734
|
}
|
740
735
|
*b = '\0';
|
741
736
|
rb_raise(oj_json_generator_error_class, "Partial character in string. %s @ %d", buf, line);
|
742
737
|
}
|
743
738
|
|
744
|
-
void
|
745
|
-
oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
739
|
+
void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
746
740
|
if (oj_string_writer_class == rb_obj_class(obj)) {
|
747
|
-
|
748
|
-
|
741
|
+
StrWriter sw;
|
742
|
+
size_t len;
|
749
743
|
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
744
|
+
sw = oj_str_writer_unwrap(obj);
|
745
|
+
len = sw->out.cur - sw->out.buf;
|
746
|
+
|
747
|
+
if (0 < len) {
|
748
|
+
len--;
|
749
|
+
}
|
750
|
+
oj_dump_raw(sw->out.buf, len, out);
|
754
751
|
} else {
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
if (Yes == out->opts->trace) {
|
762
|
-
oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
763
|
-
}
|
764
|
-
oj_dump_raw(rb_string_value_ptr((VALUE*)&jv), (size_t)RSTRING_LEN(jv), out);
|
752
|
+
volatile VALUE jv;
|
753
|
+
|
754
|
+
TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyIn);
|
755
|
+
jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent));
|
756
|
+
TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyOut);
|
757
|
+
oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
|
765
758
|
}
|
766
759
|
}
|
767
760
|
|
768
|
-
void
|
769
|
-
|
770
|
-
|
771
|
-
char
|
772
|
-
|
773
|
-
bool
|
761
|
+
void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
|
762
|
+
size_t size;
|
763
|
+
char *cmap;
|
764
|
+
const char *orig = str;
|
765
|
+
bool has_hi = false;
|
766
|
+
bool do_unicode_validation = false;
|
774
767
|
|
775
768
|
switch (out->opts->escape_mode) {
|
776
769
|
case NLEsc:
|
777
|
-
|
778
|
-
|
779
|
-
|
770
|
+
cmap = newline_friendly_chars;
|
771
|
+
size = newline_friendly_size((uint8_t *)str, cnt);
|
772
|
+
break;
|
780
773
|
case ASCIIEsc:
|
781
|
-
|
782
|
-
|
783
|
-
|
774
|
+
cmap = ascii_friendly_chars;
|
775
|
+
size = ascii_friendly_size((uint8_t *)str, cnt);
|
776
|
+
break;
|
777
|
+
case SlashEsc:
|
778
|
+
has_hi = true;
|
779
|
+
cmap = slash_friendly_chars;
|
780
|
+
size = slash_friendly_size((uint8_t *)str, cnt);
|
781
|
+
break;
|
784
782
|
case XSSEsc:
|
785
|
-
|
786
|
-
|
787
|
-
|
783
|
+
cmap = xss_friendly_chars;
|
784
|
+
size = xss_friendly_size((uint8_t *)str, cnt);
|
785
|
+
break;
|
788
786
|
case JXEsc:
|
789
|
-
|
790
|
-
|
791
|
-
|
787
|
+
cmap = hixss_friendly_chars;
|
788
|
+
size = hixss_friendly_size((uint8_t *)str, cnt);
|
789
|
+
do_unicode_validation = true;
|
790
|
+
break;
|
792
791
|
case RailsXEsc: {
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
792
|
+
long sz;
|
793
|
+
|
794
|
+
cmap = rails_xss_friendly_chars;
|
795
|
+
sz = rails_xss_friendly_size((uint8_t *)str, cnt);
|
796
|
+
if (sz < 0) {
|
797
|
+
has_hi = true;
|
798
|
+
size = (size_t)-sz;
|
799
|
+
} else {
|
800
|
+
size = (size_t)sz;
|
801
|
+
}
|
802
|
+
do_unicode_validation = true;
|
803
|
+
break;
|
804
|
+
}
|
805
|
+
case RailsEsc: {
|
806
|
+
long sz;
|
807
|
+
cmap = rails_friendly_chars;
|
808
|
+
sz = rails_friendly_size((uint8_t *)str, cnt);
|
809
|
+
if (sz < 0) {
|
810
|
+
has_hi = true;
|
811
|
+
size = (size_t)-sz;
|
812
|
+
} else {
|
813
|
+
size = (size_t)sz;
|
814
|
+
}
|
815
|
+
do_unicode_validation = true;
|
816
|
+
break;
|
804
817
|
}
|
805
|
-
case RailsEsc:
|
806
|
-
cmap = rails_friendly_chars;
|
807
|
-
size = rails_friendly_size((uint8_t*)str, cnt);
|
808
|
-
break;
|
809
818
|
case JSONEsc:
|
810
|
-
default:
|
811
|
-
cmap = hibit_friendly_chars;
|
812
|
-
size = hibit_friendly_size((uint8_t*)str, cnt);
|
819
|
+
default: cmap = hibit_friendly_chars; size = hibit_friendly_size((uint8_t *)str, cnt);
|
813
820
|
}
|
814
821
|
assure_size(out, size + BUFFER_EXTRA);
|
815
822
|
*out->cur++ = '"';
|
816
823
|
|
817
824
|
if (escape1) {
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
size--;
|
825
|
-
str++;
|
826
|
-
is_sym = 0; // just to make sure
|
825
|
+
APPEND_CHARS(out->cur, "\\u00", 4);
|
826
|
+
dump_hex((uint8_t)*str, out);
|
827
|
+
cnt--;
|
828
|
+
size--;
|
829
|
+
str++;
|
830
|
+
is_sym = 0; // just to make sure
|
827
831
|
}
|
828
832
|
if (cnt == size && !has_hi) {
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
}
|
835
|
-
*out->cur++ = '"';
|
833
|
+
if (is_sym) {
|
834
|
+
*out->cur++ = ':';
|
835
|
+
}
|
836
|
+
APPEND_CHARS(out->cur, str, cnt);
|
837
|
+
*out->cur++ = '"';
|
836
838
|
} else {
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
*out->cur++ = '"';
|
839
|
+
const char *end = str + cnt;
|
840
|
+
const char *check_start = str;
|
841
|
+
|
842
|
+
if (is_sym) {
|
843
|
+
*out->cur++ = ':';
|
844
|
+
}
|
845
|
+
for (; str < end; str++) {
|
846
|
+
switch (cmap[(uint8_t)*str]) {
|
847
|
+
case '1':
|
848
|
+
if (do_unicode_validation && check_start <= str) {
|
849
|
+
if (0 != (0x80 & (uint8_t)*str)) {
|
850
|
+
if (0xC0 == (0xC0 & (uint8_t)*str)) {
|
851
|
+
check_start = check_unicode(str, end, orig);
|
852
|
+
} else {
|
853
|
+
raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig));
|
854
|
+
}
|
855
|
+
}
|
856
|
+
}
|
857
|
+
*out->cur++ = *str;
|
858
|
+
break;
|
859
|
+
case '2':
|
860
|
+
*out->cur++ = '\\';
|
861
|
+
switch (*str) {
|
862
|
+
case '\\': *out->cur++ = '\\'; break;
|
863
|
+
case '\b': *out->cur++ = 'b'; break;
|
864
|
+
case '\t': *out->cur++ = 't'; break;
|
865
|
+
case '\n': *out->cur++ = 'n'; break;
|
866
|
+
case '\f': *out->cur++ = 'f'; break;
|
867
|
+
case '\r': *out->cur++ = 'r'; break;
|
868
|
+
default: *out->cur++ = *str; break;
|
869
|
+
}
|
870
|
+
break;
|
871
|
+
case '3': // Unicode
|
872
|
+
if (0xe2 == (uint8_t)*str && do_unicode_validation && 2 <= end - str) {
|
873
|
+
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
874
|
+
str = dump_unicode(str, end, out, orig);
|
875
|
+
} else {
|
876
|
+
check_start = check_unicode(str, end, orig);
|
877
|
+
*out->cur++ = *str;
|
878
|
+
}
|
879
|
+
break;
|
880
|
+
}
|
881
|
+
str = dump_unicode(str, end, out, orig);
|
882
|
+
break;
|
883
|
+
case '6': // control characters
|
884
|
+
if (*(uint8_t *)str < 0x80) {
|
885
|
+
if (0 == (uint8_t)*str && out->opts->dump_opts.omit_null_byte) {
|
886
|
+
break;
|
887
|
+
}
|
888
|
+
APPEND_CHARS(out->cur, "\\u00", 4);
|
889
|
+
dump_hex((uint8_t)*str, out);
|
890
|
+
} else {
|
891
|
+
if (0xe2 == (uint8_t)*str && do_unicode_validation && 2 <= end - str) {
|
892
|
+
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
893
|
+
str = dump_unicode(str, end, out, orig);
|
894
|
+
} else {
|
895
|
+
check_start = check_unicode(str, end, orig);
|
896
|
+
*out->cur++ = *str;
|
897
|
+
}
|
898
|
+
break;
|
899
|
+
}
|
900
|
+
str = dump_unicode(str, end, out, orig);
|
901
|
+
}
|
902
|
+
break;
|
903
|
+
default: break; // ignore, should never happen if the table is correct
|
904
|
+
}
|
905
|
+
}
|
906
|
+
*out->cur++ = '"';
|
906
907
|
}
|
907
|
-
if (
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
908
|
+
if (do_unicode_validation && 0 < str - orig && 0 != (0x80 & *(str - 1))) {
|
909
|
+
uint8_t c = (uint8_t) * (str - 1);
|
910
|
+
int i;
|
911
|
+
int scnt = (int)(str - orig);
|
912
|
+
|
913
|
+
// Last utf-8 characters must be 0x10xxxxxx. The start must be
|
914
|
+
// 0x110xxxxx for 2 characters, 0x1110xxxx for 3, and 0x11110xxx for
|
915
|
+
// 4.
|
916
|
+
if (0 != (0x40 & c)) {
|
917
|
+
debug_raise(orig, cnt, __LINE__);
|
918
|
+
}
|
919
|
+
for (i = 1; i < (int)scnt && i < 4; i++) {
|
920
|
+
c = str[-1 - i];
|
921
|
+
if (0x80 != (0xC0 & c)) {
|
922
|
+
switch (i) {
|
923
|
+
case 1:
|
924
|
+
if (0xC0 != (0xE0 & c)) {
|
925
|
+
debug_raise(orig, cnt, __LINE__);
|
926
|
+
}
|
927
|
+
break;
|
928
|
+
case 2:
|
929
|
+
if (0xE0 != (0xF0 & c)) {
|
930
|
+
debug_raise(orig, cnt, __LINE__);
|
931
|
+
}
|
932
|
+
break;
|
933
|
+
case 3:
|
934
|
+
if (0xF0 != (0xF8 & c)) {
|
935
|
+
debug_raise(orig, cnt, __LINE__);
|
936
|
+
}
|
937
|
+
break;
|
938
|
+
default: // can't get here
|
939
|
+
break;
|
940
|
+
}
|
941
|
+
break;
|
942
|
+
}
|
943
|
+
}
|
944
|
+
if (i == (int)scnt || 4 <= i) {
|
945
|
+
debug_raise(orig, cnt, __LINE__);
|
946
|
+
}
|
946
947
|
}
|
947
948
|
*out->cur = '\0';
|
948
949
|
}
|
949
950
|
|
950
|
-
void
|
951
|
-
|
952
|
-
const char *s = rb_class2name(obj);
|
951
|
+
void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) {
|
952
|
+
const char *s = rb_class2name(obj);
|
953
953
|
|
954
954
|
oj_dump_cstr(s, strlen(s), 0, 0, out);
|
955
955
|
}
|
956
956
|
|
957
|
-
void
|
958
|
-
|
959
|
-
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
957
|
+
void oj_dump_obj_to_s(VALUE obj, Out out) {
|
958
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
960
959
|
|
961
|
-
oj_dump_cstr(
|
960
|
+
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
962
961
|
}
|
963
962
|
|
964
|
-
void
|
965
|
-
oj_dump_raw(const char *str, size_t cnt, Out out) {
|
963
|
+
void oj_dump_raw(const char *str, size_t cnt, Out out) {
|
966
964
|
assure_size(out, cnt + 10);
|
967
|
-
|
968
|
-
out->cur += cnt;
|
965
|
+
APPEND_CHARS(out->cur, str, cnt);
|
969
966
|
*out->cur = '\0';
|
970
967
|
}
|
971
968
|
|
972
|
-
void
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
969
|
+
void oj_out_init(Out out) {
|
970
|
+
out->buf = out->stack_buffer;
|
971
|
+
out->cur = out->buf;
|
972
|
+
out->end = out->buf + sizeof(out->stack_buffer) - BUFFER_EXTRA;
|
973
|
+
out->allocated = false;
|
974
|
+
}
|
975
|
+
|
976
|
+
void oj_out_free(Out out) {
|
977
|
+
if (out->allocated) {
|
978
|
+
OJ_R_FREE(out->buf); // TBD
|
979
|
+
}
|
980
|
+
}
|
981
|
+
|
982
|
+
void oj_grow_out(Out out, size_t len) {
|
983
|
+
size_t size = out->end - out->buf;
|
984
|
+
long pos = out->cur - out->buf;
|
985
|
+
char *buf = out->buf;
|
977
986
|
|
978
987
|
size *= 2;
|
979
988
|
if (size <= len * 2 + pos) {
|
980
|
-
|
989
|
+
size += len;
|
981
990
|
}
|
982
991
|
if (out->allocated) {
|
983
|
-
|
992
|
+
OJ_R_REALLOC_N(buf, char, (size + BUFFER_EXTRA));
|
984
993
|
} else {
|
985
|
-
|
986
|
-
|
987
|
-
|
994
|
+
buf = OJ_R_ALLOC_N(char, (size + BUFFER_EXTRA));
|
995
|
+
out->allocated = true;
|
996
|
+
memcpy(buf, out->buf, out->end - out->buf + BUFFER_EXTRA);
|
988
997
|
}
|
989
998
|
if (0 == buf) {
|
990
|
-
|
999
|
+
rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]", ENOSPC, strerror(ENOSPC));
|
991
1000
|
}
|
992
1001
|
out->buf = buf;
|
993
1002
|
out->end = buf + size;
|
994
1003
|
out->cur = out->buf + pos;
|
995
1004
|
}
|
996
1005
|
|
997
|
-
void
|
998
|
-
oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok) {
|
1006
|
+
void oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok) {
|
999
1007
|
assure_size(out, 4);
|
1000
|
-
|
1001
|
-
*out->cur++ = 'u';
|
1002
|
-
*out->cur++ = 'l';
|
1003
|
-
*out->cur++ = 'l';
|
1008
|
+
APPEND_CHARS(out->cur, "null", 4);
|
1004
1009
|
*out->cur = '\0';
|
1005
1010
|
}
|
1006
1011
|
|
1007
|
-
void
|
1008
|
-
oj_dump_true(VALUE obj, int depth, Out out, bool as_ok) {
|
1012
|
+
void oj_dump_true(VALUE obj, int depth, Out out, bool as_ok) {
|
1009
1013
|
assure_size(out, 4);
|
1010
|
-
|
1011
|
-
*out->cur++ = 'r';
|
1012
|
-
*out->cur++ = 'u';
|
1013
|
-
*out->cur++ = 'e';
|
1014
|
+
APPEND_CHARS(out->cur, "true", 4);
|
1014
1015
|
*out->cur = '\0';
|
1015
1016
|
}
|
1016
1017
|
|
1017
|
-
void
|
1018
|
-
oj_dump_false(VALUE obj, int depth, Out out, bool as_ok) {
|
1018
|
+
void oj_dump_false(VALUE obj, int depth, Out out, bool as_ok) {
|
1019
1019
|
assure_size(out, 5);
|
1020
|
-
|
1021
|
-
*out->cur++ = 'a';
|
1022
|
-
*out->cur++ = 'l';
|
1023
|
-
*out->cur++ = 's';
|
1024
|
-
*out->cur++ = 'e';
|
1020
|
+
APPEND_CHARS(out->cur, "false", 5);
|
1025
1021
|
*out->cur = '\0';
|
1026
1022
|
}
|
1027
1023
|
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1024
|
+
static const char digits_table[] = "\
|
1025
|
+
00010203040506070809\
|
1026
|
+
10111213141516171819\
|
1027
|
+
20212223242526272829\
|
1028
|
+
30313233343536373839\
|
1029
|
+
40414243444546474849\
|
1030
|
+
50515253545556575859\
|
1031
|
+
60616263646566676869\
|
1032
|
+
70717273747576777879\
|
1033
|
+
80818283848586878889\
|
1034
|
+
90919293949596979899";
|
1035
|
+
|
1036
|
+
char *oj_longlong_to_string(long long num, bool negative, char *buf) {
|
1037
|
+
while (100 <= num) {
|
1038
|
+
unsigned idx = num % 100 * 2;
|
1039
|
+
*buf-- = digits_table[idx + 1];
|
1040
|
+
*buf-- = digits_table[idx];
|
1041
|
+
num /= 100;
|
1042
|
+
}
|
1043
|
+
if (num < 10) {
|
1044
|
+
*buf-- = num + '0';
|
1045
|
+
} else {
|
1046
|
+
*buf-- = digits_table[num * 2 + 1];
|
1047
|
+
*buf-- = digits_table[num * 2];
|
1048
|
+
}
|
1049
|
+
|
1050
|
+
if (negative) {
|
1051
|
+
*buf = '-';
|
1052
|
+
} else {
|
1053
|
+
buf++;
|
1054
|
+
}
|
1055
|
+
return buf;
|
1056
|
+
}
|
1057
|
+
|
1058
|
+
void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
|
1059
|
+
char buf[32];
|
1060
|
+
char *b = buf + sizeof(buf) - 1;
|
1061
|
+
long long num = NUM2LL(obj);
|
1062
|
+
bool neg = false;
|
1063
|
+
size_t cnt = 0;
|
1064
|
+
bool dump_as_string = false;
|
1035
1065
|
|
1036
1066
|
if (out->opts->int_range_max != 0 && out->opts->int_range_min != 0 &&
|
1037
|
-
|
1038
|
-
|
1067
|
+
(out->opts->int_range_max < num || out->opts->int_range_min > num)) {
|
1068
|
+
dump_as_string = true;
|
1039
1069
|
}
|
1040
1070
|
if (0 > num) {
|
1041
|
-
|
1042
|
-
|
1071
|
+
neg = true;
|
1072
|
+
num = -num;
|
1043
1073
|
}
|
1044
1074
|
*b-- = '\0';
|
1045
1075
|
|
1046
1076
|
if (dump_as_string) {
|
1047
|
-
|
1077
|
+
*b-- = '"';
|
1048
1078
|
}
|
1049
1079
|
if (0 < num) {
|
1050
|
-
|
1051
|
-
*b = (num % 10) + '0';
|
1052
|
-
}
|
1053
|
-
if (neg) {
|
1054
|
-
*b = '-';
|
1055
|
-
} else {
|
1056
|
-
b++;
|
1057
|
-
}
|
1080
|
+
b = oj_longlong_to_string(num, neg, b);
|
1058
1081
|
} else {
|
1059
|
-
|
1082
|
+
*b = '0';
|
1060
1083
|
}
|
1061
1084
|
if (dump_as_string) {
|
1062
|
-
|
1063
|
-
}
|
1064
|
-
assure_size(out, (sizeof(buf) - (b - buf)));
|
1065
|
-
for (; '\0' != *b; b++) {
|
1066
|
-
*out->cur++ = *b;
|
1085
|
+
*--b = '"';
|
1067
1086
|
}
|
1087
|
+
cnt = sizeof(buf) - (b - buf) - 1;
|
1088
|
+
assure_size(out, cnt);
|
1089
|
+
APPEND_CHARS(out->cur, b, cnt);
|
1068
1090
|
*out->cur = '\0';
|
1069
1091
|
}
|
1070
1092
|
|
1071
|
-
void
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
bool dump_as_string = false;
|
1093
|
+
void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
1094
|
+
volatile VALUE rs = rb_big2str(obj, 10);
|
1095
|
+
int cnt = (int)RSTRING_LEN(rs);
|
1096
|
+
bool dump_as_string = false;
|
1076
1097
|
|
1077
|
-
if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) {
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1098
|
+
if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) { // Bignum cannot be inside of Fixnum range
|
1099
|
+
dump_as_string = true;
|
1100
|
+
assure_size(out, cnt + 2);
|
1101
|
+
*out->cur++ = '"';
|
1081
1102
|
} else {
|
1082
|
-
|
1103
|
+
assure_size(out, cnt);
|
1083
1104
|
}
|
1084
|
-
|
1085
|
-
out->cur += cnt;
|
1105
|
+
APPEND_CHARS(out->cur, RSTRING_PTR(rs), cnt);
|
1086
1106
|
if (dump_as_string) {
|
1087
|
-
|
1107
|
+
*out->cur++ = '"';
|
1088
1108
|
}
|
1089
1109
|
*out->cur = '\0';
|
1090
1110
|
}
|
1091
1111
|
|
1092
1112
|
// Removed dependencies on math due to problems with CentOS 5.4.
|
1093
|
-
void
|
1094
|
-
|
1095
|
-
char
|
1096
|
-
|
1097
|
-
|
1098
|
-
int cnt = 0;
|
1113
|
+
void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
1114
|
+
char buf[64];
|
1115
|
+
char *b;
|
1116
|
+
double d = rb_num2dbl(obj);
|
1117
|
+
int cnt = 0;
|
1099
1118
|
|
1100
1119
|
if (0.0 == d) {
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1120
|
+
b = buf;
|
1121
|
+
*b++ = '0';
|
1122
|
+
*b++ = '.';
|
1123
|
+
*b++ = '0';
|
1124
|
+
*b++ = '\0';
|
1125
|
+
cnt = 3;
|
1107
1126
|
} else if (OJ_INFINITY == d) {
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
}
|
1141
|
-
}
|
1127
|
+
if (ObjectMode == out->opts->mode) {
|
1128
|
+
strcpy(buf, inf_val);
|
1129
|
+
cnt = sizeof(inf_val) - 1;
|
1130
|
+
} else {
|
1131
|
+
NanDump nd = out->opts->dump_opts.nan_dump;
|
1132
|
+
|
1133
|
+
if (AutoNan == nd) {
|
1134
|
+
switch (out->opts->mode) {
|
1135
|
+
case CompatMode: nd = WordNan; break;
|
1136
|
+
case StrictMode: nd = RaiseNan; break;
|
1137
|
+
case NullMode: nd = NullNan; break;
|
1138
|
+
case CustomMode: nd = NullNan; break;
|
1139
|
+
default: break;
|
1140
|
+
}
|
1141
|
+
}
|
1142
|
+
switch (nd) {
|
1143
|
+
case RaiseNan: raise_strict(obj); break;
|
1144
|
+
case WordNan:
|
1145
|
+
strcpy(buf, "Infinity");
|
1146
|
+
cnt = 8;
|
1147
|
+
break;
|
1148
|
+
case NullNan:
|
1149
|
+
strcpy(buf, "null");
|
1150
|
+
cnt = 4;
|
1151
|
+
break;
|
1152
|
+
case HugeNan:
|
1153
|
+
default:
|
1154
|
+
strcpy(buf, inf_val);
|
1155
|
+
cnt = sizeof(inf_val) - 1;
|
1156
|
+
break;
|
1157
|
+
}
|
1158
|
+
}
|
1142
1159
|
} else if (-OJ_INFINITY == d) {
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
}
|
1175
|
-
}
|
1160
|
+
if (ObjectMode == out->opts->mode) {
|
1161
|
+
strcpy(buf, ninf_val);
|
1162
|
+
cnt = sizeof(ninf_val) - 1;
|
1163
|
+
} else {
|
1164
|
+
NanDump nd = out->opts->dump_opts.nan_dump;
|
1165
|
+
|
1166
|
+
if (AutoNan == nd) {
|
1167
|
+
switch (out->opts->mode) {
|
1168
|
+
case CompatMode: nd = WordNan; break;
|
1169
|
+
case StrictMode: nd = RaiseNan; break;
|
1170
|
+
case NullMode: nd = NullNan; break;
|
1171
|
+
default: break;
|
1172
|
+
}
|
1173
|
+
}
|
1174
|
+
switch (nd) {
|
1175
|
+
case RaiseNan: raise_strict(obj); break;
|
1176
|
+
case WordNan:
|
1177
|
+
strcpy(buf, "-Infinity");
|
1178
|
+
cnt = 9;
|
1179
|
+
break;
|
1180
|
+
case NullNan:
|
1181
|
+
strcpy(buf, "null");
|
1182
|
+
cnt = 4;
|
1183
|
+
break;
|
1184
|
+
case HugeNan:
|
1185
|
+
default:
|
1186
|
+
strcpy(buf, ninf_val);
|
1187
|
+
cnt = sizeof(ninf_val) - 1;
|
1188
|
+
break;
|
1189
|
+
}
|
1190
|
+
}
|
1176
1191
|
} else if (isnan(d)) {
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
}
|
1209
|
-
}
|
1192
|
+
if (ObjectMode == out->opts->mode) {
|
1193
|
+
strcpy(buf, nan_val);
|
1194
|
+
cnt = sizeof(nan_val) - 1;
|
1195
|
+
} else {
|
1196
|
+
NanDump nd = out->opts->dump_opts.nan_dump;
|
1197
|
+
|
1198
|
+
if (AutoNan == nd) {
|
1199
|
+
switch (out->opts->mode) {
|
1200
|
+
case ObjectMode: nd = HugeNan; break;
|
1201
|
+
case StrictMode: nd = RaiseNan; break;
|
1202
|
+
case NullMode: nd = NullNan; break;
|
1203
|
+
default: break;
|
1204
|
+
}
|
1205
|
+
}
|
1206
|
+
switch (nd) {
|
1207
|
+
case RaiseNan: raise_strict(obj); break;
|
1208
|
+
case WordNan:
|
1209
|
+
strcpy(buf, "NaN");
|
1210
|
+
cnt = 3;
|
1211
|
+
break;
|
1212
|
+
case NullNan:
|
1213
|
+
strcpy(buf, "null");
|
1214
|
+
cnt = 4;
|
1215
|
+
break;
|
1216
|
+
case HugeNan:
|
1217
|
+
default:
|
1218
|
+
strcpy(buf, nan_val);
|
1219
|
+
cnt = sizeof(nan_val) - 1;
|
1220
|
+
break;
|
1221
|
+
}
|
1222
|
+
}
|
1210
1223
|
} else if (d == (double)(long long int)d) {
|
1211
|
-
|
1224
|
+
cnt = snprintf(buf, sizeof(buf), "%.1f", d);
|
1212
1225
|
} else if (0 == out->opts->float_prec) {
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
1226
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
1227
|
+
|
1228
|
+
cnt = (int)RSTRING_LEN(rstr);
|
1229
|
+
if ((int)sizeof(buf) <= cnt) {
|
1230
|
+
cnt = sizeof(buf) - 1;
|
1231
|
+
}
|
1232
|
+
memcpy(buf, RSTRING_PTR(rstr), cnt);
|
1233
|
+
buf[cnt] = '\0';
|
1221
1234
|
} else {
|
1222
|
-
|
1235
|
+
cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt);
|
1223
1236
|
}
|
1224
1237
|
assure_size(out, cnt);
|
1225
|
-
|
1226
|
-
*out->cur++ = *b;
|
1227
|
-
}
|
1238
|
+
APPEND_CHARS(out->cur, buf, cnt);
|
1228
1239
|
*out->cur = '\0';
|
1229
1240
|
}
|
1230
1241
|
|
1231
|
-
int
|
1232
|
-
|
1233
|
-
int cnt = snprintf(buf, blen, format, d);
|
1242
|
+
int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *format) {
|
1243
|
+
int cnt = snprintf(buf, blen, format, d);
|
1234
1244
|
|
1235
1245
|
// Round off issues at 16 significant digits so check for obvious ones of
|
1236
1246
|
// 0001 and 9999.
|
1237
1247
|
if (17 <= cnt && (0 == strcmp("0001", buf + cnt - 4) || 0 == strcmp("9999", buf + cnt - 4))) {
|
1238
|
-
|
1248
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
1239
1249
|
|
1240
|
-
|
1241
|
-
|
1250
|
+
strcpy(buf, RSTRING_PTR(rstr));
|
1251
|
+
cnt = (int)RSTRING_LEN(rstr);
|
1242
1252
|
}
|
1243
1253
|
return cnt;
|
1244
1254
|
}
|
1245
|
-
|
1246
|
-
bool
|
1247
|
-
oj_dump_ignore(Options opts, VALUE obj) {
|
1248
|
-
if (NULL != opts->ignore && (ObjectMode == opts->mode || CustomMode == opts->mode)) {
|
1249
|
-
VALUE *vp = opts->ignore;
|
1250
|
-
VALUE clas = rb_obj_class(obj);
|
1251
|
-
|
1252
|
-
for (; Qnil != *vp; vp++) {
|
1253
|
-
if (clas == *vp) {
|
1254
|
-
return true;
|
1255
|
-
}
|
1256
|
-
}
|
1257
|
-
}
|
1258
|
-
return false;
|
1259
|
-
}
|