oj 3.13.9 → 3.13.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +9 -0
- data/ext/oj/circarray.c +1 -1
- data/ext/oj/code.c +15 -22
- data/ext/oj/custom.c +32 -59
- data/ext/oj/dump.c +129 -175
- data/ext/oj/dump.h +25 -8
- data/ext/oj/dump_compat.c +44 -81
- data/ext/oj/dump_leaf.c +14 -58
- data/ext/oj/dump_object.c +68 -129
- data/ext/oj/dump_strict.c +14 -26
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/fast.c +15 -9
- data/ext/oj/intern.c +9 -2
- data/ext/oj/intern.h +1 -1
- data/ext/oj/mimic_json.c +73 -73
- data/ext/oj/object.c +1 -1
- data/ext/oj/odd.c +83 -63
- data/ext/oj/odd.h +13 -13
- data/ext/oj/oj.c +29 -17
- data/ext/oj/oj.h +20 -2
- data/ext/oj/parse.c +3 -2
- data/ext/oj/parser.c +10 -15
- data/ext/oj/rails.c +43 -62
- data/ext/oj/rails.h +1 -1
- data/ext/oj/reader.c +2 -0
- data/ext/oj/saj.c +11 -23
- data/ext/oj/stream_writer.c +3 -1
- data/ext/oj/string_writer.c +12 -5
- data/ext/oj/wab.c +9 -9
- data/lib/oj/version.rb +1 -1
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +6 -3
- data/pages/Rails.md +12 -0
- data/test/bar.rb +1 -8
- data/test/foo.rb +70 -13
- data/test/perf_dump.rb +50 -0
- data/test/test_fast.rb +19 -0
- data/test/test_object.rb +12 -7
- data/test/test_saj.rb +1 -1
- data/test/test_various.rb +27 -2
- data/test/tests.rb +0 -1
- metadata +6 -3
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"
|
@@ -113,49 +116,39 @@ static char rails_friendly_chars[256] = "\
|
|
113
116
|
11111111111111111111111111111111";
|
114
117
|
|
115
118
|
static void raise_strict(VALUE obj) {
|
116
|
-
rb_raise(rb_eTypeError,
|
117
|
-
"Failed to dump %s Object to JSON in strict mode.",
|
118
|
-
rb_class2name(rb_obj_class(obj)));
|
119
|
+
rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in strict mode.", rb_class2name(rb_obj_class(obj)));
|
119
120
|
}
|
120
121
|
|
121
|
-
inline static size_t
|
122
|
+
inline static size_t calculate_string_size(const uint8_t *str, size_t len, const char *table) {
|
122
123
|
size_t size = 0;
|
123
124
|
size_t i = len;
|
124
125
|
|
125
|
-
for (;
|
126
|
-
size +=
|
126
|
+
for (; 3 < i; i -= 4) {
|
127
|
+
size += table[*str++];
|
128
|
+
size += table[*str++];
|
129
|
+
size += table[*str++];
|
130
|
+
size += table[*str++];
|
131
|
+
}
|
132
|
+
for (; 0 < i; i--) {
|
133
|
+
size += table[*str++];
|
127
134
|
}
|
128
135
|
return size - len * (size_t)'0';
|
129
136
|
}
|
130
137
|
|
131
|
-
inline static size_t
|
132
|
-
|
133
|
-
|
138
|
+
inline static size_t newline_friendly_size(const uint8_t *str, size_t len) {
|
139
|
+
return calculate_string_size(str, len, newline_friendly_chars);
|
140
|
+
}
|
134
141
|
|
135
|
-
|
136
|
-
|
137
|
-
}
|
138
|
-
return size - len * (size_t)'0';
|
142
|
+
inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
|
143
|
+
return calculate_string_size(str, len, hibit_friendly_chars);
|
139
144
|
}
|
140
145
|
|
141
146
|
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';
|
147
|
+
return calculate_string_size(str, len, ascii_friendly_chars);
|
149
148
|
}
|
150
149
|
|
151
150
|
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';
|
151
|
+
return calculate_string_size(str, len, xss_friendly_chars);
|
159
152
|
}
|
160
153
|
|
161
154
|
inline static size_t hixss_friendly_size(const uint8_t *str, size_t len) {
|
@@ -188,13 +181,7 @@ inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) {
|
|
188
181
|
}
|
189
182
|
|
190
183
|
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';
|
184
|
+
return calculate_string_size(str, len, rails_friendly_chars);
|
198
185
|
}
|
199
186
|
|
200
187
|
const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp) {
|
@@ -247,7 +234,7 @@ inline static void dump_hex(uint8_t c, Out out) {
|
|
247
234
|
static void raise_invalid_unicode(const char *str, int len, int pos) {
|
248
235
|
char c;
|
249
236
|
char code[32];
|
250
|
-
char
|
237
|
+
char *cp = code;
|
251
238
|
int i;
|
252
239
|
uint8_t d;
|
253
240
|
|
@@ -304,14 +291,12 @@ static const char *dump_unicode(const char *str, const char *end, Out out, const
|
|
304
291
|
code -= 0x00010000;
|
305
292
|
c1 = ((code >> 10) & 0x000003FF) + 0x0000D800;
|
306
293
|
code = (code & 0x000003FF) + 0x0000DC00;
|
307
|
-
|
308
|
-
*out->cur++ = 'u';
|
294
|
+
APPEND_CHARS(out->cur, "\\u", 2);
|
309
295
|
for (i = 3; 0 <= i; i--) {
|
310
296
|
*out->cur++ = hex_chars[(uint8_t)(c1 >> (i * 4)) & 0x0F];
|
311
297
|
}
|
312
298
|
}
|
313
|
-
|
314
|
-
*out->cur++ = 'u';
|
299
|
+
APPEND_CHARS(out->cur, "\\u", 2);
|
315
300
|
for (i = 3; 0 <= i; i--) {
|
316
301
|
*out->cur++ = hex_chars[(uint8_t)(code >> (i * 4)) & 0x0F];
|
317
302
|
}
|
@@ -360,9 +345,7 @@ long oj_check_circular(VALUE obj, Out out) {
|
|
360
345
|
} else {
|
361
346
|
if (ObjectMode == out->opts->mode) {
|
362
347
|
assure_size(out, 18);
|
363
|
-
|
364
|
-
*out->cur++ = '^';
|
365
|
-
*out->cur++ = 'r';
|
348
|
+
APPEND_CHARS(out->cur, "\"^r", 3);
|
366
349
|
dump_ulong(id, out);
|
367
350
|
*out->cur++ = '"';
|
368
351
|
}
|
@@ -374,9 +357,9 @@ long oj_check_circular(VALUE obj, Out out) {
|
|
374
357
|
|
375
358
|
void oj_dump_time(VALUE obj, Out out, int withZone) {
|
376
359
|
char buf[64];
|
377
|
-
char
|
360
|
+
char *b = buf + sizeof(buf) - 1;
|
378
361
|
long size;
|
379
|
-
char
|
362
|
+
char *dot;
|
380
363
|
int neg = 0;
|
381
364
|
long one = 1000000000;
|
382
365
|
long long sec;
|
@@ -392,12 +375,12 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
|
|
392
375
|
sec = (long long)ts.tv_sec;
|
393
376
|
nsec = ts.tv_nsec;
|
394
377
|
} else {
|
395
|
-
sec =
|
396
|
-
nsec =
|
378
|
+
sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
379
|
+
nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
397
380
|
}
|
398
381
|
#else
|
399
|
-
sec =
|
400
|
-
nsec =
|
382
|
+
sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
383
|
+
nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
401
384
|
#endif
|
402
385
|
|
403
386
|
*b-- = '\0';
|
@@ -464,8 +447,7 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
|
|
464
447
|
b++;
|
465
448
|
size = sizeof(buf) - (b - buf) - 1;
|
466
449
|
assure_size(out, size);
|
467
|
-
|
468
|
-
out->cur += size;
|
450
|
+
APPEND_CHARS(out->cur, b, size);
|
469
451
|
*out->cur = '\0';
|
470
452
|
}
|
471
453
|
|
@@ -492,12 +474,12 @@ void oj_dump_xml_time(VALUE obj, Out out) {
|
|
492
474
|
sec = ts.tv_sec;
|
493
475
|
nsec = ts.tv_nsec;
|
494
476
|
} else {
|
495
|
-
sec =
|
496
|
-
nsec =
|
477
|
+
sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
478
|
+
nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
497
479
|
}
|
498
480
|
#else
|
499
|
-
sec =
|
500
|
-
nsec =
|
481
|
+
sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
482
|
+
nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
501
483
|
#endif
|
502
484
|
|
503
485
|
assure_size(out, 36);
|
@@ -535,14 +517,7 @@ void oj_dump_xml_time(VALUE obj, Out out) {
|
|
535
517
|
}
|
536
518
|
if ((0 == nsec && !out->opts->sec_prec_set) || 0 == out->opts->sec_prec) {
|
537
519
|
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);
|
520
|
+
int len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec);
|
546
521
|
oj_dump_cstr(buf, len, 0, 0, out);
|
547
522
|
} else {
|
548
523
|
int len = sprintf(buf,
|
@@ -574,18 +549,7 @@ void oj_dump_xml_time(VALUE obj, Out out) {
|
|
574
549
|
if (9 > out->opts->sec_prec) {
|
575
550
|
format[32] = '0' + out->opts->sec_prec;
|
576
551
|
}
|
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);
|
552
|
+
len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec, tzsign, tzhour, tzmin);
|
589
553
|
oj_dump_cstr(buf, len, 0, 0, out);
|
590
554
|
}
|
591
555
|
}
|
@@ -596,12 +560,8 @@ void oj_dump_obj_to_json(VALUE obj, Options copts, Out out) {
|
|
596
560
|
|
597
561
|
void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VALUE *argv) {
|
598
562
|
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;
|
563
|
+
oj_out_init(out);
|
603
564
|
}
|
604
|
-
out->cur = out->buf;
|
605
565
|
out->circ_cnt = 0;
|
606
566
|
out->opts = copts;
|
607
567
|
out->hash_cnt = 0;
|
@@ -636,38 +596,52 @@ void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int arg
|
|
636
596
|
}
|
637
597
|
|
638
598
|
void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
|
639
|
-
char buf[4096];
|
640
599
|
struct _out out;
|
641
600
|
size_t size;
|
642
|
-
FILE
|
601
|
+
FILE *f;
|
643
602
|
int ok;
|
644
603
|
|
645
|
-
out
|
646
|
-
|
647
|
-
out.allocated = false;
|
604
|
+
oj_out_init(&out);
|
605
|
+
|
648
606
|
out.omit_nil = copts->dump_opts.omit_nil;
|
649
607
|
oj_dump_obj_to_json(obj, copts, &out);
|
650
608
|
size = out.cur - out.buf;
|
651
609
|
if (0 == (f = fopen(path, "w"))) {
|
652
|
-
|
653
|
-
xfree(out.buf);
|
654
|
-
}
|
610
|
+
oj_out_free(&out);
|
655
611
|
rb_raise(rb_eIOError, "%s", strerror(errno));
|
656
612
|
}
|
657
613
|
ok = (size == fwrite(out.buf, 1, size, f));
|
658
|
-
|
659
|
-
|
660
|
-
|
614
|
+
|
615
|
+
oj_out_free(&out);
|
616
|
+
|
661
617
|
fclose(f);
|
662
618
|
if (!ok) {
|
663
619
|
int err = ferror(f);
|
620
|
+
fclose(f);
|
664
621
|
|
665
622
|
rb_raise(rb_eIOError, "Write failed. [%d:%s]", err, strerror(err));
|
666
623
|
}
|
624
|
+
fclose(f);
|
667
625
|
}
|
668
626
|
|
627
|
+
#if !IS_WINDOWS
|
628
|
+
static void write_ready(int fd) {
|
629
|
+
struct pollfd pp;
|
630
|
+
int i;
|
631
|
+
|
632
|
+
pp.fd = fd;
|
633
|
+
pp.events = POLLERR | POLLOUT;
|
634
|
+
pp.revents = 0;
|
635
|
+
if (0 >= (i = poll(&pp, 1, 5000))) {
|
636
|
+
if (0 == i || EAGAIN == errno) {
|
637
|
+
rb_raise(rb_eIOError, "write timed out");
|
638
|
+
}
|
639
|
+
rb_raise(rb_eIOError, "write failed. %d %s.", errno, strerror(errno));
|
640
|
+
}
|
641
|
+
}
|
642
|
+
#endif
|
643
|
+
|
669
644
|
void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
670
|
-
char buf[4096];
|
671
645
|
struct _out out;
|
672
646
|
ssize_t size;
|
673
647
|
VALUE clas = rb_obj_class(stream);
|
@@ -676,41 +650,48 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
|
|
676
650
|
VALUE s;
|
677
651
|
#endif
|
678
652
|
|
679
|
-
out
|
680
|
-
|
681
|
-
out.allocated = false;
|
653
|
+
oj_out_init(&out);
|
654
|
+
|
682
655
|
out.omit_nil = copts->dump_opts.omit_nil;
|
683
656
|
oj_dump_obj_to_json(obj, copts, &out);
|
684
657
|
size = out.cur - out.buf;
|
685
658
|
if (oj_stringio_class == clas) {
|
686
659
|
rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
|
687
660
|
#if !IS_WINDOWS
|
688
|
-
} else if (rb_respond_to(stream, oj_fileno_id) &&
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
661
|
+
} else if (rb_respond_to(stream, oj_fileno_id) && Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) &&
|
662
|
+
0 != (fd = FIX2INT(s))) {
|
663
|
+
ssize_t cnt;
|
664
|
+
ssize_t total = 0;
|
665
|
+
|
666
|
+
while (true) {
|
667
|
+
if (0 > (cnt = write(fd, out.buf + total, size - total))) {
|
668
|
+
if (EAGAIN != errno) {
|
669
|
+
rb_raise(rb_eIOError, "write failed. %d %s.", errno, strerror(errno));
|
670
|
+
break;
|
671
|
+
}
|
693
672
|
}
|
694
|
-
|
673
|
+
total += cnt;
|
674
|
+
if (size <= total) {
|
675
|
+
// Completed
|
676
|
+
break;
|
677
|
+
}
|
678
|
+
write_ready(fd);
|
695
679
|
}
|
696
680
|
#endif
|
697
681
|
} else if (rb_respond_to(stream, oj_write_id)) {
|
698
682
|
rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
|
699
683
|
} else {
|
700
|
-
|
701
|
-
xfree(out.buf);
|
702
|
-
}
|
684
|
+
oj_out_free(&out);
|
703
685
|
rb_raise(rb_eArgError, "to_stream() expected an IO Object.");
|
704
686
|
}
|
705
|
-
|
706
|
-
xfree(out.buf);
|
707
|
-
}
|
687
|
+
oj_out_free(&out);
|
708
688
|
}
|
709
689
|
|
710
690
|
void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
|
711
|
-
|
691
|
+
int idx = RB_ENCODING_GET(obj);
|
712
692
|
|
713
|
-
if (
|
693
|
+
if (oj_utf8_encoding_index != idx) {
|
694
|
+
rb_encoding *enc = rb_enc_from_index(idx);
|
714
695
|
obj = rb_str_conv_enc(obj, enc, oj_utf8_encoding);
|
715
696
|
}
|
716
697
|
oj_dump_cstr(RSTRING_PTR(obj), (int)RSTRING_LEN(obj), 0, 0, out);
|
@@ -724,7 +705,7 @@ void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
|
|
724
705
|
|
725
706
|
static void debug_raise(const char *orig, size_t cnt, int line) {
|
726
707
|
char buf[1024];
|
727
|
-
char
|
708
|
+
char *b = buf;
|
728
709
|
const char *s = orig;
|
729
710
|
const char *s_end = s + cnt;
|
730
711
|
|
@@ -763,7 +744,7 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
|
763
744
|
|
764
745
|
void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
|
765
746
|
size_t size;
|
766
|
-
char
|
747
|
+
char *cmap;
|
767
748
|
const char *orig = str;
|
768
749
|
bool has_hi = false;
|
769
750
|
|
@@ -808,10 +789,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
808
789
|
*out->cur++ = '"';
|
809
790
|
|
810
791
|
if (escape1) {
|
811
|
-
|
812
|
-
*out->cur++ = 'u';
|
813
|
-
*out->cur++ = '0';
|
814
|
-
*out->cur++ = '0';
|
792
|
+
APPEND_CHARS(out->cur, "\\u00", 4);
|
815
793
|
dump_hex((uint8_t)*str, out);
|
816
794
|
cnt--;
|
817
795
|
size--;
|
@@ -822,8 +800,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
822
800
|
if (is_sym) {
|
823
801
|
*out->cur++ = ':';
|
824
802
|
}
|
825
|
-
|
826
|
-
out->cur += cnt;
|
803
|
+
APPEND_CHARS(out->cur, str, cnt);
|
827
804
|
*out->cur++ = '"';
|
828
805
|
} else {
|
829
806
|
const char *end = str + cnt;
|
@@ -835,8 +812,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
835
812
|
for (; str < end; str++) {
|
836
813
|
switch (cmap[(uint8_t)*str]) {
|
837
814
|
case '1':
|
838
|
-
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
839
|
-
check_start <= str) {
|
815
|
+
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && check_start <= str) {
|
840
816
|
if (0 != (0x80 & (uint8_t)*str)) {
|
841
817
|
if (0xC0 == (0xC0 & (uint8_t)*str)) {
|
842
818
|
check_start = check_unicode(str, end, orig);
|
@@ -860,11 +836,9 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
860
836
|
}
|
861
837
|
break;
|
862
838
|
case '3': // Unicode
|
863
|
-
if (0xe2 == (uint8_t)*str &&
|
864
|
-
(JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
839
|
+
if (0xe2 == (uint8_t)*str && (JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
865
840
|
2 <= end - str) {
|
866
|
-
if (0x80 == (uint8_t)str[1] &&
|
867
|
-
(0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
841
|
+
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
868
842
|
str = dump_unicode(str, end, out, orig);
|
869
843
|
} else {
|
870
844
|
check_start = check_unicode(str, end, orig);
|
@@ -876,17 +850,12 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
876
850
|
break;
|
877
851
|
case '6': // control characters
|
878
852
|
if (*(uint8_t *)str < 0x80) {
|
879
|
-
|
880
|
-
*out->cur++ = 'u';
|
881
|
-
*out->cur++ = '0';
|
882
|
-
*out->cur++ = '0';
|
853
|
+
APPEND_CHARS(out->cur, "\\u00", 4);
|
883
854
|
dump_hex((uint8_t)*str, out);
|
884
855
|
} else {
|
885
856
|
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])) {
|
857
|
+
(JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 2 <= end - str) {
|
858
|
+
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
890
859
|
str = dump_unicode(str, end, out, orig);
|
891
860
|
} else {
|
892
861
|
check_start = check_unicode(str, end, orig);
|
@@ -902,8 +871,8 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
902
871
|
}
|
903
872
|
*out->cur++ = '"';
|
904
873
|
}
|
905
|
-
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) &&
|
906
|
-
0
|
874
|
+
if ((JXEsc == out->opts->escape_mode || RailsXEsc == out->opts->escape_mode) && 0 < str - orig &&
|
875
|
+
0 != (0x80 & *(str - 1))) {
|
907
876
|
uint8_t c = (uint8_t) * (str - 1);
|
908
877
|
int i;
|
909
878
|
int scnt = (int)(str - orig);
|
@@ -960,16 +929,29 @@ void oj_dump_obj_to_s(VALUE obj, Out out) {
|
|
960
929
|
|
961
930
|
void oj_dump_raw(const char *str, size_t cnt, Out out) {
|
962
931
|
assure_size(out, cnt + 10);
|
963
|
-
|
964
|
-
out->cur += cnt;
|
932
|
+
APPEND_CHARS(out->cur, str, cnt);
|
965
933
|
*out->cur = '\0';
|
966
934
|
}
|
967
935
|
|
936
|
+
void oj_out_init(Out out) {
|
937
|
+
out->buf = out->stack_buffer;
|
938
|
+
out->cur = out->buf;
|
939
|
+
out->end = out->buf + sizeof(out->stack_buffer) - BUFFER_EXTRA;
|
940
|
+
out->allocated = false;
|
941
|
+
}
|
942
|
+
|
943
|
+
void oj_out_free(Out out) {
|
944
|
+
if (out->allocated) {
|
945
|
+
xfree(out->buf); // TBD
|
946
|
+
}
|
947
|
+
}
|
948
|
+
|
968
949
|
void oj_grow_out(Out out, size_t len) {
|
969
950
|
size_t size = out->end - out->buf;
|
970
951
|
long pos = out->cur - out->buf;
|
971
|
-
char
|
952
|
+
char *buf = out->buf;
|
972
953
|
|
954
|
+
printf("*** grow %ld\n", len);
|
973
955
|
size *= 2;
|
974
956
|
if (size <= len * 2 + pos) {
|
975
957
|
size += len;
|
@@ -991,37 +973,28 @@ void oj_grow_out(Out out, size_t len) {
|
|
991
973
|
|
992
974
|
void oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok) {
|
993
975
|
assure_size(out, 4);
|
994
|
-
|
995
|
-
*out->cur++ = 'u';
|
996
|
-
*out->cur++ = 'l';
|
997
|
-
*out->cur++ = 'l';
|
976
|
+
APPEND_CHARS(out->cur, "null", 4);
|
998
977
|
*out->cur = '\0';
|
999
978
|
}
|
1000
979
|
|
1001
980
|
void oj_dump_true(VALUE obj, int depth, Out out, bool as_ok) {
|
1002
981
|
assure_size(out, 4);
|
1003
|
-
|
1004
|
-
*out->cur++ = 'r';
|
1005
|
-
*out->cur++ = 'u';
|
1006
|
-
*out->cur++ = 'e';
|
982
|
+
APPEND_CHARS(out->cur, "true", 4);
|
1007
983
|
*out->cur = '\0';
|
1008
984
|
}
|
1009
985
|
|
1010
986
|
void oj_dump_false(VALUE obj, int depth, Out out, bool as_ok) {
|
1011
987
|
assure_size(out, 5);
|
1012
|
-
|
1013
|
-
*out->cur++ = 'a';
|
1014
|
-
*out->cur++ = 'l';
|
1015
|
-
*out->cur++ = 's';
|
1016
|
-
*out->cur++ = 'e';
|
988
|
+
APPEND_CHARS(out->cur, "false", 5);
|
1017
989
|
*out->cur = '\0';
|
1018
990
|
}
|
1019
991
|
|
1020
992
|
void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
|
1021
993
|
char buf[32];
|
1022
994
|
char * b = buf + sizeof(buf) - 1;
|
1023
|
-
long long num =
|
995
|
+
long long num = NUM2LL(obj);
|
1024
996
|
int neg = 0;
|
997
|
+
size_t cnt = 0;
|
1025
998
|
bool dump_as_string = false;
|
1026
999
|
|
1027
1000
|
if (out->opts->int_range_max != 0 && out->opts->int_range_min != 0 &&
|
@@ -1052,10 +1025,9 @@ void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1052
1025
|
if (dump_as_string) {
|
1053
1026
|
*--b = '"';
|
1054
1027
|
}
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
}
|
1028
|
+
cnt = sizeof(buf) - (b - buf) - 1;
|
1029
|
+
assure_size(out, cnt);
|
1030
|
+
APPEND_CHARS(out->cur, b, cnt);
|
1059
1031
|
*out->cur = '\0';
|
1060
1032
|
}
|
1061
1033
|
|
@@ -1064,16 +1036,14 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1064
1036
|
int cnt = (int)RSTRING_LEN(rs);
|
1065
1037
|
bool dump_as_string = false;
|
1066
1038
|
|
1067
|
-
if (out->opts->int_range_max != 0 ||
|
1068
|
-
out->opts->int_range_min != 0) { // Bignum cannot be inside of Fixnum range
|
1039
|
+
if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) { // Bignum cannot be inside of Fixnum range
|
1069
1040
|
dump_as_string = true;
|
1070
1041
|
assure_size(out, cnt + 2);
|
1071
1042
|
*out->cur++ = '"';
|
1072
1043
|
} else {
|
1073
1044
|
assure_size(out, cnt);
|
1074
1045
|
}
|
1075
|
-
|
1076
|
-
out->cur += cnt;
|
1046
|
+
APPEND_CHARS(out->cur, RSTRING_PTR(rs), cnt);
|
1077
1047
|
if (dump_as_string) {
|
1078
1048
|
*out->cur++ = '"';
|
1079
1049
|
}
|
@@ -1083,7 +1053,7 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1083
1053
|
// Removed dependencies on math due to problems with CentOS 5.4.
|
1084
1054
|
void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
1085
1055
|
char buf[64];
|
1086
|
-
char
|
1056
|
+
char *b;
|
1087
1057
|
double d = rb_num2dbl(obj);
|
1088
1058
|
int cnt = 0;
|
1089
1059
|
|
@@ -1206,9 +1176,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1206
1176
|
cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt);
|
1207
1177
|
}
|
1208
1178
|
assure_size(out, cnt);
|
1209
|
-
|
1210
|
-
*out->cur++ = *b;
|
1211
|
-
}
|
1179
|
+
APPEND_CHARS(out->cur, buf, cnt);
|
1212
1180
|
*out->cur = '\0';
|
1213
1181
|
}
|
1214
1182
|
|
@@ -1225,17 +1193,3 @@ int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char
|
|
1225
1193
|
}
|
1226
1194
|
return cnt;
|
1227
1195
|
}
|
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
|
-
}
|
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
|
|
@@ -50,7 +55,6 @@ extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self);
|
|
50
55
|
|
51
56
|
extern int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *format);
|
52
57
|
|
53
|
-
extern bool oj_dump_ignore(Options opts, VALUE obj);
|
54
58
|
extern time_t oj_sec_from_time_hard_way(VALUE obj);
|
55
59
|
|
56
60
|
inline static void assure_size(Out out, size_t len) {
|
@@ -63,15 +67,29 @@ inline static void fill_indent(Out out, int cnt) {
|
|
63
67
|
if (0 < out->indent) {
|
64
68
|
cnt *= out->indent;
|
65
69
|
*out->cur++ = '\n';
|
66
|
-
|
67
|
-
|
70
|
+
memset(out->cur, ' ', cnt);
|
71
|
+
out->cur += cnt;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
inline static bool dump_ignore(Options opts, VALUE obj) {
|
76
|
+
if (NULL != opts->ignore && (ObjectMode == opts->mode || CustomMode == opts->mode)) {
|
77
|
+
VALUE *vp = opts->ignore;
|
78
|
+
VALUE clas = rb_obj_class(obj);
|
79
|
+
|
80
|
+
for (; Qnil != *vp; vp++) {
|
81
|
+
if (clas == *vp) {
|
82
|
+
return true;
|
83
|
+
}
|
68
84
|
}
|
69
85
|
}
|
86
|
+
return false;
|
70
87
|
}
|
71
88
|
|
72
89
|
inline static void dump_ulong(unsigned long num, Out out) {
|
73
|
-
char
|
74
|
-
char
|
90
|
+
char buf[32];
|
91
|
+
char *b = buf + sizeof(buf) - 1;
|
92
|
+
size_t cnt = 0;
|
75
93
|
|
76
94
|
*b-- = '\0';
|
77
95
|
if (0 < num) {
|
@@ -82,9 +100,8 @@ inline static void dump_ulong(unsigned long num, Out out) {
|
|
82
100
|
} else {
|
83
101
|
*b = '0';
|
84
102
|
}
|
85
|
-
|
86
|
-
|
87
|
-
}
|
103
|
+
cnt = sizeof(buf) - (b - buf) - 1;
|
104
|
+
APPEND_CHARS(out->cur, b, cnt);
|
88
105
|
*out->cur = '\0';
|
89
106
|
}
|
90
107
|
|