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