oj 3.13.9 → 3.16.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +101 -0
  3. data/README.md +13 -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 +19 -33
  10. data/ext/oj/code.h +2 -2
  11. data/ext/oj/compat.c +20 -60
  12. data/ext/oj/custom.c +76 -155
  13. data/ext/oj/debug.c +3 -9
  14. data/ext/oj/dump.c +203 -213
  15. data/ext/oj/dump.h +26 -12
  16. data/ext/oj/dump_compat.c +565 -642
  17. data/ext/oj/dump_leaf.c +17 -63
  18. data/ext/oj/dump_object.c +59 -181
  19. data/ext/oj/dump_strict.c +24 -48
  20. data/ext/oj/encoder.c +43 -0
  21. data/ext/oj/err.c +2 -13
  22. data/ext/oj/err.h +9 -12
  23. data/ext/oj/extconf.rb +18 -7
  24. data/ext/oj/fast.c +83 -108
  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 +104 -81
  30. data/ext/oj/object.c +50 -67
  31. data/ext/oj/odd.c +89 -67
  32. data/ext/oj/odd.h +15 -15
  33. data/ext/oj/oj.c +171 -106
  34. data/ext/oj/oj.h +96 -74
  35. data/ext/oj/parse.c +169 -189
  36. data/ext/oj/parse.h +23 -24
  37. data/ext/oj/parser.c +89 -34
  38. data/ext/oj/parser.h +20 -9
  39. data/ext/oj/rails.c +86 -151
  40. data/ext/oj/rails.h +1 -1
  41. data/ext/oj/reader.c +12 -15
  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 +21 -32
  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 -22
  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 +32 -69
  62. data/lib/oj/active_support_helper.rb +1 -3
  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 +162 -150
  67. data/lib/oj/mimic.rb +6 -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/JsonGem.md +15 -0
  75. data/pages/Modes.md +6 -3
  76. data/pages/Options.md +10 -0
  77. data/pages/Rails.md +12 -0
  78. data/test/_test_active.rb +8 -9
  79. data/test/_test_active_mimic.rb +7 -8
  80. data/test/_test_mimic_rails.rb +17 -20
  81. data/test/activerecord/result_test.rb +5 -6
  82. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  83. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  84. data/test/{activesupport5 → activesupport7}/encoding_test.rb +20 -34
  85. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  86. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  87. data/test/files.rb +15 -15
  88. data/test/foo.rb +15 -15
  89. data/test/helper.rb +11 -8
  90. data/test/isolated/shared.rb +3 -2
  91. data/test/json_gem/json_addition_test.rb +2 -2
  92. data/test/json_gem/json_common_interface_test.rb +8 -6
  93. data/test/json_gem/json_encoding_test.rb +0 -0
  94. data/test/json_gem/json_ext_parser_test.rb +1 -0
  95. data/test/json_gem/json_fixtures_test.rb +3 -2
  96. data/test/json_gem/json_generator_test.rb +49 -37
  97. data/test/json_gem/json_generic_object_test.rb +11 -11
  98. data/test/json_gem/json_parser_test.rb +54 -47
  99. data/test/json_gem/json_string_matching_test.rb +9 -9
  100. data/test/json_gem/test_helper.rb +7 -3
  101. data/test/mem.rb +13 -12
  102. data/test/perf.rb +21 -26
  103. data/test/perf_compat.rb +31 -33
  104. data/test/perf_dump.rb +50 -0
  105. data/test/perf_fast.rb +80 -82
  106. data/test/perf_file.rb +27 -29
  107. data/test/perf_object.rb +65 -69
  108. data/test/perf_once.rb +12 -11
  109. data/test/perf_parser.rb +42 -48
  110. data/test/perf_saj.rb +46 -54
  111. data/test/perf_scp.rb +57 -69
  112. data/test/perf_simple.rb +41 -39
  113. data/test/perf_strict.rb +68 -70
  114. data/test/perf_wab.rb +67 -69
  115. data/test/prec.rb +3 -3
  116. data/test/sample/change.rb +0 -1
  117. data/test/sample/dir.rb +0 -1
  118. data/test/sample/doc.rb +0 -1
  119. data/test/sample/file.rb +0 -1
  120. data/test/sample/group.rb +0 -1
  121. data/test/sample/hasprops.rb +0 -1
  122. data/test/sample/layer.rb +0 -1
  123. data/test/sample/rect.rb +0 -1
  124. data/test/sample/shape.rb +0 -1
  125. data/test/sample/text.rb +0 -1
  126. data/test/sample.rb +16 -16
  127. data/test/sample_json.rb +8 -8
  128. data/test/test_compat.rb +95 -43
  129. data/test/test_custom.rb +72 -51
  130. data/test/test_debian.rb +7 -10
  131. data/test/test_fast.rb +102 -87
  132. data/test/test_file.rb +41 -30
  133. data/test/test_gc.rb +16 -5
  134. data/test/test_generate.rb +5 -5
  135. data/test/test_hash.rb +4 -4
  136. data/test/test_integer_range.rb +9 -9
  137. data/test/test_null.rb +20 -20
  138. data/test/test_object.rb +85 -96
  139. data/test/test_parser.rb +6 -22
  140. data/test/test_parser_debug.rb +27 -0
  141. data/test/test_parser_saj.rb +115 -23
  142. data/test/test_parser_usual.rb +6 -6
  143. data/test/test_rails.rb +2 -2
  144. data/test/test_saj.rb +10 -8
  145. data/test/test_scp.rb +37 -39
  146. data/test/test_strict.rb +40 -32
  147. data/test/test_various.rb +163 -84
  148. data/test/test_wab.rb +48 -44
  149. data/test/test_writer.rb +47 -47
  150. data/test/tests.rb +13 -5
  151. data/test/tests_mimic.rb +12 -3
  152. data/test/tests_mimic_addition.rb +12 -3
  153. metadata +34 -144
  154. data/test/activesupport4/decoding_test.rb +0 -108
  155. data/test/activesupport4/encoding_test.rb +0 -531
  156. data/test/activesupport4/test_helper.rb +0 -41
  157. data/test/activesupport5/test_helper.rb +0 -72
  158. data/test/bar.rb +0 -16
  159. data/test/baz.rb +0 -16
  160. data/test/bug.rb +0 -16
  161. data/test/zoo.rb +0 -13
