oj 3.13.7 → 3.13.23
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 +75 -0
- data/README.md +11 -0
- data/ext/oj/buf.h +4 -0
- data/ext/oj/circarray.c +1 -1
- data/ext/oj/code.c +15 -22
- data/ext/oj/compat.c +10 -10
- data/ext/oj/custom.c +66 -112
- data/ext/oj/dump.c +147 -184
- data/ext/oj/dump.h +25 -8
- data/ext/oj/dump_compat.c +47 -89
- data/ext/oj/dump_leaf.c +14 -58
- data/ext/oj/dump_object.c +72 -188
- data/ext/oj/dump_strict.c +19 -31
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/extconf.rb +5 -4
- data/ext/oj/fast.c +36 -24
- data/ext/oj/intern.c +22 -12
- data/ext/oj/intern.h +1 -1
- data/ext/oj/mimic_json.c +74 -73
- data/ext/oj/object.c +54 -72
- data/ext/oj/odd.c +83 -63
- data/ext/oj/odd.h +13 -13
- data/ext/oj/oj.c +166 -175
- data/ext/oj/oj.h +25 -3
- data/ext/oj/parse.c +123 -79
- data/ext/oj/parse.h +2 -0
- data/ext/oj/parser.c +77 -21
- data/ext/oj/parser.h +12 -0
- data/ext/oj/rails.c +46 -70
- data/ext/oj/rails.h +1 -1
- data/ext/oj/reader.c +2 -0
- data/ext/oj/saj.c +11 -23
- data/ext/oj/saj2.c +333 -85
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/sparse.c +4 -0
- data/ext/oj/stream_writer.c +3 -1
- data/ext/oj/strict.c +13 -13
- data/ext/oj/string_writer.c +12 -5
- data/ext/oj/usual.c +86 -131
- data/ext/oj/usual.h +68 -0
- data/ext/oj/val_stack.c +1 -1
- data/ext/oj/validate.c +21 -26
- data/ext/oj/wab.c +22 -27
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/state.rb +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +6 -3
- data/pages/Options.md +6 -0
- data/pages/Rails.md +12 -0
- data/test/activesupport7/abstract_unit.rb +49 -0
- data/test/activesupport7/decoding_test.rb +125 -0
- data/test/activesupport7/encoding_test.rb +486 -0
- data/test/activesupport7/encoding_test_cases.rb +104 -0
- data/test/activesupport7/time_zone_test_helpers.rb +47 -0
- data/test/bar.rb +3 -8
- data/test/bug.rb +16 -0
- data/test/foo.rb +71 -7
- data/test/helper.rb +8 -2
- data/test/json_gem/json_generator_test.rb +5 -4
- data/test/json_gem/json_parser_test.rb +8 -1
- data/test/json_gem/test_helper.rb +7 -3
- data/test/perf_dump.rb +50 -0
- data/test/test_compat.rb +25 -0
- data/test/test_custom.rb +13 -2
- data/test/test_fast.rb +37 -7
- data/test/test_file.rb +23 -7
- data/test/test_gc.rb +11 -0
- data/test/test_object.rb +8 -10
- data/test/test_parser.rb +3 -19
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +92 -2
- data/test/test_saj.rb +1 -1
- data/test/test_scp.rb +2 -4
- data/test/test_strict.rb +2 -0
- data/test/test_various.rb +32 -2
- data/test/test_wab.rb +2 -0
- data/test/tests.rb +9 -1
- data/test/tests_mimic.rb +9 -0
- data/test/tests_mimic_addition.rb +9 -0
- metadata +15 -115
data/ext/oj/dump.c
CHANGED
@@ -10,6 +10,9 @@
|
|
10
10
|
#include <stdlib.h>
|
11
11
|
#include <string.h>
|
12
12
|
#include <unistd.h>
|
13
|
+
#if !IS_WINDOWS
|
14
|
+
#include <poll.h>
|
15
|
+
#endif
|
13
16
|
|
14
17
|
#include "cache8.h"
|
15
18
|
#include "odd.h"
|
@@ -29,6 +32,7 @@ static const char nan_val[] = NAN_VAL;
|
|
29
32
|
typedef unsigned long ulong;
|
30
33
|
|
31
34
|
static size_t hibit_friendly_size(const uint8_t *str, size_t len);
|
35
|
+
static size_t slash_friendly_size(const uint8_t *str, size_t len);
|
32
36
|
static size_t xss_friendly_size(const uint8_t *str, size_t len);
|
33
37
|
static size_t ascii_friendly_size(const uint8_t *str, size_t len);
|
34
38
|
|
@@ -56,6 +60,17 @@ static char hibit_friendly_chars[256] = "\
|
|
56
60
|
11111111111111111111111111111111\
|
57
61
|
11111111111111111111111111111111";
|
58
62
|
|
63
|
+
// JSON standard but escape forward slashes `/`
|
64
|
+
static char slash_friendly_chars[256] = "\
|
65
|
+
66666666222622666666666666666666\
|
66
|
+
11211111111111121111111111111111\
|
67
|
+
11111111111111111111111111112111\
|
68
|
+
11111111111111111111111111111111\
|
69
|
+
11111111111111111111111111111111\
|
70
|
+
11111111111111111111111111111111\
|
71
|
+
11111111111111111111111111111111\
|
72
|
+
11111111111111111111111111111111";
|
73
|
+
|
59
74
|
// High bit set characters are always encoded as unicode. Worse case is 3
|
60
75
|
// bytes per character in the output. That makes this conservative.
|
61
76
|
static char ascii_friendly_chars[256] = "\
|
@@ -113,49 +128,43 @@ static char rails_friendly_chars[256] = "\
|
|
113
128
|
11111111111111111111111111111111";
|
114
129
|
|
115
130
|
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)));
|
131
|
+
rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in strict mode.", rb_class2name(rb_obj_class(obj)));
|
119
132
|
}
|
120
133
|
|
121
|
-
inline static size_t
|
134
|
+
inline static size_t calculate_string_size(const uint8_t *str, size_t len, const char *table) {
|
122
135
|
size_t size = 0;
|
123
136
|
size_t i = len;
|
124
137
|
|
125
|
-
for (;
|
126
|
-
size +=
|
138
|
+
for (; 3 < i; i -= 4) {
|
139
|
+
size += table[*str++];
|
140
|
+
size += table[*str++];
|
141
|
+
size += table[*str++];
|
142
|
+
size += table[*str++];
|
143
|
+
}
|
144
|
+
for (; 0 < i; i--) {
|
145
|
+
size += table[*str++];
|
127
146
|
}
|
128
147
|
return size - len * (size_t)'0';
|
129
148
|
}
|
130
149
|
|
150
|
+
inline static size_t newline_friendly_size(const uint8_t *str, size_t len) {
|
151
|
+
return calculate_string_size(str, len, newline_friendly_chars);
|
152
|
+
}
|
153
|
+
|
131
154
|
inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
|
132
|
-
|
133
|
-
|
155
|
+
return calculate_string_size(str, len, hibit_friendly_chars);
|
156
|
+
}
|
134
157
|
|
135
|
-
|
136
|
-
|
137
|
-
}
|
138
|
-
return size - len * (size_t)'0';
|
158
|
+
inline static size_t slash_friendly_size(const uint8_t *str, size_t len) {
|
159
|
+
return calculate_string_size(str, len, slash_friendly_chars);
|
139
160
|
}
|
140
161
|
|
141
162
|
inline static size_t ascii_friendly_size(const uint8_t *str, size_t len) {
|
142
|
-
|
143
|
-
size_t i = len;
|
144
|
-
|
145
|
-
for (; 0 < i; str++, i--) {
|
146
|
-
size += ascii_friendly_chars[*str];
|
147
|
-
}
|
148
|
-
return size - len * (size_t)'0';
|
163
|
+
return calculate_string_size(str, len, ascii_friendly_chars);
|
149
164
|
}
|
150
165
|
|
151
166
|
inline static size_t xss_friendly_size(const uint8_t *str, size_t len) {
|
152
|
-
|
153
|
-
size_t i = len;
|
154
|
-
|
155
|
-
for (; 0 < i; str++, i--) {
|
156
|
-
size += xss_friendly_chars[*str];
|
157
|
-
}
|
158
|
-
return size - len * (size_t)'0';
|
167
|
+
return calculate_string_size(str, len, xss_friendly_chars);
|
159
168
|
}
|
160
169
|
|
161
170
|
inline static size_t hixss_friendly_size(const uint8_t *str, size_t len) {
|
@@ -188,13 +197,7 @@ inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) {
|
|
188
197
|
}
|
189
198
|
|
190
199
|
inline static size_t rails_friendly_size(const uint8_t *str, size_t len) {
|
191
|
-
|
192
|
-
size_t i = len;
|
193
|
-
|
194
|
-
for (; 0 < i; str++, i--) {
|
195
|
-
size += rails_friendly_chars[*str];
|
196
|
-
}
|
197
|
-
return size - len * (size_t)'0';
|
200
|
+
return calculate_string_size(str, len, rails_friendly_chars);
|
198
201
|
}
|
199
202
|
|
200
203
|
const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp) {
|
@@ -247,7 +250,7 @@ inline static void dump_hex(uint8_t c, Out out) {
|
|
247
250
|
static void raise_invalid_unicode(const char *str, int len, int pos) {
|
248
251
|
char c;
|
249
252
|
char code[32];
|
250
|
-
char
|
253
|
+
char *cp = code;
|
251
254
|
int i;
|
252
255
|
uint8_t d;
|
253
256
|
|
@@ -304,14 +307,12 @@ static const char *dump_unicode(const char *str, const char *end, Out out, const
|
|
304
307
|
code -= 0x00010000;
|
305
308
|
c1 = ((code >> 10) & 0x000003FF) + 0x0000D800;
|
306
309
|
code = (code & 0x000003FF) + 0x0000DC00;
|
307
|
-
|
308
|
-
*out->cur++ = 'u';
|
310
|
+
APPEND_CHARS(out->cur, "\\u", 2);
|
309
311
|
for (i = 3; 0 <= i; i--) {
|
310
312
|
*out->cur++ = hex_chars[(uint8_t)(c1 >> (i * 4)) & 0x0F];
|
311
313
|
}
|
312
314
|
}
|
313
|
-
|
314
|
-
*out->cur++ = 'u';
|
315
|
+
APPEND_CHARS(out->cur, "\\u", 2);
|
315
316
|
for (i = 3; 0 <= i; i--) {
|
316
317
|
*out->cur++ = hex_chars[(uint8_t)(code >> (i * 4)) & 0x0F];
|
317
318
|
}
|
@@ -360,9 +361,7 @@ long oj_check_circular(VALUE obj, Out out) {
|
|
360
361
|
} else {
|
361
362
|
if (ObjectMode == out->opts->mode) {
|
362
363
|
assure_size(out, 18);
|
363
|
-
|
364
|
-
*out->cur++ = '^';
|
365
|
-
*out->cur++ = 'r';
|
364
|
+
APPEND_CHARS(out->cur, "\"^r", 3);
|
366
365
|
dump_ulong(id, out);
|
367
366
|
*out->cur++ = '"';
|
368
367
|
}
|
@@ -374,15 +373,14 @@ long oj_check_circular(VALUE obj, Out out) {
|
|
374
373
|
|
375
374
|
void oj_dump_time(VALUE obj, Out out, int withZone) {
|
376
375
|
char buf[64];
|
377
|
-
char
|
376
|
+
char *b = buf + sizeof(buf) - 1;
|
378
377
|
long size;
|
379
|
-
char
|
378
|
+
char *dot;
|
380
379
|
int neg = 0;
|
381
380
|
long one = 1000000000;
|
382
381
|
long long sec;
|
383
382
|
long long nsec;
|
384
383
|
|
385
|
-
#ifdef HAVE_RB_TIME_TIMESPEC
|
386
384
|
// rb_time_timespec as well as rb_time_timeeval have a bug that causes an
|
387
385
|
// exception to be raised if a time is before 1970 on 32 bit systems so
|
388
386
|
// check the timespec size and use the ruby calls if a 32 bit system.
|
@@ -392,13 +390,9 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
|
|
392
390
|
sec = (long long)ts.tv_sec;
|
393
391
|
nsec = ts.tv_nsec;
|
394
392
|
} else {
|
395
|
-
sec =
|
396
|
-
nsec =
|
393
|
+
sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
394
|
+
nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
397
395
|
}
|
398
|
-
#else
|
399
|
-
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
400
|
-
nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
401
|
-
#endif
|
402
396
|
|
403
397
|
*b-- = '\0';
|
404
398
|
if (withZone) {
|
@@ -464,8 +458,7 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
|
|
464
458
|
b++;
|
465
459
|
size = sizeof(buf) - (b - buf) - 1;
|
466
460
|
assure_size(out, size);
|
467
|
-
|
468
|
-
out->cur += size;
|
461
|
+
APPEND_CHARS(out->cur, b, size);
|
469
462
|
*out->cur = '\0';
|
470
463
|
}
|
471
464
|
|
@@ -485,20 +478,15 @@ void oj_dump_xml_time(VALUE obj, Out out) {
|
|
485
478
|
int tzhour, tzmin;
|
486
479
|
char tzsign = '+';
|
487
480
|
|
488
|
-
#ifdef HAVE_RB_TIME_TIMESPEC
|
489
481
|
if (16 <= sizeof(struct timespec)) {
|
490
482
|
struct timespec ts = rb_time_timespec(obj);
|
491
483
|
|
492
484
|
sec = ts.tv_sec;
|
493
485
|
nsec = ts.tv_nsec;
|
494
486
|
} else {
|
495
|
-
sec =
|
496
|
-
nsec =
|
487
|
+
sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
488
|
+
nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
497
489
|
}
|
498
|
-
#else
|
499
|
-
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
500
|
-
nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
501
|
-
#endif
|
502
490
|
|
503
491
|
assure_size(out, 36);
|
504
492
|
if (9 > out->opts->sec_prec) {
|
@@ -535,14 +523,7 @@ void oj_dump_xml_time(VALUE obj, Out out) {
|
|
535
523
|
}
|
536
524
|
if ((0 == nsec && !out->opts->sec_prec_set) || 0 == out->opts->sec_prec) {
|
537
525
|
if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
538
|
-
int len = 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);
|
526
|
+
int len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec);
|
546
527
|
oj_dump_cstr(buf, len, 0, 0, out);
|
547
528
|
} else {
|
548
529
|
int len = sprintf(buf,
|
@@ -574,18 +555,7 @@ void oj_dump_xml_time(VALUE obj, Out out) {
|
|
574
555
|
if (9 > out->opts->sec_prec) {
|
575
556
|
format[32] = '0' + out->opts->sec_prec;
|
576
557
|
}
|
577
|
-
len = sprintf(buf,
|
578
|
-
format,
|
579
|
-
ti.year,
|
580
|
-
ti.mon,
|
581
|
-
ti.day,
|
582
|
-
ti.hour,
|
583
|
-
ti.min,
|
584
|
-
ti.sec,
|
585
|
-
(long)nsec,
|
586
|
-
tzsign,
|
587
|
-
tzhour,
|
588
|
-
tzmin);
|
558
|
+
len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec, tzsign, tzhour, tzmin);
|
589
559
|
oj_dump_cstr(buf, len, 0, 0, out);
|
590
560
|
}
|
591
561
|
}
|
@@ -596,12 +566,8 @@ void oj_dump_obj_to_json(VALUE obj, Options copts, Out out) {
|
|
596
566
|
|
597
567
|
void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VALUE *argv) {
|
598
568
|
if (0 == out->buf) {
|
599
|
-
out
|
600
|
-
// 1 less than end plus extra for possible errors
|
601
|
-
out->end = out->buf + 4095 - BUFFER_EXTRA;
|
602
|
-
out->allocated = true;
|
569
|
+
oj_out_init(out);
|
603
570
|
}
|
604
|
-
out->cur = out->buf;
|
605
571
|
out->circ_cnt = 0;
|
606
572
|
out->opts = copts;
|
607
573
|
out->hash_cnt = 0;
|
@@ -636,38 +602,51 @@ void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int arg
|
|
636
602
|
}
|
637
603
|
|
638
604
|
void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
|
639
|
-
char buf[4096];
|
640
605
|
struct _out out;
|
641
606
|
size_t size;
|
642
|
-
FILE
|
607
|
+
FILE *f;
|
643
608
|
int ok;
|
644
609
|
|
645
|
-
out
|
646
|
-
|
647
|
-
out.allocated = false;
|
610
|
+
oj_out_init(&out);
|
611
|
+
|
648
612
|
out.omit_nil = copts->dump_opts.omit_nil;
|
649
613
|
oj_dump_obj_to_json(obj, copts, &out);
|
650
614
|
size = out.cur - out.buf;
|
651
615
|
if (0 == (f = fopen(path, "w"))) {
|
652
|
-
|
653
|
-
xfree(out.buf);
|
654
|
-
}
|
616
|
+
oj_out_free(&out);
|
655
617
|
rb_raise(rb_eIOError, "%s", strerror(errno));
|
656
618
|
}
|
657
619
|
ok = (size == fwrite(out.buf, 1, size, f));
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
fclose(f);
|
620
|
+
|
621
|
+
oj_out_free(&out);
|
622
|
+
|
662
623
|
if (!ok) {
|
663
624
|
int err = ferror(f);
|
625
|
+
fclose(f);
|
664
626
|
|
665
627
|
rb_raise(rb_eIOError, "Write failed. [%d:%s]", err, strerror(err));
|
666
628
|
}
|
629
|
+
fclose(f);
|
667
630
|
}
|
668
631
|
|
632
|
+
#if !IS_WINDOWS
|
633
|
+
static void write_ready(int fd) {
|
634
|
+
struct pollfd pp;
|
635
|
+
int i;
|
636
|
+
|
637
|
+
pp.fd = fd;
|
638
|
+
pp.events = POLLERR | POLLOUT;
|
639
|
+
pp.revents = 0;
|
640
|
+
if (0 >= (i = poll(&pp, 1, 5000))) {
|
641
|
+
if (0 == i || EAGAIN == errno) {
|
642
|
+
rb_raise(rb_eIOError, "write timed out");
|
643
|
+
}
|
644
|
+
rb_raise(rb_eIOError, "write failed. %d %s.", errno, strerror(errno));
|
645
|
+
}
|
646
|
+
}
|
647
|
+
#endif
|
648
|
+
|
669
649
|
void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
670
|
-
char buf[4096];
|
671
650
|
struct _out out;
|
672
651
|
ssize_t size;
|
673
652
|
VALUE clas = rb_obj_class(stream);
|
@@ -676,41 +655,48 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
|
676
655
|
VALUE s;
|
677
656
|
#endif
|
678
657
|
|
679
|
-
out
|
680
|
-
|
681
|
-
out.allocated = false;
|
658
|
+
oj_out_init(&out);
|
659
|
+
|
682
660
|
out.omit_nil = copts->dump_opts.omit_nil;
|
683
661
|
oj_dump_obj_to_json(obj, copts, &out);
|
684
662
|
size = out.cur - out.buf;
|
685
663
|
if (oj_stringio_class == clas) {
|
686
664
|
rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
|
687
665
|
#if !IS_WINDOWS
|
688
|
-
} else if (rb_respond_to(stream, oj_fileno_id) &&
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
666
|
+
} else if (rb_respond_to(stream, oj_fileno_id) && Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) &&
|
667
|
+
0 != (fd = FIX2INT(s))) {
|
668
|
+
ssize_t cnt;
|
669
|
+
ssize_t total = 0;
|
670
|
+
|
671
|
+
while (true) {
|
672
|
+
if (0 > (cnt = write(fd, out.buf + total, size - total))) {
|
673
|
+
if (EAGAIN != errno) {
|
674
|
+
rb_raise(rb_eIOError, "write failed. %d %s.", errno, strerror(errno));
|
675
|
+
break;
|
676
|
+
}
|
693
677
|
}
|
694
|
-
|
678
|
+
total += cnt;
|
679
|
+
if (size <= total) {
|
680
|
+
// Completed
|
681
|
+
break;
|
682
|
+
}
|
683
|
+
write_ready(fd);
|
695
684
|
}
|
696
685
|
#endif
|
697
686
|
} else if (rb_respond_to(stream, oj_write_id)) {
|
698
687
|
rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
|
699
688
|
} else {
|
700
|
-
|
701
|
-
xfree(out.buf);
|
702
|
-
}
|
689
|
+
oj_out_free(&out);
|
703
690
|
rb_raise(rb_eArgError, "to_stream() expected an IO Object.");
|
704
691
|
}
|
705
|
-
|
706
|
-
xfree(out.buf);
|
707
|
-
}
|
692
|
+
oj_out_free(&out);
|
708
693
|
}
|
709
694
|
|
710
695
|
void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
|
711
|
-
|
696
|
+
int idx = RB_ENCODING_GET(obj);
|
712
697
|
|
713
|
-
if (
|
698
|
+
if (oj_utf8_encoding_index != idx) {
|
699
|
+
rb_encoding *enc = rb_enc_from_index(idx);
|
714
700
|
obj = rb_str_conv_enc(obj, enc, oj_utf8_encoding);
|
715
701
|
}
|
716
702
|
oj_dump_cstr(RSTRING_PTR(obj), (int)RSTRING_LEN(obj), 0, 0, out);
|
@@ -724,7 +710,7 @@ void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
|
|
724
710
|
|
725
711
|
static void debug_raise(const char *orig, size_t cnt, int line) {
|
726
712
|
char buf[1024];
|
727
|
-
char
|
713
|
+
char *b = buf;
|
728
714
|
const char *s = orig;
|
729
715
|
const char *s_end = s + cnt;
|
730
716
|
|
@@ -750,11 +736,11 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
|
750
736
|
} else {
|
751
737
|
volatile VALUE jv;
|
752
738
|
|
753
|
-
if (Yes == out->opts->trace) {
|
739
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
754
740
|
oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
755
741
|
}
|
756
742
|
jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent));
|
757
|
-
if (Yes == out->opts->trace) {
|
743
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
758
744
|
oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
759
745
|
}
|
760
746
|
oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
|
@@ -763,7 +749,7 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
|
763
749
|
|
764
750
|
void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
|
765
751
|
size_t size;
|
766
|
-
char
|
752
|
+
char *cmap;
|
767
753
|
const char *orig = str;
|
768
754
|
bool has_hi = false;
|
769
755
|
|
@@ -776,6 +762,11 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
776
762
|
cmap = ascii_friendly_chars;
|
777
763
|
size = ascii_friendly_size((uint8_t *)str, cnt);
|
778
764
|
break;
|
765
|
+
case SlashEsc:
|
766
|
+
has_hi = true;
|
767
|
+
cmap = slash_friendly_chars;
|
768
|
+
size = slash_friendly_size((uint8_t *)str, cnt);
|
769
|
+
break;
|
779
770
|
case XSSEsc:
|
780
771
|
cmap = xss_friendly_chars;
|
781
772
|
size = xss_friendly_size((uint8_t *)str, cnt);
|
@@ -808,10 +799,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
808
799
|
*out->cur++ = '"';
|
809
800
|
|
810
801
|
if (escape1) {
|
811
|
-
|
812
|
-
*out->cur++ = 'u';
|
813
|
-
*out->cur++ = '0';
|
814
|
-
*out->cur++ = '0';
|
802
|
+
APPEND_CHARS(out->cur, "\\u00", 4);
|
815
803
|
dump_hex((uint8_t)*str, out);
|
816
804
|
cnt--;
|
817
805
|
size--;
|
@@ -822,8 +810,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
822
810
|
if (is_sym) {
|
823
811
|
*out->cur++ = ':';
|
824
812
|
}
|
825
|
-
|
826
|
-
out->cur += cnt;
|
813
|
+
APPEND_CHARS(out->cur, str, cnt);
|
827
814
|
*out->cur++ = '"';
|
828
815
|
} else {
|
829
816
|
const char *end = str + cnt;
|
@@ -835,8 +822,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
835
822
|
for (; str < end; str++) {
|
836
823
|
switch (cmap[(uint8_t)*str]) {
|
837
824
|
case '1':
|
838
|
-
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
839
|
-
check_start <= str) {
|
825
|
+
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && check_start <= str) {
|
840
826
|
if (0 != (0x80 & (uint8_t)*str)) {
|
841
827
|
if (0xC0 == (0xC0 & (uint8_t)*str)) {
|
842
828
|
check_start = check_unicode(str, end, orig);
|
@@ -860,11 +846,9 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
860
846
|
}
|
861
847
|
break;
|
862
848
|
case '3': // Unicode
|
863
|
-
if (0xe2 == (uint8_t)*str &&
|
864
|
-
(JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
849
|
+
if (0xe2 == (uint8_t)*str && (JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
865
850
|
2 <= end - str) {
|
866
|
-
if (0x80 == (uint8_t)str[1] &&
|
867
|
-
(0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
851
|
+
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
868
852
|
str = dump_unicode(str, end, out, orig);
|
869
853
|
} else {
|
870
854
|
check_start = check_unicode(str, end, orig);
|
@@ -876,17 +860,12 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
876
860
|
break;
|
877
861
|
case '6': // control characters
|
878
862
|
if (*(uint8_t *)str < 0x80) {
|
879
|
-
|
880
|
-
*out->cur++ = 'u';
|
881
|
-
*out->cur++ = '0';
|
882
|
-
*out->cur++ = '0';
|
863
|
+
APPEND_CHARS(out->cur, "\\u00", 4);
|
883
864
|
dump_hex((uint8_t)*str, out);
|
884
865
|
} else {
|
885
866
|
if (0xe2 == (uint8_t)*str &&
|
886
|
-
(JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
887
|
-
2
|
888
|
-
if (0x80 == (uint8_t)str[1] &&
|
889
|
-
(0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
867
|
+
(JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 2 <= end - str) {
|
868
|
+
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
890
869
|
str = dump_unicode(str, end, out, orig);
|
891
870
|
} else {
|
892
871
|
check_start = check_unicode(str, end, orig);
|
@@ -902,8 +881,8 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
902
881
|
}
|
903
882
|
*out->cur++ = '"';
|
904
883
|
}
|
905
|
-
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
906
|
-
0
|
884
|
+
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 0 < str - orig &&
|
885
|
+
0 != (0x80 & *(str - 1))) {
|
907
886
|
uint8_t c = (uint8_t) * (str - 1);
|
908
887
|
int i;
|
909
888
|
int scnt = (int)(str - orig);
|
@@ -960,15 +939,27 @@ void oj_dump_obj_to_s(VALUE obj, Out out) {
|
|
960
939
|
|
961
940
|
void oj_dump_raw(const char *str, size_t cnt, Out out) {
|
962
941
|
assure_size(out, cnt + 10);
|
963
|
-
|
964
|
-
out->cur += cnt;
|
942
|
+
APPEND_CHARS(out->cur, str, cnt);
|
965
943
|
*out->cur = '\0';
|
966
944
|
}
|
967
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
|
+
xfree(out->buf); // TBD
|
956
|
+
}
|
957
|
+
}
|
958
|
+
|
968
959
|
void oj_grow_out(Out out, size_t len) {
|
969
960
|
size_t size = out->end - out->buf;
|
970
961
|
long pos = out->cur - out->buf;
|
971
|
-
char
|
962
|
+
char *buf = out->buf;
|
972
963
|
|
973
964
|
size *= 2;
|
974
965
|
if (size <= len * 2 + pos) {
|
@@ -991,37 +982,28 @@ void oj_grow_out(Out out, size_t len) {
|
|
991
982
|
|
992
983
|
void oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok) {
|
993
984
|
assure_size(out, 4);
|
994
|
-
|
995
|
-
*out->cur++ = 'u';
|
996
|
-
*out->cur++ = 'l';
|
997
|
-
*out->cur++ = 'l';
|
985
|
+
APPEND_CHARS(out->cur, "null", 4);
|
998
986
|
*out->cur = '\0';
|
999
987
|
}
|
1000
988
|
|
1001
989
|
void oj_dump_true(VALUE obj, int depth, Out out, bool as_ok) {
|
1002
990
|
assure_size(out, 4);
|
1003
|
-
|
1004
|
-
*out->cur++ = 'r';
|
1005
|
-
*out->cur++ = 'u';
|
1006
|
-
*out->cur++ = 'e';
|
991
|
+
APPEND_CHARS(out->cur, "true", 4);
|
1007
992
|
*out->cur = '\0';
|
1008
993
|
}
|
1009
994
|
|
1010
995
|
void oj_dump_false(VALUE obj, int depth, Out out, bool as_ok) {
|
1011
996
|
assure_size(out, 5);
|
1012
|
-
|
1013
|
-
*out->cur++ = 'a';
|
1014
|
-
*out->cur++ = 'l';
|
1015
|
-
*out->cur++ = 's';
|
1016
|
-
*out->cur++ = 'e';
|
997
|
+
APPEND_CHARS(out->cur, "false", 5);
|
1017
998
|
*out->cur = '\0';
|
1018
999
|
}
|
1019
1000
|
|
1020
1001
|
void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
|
1021
1002
|
char buf[32];
|
1022
1003
|
char * b = buf + sizeof(buf) - 1;
|
1023
|
-
long long num =
|
1004
|
+
long long num = NUM2LL(obj);
|
1024
1005
|
int neg = 0;
|
1006
|
+
size_t cnt = 0;
|
1025
1007
|
bool dump_as_string = false;
|
1026
1008
|
|
1027
1009
|
if (out->opts->int_range_max != 0 && out->opts->int_range_min != 0 &&
|
@@ -1052,10 +1034,9 @@ void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1052
1034
|
if (dump_as_string) {
|
1053
1035
|
*--b = '"';
|
1054
1036
|
}
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
}
|
1037
|
+
cnt = sizeof(buf) - (b - buf) - 1;
|
1038
|
+
assure_size(out, cnt);
|
1039
|
+
APPEND_CHARS(out->cur, b, cnt);
|
1059
1040
|
*out->cur = '\0';
|
1060
1041
|
}
|
1061
1042
|
|
@@ -1064,16 +1045,14 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1064
1045
|
int cnt = (int)RSTRING_LEN(rs);
|
1065
1046
|
bool dump_as_string = false;
|
1066
1047
|
|
1067
|
-
if (out->opts->int_range_max != 0 ||
|
1068
|
-
out->opts->int_range_min != 0) { // Bignum cannot be inside of Fixnum range
|
1048
|
+
if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) { // Bignum cannot be inside of Fixnum range
|
1069
1049
|
dump_as_string = true;
|
1070
1050
|
assure_size(out, cnt + 2);
|
1071
1051
|
*out->cur++ = '"';
|
1072
1052
|
} else {
|
1073
1053
|
assure_size(out, cnt);
|
1074
1054
|
}
|
1075
|
-
|
1076
|
-
out->cur += cnt;
|
1055
|
+
APPEND_CHARS(out->cur, RSTRING_PTR(rs), cnt);
|
1077
1056
|
if (dump_as_string) {
|
1078
1057
|
*out->cur++ = '"';
|
1079
1058
|
}
|
@@ -1083,7 +1062,7 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1083
1062
|
// Removed dependencies on math due to problems with CentOS 5.4.
|
1084
1063
|
void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
1085
1064
|
char buf[64];
|
1086
|
-
char
|
1065
|
+
char *b;
|
1087
1066
|
double d = rb_num2dbl(obj);
|
1088
1067
|
int cnt = 0;
|
1089
1068
|
|
@@ -1162,7 +1141,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1162
1141
|
} else if (isnan(d)) {
|
1163
1142
|
if (ObjectMode == out->opts->mode) {
|
1164
1143
|
strcpy(buf, nan_val);
|
1165
|
-
cnt = sizeof(
|
1144
|
+
cnt = sizeof(nan_val) - 1;
|
1166
1145
|
} else {
|
1167
1146
|
NanDump nd = out->opts->dump_opts.nan_dump;
|
1168
1147
|
|
@@ -1206,9 +1185,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1206
1185
|
cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt);
|
1207
1186
|
}
|
1208
1187
|
assure_size(out, cnt);
|
1209
|
-
|
1210
|
-
*out->cur++ = *b;
|
1211
|
-
}
|
1188
|
+
APPEND_CHARS(out->cur, buf, cnt);
|
1212
1189
|
*out->cur = '\0';
|
1213
1190
|
}
|
1214
1191
|
|
@@ -1225,17 +1202,3 @@ int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char
|
|
1225
1202
|
}
|
1226
1203
|
return cnt;
|
1227
1204
|
}
|
1228
|
-
|
1229
|
-
bool oj_dump_ignore(Options opts, VALUE obj) {
|
1230
|
-
if (NULL != opts->ignore && (ObjectMode == opts->mode || CustomMode == opts->mode)) {
|
1231
|
-
VALUE *vp = opts->ignore;
|
1232
|
-
VALUE clas = rb_obj_class(obj);
|
1233
|
-
|
1234
|
-
for (; Qnil != *vp; vp++) {
|
1235
|
-
if (clas == *vp) {
|
1236
|
-
return true;
|
1237
|
-
}
|
1238
|
-
}
|
1239
|
-
}
|
1240
|
-
return false;
|
1241
|
-
}
|