oj 3.13.9 → 3.13.12

Sign up to get free protection for your applications and to get access to all the features.
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 newline_friendly_size(const uint8_t *str, size_t len) {
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 (; 0 < i; str++, i--) {
126
- size += newline_friendly_chars[*str];
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 hibit_friendly_size(const uint8_t *str, size_t len) {
132
- size_t size = 0;
133
- size_t i = len;
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
- for (; 0 < i; str++, i--) {
136
- size += hibit_friendly_chars[*str];
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
- size_t size = 0;
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
- size_t size = 0;
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
- size_t size = 0;
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 * cp = code;
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
- *out->cur++ = '\\';
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
- *out->cur++ = '\\';
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
- *out->cur++ = '"';
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 * b = buf + sizeof(buf) - 1;
360
+ char *b = buf + sizeof(buf) - 1;
378
361
  long size;
379
- char * dot;
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 = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
396
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
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 = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
400
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
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
- memcpy(out->cur, b, size);
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 = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
496
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
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 = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
500
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
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->buf = ALLOC_N(char, 4096);
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 * f;
601
+ FILE *f;
643
602
  int ok;
644
603
 
645
- out.buf = buf;
646
- out.end = buf + sizeof(buf) - BUFFER_EXTRA;
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
- if (out.allocated) {
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
- if (out.allocated) {
659
- xfree(out.buf);
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.buf = buf;
680
- out.end = buf + sizeof(buf) - BUFFER_EXTRA;
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
- Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) && 0 != (fd = FIX2INT(s))) {
690
- if (size != write(fd, out.buf, size)) {
691
- if (out.allocated) {
692
- xfree(out.buf);
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
- rb_raise(rb_eIOError, "Write failed. [%d:%s]", errno, strerror(errno));
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
- if (out.allocated) {
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
- if (out.allocated) {
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
- rb_encoding *enc = rb_enc_get(obj);
691
+ int idx = RB_ENCODING_GET(obj);
712
692
 
713
- if (oj_utf8_encoding != enc) {
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 * b = buf;
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 * cmap;
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
- *out->cur++ = '\\';
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
- memcpy(out->cur, str, cnt);
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
- *out->cur++ = '\\';
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 <= end - str) {
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 < str - orig && 0 != (0x80 & *(str - 1))) {
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
- memcpy(out->cur, str, cnt);
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 * buf = out->buf;
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
- *out->cur++ = 'n';
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
- *out->cur++ = 't';
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
- *out->cur++ = 'f';
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 = rb_num2ll(obj);
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
- assure_size(out, (sizeof(buf) - (b - buf)));
1056
- for (; '\0' != *b; b++) {
1057
- *out->cur++ = *b;
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
- memcpy(out->cur, RSTRING_PTR(rs), cnt);
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 * b;
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
- for (b = buf; '\0' != *b; b++) {
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
- for (; 0 < cnt; cnt--) {
67
- *out->cur++ = ' ';
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 buf[32];
74
- char *b = buf + sizeof(buf) - 1;
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
- for (; '\0' != *b; b++) {
86
- *out->cur++ = *b;
87
- }
103
+ cnt = sizeof(buf) - (b - buf) - 1;
104
+ APPEND_CHARS(out->cur, b, cnt);
88
105
  *out->cur = '\0';
89
106
  }
90
107