data/ext/oj/oj.c CHANGED
@@ -14,6 +14,7 @@
14
14
  #include "dump.h"
15
15
  #include "encode.h"
16
16
  #include "intern.h"
17
+ #include "mem.h"
17
18
  #include "odd.h"
18
19
  #include "parse.h"
19
20
  #include "rails.h"
@@ -21,7 +22,7 @@
21
22
  typedef struct _yesNoOpt {
22
23
  VALUE sym;
23
24
  char *attr;
24
- } * YesNoOpt;
25
+ } *YesNoOpt;
25
26
 
26
27
  void Init_oj();
27
28
 
@@ -32,6 +33,7 @@ ID oj_array_append_id;
32
33
  ID oj_array_end_id;
33
34
  ID oj_array_start_id;
34
35
  ID oj_as_json_id;
36
+ ID oj_at_id;
35
37
  ID oj_begin_id;
36
38
  ID oj_bigdecimal_id;
37
39
  ID oj_end_id;
@@ -45,7 +47,6 @@ ID oj_hash_key_id;
45
47
  ID oj_hash_set_id;
46
48
  ID oj_hash_start_id;
47
49
  ID oj_iconv_id;
48
- ID oj_instance_variables_id;
49
50
  ID oj_json_create_id;
50
51
  ID oj_length_id;
51
52
  ID oj_new_id;
@@ -90,7 +91,9 @@ VALUE oj_array_class_sym;
90
91
  VALUE oj_create_additions_sym;
91
92
  VALUE oj_decimal_class_sym;
92
93
  VALUE oj_hash_class_sym;
94
+ VALUE oj_in_sym;
93
95
  VALUE oj_indent_sym;
96
+ VALUE oj_nanosecond_sym;
94
97
  VALUE oj_object_class_sym;
95
98
  VALUE oj_quirks_mode_sym;
96
99
  VALUE oj_safe_sym;
@@ -120,6 +123,7 @@ static VALUE escape_mode_sym;
120
123
  static VALUE integer_range_sym;
121
124
  static VALUE fast_sym;
122
125
  static VALUE float_prec_sym;
126
+ static VALUE float_format_sym;
123
127
  static VALUE float_sym;
124
128
  static VALUE huge_sym;
125
129
  static VALUE ignore_sym;
@@ -132,11 +136,13 @@ static VALUE newline_sym;
132
136
  static VALUE nilnil_sym;
133
137
  static VALUE null_sym;
134
138
  static VALUE object_sym;
139
+ static VALUE omit_null_byte_sym;
135
140
  static VALUE omit_nil_sym;
136
141
  static VALUE rails_sym;
137
142
  static VALUE raise_sym;
138
143
  static VALUE ruby_sym;
139
144
  static VALUE sec_prec_sym;
145
+ static VALUE slash_sym;
140
146
  static VALUE strict_sym;
141
147
  static VALUE symbol_keys_sym;
142
148
  static VALUE time_format_sym;
@@ -152,7 +158,8 @@ static VALUE word_sym;
152
158
  static VALUE xmlschema_sym;
153
159
  static VALUE xss_safe_sym;
154
160
 
155
- rb_encoding *oj_utf8_encoding = 0;
161
+ rb_encoding *oj_utf8_encoding = 0;
162
+ int oj_utf8_encoding_index = 0;
156
163
 
157
164
  #ifdef HAVE_PTHREAD_MUTEX_INIT
158
165
  pthread_mutex_t oj_cache_mutex;
@@ -217,6 +224,7 @@ struct _options oj_default_options = {
217
224
  0, // array_size
218
225
  AutoNan, // nan_dump
219
226
  false, // omit_nil
227
+ false, // omit_null_byte
220
228
  MAX_DEPTH, // max_depth
221
229
  },
222
230
  {
@@ -225,7 +233,7 @@ struct _options oj_default_options = {
225
233
  NULL, // tail
226
234
  {'\0'}, // err
227
235
  },
228
- NULL, // ignore
236
+ NULL,
229
237
  };
230
238
 
