oj 3.13.11 → 3.15.0

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