oj 3.13.11 → 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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/README.md +2 -0
  4. data/ext/oj/buf.h +4 -0
  5. data/ext/oj/circarray.c +1 -1
  6. data/ext/oj/code.c +15 -22
  7. data/ext/oj/compat.c +10 -10
  8. data/ext/oj/custom.c +62 -108
  9. data/ext/oj/dump.c +85 -97
  10. data/ext/oj/dump.h +12 -8
  11. data/ext/oj/dump_compat.c +46 -88
  12. data/ext/oj/dump_leaf.c +14 -58
  13. data/ext/oj/dump_object.c +33 -156
  14. data/ext/oj/dump_strict.c +17 -29
  15. data/ext/oj/extconf.rb +5 -4
  16. data/ext/oj/fast.c +24 -22
  17. data/ext/oj/intern.c +15 -11
  18. data/ext/oj/intern.h +1 -1
  19. data/ext/oj/mimic_json.c +44 -32
  20. data/ext/oj/object.c +42 -41
  21. data/ext/oj/odd.c +83 -63
  22. data/ext/oj/odd.h +13 -13
  23. data/ext/oj/oj.c +57 -22
  24. data/ext/oj/oj.h +24 -3
  25. data/ext/oj/parse.c +114 -78
  26. data/ext/oj/parse.h +2 -0
  27. data/ext/oj/parser.c +77 -21
  28. data/ext/oj/parser.h +12 -0
  29. data/ext/oj/rails.c +41 -65
  30. data/ext/oj/rails.h +1 -1
  31. data/ext/oj/reader.c +2 -0
  32. data/ext/oj/saj.c +11 -23
  33. data/ext/oj/saj2.c +333 -85
  34. data/ext/oj/saj2.h +23 -0
  35. data/ext/oj/sparse.c +4 -0
  36. data/ext/oj/stream_writer.c +3 -1
  37. data/ext/oj/strict.c +13 -13
  38. data/ext/oj/string_writer.c +12 -5
  39. data/ext/oj/usual.c +82 -129
  40. data/ext/oj/usual.h +68 -0
  41. data/ext/oj/val_stack.c +1 -1
  42. data/ext/oj/validate.c +21 -26
  43. data/ext/oj/wab.c +21 -26
  44. data/lib/oj/saj.rb +20 -6
  45. data/lib/oj/state.rb +1 -1
  46. data/lib/oj/version.rb +1 -1
  47. data/pages/Compatibility.md +1 -1
  48. data/pages/Options.md +6 -0
  49. data/test/activesupport7/abstract_unit.rb +49 -0
  50. data/test/activesupport7/decoding_test.rb +125 -0
  51. data/test/activesupport7/encoding_test.rb +486 -0
  52. data/test/activesupport7/encoding_test_cases.rb +104 -0
  53. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  54. data/test/bar.rb +3 -8
  55. data/test/foo.rb +3 -3
  56. data/test/helper.rb +8 -2
  57. data/test/json_gem/json_generator_test.rb +5 -4
  58. data/test/json_gem/json_parser_test.rb +8 -1
  59. data/test/json_gem/test_helper.rb +7 -3
  60. data/test/perf_dump.rb +50 -0
  61. data/test/test_compat.rb +25 -0
  62. data/test/test_custom.rb +13 -2
  63. data/test/test_file.rb +23 -7
  64. data/test/test_gc.rb +11 -0
  65. data/test/test_object.rb +8 -10
  66. data/test/test_parser.rb +3 -19
  67. data/test/test_parser_debug.rb +27 -0
  68. data/test/test_parser_saj.rb +92 -2
  69. data/test/test_scp.rb +2 -4
  70. data/test/test_strict.rb +2 -0
  71. data/test/test_various.rb +8 -3
  72. data/test/test_wab.rb +2 -0
  73. data/test/tests.rb +9 -0
  74. data/test/tests_mimic.rb +9 -0
  75. data/test/tests_mimic_addition.rb +9 -0
  76. metadata +13 -116
data/ext/oj/dump.c CHANGED
@@ -32,6 +32,7 @@ static const char nan_val[] = NAN_VAL;
32
32
  typedef unsigned long ulong;
33
33
 