231
239
  /* Document-method: default_options()
@@ -239,7 +247,7 @@ struct _options oj_default_options = {
239
247
  *references
240
248
  * - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist
241
249
  * - *:symbol_keys* [_Boolean_|_nil_] use symbols instead of strings for hash keys
242
- * - *:escape_mode* [_:newline_|_:json_|_:xss_safe_|_:ascii_|_unicode_xss_|_nil_] determines the
250
+ * - *:escape_mode* [_:newline_|_:json_|_:slash_|_:xss_safe_|_:ascii_|_:unicode_xss_|_nil_] determines the
243
251
  *characters to escape
244
252
  * - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing (if dynamically modifying
245
253
  *classes or reloading classes then don't use this)
@@ -247,7 +255,7 @@ struct _options oj_default_options = {
247
255
  *to use for JSON
248
256
  * - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
249
257
  * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String
250
- * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_] load decimals as BigDecimal instead
258
+ * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_|_:ruby_] load decimals as BigDecimal instead
251
259
  *of as a Float. :auto pick the most precise for the number of digits. :float should be the same as
252
260
  *ruby. :fast may require rounding but is must faster.
253
261
  * - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead of as a Float when in
@@ -260,6 +268,8 @@ struct _options oj_default_options = {
260
268
  *seconds portion of time
261
269
  * - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping floats, 0
262
270
  *indicates use Ruby
271
+ * - *:float_format* [_String_] the C printf format string for printing floats. Default follows
272
+ * the float_precision and will be changed if float_precision is changed. The string can be no more than 6 bytes.
263
273
  * - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false
264
274
  * - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false
265
275
  * - *:use_raw_json* [_Boolean_|_nil_] call raw_json() methods on dump, default is false
@@ -286,6 +296,7 @@ struct _options oj_default_options = {
286
296
  *used
287
297
  * - *:array_class* [_Class_|_nil_] Class to use instead of Array on load
288
298
  * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted
299
+ * - *:omit_null_byte* [_true_|_false_] if true null bytes in strings will be omitted when dumping
289
300
  * - *:ignore* [_nil_|_Array_] either nil or an Array of classes to ignore when dumping
290
301
  * - *:ignore_under* [_Boolean_] if true then attributes that start with _ are ignored when dumping in
291
302
  *object or custom mode.
@@ -370,6 +381,7 @@ static VALUE get_def_opts(VALUE self) {
370
381
  oj_safe_sym,
371
382
  (Yes == oj_default_options.safe) ? Qtrue : ((No == oj_default_options.safe) ? Qfalse : Qnil));
372
383
  rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec));
384
+ rb_hash_aset(opts, float_format_sym, rb_str_new_cstr(oj_default_options.float_fmt));
373
385
  rb_hash_aset(opts, cache_str_sym, INT2FIX(oj_default_options.cache_str));
374
386
  rb_hash_aset(
375
387
  opts,
@@ -379,6 +391,7 @@ static VALUE get_def_opts(VALUE self) {
379
391
  opts,
380
392
  cache_keys_sym,
381
393
  (Yes == oj_default_options.cache_keys) ? Qtrue : ((No == oj_default_options.cache_keys) ? Qfalse : Qnil));
394
+
382
395
  switch (oj_default_options.mode) {
383
396
  case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
384
397
  case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
@@ -404,6 +417,7 @@ static VALUE get_def_opts(VALUE self) {
404
417
  switch (oj_default_options.escape_mode) {
405
418
  case NLEsc: rb_hash_aset(opts, escape_mode_sym, newline_sym); break;
406
419
  case JSONEsc: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
420
+ case SlashEsc: rb_hash_aset(opts, escape_mode_sym, slash_sym); break;
407
421
  case XSSEsc: rb_hash_aset(opts, escape_mode_sym, xss_safe_sym); break;
408
422
  case ASCIIEsc: rb_hash_aset(opts, escape_mode_sym, ascii_sym); break;
409
423
  case JXEsc: rb_hash_aset(opts, escape_mode_sym, unicode_xss_sym); break;
@@ -453,13 +467,14 @@ static VALUE get_def_opts(VALUE self) {
453
467
  default: rb_hash_aset(opts, nan_sym, auto_sym); break;
454
468
  }
455
469
  rb_hash_aset(opts, omit_nil_sym, oj_default_options.dump_opts.omit_nil ? Qtrue : Qfalse);
470
+ rb_hash_aset(opts, omit_null_byte_sym, oj_default_options.dump_opts.omit_null_byte ? Qtrue : Qfalse);
456
471
  rb_hash_aset(opts, oj_hash_class_sym, oj_default_options.hash_class);
457
472
  rb_hash_aset(opts, oj_array_class_sym, oj_default_options.array_class);
458
473
 
459
474
  if (NULL == oj_default_options.ignore) {
460
475
  rb_hash_aset(opts, ignore_sym, Qnil);
461
476
  } else {
462
- VALUE * vp;
477
+ VALUE *vp;
463
478
  volatile VALUE a = rb_ary_new();
464
479
 
465
480
  for (vp = oj_default_options.ignore; Qnil != *vp; vp++) {
@@ -508,6 +523,8 @@ static VALUE get_def_opts(VALUE self) {
508
523
  *load.
509
524
  * - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal when dumping the
510
525
  *seconds portion of time.
526
+ * - *:float_format* [_String_] the C printf format string for printing floats. Default follows
527
+ * the float_precision and will be changed if float_precision is changed. The string can be no more than 6 bytes.
511
528
  * - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping floats, 0
512
529
  *indicates use Ruby.
513
530
  * - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false.
@@ -606,7 +623,6 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
606
623
  if (set_yesno_options(k, v, copts)) {
607
624
  return ST_CONTINUE;
608
625
  }
609
-
610
626
  if (oj_indent_sym == k) {
611
627
  switch (rb_type(v)) {
612
628
  case T_NIL:
@@ -634,15 +650,9 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
634
650
  } else if (float_prec_sym == k) {
635
651
  int n;
636
652
 
637
- #ifdef RUBY_INTEGER_UNIFICATION
638
653
  if (rb_cInteger != rb_obj_class(v)) {
639
654
  rb_raise(rb_eArgError, ":float_precision must be a Integer.");
640
655
  }
641
- #else
642
- if (T_FIXNUM != rb_type(v)) {
643
- rb_raise(rb_eArgError, ":float_precision must be a Fixnum.");
644
- }
645
- #endif
646
656
  n = FIX2INT(v);
647
657
  if (0 >= n) {
648
658
  *copts->float_fmt = '\0';
@@ -657,15 +667,9 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
657
667
  } else if (cache_str_sym == k || cache_string_sym == k) {
658
668
  int n;
659
669
 
660
- #ifdef RUBY_INTEGER_UNIFICATION
661
670
  if (rb_cInteger != rb_obj_class(v)) {
662
671
  rb_raise(rb_eArgError, ":cache_str must be a Integer.");
663
672
  }
664
- #else
665
- if (T_FIXNUM != rb_type(v)) {
666
- rb_raise(rb_eArgError, ":cache_str must be a Fixnum.");
667
- }
668
- #endif
669
673
  n = FIX2INT(v);
670
674
  if (0 >= n) {
671
675
  copts->cache_str = 0;
@@ -678,15 +682,9 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
678
682
  } else if (sec_prec_sym == k) {
679
683
  int n;
680
684
 
681
- #ifdef RUBY_INTEGER_UNIFICATION
682
685
  if (rb_cInteger != rb_obj_class(v)) {
683
686
  rb_raise(rb_eArgError, ":second_precision must be a Integer.");
684
687
  }
685
- #else
686
- if (T_FIXNUM != rb_type(v)) {
687
- rb_raise(rb_eArgError, ":second_precision must be a Fixnum.");
688
- }
689
- #endif
690
688
  n = NUM2INT(v);
691
689
  if (0 > n) {
692
690
  n = 0;
@@ -733,6 +731,8 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
733
731
  copts->escape_mode = NLEsc;
734
732
  } else if (json_sym == v) {
735
733
  copts->escape_mode = JSONEsc;
734
+ } else if (slash_sym == v) {
735
+ copts->escape_mode = SlashEsc;
736
736
  } else if (xss_safe_sym == v) {
737
737
  copts->escape_mode = XSSEsc;
738
738
  } else if (ascii_sym == v) {
@@ -762,7 +762,6 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
762
762
  if (Qnil == v) {
763
763
  return ST_CONTINUE;
764
764
  }
765
-
766
765
  copts->compat_bigdec = (Qtrue == v);
767
766
  } else if (oj_decimal_class_sym == k) {
768
767
  if (rb_cFloat == v) {
@@ -775,7 +774,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
775
774
  } else if (create_id_sym == k) {
776
775
  if (Qnil == v) {
777
776
  if (oj_json_class != oj_default_options.create_id && NULL != copts->create_id) {
778
- xfree((char *)oj_default_options.create_id);
777
+ OJ_R_FREE((char *)oj_default_options.create_id);
779
778
  }
780
779
  copts->create_id = NULL;
781
780
  copts->create_id_len = 0;
@@ -784,7 +783,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
784
783
 
785
784
  len = RSTRING_LEN(v);
786
785
  if (len != copts->create_id_len || 0 != strcmp(copts->create_id, str)) {
787
- copts->create_id = ALLOC_N(char, len + 1);
786
+ copts->create_id = OJ_R_ALLOC_N(char, len + 1);
788
787
  strcpy((char *)copts->create_id, str);
789
788
  copts->create_id_len = len;
790
789
  }
@@ -875,6 +874,17 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
875
874
  } else {
876
875
  rb_raise(rb_eArgError, ":omit_nil must be true or false.");
877
876
  }
877
+ } else if (omit_null_byte_sym == k) {
878
+ if (Qnil == v) {
879
+ return ST_CONTINUE;
880
+ }
881
+ if (Qtrue == v) {
882
+ copts->dump_opts.omit_null_byte = true;
883
+ } else if (Qfalse == v) {
884
+ copts->dump_opts.omit_null_byte = false;
885
+ } else {
886
+ rb_raise(rb_eArgError, ":omit_null_byte must be true or false.");
887
+ }
878
888
  } else if (oj_ascii_only_sym == k) {
879
889
  // This is here only for backwards compatibility with the original Oj.
880
890
  if (Qtrue == v) {
@@ -904,7 +914,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
904
914
  copts->array_class = v;
905
915
  }
906
916
  } else if (ignore_sym == k) {
907
- xfree(copts->ignore);
917
+ OJ_R_FREE(copts->ignore);
908
918
  copts->ignore = NULL;
909
919
  if (Qnil != v) {
910
920
  int cnt;
@@ -914,9 +924,9 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
914
924
  if (0 < cnt) {
915
925
  int i;
916
926
 
917
- copts->ignore = ALLOC_N(VALUE, cnt + 1);
927
+ copts->ignore = OJ_R_ALLOC_N(VALUE, cnt + 1);
918
928
  for (i = 0; i < cnt; i++) {
919
- copts->ignore[i] = rb_ary_entry(v, i);
929
+ copts->ignore[i] = RARRAY_AREF(v, i);
920
930
  }
921
931
  copts->ignore[i] = Qnil;
922
932
  }
@@ -925,7 +935,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
925
935
  if (Qnil == v) {
926
936
  return ST_CONTINUE;
927
937
  }
928
- if (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) {
938
+ if (rb_obj_class(v) == rb_cRange) {
929
939
  VALUE min = rb_funcall(v, oj_begin_id, 0);
930
940
  VALUE max = rb_funcall(v, oj_end_id, 0);
931
941
 
@@ -942,7 +952,26 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
942
952
  if (Qnil == v) {
943
953
  return ST_CONTINUE;
944
954
  }
945
- copts->sym_key = (Qtrue == v) ? Yes : No;
955
+ copts->sym_key = (Qtrue == v) ? Yes : No;
956
+
957
+ } else if (oj_max_nesting_sym == k) {
958
+ if (Qtrue == v) {
959
+ copts->dump_opts.max_depth = 100;
960
+ } else if (Qfalse == v || Qnil == v) {
961
+ copts->dump_opts.max_depth = MAX_DEPTH;
962
+ } else if (T_FIXNUM == rb_type(v)) {
963
+ copts->dump_opts.max_depth = NUM2INT(v);
964
+ if (0 >= copts->dump_opts.max_depth) {
965
+ copts->dump_opts.max_depth = MAX_DEPTH;
966
+ }
967
+ }
968
+ } else if (float_format_sym == k) {
969
+ rb_check_type(v, T_STRING);
970
+ if (6 < (int)RSTRING_LEN(v)) {
971
+ rb_raise(rb_eArgError, ":float_format must be 6 bytes or less.");
972
+ }
973
+ strncpy(copts->float_fmt, RSTRING_PTR(v), (size_t)RSTRING_LEN(v));
974
+ copts->float_fmt[RSTRING_LEN(v)] = '\0';
946
975
  }
947
976
  return ST_CONTINUE;
948
977
  }
@@ -951,7 +980,6 @@ void oj_parse_options(VALUE ropts, Options copts) {
951
980
  if (T_HASH != rb_type(ropts)) {
952
981
  return;
953
982
  }
954
-
955
983
  rb_hash_foreach(ropts, parse_options_cb, (VALUE)copts);
956
984
  oj_parse_opt_match_string(&copts->str_rx, ropts);
957
985
 
@@ -1107,7 +1135,7 @@ static VALUE load(int argc, VALUE *argv, VALUE self) {
1107
1135
  * Returns [_Object_|_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
1108
1136
  */
