oj 3.11.1 → 3.11.6
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 +34 -38
- data/ext/oj/cache8.c +59 -62
- data/ext/oj/cache8.h +8 -7
- data/ext/oj/circarray.c +33 -35
- data/ext/oj/circarray.h +11 -9
- data/ext/oj/code.c +170 -174
- data/ext/oj/code.h +21 -20
- data/ext/oj/compat.c +159 -166
- data/ext/oj/custom.c +802 -851
- data/ext/oj/dump.c +766 -778
- data/ext/oj/dump.h +49 -51
- data/ext/oj/dump_compat.c +1 -0
- data/ext/oj/dump_leaf.c +116 -157
- data/ext/oj/dump_object.c +609 -628
- data/ext/oj/dump_strict.c +318 -327
- data/ext/oj/encode.h +3 -4
- data/ext/oj/err.c +39 -25
- data/ext/oj/err.h +24 -15
- data/ext/oj/extconf.rb +2 -1
- data/ext/oj/fast.c +1042 -1041
- data/ext/oj/hash.c +62 -66
- data/ext/oj/hash.h +7 -6
- data/ext/oj/hash_test.c +450 -443
- data/ext/oj/mimic_json.c +412 -402
- data/ext/oj/object.c +559 -528
- data/ext/oj/odd.c +123 -128
- data/ext/oj/odd.h +27 -25
- data/ext/oj/oj.c +1123 -924
- data/ext/oj/oj.h +286 -298
- data/ext/oj/parse.c +938 -930
- data/ext/oj/parse.h +70 -69
- data/ext/oj/rails.c +836 -839
- data/ext/oj/rails.h +7 -7
- data/ext/oj/reader.c +135 -140
- data/ext/oj/reader.h +66 -79
- data/ext/oj/resolve.c +43 -43
- data/ext/oj/resolve.h +3 -2
- data/ext/oj/rxclass.c +67 -68
- data/ext/oj/rxclass.h +12 -10
- data/ext/oj/saj.c +451 -479
- data/ext/oj/scp.c +93 -103
- data/ext/oj/sparse.c +770 -730
- data/ext/oj/stream_writer.c +120 -149
- data/ext/oj/strict.c +71 -86
- data/ext/oj/string_writer.c +198 -243
- data/ext/oj/trace.c +29 -33
- data/ext/oj/trace.h +14 -11
- data/ext/oj/util.c +103 -103
- data/ext/oj/util.h +3 -2
- data/ext/oj/val_stack.c +47 -47
- data/ext/oj/val_stack.h +79 -86
- data/ext/oj/wab.c +291 -309
- data/lib/oj/bag.rb +1 -0
- data/lib/oj/easy_hash.rb +5 -4
- data/lib/oj/mimic.rb +0 -12
- data/lib/oj/version.rb +1 -1
- data/test/activerecord/result_test.rb +7 -2
- data/test/foo.rb +35 -32
- data/test/test_fast.rb +32 -2
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +10 -0
- data/test/test_scp.rb +1 -1
- metadata +4 -2
data/ext/oj/dump.c
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
// Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
3
|
+
|
4
|
+
#include "dump.h"
|
2
5
|
|
3
6
|
#include <errno.h>
|
4
7
|
#include <math.h>
|
@@ -8,32 +11,31 @@
|
|
8
11
|
#include <string.h>
|
9
12
|
#include <unistd.h>
|
10
13
|
|
11
|
-
#include "oj.h"
|
12
14
|
#include "cache8.h"
|
13
|
-
#include "dump.h"
|
14
15
|
#include "odd.h"
|
16
|
+
#include "oj.h"
|
15
17
|
#include "trace.h"
|
16
18
|
#include "util.h"
|
17
19
|
|
18
20
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
19
|
-
#define OJ_INFINITY (1.0/0.0)
|
21
|
+
#define OJ_INFINITY (1.0 / 0.0)
|
20
22
|
|
21
23
|
#define MAX_DEPTH 1000
|
22
24
|
|
23
|
-
static const char
|
24
|
-
static const char
|
25
|
-
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;
|
26
28
|
|
27
|
-
typedef unsigned long
|
29
|
+
typedef unsigned long ulong;
|
28
30
|
|
29
|
-
static size_t
|
30
|
-
static size_t
|
31
|
-
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);
|
32
34
|
|
33
|
-
static const char
|
35
|
+
static const char hex_chars[17] = "0123456789abcdef";
|
34
36
|
|
35
37
|
// JSON standard except newlines are no escaped
|
36
|
-
static char
|
38
|
+
static char newline_friendly_chars[256] = "\
|
37
39
|
66666666221622666666666666666666\
|
38
40
|
11211111111111111111111111111111\
|
39
41
|
11111111111111111111111111112111\
|
@@ -44,7 +46,7 @@ static char newline_friendly_chars[256] = "\
|
|
44
46
|
11111111111111111111111111111111";
|
45
47
|
|
46
48
|
// JSON standard
|
47
|
-
static char
|
49
|
+
static char hibit_friendly_chars[256] = "\
|
48
50
|
66666666222622666666666666666666\
|
49
51
|
11211111111111111111111111111111\
|
50
52
|
11111111111111111111111111112111\
|
@@ -56,7 +58,7 @@ static char hibit_friendly_chars[256] = "\
|
|
56
58
|
|
57
59
|
// High bit set characters are always encoded as unicode. Worse case is 3
|
58
60
|
// bytes per character in the output. That makes this conservative.
|
59
|
-
static char
|
61
|
+
static char ascii_friendly_chars[256] = "\
|
60
62
|
66666666222622666666666666666666\
|
61
63
|
11211111111111111111111111111111\
|
62
64
|
11111111111111111111111111112111\
|
@@ -67,7 +69,7 @@ static char ascii_friendly_chars[256] = "\
|
|
67
69
|
33333333333333333333333333333333";
|
68
70
|
|
69
71
|
// XSS safe mode
|
70
|
-
static char
|
72
|
+
static char xss_friendly_chars[256] = "\
|
71
73
|
66666666222622666666666666666666\
|
72
74
|
11211161111111121111111111116161\
|
73
75
|
11111111111111111111111111112111\
|
@@ -78,7 +80,7 @@ static char xss_friendly_chars[256] = "\
|
|
78
80
|
33333333333333333333333333333333";
|
79
81
|
|
80
82
|
// JSON XSS combo
|
81
|
-
static char
|
83
|
+
static char hixss_friendly_chars[256] = "\
|
82
84
|
66666666222622666666666666666666\
|
83
85
|
11211111111111111111111111111111\
|
84
86
|
11111111111111111111111111112111\
|
@@ -89,7 +91,7 @@ static char hixss_friendly_chars[256] = "\
|
|
89
91
|
11611111111111111111111111111111";
|
90
92
|
|
91
93
|
// Rails XSS combo
|
92
|
-
static char
|
94
|
+
static char rails_xss_friendly_chars[256] = "\
|
93
95
|
66666666222622666666666666666666\
|
94
96
|
11211161111111111111111111116161\
|
95
97
|
11111111111111111111111111112111\
|
@@ -100,7 +102,7 @@ static char rails_xss_friendly_chars[256] = "\
|
|
100
102
|
11611111111111111111111111111111";
|
101
103
|
|
102
104
|
// Rails HTML non-escape
|
103
|
-
static char
|
105
|
+
static char rails_friendly_chars[256] = "\
|
104
106
|
66666666222622666666666666666666\
|
105
107
|
11211111111111111111111111111111\
|
106
108
|
11111111111111111111111111112111\
|
@@ -110,248 +112,235 @@ static char rails_friendly_chars[256] = "\
|
|
110
112
|
11111111111111111111111111111111\
|
111
113
|
11111111111111111111111111111111";
|
112
114
|
|
113
|
-
static void
|
114
|
-
|
115
|
-
|
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)));
|
116
119
|
}
|
117
120
|
|
118
|
-
inline static size_t
|
119
|
-
|
120
|
-
size_t
|
121
|
-
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;
|
122
124
|
|
123
125
|
for (; 0 < i; str++, i--) {
|
124
|
-
|
126
|
+
size += newline_friendly_chars[*str];
|
125
127
|
}
|
126
128
|
return size - len * (size_t)'0';
|
127
129
|
}
|
128
130
|
|
129
|
-
inline static size_t
|
130
|
-
|
131
|
-
size_t
|
132
|
-
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;
|
133
134
|
|
134
135
|
for (; 0 < i; str++, i--) {
|
135
|
-
|
136
|
+
size += hibit_friendly_chars[*str];
|
136
137
|
}
|
137
138
|
return size - len * (size_t)'0';
|
138
139
|
}
|
139
140
|
|
140
|
-
inline static size_t
|
141
|
-
|
142
|
-
size_t
|
143
|
-
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;
|
144
144
|
|
145
145
|
for (; 0 < i; str++, i--) {
|
146
|
-
|
146
|
+
size += ascii_friendly_chars[*str];
|
147
147
|
}
|
148
148
|
return size - len * (size_t)'0';
|
149
149
|
}
|
150
150
|
|
151
|
-
inline static size_t
|
152
|
-
|
153
|
-
size_t
|
154
|
-
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;
|
155
154
|
|
156
155
|
for (; 0 < i; str++, i--) {
|
157
|
-
|
156
|
+
size += xss_friendly_chars[*str];
|
158
157
|
}
|
159
158
|
return size - len * (size_t)'0';
|
160
159
|
}
|
161
160
|
|
162
|
-
inline static size_t
|
163
|
-
|
164
|
-
size_t
|
165
|
-
|
166
|
-
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;
|
167
165
|
|
168
166
|
for (; 0 < i; str++, i--) {
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
167
|
+
size += hixss_friendly_chars[*str];
|
168
|
+
if (0 != (0x80 & *str)) {
|
169
|
+
check = true;
|
170
|
+
}
|
173
171
|
}
|
174
172
|
return size - len * (size_t)'0' + check;
|
175
173
|
}
|
176
174
|
|
177
|
-
inline static long
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
uint8_t hi = 0;
|
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;
|
182
179
|
|
183
180
|
for (; 0 < i; str++, i--) {
|
184
|
-
|
185
|
-
|
181
|
+
size += rails_xss_friendly_chars[*str];
|
182
|
+
hi |= *str & 0x80;
|
186
183
|
}
|
187
184
|
if (0 == hi) {
|
188
|
-
|
185
|
+
return size - len * (size_t)'0';
|
189
186
|
}
|
190
187
|
return -(size - len * (size_t)'0');
|
191
188
|
}
|
192
189
|
|
193
|
-
inline static size_t
|
194
|
-
|
195
|
-
size_t
|
196
|
-
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;
|
197
193
|
|
198
194
|
for (; 0 < i; str++, i--) {
|
199
|
-
|
195
|
+
size += rails_friendly_chars[*str];
|
200
196
|
}
|
201
197
|
return size - len * (size_t)'0';
|
202
198
|
}
|
203
199
|
|
204
|
-
const char*
|
205
|
-
|
206
|
-
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;
|
207
202
|
|
208
203
|
if (AutoNan == opt) {
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
204
|
+
switch (mode) {
|
205
|
+
case CompatMode: opt = WordNan; break;
|
206
|
+
case StrictMode: opt = RaiseNan; break;
|
207
|
+
default: break;
|
208
|
+
}
|
214
209
|
}
|
215
210
|
switch (opt) {
|
216
|
-
case RaiseNan:
|
217
|
-
raise_strict(obj);
|
218
|
-
break;
|
211
|
+
case RaiseNan: raise_strict(obj); break;
|
219
212
|
case WordNan:
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
213
|
+
if (plus) {
|
214
|
+
str = "Infinity";
|
215
|
+
*lenp = 8;
|
216
|
+
} else {
|
217
|
+
str = "-Infinity";
|
218
|
+
*lenp = 9;
|
219
|
+
}
|
220
|
+
break;
|
228
221
|
case NullNan:
|
229
|
-
|
230
|
-
|
231
|
-
|
222
|
+
str = "null";
|
223
|
+
*lenp = 4;
|
224
|
+
break;
|
232
225
|
case HugeNan:
|
233
226
|
default:
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
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;
|
242
235
|
}
|
243
236
|
return str;
|
244
237
|
}
|
245
238
|
|
246
|
-
inline static void
|
247
|
-
|
248
|
-
uint8_t d = (c >> 4) & 0x0F;
|
239
|
+
inline static void dump_hex(uint8_t c, Out out) {
|
240
|
+
uint8_t d = (c >> 4) & 0x0F;
|
249
241
|
|
250
242
|
*out->cur++ = hex_chars[d];
|
251
|
-
d
|
243
|
+
d = c & 0x0F;
|
252
244
|
*out->cur++ = hex_chars[d];
|
253
245
|
}
|
254
246
|
|
255
|
-
static void
|
256
|
-
|
257
|
-
char
|
258
|
-
char
|
259
|
-
|
260
|
-
|
261
|
-
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;
|
262
253
|
|
263
254
|
*cp++ = '[';
|
264
255
|
for (i = pos; i < len && i - pos < 5; i++) {
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
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++ = ' ';
|
271
262
|
}
|
272
263
|
cp--;
|
273
264
|
*cp++ = ']';
|
274
|
-
*cp
|
265
|
+
*cp = '\0';
|
275
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,778 +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
|
-
|
773
|
-
bool has_hi = false;
|
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;
|
774
774
|
|
775
775
|
switch (out->opts->escape_mode) {
|
776
776
|
case NLEsc:
|
777
|
-
|
778
|
-
|
779
|
-
|
777
|
+
cmap = newline_friendly_chars;
|
778
|
+
size = newline_friendly_size((uint8_t *)str, cnt);
|
779
|
+
break;
|
780
780
|
case ASCIIEsc:
|
781
|
-
|
782
|
-
|
783
|
-
|
781
|
+
cmap = ascii_friendly_chars;
|
782
|
+
size = ascii_friendly_size((uint8_t *)str, cnt);
|
783
|
+
break;
|
784
784
|
case XSSEsc:
|
785
|
-
|
786
|
-
|
787
|
-
|
785
|
+
cmap = xss_friendly_chars;
|
786
|
+
size = xss_friendly_size((uint8_t *)str, cnt);
|
787
|
+
break;
|
788
788
|
case JXEsc:
|
789
|
-
|
790
|
-
|
791
|
-
|
789
|
+
cmap = hixss_friendly_chars;
|
790
|
+
size = hixss_friendly_size((uint8_t *)str, cnt);
|
791
|
+
break;
|
792
792
|
case RailsXEsc: {
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
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
804
|
}
|
805
805
|
case RailsEsc:
|
806
|
-
|
807
|
-
|
808
|
-
|
806
|
+
cmap = rails_friendly_chars;
|
807
|
+
size = rails_friendly_size((uint8_t *)str, cnt);
|
808
|
+
break;
|
809
809
|
case JSONEsc:
|
810
|
-
default:
|
811
|
-
cmap = hibit_friendly_chars;
|
812
|
-
size = hibit_friendly_size((uint8_t*)str, cnt);
|
810
|
+
default: cmap = hibit_friendly_chars; size = hibit_friendly_size((uint8_t *)str, cnt);
|
813
811
|
}
|
814
812
|
assure_size(out, size + BUFFER_EXTRA);
|
815
813
|
*out->cur++ = '"';
|
816
814
|
|
817
815
|
if (escape1) {
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
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
|
827
825
|
}
|
828
826
|
if (cnt == size && !has_hi) {
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
827
|
+
if (is_sym) {
|
828
|
+
*out->cur++ = ':';
|
829
|
+
}
|
830
|
+
for (; '\0' != *str; str++) {
|
831
|
+
*out->cur++ = *str;
|
832
|
+
}
|
833
|
+
*out->cur++ = '"';
|
836
834
|
} else {
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
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++ = '"';
|
906
910
|
}
|
907
|
-
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
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
|
+
}
|
946
951
|
}
|
947
952
|
*out->cur = '\0';
|
948
953
|
}
|
949
954
|
|
950
|
-
void
|
951
|
-
|
952
|
-
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);
|
953
957
|
|
954
958
|
oj_dump_cstr(s, strlen(s), 0, 0, out);
|
955
959
|
}
|
956
960
|
|
957
|
-
void
|
958
|
-
|
959
|
-
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);
|
960
963
|
|
961
|
-
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);
|
962
965
|
}
|
963
966
|
|
964
|
-
void
|
965
|
-
oj_dump_raw(const char *str, size_t cnt, Out out) {
|
967
|
+
void oj_dump_raw(const char *str, size_t cnt, Out out) {
|
966
968
|
assure_size(out, cnt + 10);
|
967
969
|
memcpy(out->cur, str, cnt);
|
968
970
|
out->cur += cnt;
|
969
971
|
*out->cur = '\0';
|
970
972
|
}
|
971
973
|
|
972
|
-
void
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
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;
|
977
978
|
|
978
979
|
size *= 2;
|
979
980
|
if (size <= len * 2 + pos) {
|
980
|
-
|
981
|
+
size += len;
|
981
982
|
}
|
982
983
|
if (out->allocated) {
|
983
|
-
|
984
|
+
REALLOC_N(buf, char, (size + BUFFER_EXTRA));
|
984
985
|
} else {
|
985
|
-
|
986
|
-
|
987
|
-
|
986
|
+
buf = ALLOC_N(char, (size + BUFFER_EXTRA));
|
987
|
+
out->allocated = true;
|
988
|
+
memcpy(buf, out->buf, out->end - out->buf + BUFFER_EXTRA);
|
988
989
|
}
|
989
990
|
if (0 == buf) {
|
990
|
-
|
991
|
+
rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]", ENOSPC, strerror(ENOSPC));
|
991
992
|
}
|
992
993
|
out->buf = buf;
|
993
994
|
out->end = buf + size;
|
994
995
|
out->cur = out->buf + pos;
|
995
996
|
}
|
996
997
|
|
997
|
-
void
|
998
|
-
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) {
|
999
999
|
assure_size(out, 4);
|
1000
1000
|
*out->cur++ = 'n';
|
1001
1001
|
*out->cur++ = 'u';
|
1002
1002
|
*out->cur++ = 'l';
|
1003
1003
|
*out->cur++ = 'l';
|
1004
|
-
*out->cur
|
1004
|
+
*out->cur = '\0';
|
1005
1005
|
}
|
1006
1006
|
|
1007
|
-
void
|
1008
|
-
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) {
|
1009
1008
|
assure_size(out, 4);
|
1010
1009
|
*out->cur++ = 't';
|
1011
1010
|
*out->cur++ = 'r';
|
1012
1011
|
*out->cur++ = 'u';
|
1013
1012
|
*out->cur++ = 'e';
|
1014
|
-
*out->cur
|
1013
|
+
*out->cur = '\0';
|
1015
1014
|
}
|
1016
1015
|
|
1017
|
-
void
|
1018
|
-
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) {
|
1019
1017
|
assure_size(out, 5);
|
1020
1018
|
*out->cur++ = 'f';
|
1021
1019
|
*out->cur++ = 'a';
|
1022
1020
|
*out->cur++ = 'l';
|
1023
1021
|
*out->cur++ = 's';
|
1024
1022
|
*out->cur++ = 'e';
|
1025
|
-
*out->cur
|
1023
|
+
*out->cur = '\0';
|
1026
1024
|
}
|
1027
1025
|
|
1028
|
-
void
|
1029
|
-
|
1030
|
-
char
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
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;
|
1035
1032
|
|
1036
1033
|
if (out->opts->int_range_max != 0 && out->opts->int_range_min != 0 &&
|
1037
|
-
|
1038
|
-
|
1034
|
+
(out->opts->int_range_max < num || out->opts->int_range_min > num)) {
|
1035
|
+
dump_as_string = true;
|
1039
1036
|
}
|
1040
1037
|
if (0 > num) {
|
1041
|
-
|
1042
|
-
|
1038
|
+
neg = 1;
|
1039
|
+
num = -num;
|
1043
1040
|
}
|
1044
1041
|
*b-- = '\0';
|
1045
1042
|
|
1046
1043
|
if (dump_as_string) {
|
1047
|
-
|
1044
|
+
*b-- = '"';
|
1048
1045
|
}
|
1049
1046
|
if (0 < num) {
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1047
|
+
for (; 0 < num; num /= 10, b--) {
|
1048
|
+
*b = (num % 10) + '0';
|
1049
|
+
}
|
1050
|
+
if (neg) {
|
1051
|
+
*b = '-';
|
1052
|
+
} else {
|
1053
|
+
b++;
|
1054
|
+
}
|
1058
1055
|
} else {
|
1059
|
-
|
1056
|
+
*b = '0';
|
1060
1057
|
}
|
1061
1058
|
if (dump_as_string) {
|
1062
|
-
|
1059
|
+
*--b = '"';
|
1063
1060
|
}
|
1064
1061
|
assure_size(out, (sizeof(buf) - (b - buf)));
|
1065
1062
|
for (; '\0' != *b; b++) {
|
1066
|
-
|
1063
|
+
*out->cur++ = *b;
|
1067
1064
|
}
|
1068
1065
|
*out->cur = '\0';
|
1069
1066
|
}
|
1070
1067
|
|
1071
|
-
void
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
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;
|
1076
1072
|
|
1077
|
-
if (out->opts->int_range_max != 0 ||
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
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++ = '"';
|
1081
1078
|
} else {
|
1082
|
-
|
1079
|
+
assure_size(out, cnt);
|
1083
1080
|
}
|
1084
|
-
memcpy(out->cur, rb_string_value_ptr((VALUE*)&rs), cnt);
|
1081
|
+
memcpy(out->cur, rb_string_value_ptr((VALUE *)&rs), cnt);
|
1085
1082
|
out->cur += cnt;
|
1086
1083
|
if (dump_as_string) {
|
1087
|
-
|
1084
|
+
*out->cur++ = '"';
|
1088
1085
|
}
|
1089
1086
|
*out->cur = '\0';
|
1090
1087
|
}
|
1091
1088
|
|
1092
1089
|
// Removed dependencies on math due to problems with CentOS 5.4.
|
1093
|
-
void
|
1094
|
-
|
1095
|
-
char
|
1096
|
-
|
1097
|
-
|
1098
|
-
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;
|
1099
1095
|
|
1100
1096
|
if (0.0 == d) {
|
1101
|
-
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1097
|
+
b = buf;
|
1098
|
+
*b++ = '0';
|
1099
|
+
*b++ = '.';
|
1100
|
+
*b++ = '0';
|
1101
|
+
*b++ = '\0';
|
1102
|
+
cnt = 3;
|
1107
1103
|
} else if (OJ_INFINITY == d) {
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
}
|
1141
|
-
}
|
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
|
+
}
|
1142
1136
|
} else if (-OJ_INFINITY == d) {
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
}
|
1175
|
-
}
|
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
|
+
}
|
1176
1168
|
} else if (isnan(d)) {
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
}
|
1209
|
-
}
|
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
|
+
}
|
1210
1200
|
} else if (d == (double)(long long int)d) {
|
1211
|
-
|
1201
|
+
cnt = snprintf(buf, sizeof(buf), "%.1f", d);
|
1212
1202
|
} else if (0 == out->opts->float_prec) {
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
1219
|
-
|
1220
|
-
|
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';
|
1221
1211
|
} else {
|
1222
|
-
|
1212
|
+
cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt);
|
1223
1213
|
}
|
1224
1214
|
assure_size(out, cnt);
|
1225
1215
|
for (b = buf; '\0' != *b; b++) {
|
1226
|
-
|
1216
|
+
*out->cur++ = *b;
|
1227
1217
|
}
|
1228
1218
|
*out->cur = '\0';
|
1229
1219
|
}
|
1230
1220
|
|
1231
|
-
int
|
1232
|
-
|
1233
|
-
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);
|
1234
1223
|
|
1235
1224
|
// Round off issues at 16 significant digits so check for obvious ones of
|
1236
1225
|
// 0001 and 9999.
|
1237
1226
|
if (17 <= cnt && (0 == strcmp("0001", buf + cnt - 4) || 0 == strcmp("9999", buf + cnt - 4))) {
|
1238
|
-
|
1227
|
+
volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
1239
1228
|
|
1240
|
-
|
1241
|
-
|
1229
|
+
strcpy(buf, rb_string_value_ptr((VALUE *)&rstr));
|
1230
|
+
cnt = (int)RSTRING_LEN(rstr);
|
1242
1231
|
}
|
1243
1232
|
return cnt;
|
1244
1233
|
}
|
1245
1234
|
|
1246
|
-
bool
|
1247
|
-
oj_dump_ignore(Options opts, VALUE obj) {
|
1235
|
+
bool oj_dump_ignore(Options opts, VALUE obj) {
|
1248
1236
|
if (NULL != opts->ignore && (ObjectMode == opts->mode || CustomMode == opts->mode)) {
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
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
|
+
}
|
1257
1245
|
}
|
1258
1246
|
return false;
|
1259
1247
|
}
|