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