1109
1137
  static VALUE load_file(int argc, VALUE *argv, VALUE self) {
1110
- char * path;
1138
+ char *path;
1111
1139
  int fd;
1112
1140
  Mode mode = oj_default_options.mode;
1113
1141
  struct _parseInfo pi;
@@ -1115,7 +1143,7 @@ static VALUE load_file(int argc, VALUE *argv, VALUE self) {
1115
1143
  if (1 > argc) {
1116
1144
  rb_raise(rb_eArgError, "Wrong number of arguments to load().");
1117
1145
  }
1118
- Check_Type(*argv, T_STRING);
1146
+ path = StringValuePtr(*argv);
1119
1147
  parse_info_init(&pi);
1120
1148
  pi.options = oj_default_options;
1121
1149
  pi.handler = Qnil;
@@ -1146,8 +1174,17 @@ static VALUE load_file(int argc, VALUE *argv, VALUE self) {
1146
1174
  }
1147
1175
  }
1148
1176
  }
1149
- path = StringValuePtr(*argv);
1150
- if (0 == (fd = open(path, O_RDONLY))) {
1177
+ #ifdef _WIN32
1178
+ {
1179
+ WCHAR *wide_path;
1180
+ wide_path = rb_w32_mbstr_to_wstr(CP_UTF8, path, -1, NULL);
1181
+ fd = rb_w32_wopen(wide_path, O_RDONLY);
1182
+ OJ_FREE(wide_path);
1183
+ }
1184
+ #else
1185
+ fd = open(path, O_RDONLY);
1186
+ #endif
1187
+ if (0 == fd) {
1151
1188
  rb_raise(rb_eIOError, "%s", strerror(errno));
1152
1189
  }
1153
1190
  switch (mode) {
@@ -1220,10 +1257,10 @@ static VALUE safe_load(VALUE self, VALUE doc) {
1220
1257
  */
1221
1258
 
1222
1259
  struct dump_arg {
1223
- struct _out * out;
1260
+ struct _out *out;
1224
1261
  struct _options *copts;
1225
1262
  int argc;
1226
- VALUE * argv;
1263
+ VALUE *argv;
1227
1264
  };
1228
1265
 
1229
1266
  static VALUE dump_body(VALUE a) {
@@ -1243,9 +1280,8 @@ static VALUE dump_body(VALUE a) {
1243
1280
  static VALUE dump_ensure(VALUE a) {
1244
1281
  volatile struct dump_arg *arg = (void *)a;
1245
1282
 
1246
- if (arg->out->allocated) {
1247
- xfree(arg->out->buf);
1248
- }
1283
+ oj_out_free(arg->out);
1284
+
1249
1285
  return Qnil;
1250
1286
  }
1251
1287
 
@@ -1257,7 +1293,6 @@ static VALUE dump_ensure(VALUE a) {
1257
1293
  * - *options* [_Hash_] same as default_options
1258
1294
  */
1259
1295
  static VALUE dump(int argc, VALUE *argv, VALUE self) {
1260
- char buf[4096];
1261
1296
  struct dump_arg arg;
1262
1297
  struct _out out;
1263
1298
  struct _options copts = oj_default_options;
@@ -1279,11 +1314,10 @@ static VALUE dump(int argc, VALUE *argv, VALUE self) {
1279
1314
  arg.argc = argc;
1280
1315
  arg.argv = argv;
1281
1316
 
1282
- arg.out->buf = buf;
1283
- arg.out->end = buf + sizeof(buf) - 10;
1284
- arg.out->allocated = false;
1285
- arg.out->omit_nil = copts.dump_opts.omit_nil;
1286
- arg.out->caller = CALLER_DUMP;
1317
+ oj_out_init(arg.out);
1318
+
1319
+ arg.out->omit_nil = copts.dump_opts.omit_nil;
1320
+ arg.out->omit_null_byte = copts.dump_opts.omit_null_byte;
1287
1321
 
1288
1322
  return rb_ensure(dump_body, (VALUE)&arg, dump_ensure, (VALUE)&arg);
1289
1323
  }
@@ -1295,8 +1329,9 @@ static VALUE dump(int argc, VALUE *argv, VALUE self) {
1295
1329
  * will be called. The mode is set to :compat.
1296
1330
  * - *obj* [_Object_] Object to serialize as an JSON document String
1297
1331
  * - *options* [_Hash_]
1298
- * - *:max_nesting* [_boolean_] It true nesting is limited to 100. The option to detect circular
1299
- * references is available but is not compatible with the json gem., default is false
1332
+ * - *:max_nesting* [_Fixnum_|_boolean_] It true nesting is limited to 100. If a Fixnum nesting
1333
+ * is set to the provided value. The option to detect circular references is available but is not
1334
+ * compatible with the json gem., default is false or unlimited.
1300
1335
  * - *:allow_nan* [_boolean_] If true non JSON compliant words such as Nan and Infinity will be
1301
1336
  * used as appropriate, default is true.
1302
1337
  * - *:quirks_mode* [_boolean_] Allow single JSON values instead of documents, default is true
@@ -1313,7 +1348,6 @@ static VALUE dump(int argc, VALUE *argv, VALUE self) {
1313
1348
  * Returns [_String_] the encoded JSON.
1314
1349
  */
1315
1350
  static VALUE to_json(int argc, VALUE *argv, VALUE self) {
1316
- char buf[4096];
1317
1351
  struct _out out;
1318
1352
  struct _options copts = oj_default_options;
1319
1353
  VALUE rstr;
@@ -1328,10 +1362,11 @@ static VALUE to_json(int argc, VALUE *argv, VALUE self) {
1328
1362
  }
1329
1363
  copts.mode = CompatMode;
1330
1364
  copts.to_json = Yes;
1331
- out.buf = buf;
1332
- out.end = buf + sizeof(buf) - 10;
1333
- out.allocated = false;
1334
- out.omit_nil = copts.dump_opts.omit_nil;
1365
+
1366
+ oj_out_init(&out);
1367
+
1368
+ out.omit_nil = copts.dump_opts.omit_nil;
1369
+ out.omit_null_byte = copts.dump_opts.omit_null_byte;
1335
1370
  // For obj.to_json or generate nan is not allowed but if called from dump
1336
1371
  // it is.
1337
1372
  oj_dump_obj_to_json_using_params(*argv, &copts, &out, argc - 1, argv + 1);
@@ -1341,9 +1376,9 @@ static VALUE to_json(int argc, VALUE *argv, VALUE self) {
1341
1376
  }
1342
1377
  rstr = rb_str_new2(out.buf);
1343
1378
  rstr = oj_encode(rstr);
1344
- if (out.allocated) {
1345
- xfree(out.buf);
1346
- }
1379
+
1380
+ oj_out_free(&out);
1381
+
1347
1382
  return rstr;
1348
1383
  }
1349
1384
 
@@ -1363,7 +1398,6 @@ static VALUE to_file(int argc, VALUE *argv, VALUE self) {
1363
1398
  if (3 == argc) {
1364
1399
  oj_parse_options(argv[2], &copts);
1365
1400
  }
1366
- Check_Type(*argv, T_STRING);
1367
1401
  oj_write_obj_to_file(argv[1], StringValuePtr(*argv), &copts);
1368
1402
 
1369
1403
  return Qnil;
@@ -1703,6 +1737,18 @@ static VALUE protect_require(VALUE x) {
1703
1737
  return Qnil;
1704
1738
  }
1705
1739
 
1740
+ extern void print_all_odds(const char *label);
1741
+
1742
+ static VALUE debug_odd(VALUE self, VALUE label) {
1743
+ print_all_odds(RSTRING_PTR(label));
1744
+ return Qnil;
1745
+ }
1746
+
1747
+ static VALUE mem_report(VALUE self) {
1748
+ oj_mem_report();
1749
+ return Qnil;
1750
+ }
1751
+
1706
1752
  /* Document-module: Oj
1707
1753
  *
1708
1754
  * Optimized JSON (Oj), as the name implies was written to provide speed
@@ -1731,15 +1777,19 @@ static VALUE protect_require(VALUE x) {
1731
1777
  *
1732
1778
  * - *:wab* specifically for WAB data exchange.
1733
1779
  */
1734
- void Init_oj() {
1780
+ void Init_oj(void) {
1735
1781
  int err = 0;
1736
1782
 
1737
1783
  #if HAVE_RB_EXT_RACTOR_SAFE
1738
1784
  rb_ext_ractor_safe(true);
1739
1785
  #endif
1740
1786
  Oj = rb_define_module("Oj");
1787
+ rb_gc_register_address(&Oj);
1741
1788
 
1742
1789
  oj_cstack_class = rb_define_class_under(Oj, "CStack", rb_cObject);
1790
+ rb_gc_register_address(&oj_cstack_class);
1791
+
1792
+ rb_undef_alloc_func(oj_cstack_class);
1743
1793
 
1744
1794
  oj_string_writer_init();
1745
1795
  oj_stream_writer_init();
@@ -1748,9 +1798,11 @@ void Init_oj() {
1748
1798
  // On Rubinius the require fails but can be done from a ruby file.
1749
1799
  rb_protect(protect_require, Qnil, &err);
1750
1800
  rb_require("stringio");
1751
- oj_utf8_encoding = rb_enc_find("UTF-8");
1801
+ oj_utf8_encoding_index = rb_enc_find_index("UTF-8");
1802
+ oj_utf8_encoding = rb_enc_from_index(oj_utf8_encoding_index);
1752
1803
 
1753
1804
  // rb_define_module_function(Oj, "hash_test", hash_test, 0);
1805
+ rb_define_module_function(Oj, "debug_odd", debug_odd, 1);
1754
1806
 
1755
1807
  rb_define_module_function(Oj, "default_options", get_def_opts, 0);
1756
1808
  rb_define_module_function(Oj, "default_options=", set_def_opts, 1);
@@ -1784,49 +1836,51 @@ void Init_oj() {
1784
1836
 
1785
1837
  rb_define_module_function(Oj, "optimize_rails", oj_optimize_rails, 0);
1786
1838
 
1787
- oj_add_value_id = rb_intern("add_value");
1788
- oj_array_append_id = rb_intern("array_append");
1789
- oj_array_end_id = rb_intern("array_end");
1790
- oj_array_start_id = rb_intern("array_start");
1791
- oj_as_json_id = rb_intern("as_json");
1792
- oj_begin_id = rb_intern("begin");
1793
- oj_bigdecimal_id = rb_intern("BigDecimal");
1794
- oj_end_id = rb_intern("end");
1795
- oj_error_id = rb_intern("error");
1796
- oj_exclude_end_id = rb_intern("exclude_end?");
1797
- oj_file_id = rb_intern("file?");
1798
- oj_fileno_id = rb_intern("fileno");
1799
- oj_ftype_id = rb_intern("ftype");
1800
- oj_hash_end_id = rb_intern("hash_end");
1801
- oj_hash_key_id = rb_intern("hash_key");
1802
- oj_hash_set_id = rb_intern("hash_set");
1803
- oj_hash_start_id = rb_intern("hash_start");
1804
- oj_iconv_id = rb_intern("iconv");
1805
- oj_instance_variables_id = rb_intern("instance_variables");
1806
- oj_json_create_id = rb_intern("json_create");
1807
- oj_length_id = rb_intern("length");
1808
- oj_new_id = rb_intern("new");
1809
- oj_parse_id = rb_intern("parse");
1810
- oj_pos_id = rb_intern("pos");
1811
- oj_raw_json_id = rb_intern("raw_json");
1812
- oj_read_id = rb_intern("read");
1813
- oj_readpartial_id = rb_intern("readpartial");
1814
- oj_replace_id = rb_intern("replace");
1815
- oj_stat_id = rb_intern("stat");
1816
- oj_string_id = rb_intern("string");
1817
- oj_to_h_id = rb_intern("to_h");
1818
- oj_to_hash_id = rb_intern("to_hash");
1819
- oj_to_json_id = rb_intern("to_json");
1820
- oj_to_s_id = rb_intern("to_s");
1821
- oj_to_sym_id = rb_intern("to_sym");
1822
- oj_to_time_id = rb_intern("to_time");
1823
- oj_tv_nsec_id = rb_intern("tv_nsec");
1824
- oj_tv_sec_id = rb_intern("tv_sec");
1825
- oj_tv_usec_id = rb_intern("tv_usec");
1826
- oj_utc_id = rb_intern("utc");
1827
- oj_utc_offset_id = rb_intern("utc_offset");
1828
- oj_utcq_id = rb_intern("utc?");
1829
- oj_write_id = rb_intern("write");
1839
+ rb_define_module_function(Oj, "mem_report", mem_report, 0);
1840
+
1841
+ oj_add_value_id = rb_intern("add_value");
1842
+ oj_array_append_id = rb_intern("array_append");
1843
+ oj_array_end_id = rb_intern("array_end");
1844
+ oj_array_start_id = rb_intern("array_start");
1845
+ oj_as_json_id = rb_intern("as_json");
1846
+ oj_at_id = rb_intern("at");
1847
+ oj_begin_id = rb_intern("begin");
1848
+ oj_bigdecimal_id = rb_intern("BigDecimal");
1849
+ oj_end_id = rb_intern("end");
1850
+ oj_error_id = rb_intern("error");
1851
+ oj_exclude_end_id = rb_intern("exclude_end?");
1852
+ oj_file_id = rb_intern("file?");
1853
+ oj_fileno_id = rb_intern("fileno");
1854
+ oj_ftype_id = rb_intern("ftype");
1855
+ oj_hash_end_id = rb_intern("hash_end");
1856
+ oj_hash_key_id = rb_intern("hash_key");
1857
+ oj_hash_set_id = rb_intern("hash_set");
1858
+ oj_hash_start_id = rb_intern("hash_start");
1859
+ oj_iconv_id = rb_intern("iconv");
1860
+ oj_json_create_id = rb_intern("json_create");
1861
+ oj_length_id = rb_intern("length");
1862
+ oj_new_id = rb_intern("new");
1863
+ oj_parse_id = rb_intern("parse");
1864
+ oj_pos_id = rb_intern("pos");
1865
+ oj_raw_json_id = rb_intern("raw_json");
1866
+ oj_read_id = rb_intern("read");
1867
+ oj_readpartial_id = rb_intern("readpartial");
1868
+ oj_replace_id = rb_intern("replace");
1869
+ oj_stat_id = rb_intern("stat");
1870
+ oj_string_id = rb_intern("string");
1871
+ oj_to_h_id = rb_intern("to_h");
1872
+ oj_to_hash_id = rb_intern("to_hash");
1873
+ oj_to_json_id = rb_intern("to_json");
1874
+ oj_to_s_id = rb_intern("to_s");
1875
+ oj_to_sym_id = rb_intern("to_sym");
1876
+ oj_to_time_id = rb_intern("to_time");
1877
+ oj_tv_nsec_id = rb_intern("tv_nsec");
1878
+ oj_tv_sec_id = rb_intern("tv_sec");
1879
+ oj_tv_usec_id = rb_intern("tv_usec");
1880
+ oj_utc_id = rb_intern("utc");
1881
+ oj_utc_offset_id = rb_intern("utc_offset");
1882
+ oj_utcq_id = rb_intern("utc?");
1883
+ oj_write_id = rb_intern("write");
1830
1884
 
1831
1885
  rb_require("oj/bag");
1832
1886
  rb_require("oj/error");
@@ -1897,6 +1951,8 @@ void Init_oj() {
1897
1951
  rb_gc_register_address(&integer_range_sym);
1898
1952
  fast_sym = ID2SYM(rb_intern("fast"));
1899
1953
  rb_gc_register_address(&fast_sym);
1954
+ float_format_sym = ID2SYM(rb_intern("float_format"));
1955
+ rb_gc_register_address(&float_format_sym);
1900
1956
  float_prec_sym = ID2SYM(rb_intern("float_precision"));
1901
1957
  rb_gc_register_address(&float_prec_sym);
1902
1958
  float_sym = ID2SYM(rb_intern("float"));
@@ -1937,10 +1993,14 @@ void Init_oj() {
1937
1993
  rb_gc_register_address(&oj_decimal_class_sym);
1938
1994
  oj_hash_class_sym = ID2SYM(rb_intern("hash_class"));
1939
1995
  rb_gc_register_address(&oj_hash_class_sym);
1996
+ oj_in_sym = ID2SYM(rb_intern("in"));
1997
+ rb_gc_register_address(&oj_in_sym);
1940
1998
  oj_indent_sym = ID2SYM(rb_intern("indent"));
1941
1999
  rb_gc_register_address(&oj_indent_sym);
1942
2000
  oj_max_nesting_sym = ID2SYM(rb_intern("max_nesting"));
1943
2001
  rb_gc_register_address(&oj_max_nesting_sym);
2002
+ oj_nanosecond_sym = ID2SYM(rb_intern("nanosecond"));
2003
+ rb_gc_register_address(&oj_nanosecond_sym);
1944
2004
  oj_object_class_sym = ID2SYM(rb_intern("object_class"));
1945
2005
  rb_gc_register_address(&oj_object_class_sym);
1946
2006
  oj_object_nl_sym = ID2SYM(rb_intern("object_nl"));
@@ -1949,6 +2009,8 @@ void Init_oj() {
1949
2009
  rb_gc_register_address(&oj_quirks_mode_sym);
1950
2010
  oj_safe_sym = ID2SYM(rb_intern("safe"));
1951
2011
  rb_gc_register_address(&oj_safe_sym);
2012
+ omit_null_byte_sym = ID2SYM(rb_intern("omit_null_byte"));
2013
+ rb_gc_register_address(&omit_null_byte_sym);
1952
2014
  oj_space_before_sym = ID2SYM(rb_intern("space_before"));
1953
2015
  rb_gc_register_address(&oj_space_before_sym);
1954
2016
  oj_space_sym = ID2SYM(rb_intern("space"));
@@ -1965,6 +2027,8 @@ void Init_oj() {
1965
2027
  rb_gc_register_address(&ruby_sym);
1966
2028
  sec_prec_sym = ID2SYM(rb_intern("second_precision"));
1967
2029
  rb_gc_register_address(&sec_prec_sym);
2030
+ slash_sym = ID2SYM(rb_intern("slash"));
2031
+ rb_gc_register_address(&slash_sym);
1968
2032
  strict_sym = ID2SYM(rb_intern("strict"));
1969
2033
  rb_gc_register_address(&strict_sym);
1970
2034
  symbol_keys_sym = ID2SYM(rb_intern("symbol_keys"));
@@ -2017,4 +2081,5 @@ void Init_oj() {
2017
2081
  oj_init_doc();
2018
2082
 
2019
2083
  oj_parser_init();
2084
+ oj_scanner_init();
2020
2085
  }