oj 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oj might be problematic. Click here for more details.
- data/README.md +3 -3
- data/ext/oj/dump.c +79 -87
- data/ext/oj/extconf.rb +32 -2
- data/ext/oj/fast.c +26 -37
- data/ext/oj/load.c +83 -79
- data/ext/oj/oj.c +120 -117
- data/ext/oj/oj.h +28 -39
- data/lib/oj/version.rb +1 -1
- data/test/tests.rb +119 -15
- metadata +3 -2
data/README.md
CHANGED
@@ -24,11 +24,11 @@ A fast JSON parser and Object marshaller as a Ruby gem.
|
|
24
24
|
|
25
25
|
## <a name="release">Release Notes</a>
|
26
26
|
|
27
|
-
### Release 1.2.
|
27
|
+
### Release 1.2.1
|
28
28
|
|
29
|
-
-
|
29
|
+
- Organized compile configuration better.
|
30
30
|
|
31
|
-
-
|
31
|
+
- as_json() support now more flexible thanks to a contribution by sauliusg.
|
32
32
|
|
33
33
|
## <a name="description">Description</a>
|
34
34
|
|
data/ext/oj/dump.c
CHANGED
@@ -39,18 +39,11 @@
|
|
39
39
|
#include "oj.h"
|
40
40
|
#include "cache8.h"
|
41
41
|
|
42
|
-
#
|
43
|
-
#define HAS_TIMESPEC
|
44
|
-
#endif
|
45
|
-
|
46
|
-
#ifndef HAVE_RUBY_ENCODING_H
|
47
|
-
#define rb_eEncodingError rb_eException
|
48
|
-
#endif
|
49
|
-
#ifdef RUBINIUS
|
42
|
+
#if !HAS_ENCODING_SUPPORT
|
50
43
|
#define rb_eEncodingError rb_eException
|
51
44
|
#endif
|
52
45
|
|
53
|
-
typedef unsigned long
|
46
|
+
typedef unsigned long ulong;
|
54
47
|
|
55
48
|
typedef struct _Out {
|
56
49
|
char *buf;
|
@@ -64,7 +57,7 @@ typedef struct _Out {
|
|
64
57
|
uint32_t hash_cnt;
|
65
58
|
} *Out;
|
66
59
|
|
67
|
-
static void
|
60
|
+
static void dump_obj_to_json(VALUE obj, Options copts, Out out);
|
68
61
|
static void raise_strict(VALUE obj);
|
69
62
|
static void dump_val(VALUE obj, int depth, Out out);
|
70
63
|
static void dump_nil(Out out);
|
@@ -91,16 +84,16 @@ static void dump_data_comp(VALUE obj, Out out);
|
|
91
84
|
static void dump_data_obj(VALUE obj, Out out);
|
92
85
|
static void dump_obj_comp(VALUE obj, int depth, Out out);
|
93
86
|
static void dump_obj_obj(VALUE obj, int depth, Out out);
|
94
|
-
#
|
87
|
+
#if HAS_RSTRUCT
|
95
88
|
static void dump_struct_comp(VALUE obj, int depth, Out out);
|
96
89
|
static void dump_struct_obj(VALUE obj, int depth, Out out);
|
97
90
|
#endif
|
98
|
-
#if
|
91
|
+
#if HAS_IVAR_HELPERS
|
99
92
|
static int dump_attr_cb(ID key, VALUE value, Out out);
|
100
93
|
#endif
|
101
94
|
static void dump_obj_attrs(VALUE obj, int with_class, slot_t id, int depth, Out out);
|
102
95
|
|
103
|
-
static void
|
96
|
+
static void grow(Out out, size_t len);
|
104
97
|
static size_t hibit_friendly_size(const u_char *str, size_t len);
|
105
98
|
static size_t ascii_friendly_size(const u_char *str, size_t len);
|
106
99
|
|
@@ -115,7 +108,7 @@ static void dump_leaf_hash(Leaf leaf, int depth, Out out);
|
|
115
108
|
|
116
109
|
static const char hex_chars[17] = "0123456789abcdef";
|
117
110
|
|
118
|
-
static char
|
111
|
+
static char hibit_friendly_chars[256] = "\
|
119
112
|
66666666222622666666666666666666\
|
120
113
|
11211111111111121111111111111111\
|
121
114
|
11111111111111111111111111112111\
|
@@ -127,7 +120,7 @@ static char hibit_friendly_chars[256] = "\
|
|
127
120
|
|
128
121
|
// High bit set characters are always encoded as unicode. Worse case is 3
|
129
122
|
// bytes per character in the output. That makes this conservative.
|
130
|
-
static char
|
123
|
+
static char ascii_friendly_chars[256] = "\
|
131
124
|
66666666222622666666666666666666\
|
132
125
|
11211111111111121111111111111111\
|
133
126
|
11111111111111111111111111112111\
|
@@ -161,20 +154,20 @@ inline static void
|
|
161
154
|
fill_indent(Out out, int cnt) {
|
162
155
|
if (0 < cnt && 0 < out->indent) {
|
163
156
|
cnt *= out->indent;
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
157
|
+
*out->cur++ = '\n';
|
158
|
+
for (; 0 < cnt; cnt--) {
|
159
|
+
*out->cur++ = ' ';
|
160
|
+
}
|
168
161
|
}
|
169
162
|
}
|
170
163
|
|
171
164
|
inline static const char*
|
172
165
|
ulong2str(uint32_t num, char *end) {
|
173
|
-
char
|
166
|
+
char *b;
|
174
167
|
|
175
168
|
*end-- = '\0';
|
176
169
|
for (b = end; 0 < num || b == end; num /= 10, b--) {
|
177
|
-
|
170
|
+
*b = (num % 10) + '0';
|
178
171
|
}
|
179
172
|
b++;
|
180
173
|
|
@@ -183,20 +176,20 @@ ulong2str(uint32_t num, char *end) {
|
|
183
176
|
|
184
177
|
inline static void
|
185
178
|
dump_ulong(unsigned long num, Out out) {
|
186
|
-
char
|
187
|
-
char
|
179
|
+
char buf[32];
|
180
|
+
char *b = buf + sizeof(buf) - 1;
|
188
181
|
|
189
182
|
*b-- = '\0';
|
190
183
|
if (0 < num) {
|
191
|
-
|
192
|
-
|
193
|
-
|
184
|
+
for (; 0 < num; num /= 10, b--) {
|
185
|
+
*b = (num % 10) + '0';
|
186
|
+
}
|
194
187
|
b++;
|
195
188
|
} else {
|
196
|
-
|
189
|
+
*b = '0';
|
197
190
|
}
|
198
191
|
for (; '\0' != *b; b++) {
|
199
|
-
|
192
|
+
*out->cur++ = *b;
|
200
193
|
}
|
201
194
|
*out->cur = '\0';
|
202
195
|
}
|
@@ -206,14 +199,14 @@ grow(Out out, size_t len) {
|
|
206
199
|
size_t size = out->end - out->buf;
|
207
200
|
long pos = out->cur - out->buf;
|
208
201
|
char *buf;
|
209
|
-
|
202
|
+
|
210
203
|
size *= 2;
|
211
204
|
if (size <= len * 2 + pos) {
|
212
|
-
|
205
|
+
size += len;
|
213
206
|
}
|
214
207
|
buf = REALLOC_N(out->buf, char, (size + 10));
|
215
208
|
if (0 == buf) { // 1 extra for terminator character plus extra (paranoid)
|
216
|
-
|
209
|
+
rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC));
|
217
210
|
}
|
218
211
|
out->buf = buf;
|
219
212
|
out->end = buf + size;
|
@@ -251,7 +244,7 @@ dump_unicode(const char *str, const char *end, Out out) {
|
|
251
244
|
cnt = 5;
|
252
245
|
code = b & 0x00000001;
|
253
246
|
} else {
|
254
|
-
|
247
|
+
rb_raise(rb_eEncodingError, "Invalid Unicode\n");
|
255
248
|
}
|
256
249
|
str++;
|
257
250
|
for (; 0 < cnt; cnt--, str++) {
|
@@ -311,10 +304,10 @@ check_circular(VALUE obj, Out out) {
|
|
311
304
|
|
312
305
|
static void
|
313
306
|
dump_nil(Out out) {
|
314
|
-
size_t
|
307
|
+
size_t size = 4;
|
315
308
|
|
316
309
|
if (out->end - out->cur <= (long)size) {
|
317
|
-
|
310
|
+
grow(out, size);
|
318
311
|
}
|
319
312
|
*out->cur++ = 'n';
|
320
313
|
*out->cur++ = 'u';
|
@@ -325,10 +318,10 @@ dump_nil(Out out) {
|
|
325
318
|
|
326
319
|
static void
|
327
320
|
dump_true(Out out) {
|
328
|
-
size_t
|
321
|
+
size_t size = 4;
|
329
322
|
|
330
323
|
if (out->end - out->cur <= (long)size) {
|
331
|
-
|
324
|
+
grow(out, size);
|
332
325
|
}
|
333
326
|
*out->cur++ = 't';
|
334
327
|
*out->cur++ = 'r';
|
@@ -339,10 +332,10 @@ dump_true(Out out) {
|
|
339
332
|
|
340
333
|
static void
|
341
334
|
dump_false(Out out) {
|
342
|
-
size_t
|
335
|
+
size_t size = 5;
|
343
336
|
|
344
337
|
if (out->end - out->cur <= (long)size) {
|
345
|
-
|
338
|
+
grow(out, size);
|
346
339
|
}
|
347
340
|
*out->cur++ = 'f';
|
348
341
|
*out->cur++ = 'a';
|
@@ -354,33 +347,33 @@ dump_false(Out out) {
|
|
354
347
|
|
355
348
|
static void
|
356
349
|
dump_fixnum(VALUE obj, Out out) {
|
357
|
-
char
|
358
|
-
char
|
350
|
+
char buf[32];
|
351
|
+
char *b = buf + sizeof(buf) - 1;
|
359
352
|
long num = NUM2LONG(obj);
|
360
|
-
int
|
353
|
+
int neg = 0;
|
361
354
|
|
362
355
|
if (0 > num) {
|
363
|
-
|
364
|
-
|
356
|
+
neg = 1;
|
357
|
+
num = -num;
|
365
358
|
}
|
366
359
|
*b-- = '\0';
|
367
360
|
if (0 < num) {
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
361
|
+
for (; 0 < num; num /= 10, b--) {
|
362
|
+
*b = (num % 10) + '0';
|
363
|
+
}
|
364
|
+
if (neg) {
|
365
|
+
*b = '-';
|
366
|
+
} else {
|
367
|
+
b++;
|
368
|
+
}
|
376
369
|
} else {
|
377
|
-
|
370
|
+
*b = '0';
|
378
371
|
}
|
379
372
|
if (out->end - out->cur <= (long)(sizeof(buf) - (b - buf))) {
|
380
|
-
|
373
|
+
grow(out, sizeof(buf) - (b - buf));
|
381
374
|
}
|
382
375
|
for (; '\0' != *b; b++) {
|
383
|
-
|
376
|
+
*out->cur++ = *b;
|
384
377
|
}
|
385
378
|
*out->cur = '\0';
|
386
379
|
}
|
@@ -391,7 +384,7 @@ dump_bignum(VALUE obj, Out out) {
|
|
391
384
|
int cnt = (int)RSTRING_LEN(rs);
|
392
385
|
|
393
386
|
if (out->end - out->cur <= (long)cnt) {
|
394
|
-
|
387
|
+
grow(out, cnt);
|
395
388
|
}
|
396
389
|
memcpy(out->cur, StringValuePtr(rs), cnt);
|
397
390
|
out->cur += cnt;
|
@@ -432,10 +425,10 @@ dump_float(VALUE obj, Out out) {
|
|
432
425
|
break;
|
433
426
|
}
|
434
427
|
if (out->end - out->cur <= (long)cnt) {
|
435
|
-
|
428
|
+
grow(out, cnt);
|
436
429
|
}
|
437
430
|
for (b = buf; '\0' != *b; b++) {
|
438
|
-
|
431
|
+
*out->cur++ = *b;
|
439
432
|
}
|
440
433
|
*out->cur = '\0';
|
441
434
|
}
|
@@ -599,7 +592,7 @@ dump_array(VALUE a, int depth, Out out) {
|
|
599
592
|
}
|
600
593
|
size = 2;
|
601
594
|
if (out->end - out->cur <= (long)size) {
|
602
|
-
|
595
|
+
grow(out, size);
|
603
596
|
}
|
604
597
|
if (0 == cnt) {
|
605
598
|
*out->cur++ = ']';
|
@@ -916,13 +909,17 @@ dump_time(VALUE obj, Out out) {
|
|
916
909
|
char *b = buf + sizeof(buf) - 1;
|
917
910
|
long size;
|
918
911
|
char *dot = b - 10;
|
919
|
-
#
|
912
|
+
#if HAS_RB_TIME_TIMESPEC
|
920
913
|
struct timespec ts = rb_time_timespec(obj);
|
921
914
|
time_t sec = ts.tv_sec;
|
922
915
|
long nsec = ts.tv_nsec;
|
923
916
|
#else
|
924
917
|
time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
918
|
+
#if HAS_NANO_TIME
|
925
919
|
long nsec = NUM2LONG(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
920
|
+
#else
|
921
|
+
long nsec = NUM2LONG(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
|
922
|
+
#endif
|
926
923
|
#endif
|
927
924
|
|
928
925
|
*b-- = '\0';
|
@@ -986,12 +983,7 @@ dump_obj_comp(VALUE obj, int depth, Out out) {
|
|
986
983
|
}
|
987
984
|
dump_hash(h, depth, out->opts->mode, out);
|
988
985
|
} else if (rb_respond_to(obj, oj_as_json_id)) {
|
989
|
-
|
990
|
-
|
991
|
-
if (T_HASH != rb_type(h)) {
|
992
|
-
rb_raise(rb_eTypeError, "%s.as_json() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
|
993
|
-
}
|
994
|
-
dump_hash(h, depth, out->opts->mode, out);
|
986
|
+
dump_val(rb_funcall(obj, oj_as_json_id, 0), depth, out);
|
995
987
|
} else if (rb_respond_to(obj, oj_to_json_id)) {
|
996
988
|
VALUE rs = rb_funcall(obj, oj_to_json_id, 0);
|
997
989
|
const char *s = StringValuePtr(rs);
|
@@ -1017,7 +1009,7 @@ dump_obj_obj(VALUE obj, int depth, Out out) {
|
|
1017
1009
|
}
|
1018
1010
|
}
|
1019
1011
|
|
1020
|
-
#if
|
1012
|
+
#if HAS_IVAR_HELPERS
|
1021
1013
|
static int
|
1022
1014
|
dump_attr_cb(ID key, VALUE value, Out out) {
|
1023
1015
|
int depth = out->depth;
|
@@ -1090,7 +1082,7 @@ dump_obj_attrs(VALUE obj, int with_class, slot_t id, int depth, Out out) {
|
|
1090
1082
|
{
|
1091
1083
|
int cnt;
|
1092
1084
|
// use encoding as the indicator for Ruby 1.8.7 or 1.9.x
|
1093
|
-
#if
|
1085
|
+
#if HAS_IVAR_HELPERS
|
1094
1086
|
cnt = (int)rb_ivar_count(obj);
|
1095
1087
|
#else
|
1096
1088
|
VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0);
|
@@ -1105,14 +1097,14 @@ dump_obj_attrs(VALUE obj, int with_class, slot_t id, int depth, Out out) {
|
|
1105
1097
|
*out->cur++ = ',';
|
1106
1098
|
}
|
1107
1099
|
out->depth = depth + 1;
|
1108
|
-
#if
|
1100
|
+
#if HAS_IVAR_HELPERS
|
1109
1101
|
rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
|
1110
1102
|
out->cur--; // backup to overwrite last comma
|
1111
1103
|
#else
|
1112
1104
|
size = d2 * out->indent + 1;
|
1113
1105
|
for (i = cnt; 0 < i; i--, np++) {
|
1114
1106
|
if (out->end - out->cur <= (long)size) {
|
1115
|
-
|
1107
|
+
grow(out, size);
|
1116
1108
|
}
|
1117
1109
|
vid = rb_to_id(*np);
|
1118
1110
|
fill_indent(out, d2);
|
@@ -1131,7 +1123,7 @@ dump_obj_attrs(VALUE obj, int with_class, slot_t id, int depth, Out out) {
|
|
1131
1123
|
*out->cur++ = ':';
|
1132
1124
|
dump_val(rb_ivar_get(obj, vid), d2, out);
|
1133
1125
|
if (out->end - out->cur <= 2) {
|
1134
|
-
|
1126
|
+
grow(out, 2);
|
1135
1127
|
}
|
1136
1128
|
if (1 < i) {
|
1137
1129
|
*out->cur++ = ',';
|
@@ -1144,7 +1136,7 @@ dump_obj_attrs(VALUE obj, int with_class, slot_t id, int depth, Out out) {
|
|
1144
1136
|
*out->cur = '\0';
|
1145
1137
|
}
|
1146
1138
|
|
1147
|
-
#
|
1139
|
+
#if HAS_RSTRUCT
|
1148
1140
|
static void
|
1149
1141
|
dump_struct_comp(VALUE obj, int depth, Out out) {
|
1150
1142
|
if (rb_respond_to(obj, oj_to_hash_id)) {
|
@@ -1179,7 +1171,7 @@ dump_struct_obj(VALUE obj, int depth, Out out) {
|
|
1179
1171
|
int d3 = d2 + 1;
|
1180
1172
|
size_t len = strlen(class_name);
|
1181
1173
|
size_t size = d2 * out->indent + d3 * out->indent + 10 + len;
|
1182
|
-
|
1174
|
+
|
1183
1175
|
if (out->end - out->cur <= (long)size) {
|
1184
1176
|
grow(out, size);
|
1185
1177
|
}
|
@@ -1274,7 +1266,7 @@ dump_val(VALUE obj, int depth, Out out) {
|
|
1274
1266
|
default: dump_data_obj(obj, out); break;
|
1275
1267
|
}
|
1276
1268
|
break;
|
1277
|
-
#
|
1269
|
+
#if HAS_RSTRUCT
|
1278
1270
|
case T_STRUCT: // for Range
|
1279
1271
|
switch (out->opts->mode) {
|
1280
1272
|
case StrictMode: raise_strict(obj); break;
|
@@ -1316,12 +1308,12 @@ dump_obj_to_json(VALUE obj, Options copts, Out out) {
|
|
1316
1308
|
out->opts = copts;
|
1317
1309
|
out->hash_cnt = 0;
|
1318
1310
|
if (Yes == copts->circular) {
|
1319
|
-
|
1311
|
+
oj_cache8_new(&out->circ_cache);
|
1320
1312
|
}
|
1321
1313
|
out->indent = copts->indent;
|
1322
1314
|
dump_val(obj, 0, out);
|
1323
1315
|
if (Yes == copts->circular) {
|
1324
|
-
|
1316
|
+
oj_cache8_delete(out->circ_cache);
|
1325
1317
|
}
|
1326
1318
|
}
|
1327
1319
|
|
@@ -1337,18 +1329,18 @@ oj_write_obj_to_str(VALUE obj, Options copts) {
|
|
1337
1329
|
void
|
1338
1330
|
oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
|
1339
1331
|
struct _Out out;
|
1340
|
-
size_t
|
1341
|
-
FILE
|
1332
|
+
size_t size;
|
1333
|
+
FILE *f;
|
1342
1334
|
|
1343
1335
|
dump_obj_to_json(obj, copts, &out);
|
1344
1336
|
size = out.cur - out.buf;
|
1345
1337
|
if (0 == (f = fopen(path, "w"))) {
|
1346
|
-
|
1338
|
+
rb_raise(rb_eIOError, "%s\n", strerror(errno));
|
1347
1339
|
}
|
1348
1340
|
if (size != fwrite(out.buf, 1, size, f)) {
|
1349
|
-
|
1341
|
+
int err = ferror(f);
|
1350
1342
|
|
1351
|
-
|
1343
|
+
rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", err, strerror(err));
|
1352
1344
|
}
|
1353
1345
|
xfree(out.buf);
|
1354
1346
|
fclose(f);
|
@@ -1425,7 +1417,7 @@ dump_leaf_array(Leaf leaf, int depth, Out out) {
|
|
1425
1417
|
|
1426
1418
|
size = 2;
|
1427
1419
|
if (out->end - out->cur <= (long)size) {
|
1428
|
-
|
1420
|
+
grow(out, size);
|
1429
1421
|
}
|
1430
1422
|
*out->cur++ = '[';
|
1431
1423
|
if (0 == leaf->elements) {
|
@@ -1463,7 +1455,7 @@ dump_leaf_hash(Leaf leaf, int depth, Out out) {
|
|
1463
1455
|
|
1464
1456
|
size = 2;
|
1465
1457
|
if (out->end - out->cur <= (long)size) {
|
1466
|
-
|
1458
|
+
grow(out, size);
|
1467
1459
|
}
|
1468
1460
|
*out->cur++ = '{';
|
1469
1461
|
if (0 == leaf->elements) {
|
@@ -1553,18 +1545,18 @@ oj_write_leaf_to_str(Leaf leaf, Options copts) {
|
|
1553
1545
|
void
|
1554
1546
|
oj_write_leaf_to_file(Leaf leaf, const char *path, Options copts) {
|
1555
1547
|
struct _Out out;
|
1556
|
-
size_t
|
1557
|
-
FILE
|
1548
|
+
size_t size;
|
1549
|
+
FILE *f;
|
1558
1550
|
|
1559
1551
|
dump_leaf_to_json(leaf, copts, &out);
|
1560
1552
|
size = out.cur - out.buf;
|
1561
1553
|
if (0 == (f = fopen(path, "w"))) {
|
1562
|
-
|
1554
|
+
rb_raise(rb_eIOError, "%s\n", strerror(errno));
|
1563
1555
|
}
|
1564
1556
|
if (size != fwrite(out.buf, 1, size, f)) {
|
1565
|
-
|
1557
|
+
int err = ferror(f);
|
1566
1558
|
|
1567
|
-
|
1559
|
+
rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", err, strerror(err));
|
1568
1560
|
}
|
1569
1561
|
xfree(out.buf);
|
1570
1562
|
fclose(f);
|