34
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);
35
36
  static size_t xss_friendly_size(const uint8_t *str, size_t len);
36
37
  static size_t ascii_friendly_size(const uint8_t *str, size_t len);
37
38
 
@@ -59,6 +60,17 @@ static char hibit_friendly_chars[256] = "\
59
60
  11111111111111111111111111111111\
60
61
  11111111111111111111111111111111";
61
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
+
62
74
  // High bit set characters are always encoded as unicode. Worse case is 3
63
75
  // bytes per character in the output. That makes this conservative.
64
76
  static char ascii_friendly_chars[256] = "\
@@ -143,6 +155,10 @@ inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
143
155
  return calculate_string_size(str, len, hibit_friendly_chars);
144
156
  }
145
157
 
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);
160
+ }
161
+
146
162
  inline static size_t ascii_friendly_size(const uint8_t *str, size_t len) {
147
163
  return calculate_string_size(str, len, ascii_friendly_chars);
148
164
  }
@@ -234,7 +250,7 @@ inline static void dump_hex(uint8_t c, Out out) {
234
250
  static void raise_invalid_unicode(const char *str, int len, int pos) {
235
251
  char c;
236
252
  char code[32];
237
- char * cp = code;
253
+ char *cp = code;
238
254
  int i;
239
255
  uint8_t d;
240
256
 
@@ -291,14 +307,12 @@ static const char *dump_unicode(const char *str, const char *end, Out out, const
291
307
  code -= 0x00010000;
292
308
  c1 = ((code >> 10) & 0x000003FF) + 0x0000D800;
293
309
  code = (code & 0x000003FF) + 0x0000DC00;
294
- *out->cur++ = '\\';
295
- *out->cur++ = 'u';
310
+ APPEND_CHARS(out->cur, "\\u", 2);
296
311
  for (i = 3; 0 <= i; i--) {
297
312
  *out->cur++ = hex_chars[(uint8_t)(c1 >> (i * 4)) & 0x0F];
298
313
  }
299
314
  }
300
- *out->cur++ = '\\';
301
- *out->cur++ = 'u';
315
+ APPEND_CHARS(out->cur, "\\u", 2);
302
316
  for (i = 3; 0 <= i; i--) {
303
317
  *out->cur++ = hex_chars[(uint8_t)(code >> (i * 4)) & 0x0F];
304
318
  }
@@ -347,9 +361,7 @@ long oj_check_circular(VALUE obj, Out out) {
347
361
  } else {
348
362
  if (ObjectMode == out->opts->mode) {
349
363
  assure_size(out, 18);
350
- *out->cur++ = '"';
351
- *out->cur++ = '^';
352
- *out->cur++ = 'r';
364
+ APPEND_CHARS(out->cur, "\"^r", 3);
353
365
  dump_ulong(id, out);
354
366
  *out->cur++ = '"';
355
367
  }
@@ -361,15 +373,14 @@ long oj_check_circular(VALUE obj, Out out) {
361
373
 
362
374
  void oj_dump_time(VALUE obj, Out out, int withZone) {
363
375
  char buf[64];
364
- char * b = buf + sizeof(buf) - 1;
376
+ char *b = buf + sizeof(buf) - 1;
365
377
  long size;
366
- char * dot;
378
+ char *dot;
367
379
  int neg = 0;
368
380
  long one = 1000000000;
369
381
  long long sec;
370
382
  long long nsec;
371
383
 
372
- #ifdef HAVE_RB_TIME_TIMESPEC
373
384
  // rb_time_timespec as well as rb_time_timeeval have a bug that causes an
374
385
  // exception to be raised if a time is before 1970 on 32 bit systems so
375
386
  // check the timespec size and use the ruby calls if a 32 bit system.
@@ -379,13 +390,9 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
379
390
  sec = (long long)ts.tv_sec;
380
391
  nsec = ts.tv_nsec;
381
392
  } else {
382
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
383
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
393
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
394
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
384
395
  }
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
396
 
390
397
  *b-- = '\0';
391
398
  if (withZone) {
@@ -451,8 +458,7 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
451
458
  b++;
452
459
  size = sizeof(buf) - (b - buf) - 1;
453
460
  assure_size(out, size);
454
- memcpy(out->cur, b, size);
455
- out->cur += size;
461
+ APPEND_CHARS(out->cur, b, size);
456
462
  *out->cur = '\0';
457
463
  }
458
464
 
@@ -472,20 +478,15 @@ void oj_dump_xml_time(VALUE obj, Out out) {
472
478
  int tzhour, tzmin;
473
479
  char tzsign = '+';
474
480
 
475
- #ifdef HAVE_RB_TIME_TIMESPEC
476
481
  if (16 <= sizeof(struct timespec)) {
477
482
  struct timespec ts = rb_time_timespec(obj);
478
483
 
479
484
  sec = ts.tv_sec;
480
485
  nsec = ts.tv_nsec;
481
486
  } else {
482
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
483
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
487
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
488
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
484
489
  }
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
490
 
490
491
  assure_size(out, 36);
491
492
  if (9 > out->opts->sec_prec) {
@@ -565,12 +566,8 @@ void oj_dump_obj_to_json(VALUE obj, Options copts, Out out) {
565
566
 
566
567
  void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int argc, VALUE *argv) {
567
568
  if (0 == out->buf) {
568
- out->buf = ALLOC_N(char, 4096);
569
- // 1 less than end plus extra for possible errors
570
- out->end = out->buf + 4095 - BUFFER_EXTRA;
571
- out->allocated = true;
569
+ oj_out_init(out);
572
570
  }
573
- out->cur = out->buf;
574
571
  out->circ_cnt = 0;
575
572
  out->opts = copts;
576
573
  out->hash_cnt = 0;
@@ -605,36 +602,34 @@ void oj_dump_obj_to_json_using_params(VALUE obj, Options copts, Out out, int arg
605
602
  }
606
603
 
607
604
  void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
608
- char buf[4096];
609
605
  struct _out out;
610
606
  size_t size;
611
- FILE * f;
607
+ FILE *f;
612
608
  int ok;
613
609
 
614
- out.buf = buf;
615
- out.end = buf + sizeof(buf) - BUFFER_EXTRA;
616
- out.allocated = false;
610
+ oj_out_init(&out);
611
+
617
612
  out.omit_nil = copts->dump_opts.omit_nil;
618
613
  oj_dump_obj_to_json(obj, copts, &out);
619
614
  size = out.cur - out.buf;
620
615
  if (0 == (f = fopen(path, "w"))) {
621
- if (out.allocated) {
622
- xfree(out.buf);
623
- }
616
+ oj_out_free(&out);
624
617
  rb_raise(rb_eIOError, "%s", strerror(errno));
625
618
  }
626
619
  ok = (size == fwrite(out.buf, 1, size, f));
627
- if (out.allocated) {
628
- xfree(out.buf);
629
- }
630
- fclose(f);
620
+
621
+ oj_out_free(&out);
622
+
631
623
  if (!ok) {
632
624
  int err = ferror(f);
625
+ fclose(f);
633
626
 
634
627
  rb_raise(rb_eIOError, "Write failed. [%d:%s]", err, strerror(err));
635
628
  }
629
+ fclose(f);
636
630
  }
637
631
 
632
+ #if !IS_WINDOWS
638
633
  static void write_ready(int fd) {
639
634
  struct pollfd pp;
640
635
  int i;
@@ -649,9 +644,9 @@ static void write_ready(int fd) {
649
644
  rb_raise(rb_eIOError, "write failed. %d %s.", errno, strerror(errno));
650
645
  }
651
646
  }
647
+ #endif
652
648
 
653
649
  void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
654
- char buf[4096];
655
650
  struct _out out;
656
651
  ssize_t size;
657
652
  VALUE clas = rb_obj_class(stream);
@@ -660,9 +655,8 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
660
655
  VALUE s;
661
656
  #endif
662
657
 
663
- out.buf = buf;
664
- out.end = buf + sizeof(buf) - BUFFER_EXTRA;
665
- out.allocated = false;
658
+ oj_out_init(&out);
659
+
666
660
  out.omit_nil = copts->dump_opts.omit_nil;
667
661
  oj_dump_obj_to_json(obj, copts, &out);
668
662
  size = out.cur - out.buf;
@@ -692,20 +686,17 @@ void oj_write_obj_to_stream(VALUE obj, VALUE stream, Options copts) {
692
686
  } else if (rb_respond_to(stream, oj_write_id)) {
693
687
  rb_funcall(stream, oj_write_id, 1, rb_str_new(out.buf, size));
694
688
  } else {
695
- if (out.allocated) {
696
- xfree(out.buf);
697
- }
689
+ oj_out_free(&out);
698
690
  rb_raise(rb_eArgError, "to_stream() expected an IO Object.");
699
691
  }
700
- if (out.allocated) {
701
- xfree(out.buf);
702
- }
692
+ oj_out_free(&out);
703
693
  }
704
694
 
705
695
  void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
706
- rb_encoding *enc = rb_enc_get(obj);
696
+ int idx = RB_ENCODING_GET(obj);
707
697
 
708
- if (oj_utf8_encoding != enc) {
698
+ if (oj_utf8_encoding_index != idx) {
699
+ rb_encoding *enc = rb_enc_from_index(idx);
709
700
  obj = rb_str_conv_enc(obj, enc, oj_utf8_encoding);
710
701
  }
711
702
  oj_dump_cstr(RSTRING_PTR(obj), (int)RSTRING_LEN(obj), 0, 0, out);
@@ -719,7 +710,7 @@ void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
719
710
 
720
711
  static void debug_raise(const char *orig, size_t cnt, int line) {
721
712
  char buf[1024];
722
- char * b = buf;
713
+ char *b = buf;
723
714
  const char *s = orig;
724
715
  const char *s_end = s + cnt;
725
716
 
@@ -745,11 +736,11 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
745
736
  } else {
746
737
  volatile VALUE jv;
747
738
 
748
- if (Yes == out->opts->trace) {
739
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
749
740
  oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
750
741
  }
751
742
  jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent));
752
- if (Yes == out->opts->trace) {
743
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
753
744
  oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
754
745
  }
755
746
  oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
@@ -758,7 +749,7 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
758
749
 
759
750
  void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
760
751
  size_t size;
761
- char * cmap;
752
+ char *cmap;
762
753
  const char *orig = str;
763
754
  bool has_hi = false;
764
755
 
@@ -771,6 +762,11 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
771
762
  cmap = ascii_friendly_chars;
772
763
  size = ascii_friendly_size((uint8_t *)str, cnt);
773
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;
774
770
  case XSSEsc:
775
771
  cmap = xss_friendly_chars;
776
772
  size = xss_friendly_size((uint8_t *)str, cnt);
@@ -803,10 +799,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
803
799
  *out->cur++ = '"';
804
800
 
805
801
  if (escape1) {
806
- *out->cur++ = '\\';
807
- *out->cur++ = 'u';
808
- *out->cur++ = '0';
809
- *out->cur++ = '0';
802
+ APPEND_CHARS(out->cur, "\\u00", 4);
810
803
  dump_hex((uint8_t)*str, out);
811
804
  cnt--;
812
805
  size--;
@@ -817,8 +810,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
817
810
  if (is_sym) {
818
811
  *out->cur++ = ':';
819
812
  }
820
- memcpy(out->cur, str, cnt);
821
- out->cur += cnt;
813
+ APPEND_CHARS(out->cur, str, cnt);
822
814
  *out->cur++ = '"';
823
815
  } else {
824
816
  const char *end = str + cnt;
@@ -868,10 +860,7 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
868
860
  break;
869
861
  case '6': // control characters
870
862
  if (*(uint8_t *)str < 0x80) {
871
- *out->cur++ = '\\';
872
- *out->cur++ = 'u';
873
- *out->cur++ = '0';
874
- *out->cur++ = '0';
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 &&
@@ -950,15 +939,27 @@ void oj_dump_obj_to_s(VALUE obj, Out out) {
950
939
 
951
940
  void oj_dump_raw(const char *str, size_t cnt, Out out) {
952
941
  assure_size(out, cnt + 10);
953
- memcpy(out->cur, str, cnt);
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
+ xfree(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 * buf = out->buf;
962
+ char *buf = out->buf;
962
963
 
963
964
  size *= 2;
964
965
  if (size <= len * 2 + pos) {
@@ -981,37 +982,28 @@ 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
- *out->cur++ = 'n';
985
- *out->cur++ = 'u';
986
- *out->cur++ = 'l';
987
- *out->cur++ = 'l';
985
+ APPEND_CHARS(out->cur, "null", 4);
988
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
- *out->cur++ = 't';
994
- *out->cur++ = 'r';
995
- *out->cur++ = 'u';
996
- *out->cur++ = 'e';
991
+ APPEND_CHARS(out->cur, "true", 4);
997
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
- *out->cur++ = 'f';
1003
- *out->cur++ = 'a';
1004
- *out->cur++ = 'l';
1005
- *out->cur++ = 's';
1006
- *out->cur++ = 'e';
997
+ APPEND_CHARS(out->cur, "false", 5);
1007
998
  *out->cur = '\0';
1008
999
  }
1009
1000
 
1010
1001
  void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
1011
1002
  char buf[32];
1012
1003
  char * b = buf + sizeof(buf) - 1;
1013
- long long num = rb_num2ll(obj);
1004
+ long long num = NUM2LL(obj);
1014
1005
  int neg = 0;
1006
+ size_t cnt = 0;
1015
1007
  bool dump_as_string = false;
1016
1008
 
1017
1009
  if (out->opts->int_range_max != 0 && out->opts->int_range_min != 0 &&
@@ -1042,10 +1034,9 @@ void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
1042
1034
  if (dump_as_string) {
1043
1035
  *--b = '"';
1044
1036
  }
1045
- assure_size(out, (sizeof(buf) - (b - buf)));
1046
- for (; '\0' != *b; b++) {
1047
- *out->cur++ = *b;
1048
- }
1037
+ cnt = sizeof(buf) - (b - buf) - 1;
1038
+ assure_size(out, cnt);
1039
+ APPEND_CHARS(out->cur, b, cnt);
1049
1040
  *out->cur = '\0';
1050
1041
  }
1051
1042
 
@@ -1061,8 +1052,7 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
1061
1052
  } else {
1062
1053
  assure_size(out, cnt);
1063
1054
  }
1064
- memcpy(out->cur, RSTRING_PTR(rs), cnt);
1065
- out->cur += cnt;
1055
+ APPEND_CHARS(out->cur, RSTRING_PTR(rs), cnt);
1066
1056
  if (dump_as_string) {
1067
1057
  *out->cur++ = '"';
1068
1058
  }
@@ -1072,7 +1062,7 @@ void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
1072
1062
  // Removed dependencies on math due to problems with CentOS 5.4.
1073
1063
  void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1074
1064
  char buf[64];
1075
- char * b;
1065
+ char *b;
1076
1066
  double d = rb_num2dbl(obj);
1077
1067
  int cnt = 0;
1078
1068
 
@@ -1151,7 +1141,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1151
1141
  } else if (isnan(d)) {
1152
1142
  if (ObjectMode == out->opts->mode) {
1153
1143
  strcpy(buf, nan_val);
1154
- cnt = sizeof(ninf_val) - 1;
1144
+ cnt = sizeof(nan_val) - 1;
1155
1145
  } else {
1156
1146
  NanDump nd = out->opts->dump_opts.nan_dump;
1157
1147
 
@@ -1195,9 +1185,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1195
1185
  cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, out->opts->float_fmt);
1196
1186
  }
1197
1187
  assure_size(out, cnt);
1198
- for (b = buf; '\0' != *b; b++) {
1199
- *out->cur++ = *b;
1200
- }
1188
+ APPEND_CHARS(out->cur, buf, cnt);
1201
1189
  *out->cur = '\0';
1202
1190
  }
1203
1191
 
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
- for (; 0 < cnt; cnt--) {
66
- *out->cur++ = ' ';
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 buf[32];
87
- char *b = buf + sizeof(buf) - 1;
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
- for (; '\0' != *b; b++) {
99
- *out->cur++ = *b;
100
- }
103
+ cnt = sizeof(buf) - (b - buf) - 1;
104
+ APPEND_CHARS(out->cur, b, cnt);
101
105
  *out->cur = '\0';
102
106
  }
103
107