oj 3.13.9 → 3.16.1

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 (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
  }