oj 3.13.11 → 3.15.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/CHANGELOG.md +74 -0
- data/README.md +4 -2
- data/ext/oj/buf.h +11 -6
- data/ext/oj/cache.c +25 -24
- data/ext/oj/cache8.c +10 -9
- data/ext/oj/circarray.c +8 -6
- data/ext/oj/circarray.h +2 -2
- data/ext/oj/code.c +17 -24
- data/ext/oj/code.h +2 -2
- data/ext/oj/compat.c +17 -44
- data/ext/oj/custom.c +70 -141
- data/ext/oj/debug.c +3 -9
- data/ext/oj/dump.c +128 -118
- data/ext/oj/dump.h +12 -8
- data/ext/oj/dump_compat.c +564 -641
- data/ext/oj/dump_leaf.c +17 -63
- data/ext/oj/dump_object.c +70 -199
- data/ext/oj/dump_strict.c +22 -46
- data/ext/oj/encoder.c +1 -1
- data/ext/oj/err.c +2 -13
- data/ext/oj/err.h +9 -12
- data/ext/oj/extconf.rb +14 -5
- data/ext/oj/fast.c +75 -103
- data/ext/oj/intern.c +52 -50
- data/ext/oj/intern.h +4 -8
- data/ext/oj/mem.c +318 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +75 -47
- data/ext/oj/object.c +49 -66
- data/ext/oj/odd.c +89 -67
- data/ext/oj/odd.h +15 -15
- data/ext/oj/oj.c +140 -99
- data/ext/oj/oj.h +80 -51
- data/ext/oj/parse.c +162 -184
- data/ext/oj/parse.h +7 -10
- data/ext/oj/parser.c +89 -34
- data/ext/oj/parser.h +18 -7
- data/ext/oj/rails.c +82 -146
- data/ext/oj/rails.h +1 -1
- data/ext/oj/reader.c +11 -12
- data/ext/oj/reader.h +4 -2
- data/ext/oj/resolve.c +3 -4
- data/ext/oj/rxclass.c +6 -5
- data/ext/oj/rxclass.h +1 -1
- data/ext/oj/saj.c +20 -31
- data/ext/oj/saj2.c +329 -93
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/scp.c +3 -14
- data/ext/oj/sparse.c +26 -70
- data/ext/oj/stream_writer.c +12 -22
- data/ext/oj/strict.c +20 -52
- data/ext/oj/string_writer.c +21 -21
- data/ext/oj/trace.h +31 -4
- data/ext/oj/usual.c +105 -150
- data/ext/oj/usual.h +68 -0
- data/ext/oj/util.h +1 -1
- data/ext/oj/val_stack.c +1 -1
- data/ext/oj/val_stack.h +8 -7
- data/ext/oj/validate.c +21 -26
- data/ext/oj/wab.c +31 -68
- data/lib/oj/active_support_helper.rb +0 -1
- data/lib/oj/bag.rb +7 -1
- data/lib/oj/easy_hash.rb +4 -5
- data/lib/oj/error.rb +0 -1
- data/lib/oj/json.rb +4 -2
- data/lib/oj/mimic.rb +4 -2
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/state.rb +9 -6
- data/lib/oj/version.rb +1 -2
- data/lib/oj.rb +2 -0
- data/pages/Compatibility.md +1 -1
- data/pages/InstallOptions.md +20 -0
- data/pages/Options.md +10 -0
- data/test/_test_active.rb +8 -9
- data/test/_test_active_mimic.rb +7 -8
- data/test/_test_mimic_rails.rb +17 -20
- data/test/activerecord/result_test.rb +5 -6
- data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
- data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
- data/test/{activesupport5 → activesupport7}/encoding_test.rb +20 -34
- data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
- data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
- data/test/files.rb +15 -15
- data/test/foo.rb +9 -71
- data/test/helper.rb +11 -8
- data/test/isolated/shared.rb +3 -2
- data/test/json_gem/json_addition_test.rb +2 -2
- data/test/json_gem/json_common_interface_test.rb +4 -4
- data/test/json_gem/json_encoding_test.rb +0 -0
- data/test/json_gem/json_ext_parser_test.rb +1 -0
- data/test/json_gem/json_fixtures_test.rb +3 -2
- data/test/json_gem/json_generator_test.rb +48 -36
- data/test/json_gem/json_generic_object_test.rb +11 -11
- data/test/json_gem/json_parser_test.rb +54 -47
- data/test/json_gem/json_string_matching_test.rb +9 -9
- data/test/json_gem/test_helper.rb +7 -3
- data/test/mem.rb +13 -12
- data/test/perf.rb +21 -26
- data/test/perf_compat.rb +31 -33
- data/test/perf_dump.rb +50 -0
- data/test/perf_fast.rb +80 -82
- data/test/perf_file.rb +27 -29
- data/test/perf_object.rb +65 -69
- data/test/perf_once.rb +12 -11
- data/test/perf_parser.rb +42 -48
- data/test/perf_saj.rb +46 -54
- data/test/perf_scp.rb +57 -69
- data/test/perf_simple.rb +41 -39
- data/test/perf_strict.rb +68 -70
- data/test/perf_wab.rb +67 -69
- data/test/prec.rb +3 -3
- data/test/sample/change.rb +0 -1
- data/test/sample/dir.rb +0 -1
- data/test/sample/doc.rb +0 -1
- data/test/sample/file.rb +0 -1
- data/test/sample/group.rb +0 -1
- data/test/sample/hasprops.rb +0 -1
- data/test/sample/layer.rb +0 -1
- data/test/sample/rect.rb +0 -1
- data/test/sample/shape.rb +0 -1
- data/test/sample/text.rb +0 -1
- data/test/sample.rb +16 -16
- data/test/sample_json.rb +8 -8
- data/test/test_compat.rb +76 -42
- data/test/test_custom.rb +72 -51
- data/test/test_debian.rb +7 -10
- data/test/test_fast.rb +86 -90
- data/test/test_file.rb +41 -30
- data/test/test_gc.rb +16 -5
- data/test/test_generate.rb +5 -5
- data/test/test_hash.rb +4 -4
- data/test/test_integer_range.rb +9 -9
- data/test/test_null.rb +20 -20
- data/test/test_object.rb +85 -96
- data/test/test_parser.rb +6 -22
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +115 -23
- data/test/test_parser_usual.rb +6 -6
- data/test/test_rails.rb +2 -2
- data/test/test_saj.rb +10 -8
- data/test/test_scp.rb +37 -39
- data/test/test_strict.rb +30 -32
- data/test/test_various.rb +147 -99
- data/test/test_wab.rb +48 -44
- data/test/test_writer.rb +47 -47
- data/test/tests.rb +13 -4
- data/test/tests_mimic.rb +12 -3
- data/test/tests_mimic_addition.rb +12 -3
- metadata +33 -144
- data/test/activesupport4/decoding_test.rb +0 -108
- data/test/activesupport4/encoding_test.rb +0 -531
- data/test/activesupport4/test_helper.rb +0 -41
- data/test/activesupport5/test_helper.rb +0 -72
- data/test/bar.rb +0 -16
- data/test/baz.rb +0 -16
- data/test/bug.rb +0 -16
- data/test/zoo.rb +0 -13
data/ext/oj/debug.c
CHANGED
@@ -30,9 +30,7 @@ static void add_int(struct _ojParser *p) {
|
|
30
30
|
switch (p->stack[p->depth]) {
|
31
31
|
case TOP_FUN: printf("*** add_int %lld at top\n", (long long)p->num.fixnum); break;
|
32
32
|
case ARRAY_FUN: printf("*** add_int %lld to array\n", (long long)p->num.fixnum); break;
|
33
|
-
case OBJECT_FUN:
|
34
|
-
printf("*** add_int %lld with '%s'\n", (long long)p->num.fixnum, buf_str(&p->key));
|
35
|
-
break;
|
33
|
+
case OBJECT_FUN: printf("*** add_int %lld with '%s'\n", (long long)p->num.fixnum, buf_str(&p->key)); break;
|
36
34
|
}
|
37
35
|
}
|
38
36
|
|
@@ -48,9 +46,7 @@ static void add_big(struct _ojParser *p) {
|
|
48
46
|
switch (p->stack[p->depth]) {
|
49
47
|
case TOP_FUN: printf("*** add_big %s at top\n", buf_str(&p->buf)); break;
|
50
48
|
case ARRAY_FUN: printf("*** add_big %s to array\n", buf_str(&p->buf)); break;
|
51
|
-
case OBJECT_FUN:
|
52
|
-
printf("*** add_big %s with '%s'\n", buf_str(&p->buf), buf_str(&p->key));
|
53
|
-
break;
|
49
|
+
case OBJECT_FUN: printf("*** add_big %s with '%s'\n", buf_str(&p->buf), buf_str(&p->key)); break;
|
54
50
|
}
|
55
51
|
}
|
56
52
|
|
@@ -58,9 +54,7 @@ static void add_str(struct _ojParser *p) {
|
|
58
54
|
switch (p->stack[p->depth]) {
|
59
55
|
case TOP_FUN: printf("*** add_str '%s' at top\n", buf_str(&p->buf)); break;
|
60
56
|
case ARRAY_FUN: printf("*** add_str '%s' to array\n", buf_str(&p->buf)); break;
|
61
|
-
case OBJECT_FUN:
|
62
|
-
printf("*** add_str '%s' with '%s'\n", buf_str(&p->buf), buf_str(&p->key));
|
63
|
-
break;
|
57
|
+
case OBJECT_FUN: printf("*** add_str '%s' with '%s'\n", buf_str(&p->buf), buf_str(&p->key)); break;
|
64
58
|
}
|
65
59
|
}
|
66
60
|
|
data/ext/oj/dump.c
CHANGED
@@ -15,6 +15,7 @@
|
|
15
15
|
#endif
|
16
16
|
|
17
17
|
#include "cache8.h"
|
18
|
+
#include "mem.h"
|
18
19
|
#include "odd.h"
|
19
20
|
#include "oj.h"
|
20
21
|
#include "trace.h"
|
@@ -32,6 +33,7 @@ static const char nan_val[] = NAN_VAL;
|
|
32
33
|
typedef unsigned long ulong;
|
33
34
|
|
34
35
|
static size_t hibit_friendly_size(const uint8_t *str, size_t len);
|
36
|
+
static size_t slash_friendly_size(const uint8_t *str, size_t len);
|
35
37
|
static size_t xss_friendly_size(const uint8_t *str, size_t len);
|
36
38
|
static size_t ascii_friendly_size(const uint8_t *str, size_t len);
|
37
39
|
|
@@ -59,6 +61,17 @@ static char hibit_friendly_chars[256] = "\
|
|
59
61
|
11111111111111111111111111111111\
|
60
62
|
11111111111111111111111111111111";
|
61
63
|
|
64
|
+
// JSON standard but escape forward slashes `/`
|
65
|
+
static char slash_friendly_chars[256] = "\
|
66
|
+
66666666222622666666666666666666\
|
67
|
+
11211111111111121111111111111111\
|
68
|
+
11111111111111111111111111112111\
|
69
|
+
11111111111111111111111111111111\
|
70
|
+
11111111111111111111111111111111\
|
71
|
+
11111111111111111111111111111111\
|
72
|
+
11111111111111111111111111111111\
|
73
|
+
11111111111111111111111111111111";
|
74
|
+
|
62
75
|
// High bit set characters are always encoded as unicode. Worse case is 3
|
63
76
|
// bytes per character in the output. That makes this conservative.
|
64
77
|
static char ascii_friendly_chars[256] = "\
|
@@ -143,6 +156,10 @@ inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
|
|
143
156
|
return calculate_string_size(str, len, hibit_friendly_chars);
|
144
157
|
}
|
145
158
|
|
159
|
+
inline static size_t slash_friendly_size(const uint8_t *str, size_t len) {
|
160
|
+
return calculate_string_size(str, len, slash_friendly_chars);
|
161
|
+
}
|
162
|
+
|
146
163
|
inline static size_t ascii_friendly_size(const uint8_t *str, size_t len) {
|
147
164
|
return calculate_string_size(str, len, ascii_friendly_chars);
|
148
165
|
}
|
@@ -234,7 +251,7 @@ inline static void dump_hex(uint8_t c, Out out) {
|
|
234
251
|
static void raise_invalid_unicode(const char *str, int len, int pos) {
|
235
252
|
char c;
|
236
253
|
char code[32];
|
237
|
-
char
|
254
|
+
char *cp = code;
|
238
255
|
int i;
|
239
256
|
uint8_t d;
|
240
257
|
|
@@ -289,16 +306,14 @@ static const char *dump_unicode(const char *str, const char *end, Out out, const
|
|
289
306
|
uint32_t c1;
|
290
307
|
|
291
308
|
code -= 0x00010000;
|
292
|
-
c1
|
293
|
-
code
|
294
|
-
|
295
|
-
*out->cur++ = 'u';
|
309
|
+
c1 = ((code >> 10) & 0x000003FF) + 0x0000D800;
|
310
|
+
code = (code & 0x000003FF) + 0x0000DC00;
|
311
|
+
APPEND_CHARS(out->cur, "\\u", 2);
|
296
312
|
for (i = 3; 0 <= i; i--) {
|
297
313
|
*out->cur++ = hex_chars[(uint8_t)(c1 >> (i * 4)) & 0x0F];
|
298
314
|
}
|
299
315
|
}
|
300
|
-
|
301
|
-
*out->cur++ = 'u';
|
316
|
+
APPEND_CHARS(out->cur, "\\u", 2);
|
302
317
|
for (i = 3; 0 <= i; i--) {
|
303
318
|
*out->cur++ = hex_chars[(uint8_t)(code >> (i * 4)) & 0x0F];
|
304
319
|
}
|
@@ -347,9 +362,7 @@ long oj_check_circular(VALUE obj, Out out) {
|
|
347
362
|
} else {
|
348
363
|
if (ObjectMode == out->opts->mode) {
|
349
364
|
assure_size(out, 18);
|
350
|
-
|
351
|
-
*out->cur++ = '^';
|
352
|
-
*out->cur++ = 'r';
|
365
|
+
APPEND_CHARS(out->cur, "\"^r", 3);
|
353
366
|
dump_ulong(id, out);
|
354
367
|
*out->cur++ = '"';
|
355
368
|
}
|
@@ -361,15 +374,14 @@ long oj_check_circular(VALUE obj, Out out) {
|
|
361
374
|
|
362
375
|
void oj_dump_time(VALUE obj, Out out, int withZone) {
|
363
376
|
char buf[64];
|
364
|
-
char
|
377
|
+
char *b = buf + sizeof(buf) - 1;
|
365
378
|
long size;
|
366
|
-
char
|
379
|
+
char *dot;
|
367
380
|
int neg = 0;
|
368
381
|
long one = 1000000000;
|
369
382
|
long long sec;
|
370
383
|
long long nsec;
|
371
384
|
|
372
|
-
#ifdef HAVE_RB_TIME_TIMESPEC
|
373
385
|
// rb_time_timespec as well as rb_time_timeeval have a bug that causes an
|
374
386
|
// exception to be raised if a time is before 1970 on 32 bit systems so
|
375
387
|
// check the timespec size and use the ruby calls if a 32 bit system.
|
@@ -379,13 +391,9 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
|
|
379
391
|
sec = (long long)ts.tv_sec;
|
380
392
|
nsec = ts.tv_nsec;
|
381
393
|
} else {
|
382
|
-
sec =
|
383
|
-
nsec =
|
394
|
+
sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
395
|
+
nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
384
396
|
}
|
385
|
-
#else
|
386
|
-
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
387
|
-
nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
388
|
-
#endif
|
389
397
|
|
390
398
|
*b-- = '\0';
|
391
399
|
if (withZone) {
|
@@ -451,13 +459,12 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
|
|
451
459
|
b++;
|
452
460
|
size = sizeof(buf) - (b - buf) - 1;
|
453
461
|
assure_size(out, size);
|
454
|
-
|
455
|
-
out->cur += size;
|
462
|
+
APPEND_CHARS(out->cur, b, size);
|
456
463
|
*out->cur = '\0';
|
457
464
|
}
|
458
465
|
|
459
466
|
void oj_dump_ruby_time(VALUE obj, Out out) {
|
460
|
-
volatile VALUE rstr =
|
467
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
461
468
|
|
462
469
|
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
463
470
|
}
|
@@ -472,20 +479,15 @@ void oj_dump_xml_time(VALUE obj, Out out) {
|
|
472
479
|
int tzhour, tzmin;
|
473
480
|
char tzsign = '+';
|
474
481
|
|
475
|
-
#ifdef HAVE_RB_TIME_TIMESPEC
|
476
482
|
if (16 <= sizeof(struct timespec)) {
|
477
483
|
struct timespec ts = rb_time_timespec(obj);
|
478
484
|
|
479
485
|
sec = ts.tv_sec;
|
480
486
|
nsec = ts.tv_nsec;
|
481
487
|
} else {
|
482
|
-
sec =
|
483
|
-
nsec =
|
488
|
+
sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
489
|
+
nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
484
490
|
}
|
485
|
-
#else
|
486
|
-
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
487
|
-
nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
488
|
-
#endif
|
489
491
|
|
490
492
|
assure_size(out, 36);
|
491
493
|
if (9 > out->opts->sec_prec) {
|
@@ -565,12 +567,8 @@ void oj_dump_obj_to_json(VALUE obj, Options copts, Out out) {
|
|
565
567
|
|
566
568
|
void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VALUE *argv) {
|
567
569
|
if (0 == out->buf) {
|
568
|
-
out
|
569
|
-
// 1 less than end plus extra for possible errors
|
570
|
-
out->end = out->buf + 4095 - BUFFER_EXTRA;
|
571
|
-
out->allocated = true;
|
570
|
+
oj_out_init(out);
|
572
571
|
}
|
573
|
-
out->cur = out->buf;
|
574
572
|
out->circ_cnt = 0;
|
575
573
|
out->opts = copts;
|
576
574
|
out->hash_cnt = 0;
|
@@ -605,36 +603,34 @@ void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int arg
|
|
605
603
|
}
|
606
604
|
|
607
605
|
void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
|
608
|
-
char buf[4096];
|
609
606
|
struct _out out;
|
610
607
|
size_t size;
|
611
|
-
FILE
|
608
|
+
FILE *f;
|
612
609
|
int ok;
|
613
610
|
|
614
|
-
out
|
615
|
-
|
616
|
-
out.
|
617
|
-
out.omit_nil = copts->dump_opts.omit_nil;
|
611
|
+
oj_out_init(&out);
|
612
|
+
|
613
|
+
out.omit_nil = copts->dump_opts.omit_nil;
|
618
614
|
oj_dump_obj_to_json(obj, copts, &out);
|
619
615
|
size = out.cur - out.buf;
|
620
616
|
if (0 == (f = fopen(path, "w"))) {
|
621
|
-
|
622
|
-
xfree(out.buf);
|
623
|
-
}
|
617
|
+
oj_out_free(&out);
|
624
618
|
rb_raise(rb_eIOError, "%s", strerror(errno));
|
625
619
|
}
|
626
620
|
ok = (size == fwrite(out.buf, 1, size, f));
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
fclose(f);
|
621
|
+
|
622
|
+
oj_out_free(&out);
|
623
|
+
|
631
624
|
if (!ok) {
|
632
625
|
int err = ferror(f);
|
626
|
+
fclose(f);
|
633
627
|
|
634
628
|
rb_raise(rb_eIOError, "Write failed. [%d:%s]", err, strerror(err));
|
635
629
|
}
|
630
|
+
fclose(f);
|
636
631
|
}
|
637
632
|
|
633
|
+
#if !IS_WINDOWS
|
638
634
|
static void write_ready(int fd) {
|
639
635
|
struct pollfd pp;
|
640
636
|
int i;
|
@@ -649,9 +645,9 @@ static void write_ready(int fd) {
|
|
649
645
|
rb_raise(rb_eIOError, "write failed. %d %s.", errno, strerror(errno));
|
650
646
|
}
|
651
647
|
}
|
648
|
+
#endif
|
652
649
|
|
653
650
|
void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
654
|
-
char buf[4096];
|
655
651
|
struct _out out;
|
656
652
|
ssize_t size;
|
657
653
|
VALUE clas = rb_obj_class(stream);
|
@@ -660,10 +656,9 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
|
660
656
|
VALUE s;
|
661
657
|
#endif
|
662
658
|
|
663
|
-
out
|
664
|
-
|
665
|
-
out.
|
666
|
-
out.omit_nil = copts->dump_opts.omit_nil;
|
659
|
+
oj_out_init(&out);
|
660
|
+
|
661
|
+
out.omit_nil = copts->dump_opts.omit_nil;
|
667
662
|
oj_dump_obj_to_json(obj, copts, &out);
|
668
663
|
size = out.cur - out.buf;
|
669
664
|
if (oj_stringio_class == clas) {
|
@@ -692,21 +687,18 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
|
692
687
|
} else if (rb_respond_to(stream, oj_write_id)) {
|
693
688
|
rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
|
694
689
|
} else {
|
695
|
-
|
696
|
-
xfree(out.buf);
|
697
|
-
}
|
690
|
+
oj_out_free(&out);
|
698
691
|
rb_raise(rb_eArgError, "to_stream() expected an IO Object.");
|
699
692
|
}
|
700
|
-
|
701
|
-
xfree(out.buf);
|
702
|
-
}
|
693
|
+
oj_out_free(&out);
|
703
694
|
}
|
704
695
|
|
705
696
|
void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
|
706
|
-
|
697
|
+
int idx = RB_ENCODING_GET(obj);
|
707
698
|
|
708
|
-
if (
|
709
|
-
|
699
|
+
if (oj_utf8_encoding_index != idx) {
|
700
|
+
rb_encoding *enc = rb_enc_from_index(idx);
|
701
|
+
obj = rb_str_conv_enc(obj, enc, oj_utf8_encoding);
|
710
702
|
}
|
711
703
|
oj_dump_cstr(RSTRING_PTR(obj), (int)RSTRING_LEN(obj), 0, 0, out);
|
712
704
|
}
|
@@ -719,7 +711,7 @@ void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
|
|
719
711
|
|
720
712
|
static void debug_raise(const char *orig, size_t cnt, int line) {
|
721
713
|
char buf[1024];
|
722
|
-
char
|
714
|
+
char *b = buf;
|
723
715
|
const char *s = orig;
|
724
716
|
const char *s_end = s + cnt;
|
725
717
|
|
@@ -745,20 +737,16 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
|
745
737
|
} else {
|
746
738
|
volatile VALUE jv;
|
747
739
|
|
748
|
-
|
749
|
-
oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
750
|
-
}
|
740
|
+
TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyIn);
|
751
741
|
jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent));
|
752
|
-
|
753
|
-
oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
754
|
-
}
|
742
|
+
TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyOut);
|
755
743
|
oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
|
756
744
|
}
|
757
745
|
}
|
758
746
|
|
759
747
|
void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
|
760
748
|
size_t size;
|
761
|
-
char
|
749
|
+
char *cmap;
|
762
750
|
const char *orig = str;
|
763
751
|
bool has_hi = false;
|
764
752
|
|
@@ -771,6 +759,11 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
771
759
|
cmap = ascii_friendly_chars;
|
772
760
|
size = ascii_friendly_size((uint8_t *)str, cnt);
|
773
761
|
break;
|
762
|
+
case SlashEsc:
|
763
|
+
has_hi = true;
|
764
|
+
cmap = slash_friendly_chars;
|
765
|
+
size = slash_friendly_size((uint8_t *)str, cnt);
|
766
|
+
break;
|
774
767
|
case XSSEsc:
|
775
768
|
cmap = xss_friendly_chars;
|
776
769
|
size = xss_friendly_size((uint8_t *)str, cnt);
|
@@ -803,10 +796,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
803
796
|
*out->cur++ = '"';
|
804
797
|
|
805
798
|
if (escape1) {
|
806
|
-
|
807
|
-
*out->cur++ = 'u';
|
808
|
-
*out->cur++ = '0';
|
809
|
-
*out->cur++ = '0';
|
799
|
+
APPEND_CHARS(out->cur, "\\u00", 4);
|
810
800
|
dump_hex((uint8_t)*str, out);
|
811
801
|
cnt--;
|
812
802
|
size--;
|
@@ -817,8 +807,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
817
807
|
if (is_sym) {
|
818
808
|
*out->cur++ = ':';
|
819
809
|
}
|
820
|
-
|
821
|
-
out->cur += cnt;
|
810
|
+
APPEND_CHARS(out->cur, str, cnt);
|
822
811
|
*out->cur++ = '"';
|
823
812
|
} else {
|
824
813
|
const char *end = str + cnt;
|
@@ -868,10 +857,10 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
868
857
|
break;
|
869
858
|
case '6': // control characters
|
870
859
|
if (*(uint8_t *)str < 0x80) {
|
871
|
-
*out->
|
872
|
-
|
873
|
-
|
874
|
-
|
860
|
+
if (0 == (uint8_t)*str && out->opts->dump_opts.omit_null_byte) {
|
861
|
+
break;
|
862
|
+
}
|
863
|
+
APPEND_CHARS(out->cur, "\\u00", 4);
|
875
864
|
dump_hex((uint8_t)*str, out);
|
876
865
|
} else {
|
877
866
|
if (0xe2 == (uint8_t)*str &&
|
@@ -943,31 +932,43 @@ void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) {
|
|
943
932
|
}
|
944
933
|
|
945
934
|
void oj_dump_obj_to_s(VALUE obj, Out out) {
|
946
|
-
volatile VALUE rstr =
|
935
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
947
936
|
|
948
937
|
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
949
938
|
}
|
950
939
|
|
951
940
|
void oj_dump_raw(const char *str, size_t cnt, Out out) {
|
952
941
|
assure_size(out, cnt + 10);
|
953
|
-
|
954
|
-
out->cur += cnt;
|
942
|
+
APPEND_CHARS(out->cur, str, cnt);
|
955
943
|
*out->cur = '\0';
|
956
944
|
}
|
957
945
|
|
946
|
+
void oj_out_init(Out out) {
|
947
|
+
out->buf = out->stack_buffer;
|
948
|
+
out->cur = out->buf;
|
949
|
+
out->end = out->buf + sizeof(out->stack_buffer) - BUFFER_EXTRA;
|
950
|
+
out->allocated = false;
|
951
|
+
}
|
952
|
+
|
953
|
+
void oj_out_free(Out out) {
|
954
|
+
if (out->allocated) {
|
955
|
+
OJ_R_FREE(out->buf); // TBD
|
956
|
+
}
|
957
|
+
}
|
958
|
+
|
958
959
|
void oj_grow_out(Out out, size_t len) {
|
959
960
|
size_t size = out->end - out->buf;
|
960
961
|
long pos = out->cur - out->buf;
|
961
|
-
char
|
962
|
+
char *buf = out->buf;
|
962
963
|
|
963
964
|
size *= 2;
|
964
965
|
if (size <= len * 2 + pos) {
|
965
966
|
size += len;
|
966
967
|
}
|
967
968
|
if (out->allocated) {
|
968
|
-
|
969
|
+
OJ_R_REALLOC_N(buf, char, (size + BUFFER_EXTRA));
|
969
970
|
} else {
|
970
|
-
buf =
|
971
|
+
buf = OJ_R_ALLOC_N(char, (size + BUFFER_EXTRA));
|
971
972
|
out->allocated = true;
|
972
973
|
memcpy(buf, out->buf, out->end - out->buf + BUFFER_EXTRA);
|
973
974
|
}
|
@@ -981,37 +982,40 @@ void oj_grow_out(Out out, size_t len) {
|
|
981
982
|
|
982
983
|
void oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok) {
|
983
984
|
assure_size(out, 4);
|
984
|
-
|
985
|
-
*out->cur
|
986
|
-
*out->cur++ = 'l';
|
987
|
-
*out->cur++ = 'l';
|
988
|
-
*out->cur = '\0';
|
985
|
+
APPEND_CHARS(out->cur, "null", 4);
|
986
|
+
*out->cur = '\0';
|
989
987
|
}
|
990
988
|
|
991
989
|
void oj_dump_true(VALUE obj, int depth, Out out, bool as_ok) {
|
992
990
|
assure_size(out, 4);
|
993
|
-
|
994
|
-
*out->cur
|
995
|
-
*out->cur++ = 'u';
|
996
|
-
*out->cur++ = 'e';
|
997
|
-
*out->cur = '\0';
|
991
|
+
APPEND_CHARS(out->cur, "true", 4);
|
992
|
+
*out->cur = '\0';
|
998
993
|
}
|
999
994
|
|
1000
995
|
void oj_dump_false(VALUE obj, int depth, Out out, bool as_ok) {
|
1001
996
|
assure_size(out, 5);
|
1002
|
-
|
1003
|
-
*out->cur
|
1004
|
-
*out->cur++ = 'l';
|
1005
|
-
*out->cur++ = 's';
|
1006
|
-
*out->cur++ = 'e';
|
1007
|
-
*out->cur = '\0';
|
997
|
+
APPEND_CHARS(out->cur, "false", 5);
|
998
|
+
*out->cur = '\0';
|
1008
999
|
}
|
1009
1000
|
|
1001
|
+
static const char digits_table[] = "\
|
1002
|
+
00010203040506070809\
|
1003
|
+
10111213141516171819\
|
1004
|
+
20212223242526272829\
|
1005
|
+
30313233343536373839\
|
1006
|
+
40414243444546474849\
|
1007
|
+
50515253545556575859\
|
1008
|
+
60616263646566676869\
|
1009
|
+
70717273747576777879\
|
1010
|
+
80818283848586878889\
|
1011
|
+
90919293949596979899";
|
1012
|
+
|
1010
1013
|
void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
|
1011
1014
|
char buf[32];
|
1012
|
-
char
|
1013
|
-
long long num =
|
1015
|
+
char *b = buf + sizeof(buf) - 1;
|
1016
|
+
long long num = NUM2LL(obj);
|
1014
1017
|
int neg = 0;
|
1018
|
+
size_t cnt = 0;
|
1015
1019
|
bool dump_as_string = false;
|
1016
1020
|
|
1017
1021
|
if (out->opts->int_range_max != 0 && out->opts->int_range_min != 0 &&
|
@@ -1028,9 +1032,19 @@ void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1028
1032
|
*b-- = '"';
|
1029
1033
|
}
|
1030
1034
|
if (0 < num) {
|
1031
|
-
|
1032
|
-
|
1035
|
+
while (100 <= num) {
|
1036
|
+
unsigned idx = num % 100 * 2;
|
1037
|
+
*b-- = digits_table[idx + 1];
|
1038
|
+
*b-- = digits_table[idx];
|
1039
|
+
num /= 100;
|
1040
|
+
}
|
1041
|
+
if (num < 10) {
|
1042
|
+
*b-- = num + '0';
|
1043
|
+
} else {
|
1044
|
+
*b-- = digits_table[num * 2 + 1];
|
1045
|
+
*b-- = digits_table[num * 2];
|
1033
1046
|
}
|
1047
|
+
|
1034
1048
|
if (neg) {
|
1035
1049
|
*b = '-';
|
1036
1050
|
} else {
|
@@ -1042,10 +1056,9 @@ void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1042
1056
|
if (dump_as_string) {
|
1043
1057
|
*--b = '"';
|
1044
1058
|
}
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
}
|
1059
|
+
cnt = sizeof(buf) - (b - buf) - 1;
|
1060
|
+
assure_size(out, cnt);
|
1061
|
+
APPEND_CHARS(out->cur, b, cnt);
|
1049
1062
|
*out->cur = '\0';
|
1050
1063
|
}
|
1051
1064
|
|
@@ -1061,8 +1074,7 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1061
1074
|
} else {
|
1062
1075
|
assure_size(out, cnt);
|
1063
1076
|
}
|
1064
|
-
|
1065
|
-
out->cur += cnt;
|
1077
|
+
APPEND_CHARS(out->cur, RSTRING_PTR(rs), cnt);
|
1066
1078
|
if (dump_as_string) {
|
1067
1079
|
*out->cur++ = '"';
|
1068
1080
|
}
|
@@ -1072,7 +1084,7 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1072
1084
|
// Removed dependencies on math due to problems with CentOS 5.4.
|
1073
1085
|
void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
1074
1086
|
char buf[64];
|
1075
|
-
char
|
1087
|
+
char *b;
|
1076
1088
|
double d = rb_num2dbl(obj);
|
1077
1089
|
int cnt = 0;
|
1078
1090
|
|
@@ -1151,7 +1163,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1151
1163
|
} else if (isnan(d)) {
|
1152
1164
|
if (ObjectMode == out->opts->mode) {
|
1153
1165
|
strcpy(buf, nan_val);
|
1154
|
-
cnt = sizeof(
|
1166
|
+
cnt = sizeof(nan_val) - 1;
|
1155
1167
|
} else {
|
1156
1168
|
NanDump nd = out->opts->dump_opts.nan_dump;
|
1157
1169
|
|
@@ -1183,7 +1195,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1183
1195
|
} else if (d == (double)(long long int)d) {
|
1184
1196
|
cnt = snprintf(buf, sizeof(buf), "%.1f", d);
|
1185
1197
|
} else if (0 == out->opts->float_prec) {
|
1186
|
-
volatile VALUE rstr =
|
1198
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
1187
1199
|
|
1188
1200
|
cnt = (int)RSTRING_LEN(rstr);
|
1189
1201
|
if ((int)sizeof(buf) <= cnt) {
|
@@ -1195,9 +1207,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1195
1207
|
cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt);
|
1196
1208
|
}
|
1197
1209
|
assure_size(out, cnt);
|
1198
|
-
|
1199
|
-
*out->cur++ = *b;
|
1200
|
-
}
|
1210
|
+
APPEND_CHARS(out->cur, buf, cnt);
|
1201
1211
|
*out->cur = '\0';
|
1202
1212
|
}
|
1203
1213
|
|
@@ -1207,7 +1217,7 @@ int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char
|
|
1207
1217
|
// Round off issues at 16 significant digits so check for obvious ones of
|
1208
1218
|
// 0001 and 9999.
|
1209
1219
|
if (17 <= cnt && (0 == strcmp("0001", buf + cnt - 4) || 0 == strcmp("9999", buf + cnt - 4))) {
|
1210
|
-
volatile VALUE rstr =
|
1220
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
1211
1221
|
|
1212
1222
|
strcpy(buf, RSTRING_PTR(rstr));
|
1213
1223
|
cnt = (int)RSTRING_LEN(rstr);
|
data/ext/oj/dump.h
CHANGED
@@ -32,6 +32,11 @@ extern void oj_dump_obj_to_s(VALUE obj, Out out);
|
|
32
32
|
|
33
33
|
extern const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp);
|
34
34
|
|
35
|
+
// initialize an out buffer with the provided stack allocated memory
|
36
|
+
extern void oj_out_init(Out out);
|
37
|
+
// clean up the out buffer if it uses heap allocated memory
|
38
|
+
extern void oj_out_free(Out out);
|
39
|
+
|
35
40
|
extern void oj_grow_out(Out out, size_t len);
|
36
41
|
extern long oj_check_circular(VALUE obj, Out out);
|
37
42
|
|
@@ -62,9 +67,8 @@ inline static void fill_indent(Out out, int cnt) {
|
|
62
67
|
if (0 < out->indent) {
|
63
68
|
cnt *= out->indent;
|
64
69
|
*out->cur++ = '\n';
|
65
|
-
|
66
|
-
|
67
|
-
}
|
70
|
+
memset(out->cur, ' ', cnt);
|
71
|
+
out->cur += cnt;
|
68
72
|
}
|
69
73
|
}
|
70
74
|
|
@@ -83,8 +87,9 @@ inline static bool dump_ignore(Options opts, VALUE obj) {
|
|
83
87
|
}
|
84
88
|
|
85
89
|
inline static void dump_ulong(unsigned long num, Out out) {
|
86
|
-
char
|
87
|
-
char
|
90
|
+
char buf[32];
|
91
|
+
char *b = buf + sizeof(buf) - 1;
|
92
|
+
size_t cnt = 0;
|
88
93
|
|
89
94
|
*b-- = '\0';
|
90
95
|
if (0 < num) {
|
@@ -95,9 +100,8 @@ inline static void dump_ulong(unsigned long num, Out out) {
|
|
95
100
|
} else {
|
96
101
|
*b = '0';
|
97
102
|
}
|
98
|
-
|
99
|
-
|
100
|
-
}
|
103
|
+
cnt = sizeof(buf) - (b - buf) - 1;
|
104
|
+
APPEND_CHARS(out->cur, b, cnt);
|
101
105
|
*out->cur = '\0';
|
102
106
|
}
|
103
107
|
|