oj 3.11.5 → 3.16.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1421 -0
  3. data/README.md +19 -5
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +20 -6
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +10 -9
  9. data/ext/oj/circarray.c +8 -6
  10. data/ext/oj/circarray.h +2 -2
  11. data/ext/oj/code.c +19 -33
  12. data/ext/oj/code.h +2 -2
  13. data/ext/oj/compat.c +27 -77
  14. data/ext/oj/custom.c +86 -179
  15. data/ext/oj/debug.c +126 -0
  16. data/ext/oj/dump.c +256 -249
  17. data/ext/oj/dump.h +26 -12
  18. data/ext/oj/dump_compat.c +565 -642
  19. data/ext/oj/dump_leaf.c +17 -63
  20. data/ext/oj/dump_object.c +65 -187
  21. data/ext/oj/dump_strict.c +27 -51
  22. data/ext/oj/encoder.c +43 -0
  23. data/ext/oj/err.c +2 -13
  24. data/ext/oj/err.h +24 -8
  25. data/ext/oj/extconf.rb +21 -6
  26. data/ext/oj/fast.c +149 -149
  27. data/ext/oj/intern.c +313 -0
  28. data/ext/oj/intern.h +22 -0
  29. data/ext/oj/mem.c +318 -0
  30. data/ext/oj/mem.h +53 -0
  31. data/ext/oj/mimic_json.c +121 -106
  32. data/ext/oj/object.c +85 -162
  33. data/ext/oj/odd.c +89 -67
  34. data/ext/oj/odd.h +15 -15
  35. data/ext/oj/oj.c +542 -411
  36. data/ext/oj/oj.h +99 -73
  37. data/ext/oj/parse.c +175 -187
  38. data/ext/oj/parse.h +26 -24
  39. data/ext/oj/parser.c +1600 -0
  40. data/ext/oj/parser.h +101 -0
  41. data/ext/oj/rails.c +112 -159
  42. data/ext/oj/rails.h +1 -1
  43. data/ext/oj/reader.c +11 -14
  44. data/ext/oj/reader.h +4 -2
  45. data/ext/oj/resolve.c +5 -24
  46. data/ext/oj/rxclass.c +7 -6
  47. data/ext/oj/rxclass.h +1 -1
  48. data/ext/oj/saj.c +22 -33
  49. data/ext/oj/saj2.c +584 -0
  50. data/ext/oj/saj2.h +23 -0
  51. data/ext/oj/scp.c +5 -28
  52. data/ext/oj/sparse.c +28 -72
  53. data/ext/oj/stream_writer.c +50 -40
  54. data/ext/oj/strict.c +56 -61
  55. data/ext/oj/string_writer.c +72 -39
  56. data/ext/oj/trace.h +31 -4
  57. data/ext/oj/usual.c +1218 -0
  58. data/ext/oj/usual.h +69 -0
  59. data/ext/oj/util.h +1 -1
  60. data/ext/oj/val_stack.c +14 -3
  61. data/ext/oj/val_stack.h +8 -7
  62. data/ext/oj/validate.c +46 -0
  63. data/ext/oj/wab.c +63 -88
  64. data/lib/oj/active_support_helper.rb +1 -3
  65. data/lib/oj/bag.rb +7 -1
  66. data/lib/oj/easy_hash.rb +4 -5
  67. data/lib/oj/error.rb +1 -2
  68. data/lib/oj/json.rb +162 -150
  69. data/lib/oj/mimic.rb +9 -7
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/schandler.rb +5 -4
  72. data/lib/oj/state.rb +12 -8
  73. data/lib/oj/version.rb +1 -2
  74. data/lib/oj.rb +2 -0
  75. data/pages/Compatibility.md +1 -1
  76. data/pages/InstallOptions.md +20 -0
  77. data/pages/JsonGem.md +15 -0
  78. data/pages/Modes.md +8 -3
  79. data/pages/Options.md +43 -5
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +14 -2
  82. data/test/_test_active.rb +8 -9
  83. data/test/_test_active_mimic.rb +7 -8
  84. data/test/_test_mimic_rails.rb +17 -20
  85. data/test/activerecord/result_test.rb +5 -6
  86. data/test/activesupport6/encoding_test.rb +63 -28
  87. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  88. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  89. data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
  90. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  91. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  92. data/test/files.rb +15 -15
  93. data/test/foo.rb +16 -45
  94. data/test/helper.rb +11 -8
  95. data/test/isolated/shared.rb +3 -2
  96. data/test/json_gem/json_addition_test.rb +2 -2
  97. data/test/json_gem/json_common_interface_test.rb +8 -6
  98. data/test/json_gem/json_encoding_test.rb +0 -0
  99. data/test/json_gem/json_ext_parser_test.rb +1 -0
  100. data/test/json_gem/json_fixtures_test.rb +3 -2
  101. data/test/json_gem/json_generator_test.rb +56 -38
  102. data/test/json_gem/json_generic_object_test.rb +11 -11
  103. data/test/json_gem/json_parser_test.rb +54 -47
  104. data/test/json_gem/json_string_matching_test.rb +9 -9
  105. data/test/json_gem/test_helper.rb +7 -3
  106. data/test/mem.rb +34 -0
  107. data/test/perf.rb +22 -27
  108. data/test/perf_compat.rb +31 -33
  109. data/test/perf_dump.rb +50 -0
  110. data/test/perf_fast.rb +80 -82
  111. data/test/perf_file.rb +27 -29
  112. data/test/perf_object.rb +65 -69
  113. data/test/perf_once.rb +59 -0
  114. data/test/perf_parser.rb +183 -0
  115. data/test/perf_saj.rb +46 -54
  116. data/test/perf_scp.rb +58 -69
  117. data/test/perf_simple.rb +41 -39
  118. data/test/perf_strict.rb +74 -82
  119. data/test/perf_wab.rb +67 -69
  120. data/test/prec.rb +5 -5
  121. data/test/sample/change.rb +0 -1
  122. data/test/sample/dir.rb +0 -1
  123. data/test/sample/doc.rb +0 -1
  124. data/test/sample/file.rb +0 -1
  125. data/test/sample/group.rb +0 -1
  126. data/test/sample/hasprops.rb +0 -1
  127. data/test/sample/layer.rb +0 -1
  128. data/test/sample/rect.rb +0 -1
  129. data/test/sample/shape.rb +0 -1
  130. data/test/sample/text.rb +0 -1
  131. data/test/sample.rb +16 -16
  132. data/test/sample_json.rb +8 -8
  133. data/test/test_compat.rb +95 -43
  134. data/test/test_custom.rb +73 -51
  135. data/test/test_debian.rb +7 -10
  136. data/test/test_fast.rb +135 -79
  137. data/test/test_file.rb +41 -30
  138. data/test/test_gc.rb +16 -5
  139. data/test/test_generate.rb +5 -5
  140. data/test/test_hash.rb +5 -5
  141. data/test/test_integer_range.rb +9 -9
  142. data/test/test_null.rb +20 -20
  143. data/test/test_object.rb +99 -96
  144. data/test/test_parser.rb +11 -0
  145. data/test/test_parser_debug.rb +27 -0
  146. data/test/test_parser_saj.rb +337 -0
  147. data/test/test_parser_usual.rb +251 -0
  148. data/test/test_rails.rb +2 -2
  149. data/test/test_saj.rb +10 -8
  150. data/test/test_scp.rb +37 -39
  151. data/test/test_strict.rb +40 -32
  152. data/test/test_various.rb +165 -84
  153. data/test/test_wab.rb +48 -44
  154. data/test/test_writer.rb +47 -47
  155. data/test/tests.rb +13 -5
  156. data/test/tests_mimic.rb +12 -3
  157. data/test/tests_mimic_addition.rb +12 -3
  158. metadata +74 -128
  159. data/ext/oj/hash.c +0 -131
  160. data/ext/oj/hash.h +0 -19
  161. data/ext/oj/hash_test.c +0 -491
  162. data/test/activesupport4/decoding_test.rb +0 -108
  163. data/test/activesupport4/encoding_test.rb +0 -531
  164. data/test/activesupport4/test_helper.rb +0 -41
  165. data/test/activesupport5/test_helper.rb +0 -72
  166. data/test/bar.rb +0 -35
  167. data/test/baz.rb +0 -16
  168. data/test/zoo.rb +0 -13
data/ext/oj/oj.c CHANGED
@@ -13,7 +13,8 @@
13
13
 
14
14
  #include "dump.h"
15
15
  #include "encode.h"
16
- #include "hash.h"
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
 
@@ -35,22 +36,22 @@ ID oj_as_json_id;
35
36
  ID oj_begin_id;
36
37
  ID oj_bigdecimal_id;
37
38
  ID oj_end_id;
39
+ ID oj_eofq_id;
38
40
  ID oj_exclude_end_id;
39
41
  ID oj_error_id;
40
42
  ID oj_file_id;
41
43
  ID oj_fileno_id;
42
44
  ID oj_ftype_id;
43
- ID oj_has_key_id;
44
45
  ID oj_hash_end_id;
45
46
  ID oj_hash_key_id;
46
47
  ID oj_hash_set_id;
47
48
  ID oj_hash_start_id;
48
49
  ID oj_iconv_id;
49
- ID oj_instance_variables_id;
50
50
  ID oj_json_create_id;
51
51
  ID oj_length_id;
52
52
  ID oj_new_id;
53
53
  ID oj_parse_id;
54
+ ID oj_plus_id;
54
55
  ID oj_pos_id;
55
56
  ID oj_raw_json_id;
56
57
  ID oj_read_id;
@@ -95,6 +96,7 @@ VALUE oj_indent_sym;
95
96
  VALUE oj_object_class_sym;
96
97
  VALUE oj_quirks_mode_sym;
97
98
  VALUE oj_safe_sym;
99
+ VALUE oj_symbolize_names_sym;
98
100
  VALUE oj_trace_sym;
99
101
 
100
102
  static VALUE allow_blank_sym;
@@ -106,6 +108,9 @@ static VALUE auto_sym;
106
108
  static VALUE bigdecimal_as_decimal_sym;
107
109
  static VALUE bigdecimal_load_sym;
108
110
  static VALUE bigdecimal_sym;
111
+ static VALUE cache_keys_sym;
112
+ static VALUE cache_str_sym;
113
+ static VALUE cache_string_sym;
109
114
  static VALUE circular_sym;
110
115
  static VALUE class_cache_sym;
111
116
  static VALUE compat_bigdecimal_sym;
@@ -117,6 +122,7 @@ static VALUE escape_mode_sym;
117
122
  static VALUE integer_range_sym;
118
123
  static VALUE fast_sym;
119
124
  static VALUE float_prec_sym;
125
+ static VALUE float_format_sym;
120
126
  static VALUE float_sym;
121
127
  static VALUE huge_sym;
122
128
  static VALUE ignore_sym;
@@ -129,11 +135,13 @@ static VALUE newline_sym;
129
135
  static VALUE nilnil_sym;
130
136
  static VALUE null_sym;
131
137
  static VALUE object_sym;
138
+ static VALUE omit_null_byte_sym;
132
139
  static VALUE omit_nil_sym;
133
140
  static VALUE rails_sym;
134
141
  static VALUE raise_sym;
135
142
  static VALUE ruby_sym;
136
143
  static VALUE sec_prec_sym;
144
+ static VALUE slash_sym;
137
145
  static VALUE strict_sym;
138
146
  static VALUE symbol_keys_sym;
139
147
  static VALUE time_format_sym;
@@ -149,7 +157,8 @@ static VALUE word_sym;
149
157
  static VALUE xmlschema_sym;
150
158
  static VALUE xss_safe_sym;
151
159
 
152
- rb_encoding *oj_utf8_encoding = 0;
160
+ rb_encoding *oj_utf8_encoding = 0;
161
+ int oj_utf8_encoding_index = 0;
153
162
 
154
163
  #ifdef HAVE_PTHREAD_MUTEX_INIT
155
164
  pthread_mutex_t oj_cache_mutex;
@@ -157,6 +166,8 @@ pthread_mutex_t oj_cache_mutex;
157
166
  VALUE oj_cache_mutex = Qnil;
158
167
  #endif
159
168
 
169
+ extern void oj_parser_init();
170
+
160
171
  const char oj_json_class[] = "json_class";
161
172
 
162
173
  struct _options oj_default_options = {
@@ -186,6 +197,8 @@ struct _options oj_default_options = {
186
197
  No, // safe
187
198
  false, // sec_prec_set
188
199
  No, // ignore_under
200
+ Yes, // cache_keys
201
+ 0, // cache_str
189
202
  0, // int_range_min
190
203
  0, // int_range_max
191
204
  oj_json_class, // create_id
@@ -210,6 +223,7 @@ struct _options oj_default_options = {
210
223
  0, // array_size
211
224
  AutoNan, // nan_dump
212
225
  false, // omit_nil
226
+ false, // omit_null_byte
213
227
  MAX_DEPTH, // max_depth
214
228
  },
215
229
  {
@@ -218,74 +232,89 @@ struct _options oj_default_options = {
218
232
  NULL, // tail
219
233
  {'\0'}, // err
220
234
  },
221
- NULL, // ignore
235
+ NULL,
222
236
  };
223
237
 
224
238
  /* Document-method: default_options()
225
239
  * call-seq: default_options()
226
240
  *
227
241
  * Returns the default load and dump options as a Hash. The options are
228
- * - *:indent* [_Fixnum_|_String_|_nil_] number of spaces to indent each element in an JSON
229
- *document, zero or nil is no newline between JSON elements, negative indicates no newline between
230
- *top level JSON elements in a stream, a String indicates the string should be used for indentation
231
- * - *:circular* [_Boolean_|_nil_] support circular references while dumping as well as shared
232
- *references
242
+ * - *:indent* [_Fixnum_|_String_|_nil_] number of spaces to indent each element
243
+ * in an JSON document, zero or nil is no newline between JSON elements,
244
+ * negative indicates no newline between top level JSON elements in a stream,
245
+ * a String indicates the string should be used for indentation
246
+ * - *:circular* [_Boolean_|_nil_] support circular references while dumping as
247
+ * well as shared references
233
248
  * - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist
234
249
  * - *:symbol_keys* [_Boolean_|_nil_] use symbols instead of strings for hash keys
235
- * - *:escape_mode* [_:newline_|_:json_|_:xss_safe_|_:ascii_|_unicode_xss_|_nil_] determines the
236
- *characters to escape
237
- * - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing (if dynamically modifying
238
- *classes or reloading classes then don't use this)
239
- * - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_|_:wab_] load and dump modes
240
- *to use for JSON
250
+ * - *:escape_mode* [_:newline_|_:json_|_:slash_|_:xss_safe_|_:ascii_|_:unicode_xss_|_nil_]
251
+ * determines the characters to escape
252
+ * - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing (if dynamically
253
+ * modifying classes or reloading classes then don't use this)
254
+ * - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_|_:wab_] load and
255
+ * dump modes to use for JSON
241
256
  * - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
242
- * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String
243
- * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_] load decimals as BigDecimal instead
244
- *of as a Float. :auto pick the most precise for the number of digits. :float should be the same as
245
- *ruby. :fast may require rounding but is must faster.
246
- * - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead of as a Float when in
247
- *compat or rails mode.
248
- * - *:create_id* [_String_|_nil_] create id for json compatible object encoding, default is
249
- *'json_class'
250
- * - *:create_additions* [_Boolean_|_nil_] if true allow creation of instances using create_id on
251
- *load.
252
- * - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal when dumping the
253
- *seconds portion of time
254
- * - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping floats, 0
255
- *indicates use Ruby
257
+ * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or
258
+ * as a String
259
+ * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_|_:ruby_] load decimals
260
+ * as BigDecimal instead of as a Float. :auto pick the most precise for the number
261
+ * of digits. :float should be the same as ruby. :fast may require rounding but is
262
+ * must faster.
263
+ * - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead of as
264
+ * a Float when in compat or rails mode.
265
+ * - *:create_id* [_String_|_nil_] create id for json compatible object encoding,
266
+ * default is 'json_class'
267
+ * - *:create_additions* [_Boolean_|_nil_] if true allow creation of instances using
268
+ * create_id on load.
269
+ * - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal when
270
+ * dumping the seconds portion of time
271
+ * - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping
272
+ * floats, 0 indicates use Ruby
273
+ * - *:float_format* [_String_] the C printf format string for printing floats.
274
+ * Default follows the float_precision and will be changed if float_precision is
275
+ * changed. The string can be no more than 6 bytes.
256
276
  * - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false
257
277
  * - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false
258
278
  * - *:use_raw_json* [_Boolean_|_nil_] call raw_json() methods on dump, default is false
259
- * - *:nilnil* [_Boolean_|_nil_] if true a nil input to load will return nil and not raise an
260
- *Exception
279
+ * - *:nilnil* [_Boolean_|_nil_] if true a nil input to load will return nil and
280
+ * not raise an Exception
261
281
  * - *:empty_string* [_Boolean_|_nil_] if true an empty input will not raise an Exception
262
282
  * - *:allow_gc* [_Boolean_|_nil_] allow or prohibit GC during parsing, default is true (allow)
263
- * - *:quirks_mode* [_true,_|_false_|_nil_] Allow single JSON values instead of documents, default
264
- *is true (allow)
265
- * - *:allow_invalid_unicode* [_true,_|_false_|_nil_] Allow invalid unicode, default is false (don't
266
- *allow)
267
- * - *:allow_nan* [_true,_|_false_|_nil_] Allow Nan, Infinity, and -Infinity to be parsed, default
268
- *is true (allow)
269
- * - *:indent_str* [_String_|_nil_] String to use for indentation, overriding the indent option is
270
- *not nil
271
- * - *:space* [_String_|_nil_] String to use for the space after the colon in JSON object fields
272
- * - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object fields
283
+ * - *:quirks_mode* [_true,_|_false_|_nil_] Allow single JSON values instead of
284
+ * documents, default is true (allow)
285
+ * - *:allow_invalid_unicode* [_true,_|_false_|_nil_] Allow invalid unicode,
286
+ * default is false (don't allow)
287
+ * - *:allow_nan* [_true,_|_false_|_nil_] Allow Nan, Infinity, and -Infinity to
288
+ * be parsed, default is true (allow)
289
+ * - *:indent_str* [_String_|_nil_] String to use for indentation, overriding the
290
+ * indent option is not nil
291
+ * - *:space* [_String_|_nil_] String to use for the space after the colon in JSON
292
+ * object fields
293
+ * - *:space_before* [_String_|_nil_] String to use before the colon separator in
294
+ * JSON object fields
273
295
  * - *:object_nl* [_String_|_nil_] String to use after a JSON object field value
274
296
  * - *:array_nl* [_String_|_nil_] String to use after a JSON array value
275
- * - *:nan* [_:null_|_:huge_|_:word_|_:raise_|_:auto_] how to dump Infinity and NaN. :null places a
276
- *null, :huge places a huge number, :word places Infinity or NaN, :raise raises and exception, :auto
277
- *uses default for each mode.
278
- * - *:hash_class* [_Class_|_nil_] Class to use instead of Hash on load, :object_class can also be
279
- *used
297
+ * - *:nan* [_:null_|_:huge_|_:word_|_:raise_|_:auto_] how to dump Infinity and
298
+ * NaN. :null places a null, :huge places a huge number, :word places Infinity
299
+ * or NaN, :raise raises and exception, :auto uses default for each mode.
300
+ * - *:hash_class* [_Class_|_nil_] Class to use instead of Hash on load,
301
+ * :object_class can also be used
280
302
  * - *:array_class* [_Class_|_nil_] Class to use instead of Array on load
281
- * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted
282
- * - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
283
- * - *:ignore_under* [Boolean] if true then attributes that start with _ are ignored when dumping in
284
- *object or custom mode.
303
+ * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil
304
+ * values are omitted
305
+ * - *:omit_null_byte* [_true_|_false_] if true null bytes in strings will be
306
+ * omitted when dumping
307
+ * - *:ignore* [_nil_|_Array_] either nil or an Array of classes to ignore when dumping
308
+ * - *:ignore_under* [_Boolean_] if true then attributes that start with _ are
309
+ * ignored when dumping in object or custom mode.
310
+ * - *:cache_keys* [_Boolean_] if true then hash keys are cached if less than 35 bytes.
311
+ * - *:cache_str* [_Fixnum_] maximum string value length to cache (strings less
312
+ * than this are cached)
285
313
  * - *:integer_range* [_Range_] Dump integers outside range as strings.
286
- * - *:trace* [_true,_|_false_] Trace all load and dump calls, default is false (trace is off)
287
- * - *:safe* [_true,_|_false_] Safe mimic breaks JSON mimic to be safer, default is false (safe is
288
- *off)
314
+ * - *:trace* [_true,_|_false_] Trace all load and dump calls, default is false
315
+ * (trace is off)
316
+ * - *:safe* [_true,_|_false_] Safe mimic breaks JSON mimic to be safer, default
317
+ * is false (safe is off)
289
318
  *
290
319
  * Return [_Hash_] all current option settings.
291
320
  */
@@ -300,100 +329,78 @@ static VALUE get_def_opts(VALUE self) {
300
329
  rb_hash_aset(opts, sec_prec_sym, INT2FIX(oj_default_options.sec_prec));
301
330
  rb_hash_aset(opts,
302
331
  circular_sym,
303
- (Yes == oj_default_options.circular)
304
- ? Qtrue
305
- : ((No == oj_default_options.circular) ? Qfalse : Qnil));
306
- rb_hash_aset(opts,
307
- class_cache_sym,
308
- (Yes == oj_default_options.class_cache)
309
- ? Qtrue
310
- : ((No == oj_default_options.class_cache) ? Qfalse : Qnil));
311
- rb_hash_aset(opts,
312
- auto_define_sym,
313
- (Yes == oj_default_options.auto_define)
314
- ? Qtrue
315
- : ((No == oj_default_options.auto_define) ? Qfalse : Qnil));
332
+ (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil));
333
+ rb_hash_aset(
334
+ opts,
335
+ class_cache_sym,
336
+ (Yes == oj_default_options.class_cache) ? Qtrue : ((No == oj_default_options.class_cache) ? Qfalse : Qnil));
337
+ rb_hash_aset(
338
+ opts,
339
+ auto_define_sym,
340
+ (Yes == oj_default_options.auto_define) ? Qtrue : ((No == oj_default_options.auto_define) ? Qfalse : Qnil));
316
341
  rb_hash_aset(opts,
317
342
  symbol_keys_sym,
318
- (Yes == oj_default_options.sym_key)
319
- ? Qtrue
320
- : ((No == oj_default_options.sym_key) ? Qfalse : Qnil));
321
- rb_hash_aset(opts,
322
- bigdecimal_as_decimal_sym,
323
- (Yes == oj_default_options.bigdec_as_num)
324
- ? Qtrue
325
- : ((No == oj_default_options.bigdec_as_num) ? Qfalse : Qnil));
326
- rb_hash_aset(opts,
327
- oj_create_additions_sym,
328
- (Yes == oj_default_options.create_ok)
329
- ? Qtrue
330
- : ((No == oj_default_options.create_ok) ? Qfalse : Qnil));
343
+ (Yes == oj_default_options.sym_key) ? Qtrue : ((No == oj_default_options.sym_key) ? Qfalse : Qnil));
344
+ rb_hash_aset(
345
+ opts,
346
+ bigdecimal_as_decimal_sym,
347
+ (Yes == oj_default_options.bigdec_as_num) ? Qtrue : ((No == oj_default_options.bigdec_as_num) ? Qfalse : Qnil));
348
+ rb_hash_aset(
349
+ opts,
350
+ oj_create_additions_sym,
351
+ (Yes == oj_default_options.create_ok) ? Qtrue : ((No == oj_default_options.create_ok) ? Qfalse : Qnil));
331
352
  rb_hash_aset(opts,
332
353
  use_to_json_sym,
333
- (Yes == oj_default_options.to_json)
334
- ? Qtrue
335
- : ((No == oj_default_options.to_json) ? Qfalse : Qnil));
354
+ (Yes == oj_default_options.to_json) ? Qtrue : ((No == oj_default_options.to_json) ? Qfalse : Qnil));
336
355
  rb_hash_aset(opts,
337
356
  use_to_hash_sym,
338
- (Yes == oj_default_options.to_hash)
339
- ? Qtrue
340
- : ((No == oj_default_options.to_hash) ? Qfalse : Qnil));
357
+ (Yes == oj_default_options.to_hash) ? Qtrue : ((No == oj_default_options.to_hash) ? Qfalse : Qnil));
341
358
  rb_hash_aset(opts,
342
359
  use_as_json_sym,
343
- (Yes == oj_default_options.as_json)
344
- ? Qtrue
345
- : ((No == oj_default_options.as_json) ? Qfalse : Qnil));
360
+ (Yes == oj_default_options.as_json) ? Qtrue : ((No == oj_default_options.as_json) ? Qfalse : Qnil));
346
361
  rb_hash_aset(opts,
347
362
  use_raw_json_sym,
348
- (Yes == oj_default_options.raw_json)
349
- ? Qtrue
350
- : ((No == oj_default_options.raw_json) ? Qfalse : Qnil));
363
+ (Yes == oj_default_options.raw_json) ? Qtrue : ((No == oj_default_options.raw_json) ? Qfalse : Qnil));
351
364
  rb_hash_aset(opts,
352
365
  nilnil_sym,
353
- (Yes == oj_default_options.nilnil)
354
- ? Qtrue
355
- : ((No == oj_default_options.nilnil) ? Qfalse : Qnil));
356
- rb_hash_aset(opts,
357
- empty_string_sym,
358
- (Yes == oj_default_options.empty_string)
359
- ? Qtrue
360
- : ((No == oj_default_options.empty_string) ? Qfalse : Qnil));
366
+ (Yes == oj_default_options.nilnil) ? Qtrue : ((No == oj_default_options.nilnil) ? Qfalse : Qnil));
367
+ rb_hash_aset(
368
+ opts,
369
+ empty_string_sym,
370
+ (Yes == oj_default_options.empty_string) ? Qtrue : ((No == oj_default_options.empty_string) ? Qfalse : Qnil));
361
371
  rb_hash_aset(opts,
362
372
  allow_gc_sym,
363
- (Yes == oj_default_options.allow_gc)
364
- ? Qtrue
365
- : ((No == oj_default_options.allow_gc) ? Qfalse : Qnil));
366
- rb_hash_aset(opts,
367
- oj_quirks_mode_sym,
368
- (Yes == oj_default_options.quirks_mode)
369
- ? Qtrue
370
- : ((No == oj_default_options.quirks_mode) ? Qfalse : Qnil));
371
- rb_hash_aset(opts,
372
- allow_invalid_unicode_sym,
373
- (Yes == oj_default_options.allow_invalid)
374
- ? Qtrue
375
- : ((No == oj_default_options.allow_invalid) ? Qfalse : Qnil));
376
- rb_hash_aset(opts,
377
- oj_allow_nan_sym,
378
- (Yes == oj_default_options.allow_nan)
379
- ? Qtrue
380
- : ((No == oj_default_options.allow_nan) ? Qfalse : Qnil));
373
+ (Yes == oj_default_options.allow_gc) ? Qtrue : ((No == oj_default_options.allow_gc) ? Qfalse : Qnil));
374
+ rb_hash_aset(
375
+ opts,
376
+ oj_quirks_mode_sym,
377
+ (Yes == oj_default_options.quirks_mode) ? Qtrue : ((No == oj_default_options.quirks_mode) ? Qfalse : Qnil));
378
+ rb_hash_aset(
379
+ opts,
380
+ allow_invalid_unicode_sym,
381
+ (Yes == oj_default_options.allow_invalid) ? Qtrue : ((No == oj_default_options.allow_invalid) ? Qfalse : Qnil));
382
+ rb_hash_aset(
383
+ opts,
384
+ oj_allow_nan_sym,
385
+ (Yes == oj_default_options.allow_nan) ? Qtrue : ((No == oj_default_options.allow_nan) ? Qfalse : Qnil));
381
386
  rb_hash_aset(opts,
382
387
  oj_trace_sym,
383
- (Yes == oj_default_options.trace)
384
- ? Qtrue
385
- : ((No == oj_default_options.trace) ? Qfalse : Qnil));
388
+ (Yes == oj_default_options.trace) ? Qtrue : ((No == oj_default_options.trace) ? Qfalse : Qnil));
386
389
  rb_hash_aset(opts,
387
390
  oj_safe_sym,
388
- (Yes == oj_default_options.safe)
389
- ? Qtrue
390
- : ((No == oj_default_options.safe) ? Qfalse : Qnil));
391
+ (Yes == oj_default_options.safe) ? Qtrue : ((No == oj_default_options.safe) ? Qfalse : Qnil));
391
392
  rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec));
392
- rb_hash_aset(opts,
393
- ignore_under_sym,
394
- (Yes == oj_default_options.ignore_under)
395
- ? Qtrue
396
- : ((No == oj_default_options.ignore_under) ? Qfalse : Qnil));
393
+ rb_hash_aset(opts, float_format_sym, rb_str_new_cstr(oj_default_options.float_fmt));
394
+ rb_hash_aset(opts, cache_str_sym, INT2FIX(oj_default_options.cache_str));
395
+ rb_hash_aset(
396
+ opts,
397
+ ignore_under_sym,
398
+ (Yes == oj_default_options.ignore_under) ? Qtrue : ((No == oj_default_options.ignore_under) ? Qfalse : Qnil));
399
+ rb_hash_aset(
400
+ opts,
401
+ cache_keys_sym,
402
+ (Yes == oj_default_options.cache_keys) ? Qtrue : ((No == oj_default_options.cache_keys) ? Qfalse : Qnil));
403
+
397
404
  switch (oj_default_options.mode) {
398
405
  case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
399
406
  case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
@@ -419,6 +426,7 @@ static VALUE get_def_opts(VALUE self) {
419
426
  switch (oj_default_options.escape_mode) {
420
427
  case NLEsc: rb_hash_aset(opts, escape_mode_sym, newline_sym); break;
421
428
  case JSONEsc: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
429
+ case SlashEsc: rb_hash_aset(opts, escape_mode_sym, slash_sym); break;
422
430
  case XSSEsc: rb_hash_aset(opts, escape_mode_sym, xss_safe_sym); break;
423
431
  case ASCIIEsc: rb_hash_aset(opts, escape_mode_sym, ascii_sym); break;
424
432
  case JXEsc: rb_hash_aset(opts, escape_mode_sym, unicode_xss_sym); break;
@@ -439,30 +447,25 @@ static VALUE get_def_opts(VALUE self) {
439
447
  default: rb_hash_aset(opts, bigdecimal_load_sym, auto_sym); break;
440
448
  }
441
449
  rb_hash_aset(opts, compat_bigdecimal_sym, oj_default_options.compat_bigdec ? Qtrue : Qfalse);
450
+ rb_hash_aset(opts,
451
+ create_id_sym,
452
+ (NULL == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));
442
453
  rb_hash_aset(
443
454
  opts,
444
- create_id_sym,
445
- (NULL == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));
446
- rb_hash_aset(opts,
447
- oj_space_sym,
448
- (0 == oj_default_options.dump_opts.after_size)
449
- ? Qnil
450
- : rb_str_new2(oj_default_options.dump_opts.after_sep));
451
- rb_hash_aset(opts,
452
- oj_space_before_sym,
453
- (0 == oj_default_options.dump_opts.before_size)
454
- ? Qnil
455
- : rb_str_new2(oj_default_options.dump_opts.before_sep));
456
- rb_hash_aset(opts,
457
- oj_object_nl_sym,
458
- (0 == oj_default_options.dump_opts.hash_size)
459
- ? Qnil
460
- : rb_str_new2(oj_default_options.dump_opts.hash_nl));
461
- rb_hash_aset(opts,
462
- oj_array_nl_sym,
463
- (0 == oj_default_options.dump_opts.array_size)
464
- ? Qnil
465
- : rb_str_new2(oj_default_options.dump_opts.array_nl));
455
+ oj_space_sym,
456
+ (0 == oj_default_options.dump_opts.after_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.after_sep));
457
+ rb_hash_aset(
458
+ opts,
459
+ oj_space_before_sym,
460
+ (0 == oj_default_options.dump_opts.before_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.before_sep));
461
+ rb_hash_aset(
462
+ opts,
463
+ oj_object_nl_sym,
464
+ (0 == oj_default_options.dump_opts.hash_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.hash_nl));
465
+ rb_hash_aset(
466
+ opts,
467
+ oj_array_nl_sym,
468
+ (0 == oj_default_options.dump_opts.array_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.array_nl));
466
469
 
467
470
  switch (oj_default_options.dump_opts.nan_dump) {
468
471
  case NullNan: rb_hash_aset(opts, nan_sym, null_sym); break;
@@ -473,13 +476,14 @@ static VALUE get_def_opts(VALUE self) {
473
476
  default: rb_hash_aset(opts, nan_sym, auto_sym); break;
474
477
  }
475
478
  rb_hash_aset(opts, omit_nil_sym, oj_default_options.dump_opts.omit_nil ? Qtrue : Qfalse);
479
+ rb_hash_aset(opts, omit_null_byte_sym, oj_default_options.dump_opts.omit_null_byte ? Qtrue : Qfalse);
476
480
  rb_hash_aset(opts, oj_hash_class_sym, oj_default_options.hash_class);
477
481
  rb_hash_aset(opts, oj_array_class_sym, oj_default_options.array_class);
478
482
 
479
483
  if (NULL == oj_default_options.ignore) {
480
484
  rb_hash_aset(opts, ignore_sym, Qnil);
481
485
  } else {
482
- VALUE * vp;
486
+ VALUE *vp;
483
487
  volatile VALUE a = rb_ary_new();
484
488
 
485
489
  for (vp = oj_default_options.ignore; Qnil != *vp; vp++) {
@@ -495,68 +499,69 @@ static VALUE get_def_opts(VALUE self) {
495
499
  *
496
500
  * Sets the default options for load and dump.
497
501
  * - *opts* [_Hash_] options to change
498
- * - *:indent* [_Fixnum_|_String_|_nil_] number of spaces to indent each element in a JSON
499
- *document or the String to use for identation.
502
+ * - *:indent* [_Fixnum_|_String_|_nil_] number of spaces to indent each element
503
+ * in a JSON document or the String to use for indentation.
500
504
  * - :circular [_Boolean_|_nil_] support circular references while dumping.
501
505
  * - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist.
502
506
  * - *:symbol_keys* [_Boolean_|_nil_] convert hash keys to symbols.
503
507
  * - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing.
504
- * - *:escape* [_:newline_|_:json_|_:xss_safe_|_:ascii_|_unicode_xss_|_nil_] mode encodes all
505
- *high-bit characters as escaped sequences if :ascii, :json is standand UTF-8 JSON encoding,
506
- *:newline is the same as :json but newlines are not escaped, :unicode_xss allows unicode but
507
- *escapes &, <, and >, and any \u20xx characters along with some others, and :xss_safe escapes &, <,
508
- *and >, and some others.
509
- * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a
510
- *String.
511
- * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_nil_] load decimals as BigDecimal instead
512
- *of as a Float. :auto pick the most precise for the number of digits.
513
- * - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead of as a Float in
514
- *compat mode.
515
- * - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_|_:wab_] load and dump mode
516
- *to use for JSON :strict raises an exception when a non-supported Object is encountered. :compat
517
- *attempts to extract variable values from an Object using to_json() or to_hash() then it walks the
518
- *Object's variables if neither is found. The :object mode ignores to_hash() and to_json() methods
519
- *and encodes variables using code internal to the Oj gem. The :null mode ignores non-supported
520
- *Objects and replaces them with a null. The :custom mode honors all dump options. The :rails more
521
- *mimics rails and Active behavior.
522
- * - *:time_format* [_:unix_|_:xmlschema_|_:ruby_] time format when dumping in :compat mode :unix
523
- *decimal number denoting the number of seconds since 1/1/1970, :unix_zone decimal number denoting
524
- *the number of seconds since 1/1/1970 plus the utc_offset in the exponent, :xmlschema date-time
525
- *format taken from XML Schema as a String, :ruby Time.to_s formatted String.
508
+ * - *:escape* [_:newline_|_:json_|_:xss_safe_|_:ascii_|_unicode_xss_|_nil_]
509
+ * mode encodes all high-bit characters as escaped sequences if :ascii, :json
510
+ * is standand UTF-8 JSON encoding, :newline is the same as :json but newlines
511
+ * are not escaped, :unicode_xss allows unicode but escapes &, <, and >, and
512
+ * any \u20xx characters along with some others, and :xss_safe escapes &, <,
513
+ * and >, and some others.
514
+ * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal
515
+ * number or as a String.
516
+ * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_nil_] load decimals as
517
+ * BigDecimal instead of as a Float. :auto pick the most precise for the number of digits.
518
+ * - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead
519
+ * of as a Float in compat mode.
520
+ * - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_|_:wab_] load
521
+ * and dump mode to use for JSON :strict raises an exception when a non-supported
522
+ * Object is encountered. :compat attempts to extract variable values from an
523
+ * Object using to_json() or to_hash() then it walks the Object's variables if
524
+ * neither is found. The :object mode ignores to_hash() and to_json() methods
525
+ * and encodes variables using code internal to the Oj gem. The :null mode
526
+ * ignores non-supported Objects and replaces them with a null. The :custom
527
+ * mode honors all dump options. The :rails more mimics rails and Active behavior.
528
+ * - *:time_format* [_:unix_|_:xmlschema_|_:ruby_] time format when dumping in :compat
529
+ * mode :unix decimal number denoting the number of seconds since 1/1/1970,
530
+ * :unix_zone decimal number denoting the number of seconds since 1/1/1970
531
+ * plus the utc_offset in the exponent, :xmlschema date-time format taken
532
+ * from XML Schema as a String, :ruby Time.to_s formatted String.
526
533
  * - *:create_id* [_String_|_nil_] create id for json compatible object encoding
527
- * - *:create_additions* [_Boolean_|_nil_] if true allow creation of instances using create_id on
528
- *load.
529
- * - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal when dumping the
530
- *seconds portion of time.
531
- * - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping floats, 0
532
- *indicates use Ruby.
534
+ * - *:create_additions* [_Boolean_|_nil_] if true allow creation of instances using create_id on load.
535
+ * - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal
536
+ * when dumping the seconds portion of time.
537
+ * - *:float_format* [_String_] the C printf format string for printing floats.
538
+ * Default follows the float_precision and will be changed if float_precision
539
+ * is changed. The string can be no more than 6 bytes.
540
+ * - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping floats, 0 indicates use Ruby.
533
541
  * - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false.
534
542
  * - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false.
535
543
  * - *:use_to_hash* [_Boolean_|_nil_] call to_hash() methods on dump, default is false.
536
544
  * - *:use_raw_json* [_Boolean_|_nil_] call raw_json() methods on dump, default is false.
537
- * - *:nilnil* [_Boolean_|_nil_] if true a nil input to load will return nil and not raise an
538
- *Exception.
545
+ * - *:nilnil* [_Boolean_|_nil_] if true a nil input to load will return nil and not raise an Exception.
539
546
  * - *:allow_gc* [_Boolean_|_nil_] allow or prohibit GC during parsing, default is true (allow).
540
- * - *:quirks_mode* [_Boolean_|_nil_] allow single JSON values instead of documents, default is
541
- *true (allow).
542
- * - *:allow_invalid_unicode* [_Boolean_|_nil_] allow invalid unicode, default is false (don't
543
- *allow).
547
+ * - *:quirks_mode* [_Boolean_|_nil_] allow single JSON values instead of documents, default is true (allow).
548
+ * - *:allow_invalid_unicode* [_Boolean_|_nil_] allow invalid unicode, default is false (don't allow).
544
549
  * - *:allow_nan* [_Boolean_|_nil_] allow Nan, Infinity, and -Infinity, default is true (allow).
545
550
  * - *:space* [_String_|_nil_] String to use for the space after the colon in JSON object fields.
546
- * - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object
547
- *fields.
551
+ * - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object fields.
548
552
  * - *:object_nl* [_String_|_nil_] String to use after a JSON object field value.
549
553
  * - *:array_nl* [_String_|_nil_] String to use after a JSON array value
550
- * - *:nan* [_:null_|_:huge_|_:word_|_:raise_] how to dump Infinity and NaN in null, strict, and
551
- *compat mode. :null places a null, :huge places a huge number, :word places Infinity or NaN, :raise
552
- *raises and exception, :auto uses default for each mode.
553
- * - *:hash_class* [_Class_|_nil_] Class to use instead of Hash on load, :object_class can also be
554
- *used.
554
+ * - *:nan* [_:null_|_:huge_|_:word_|_:raise_] how to dump Infinity and NaN in null,
555
+ * strict, and compat mode. :null places a null, :huge places a huge number, :word
556
+ * places Infinity or NaN, :raise raises and exception, :auto uses default for each mode.
557
+ * - *:hash_class* [_Class_|_nil_] Class to use instead of Hash on load, :object_class can also be used.
555
558
  * - *:array_class* [_Class_|_nil_] Class to use instead of Array on load.
556
559
  * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted.
557
560
  * - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
558
- * - *:ignore_under* [_Boolean_] if true then attributes that start with _ are ignored when
559
- *dumping in object or custom mode.
561
+ * - *:ignore_under* [_Boolean_] if true then attributes that start with _ are
562
+ * ignored when dumping in object or custom mode.
563
+ * - *:cache_keys* [_Boolean_] if true then hash keys are cached
564
+ * - *:cache_str* [_Fixnum_] maximum string value length to cache (strings less than this are cached)
560
565
  * - *:integer_range* [_Range_] Dump integers outside range as strings.
561
566
  * - *:trace* [_Boolean_] turn trace on or off.
562
567
  * - *:safe* [_Boolean_] turn safe mimic on or off.
@@ -568,7 +573,14 @@ static VALUE set_def_opts(VALUE self, VALUE opts) {
568
573
  return Qnil;
569
574
  }
570
575
 
571
- void oj_parse_options(VALUE ropts, Options copts) {
576
+ bool oj_hash_has_key(VALUE hash, VALUE key) {
577
+ if (Qundef == rb_hash_lookup2(hash, key, Qundef)) {
578
+ return false;
579
+ }
580
+ return true;
581
+ }
582
+
583
+ bool set_yesno_options(VALUE key, VALUE value, Options copts) {
572
584
  struct _yesNoOpt ynos[] = {{circular_sym, &copts->circular},
573
585
  {auto_define_sym, &copts->auto_define},
574
586
  {symbol_keys_sym, &copts->sym_key},
@@ -589,16 +601,35 @@ void oj_parse_options(VALUE ropts, Options copts) {
589
601
  {oj_safe_sym, &copts->safe},
590
602
  {ignore_under_sym, &copts->ignore_under},
591
603
  {oj_create_additions_sym, &copts->create_ok},
604
+ {cache_keys_sym, &copts->cache_keys},
592
605
  {Qnil, 0}};
593
606
  YesNoOpt o;
594
- volatile VALUE v;
595
- size_t len;
596
607
 
597
- if (T_HASH != rb_type(ropts)) {
598
- return;
608
+ for (o = ynos; 0 != o->attr; o++) {
609
+ if (key == o->sym) {
610
+ if (Qnil == value) {
611
+ *o->attr = NotSet;
612
+ } else if (Qtrue == value) {
613
+ *o->attr = Yes;
614
+ } else if (Qfalse == value) {
615
+ *o->attr = No;
616
+ } else {
617
+ rb_raise(rb_eArgError, "%s must be true, false, or nil.", rb_id2name(key));
618
+ }
619
+ return true;
620
+ }
599
621
  }
600
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_indent_sym)) {
601
- v = rb_hash_lookup(ropts, oj_indent_sym);
622
+ return false;
623
+ }
624
+
625
+ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
626
+ Options copts = (Options)opts;
627
+ size_t len;
628
+
629
+ if (set_yesno_options(k, v, copts)) {
630
+ return ST_CONTINUE;
631
+ }
632
+ if (oj_indent_sym == k) {
602
633
  switch (rb_type(v)) {
603
634
  case T_NIL:
604
635
  copts->dump_opts.indent_size = 0;
@@ -622,19 +653,12 @@ void oj_parse_options(VALUE ropts, Options copts) {
622
653
  break;
623
654
  default: rb_raise(rb_eTypeError, "indent must be a Fixnum, String, or nil."); break;
624
655
  }
625
- }
626
- if (Qnil != (v = rb_hash_lookup(ropts, float_prec_sym))) {
656
+ } else if (float_prec_sym == k) {
627
657
  int n;
628
658
 
629
- #ifdef RUBY_INTEGER_UNIFICATION
630
659
  if (rb_cInteger != rb_obj_class(v)) {
631
660
  rb_raise(rb_eArgError, ":float_precision must be a Integer.");
632
661
  }
633
- #else
634
- if (T_FIXNUM != rb_type(v)) {
635
- rb_raise(rb_eArgError, ":float_precision must be a Fixnum.");
636
- }
637
- #endif
638
662
  n = FIX2INT(v);
639
663
  if (0 >= n) {
640
664
  *copts->float_fmt = '\0';
@@ -646,19 +670,27 @@ void oj_parse_options(VALUE ropts, Options copts) {
646
670
  sprintf(copts->float_fmt, "%%0.%dg", n);
647
671
  copts->float_prec = n;
648
672
  }
649
- }
650
- if (Qnil != (v = rb_hash_lookup(ropts, sec_prec_sym))) {
673
+ } else if (cache_str_sym == k || cache_string_sym == k) {
651
674
  int n;
652
675
 
653
- #ifdef RUBY_INTEGER_UNIFICATION
654
676
  if (rb_cInteger != rb_obj_class(v)) {
655
- rb_raise(rb_eArgError, ":second_precision must be a Integer.");
677
+ rb_raise(rb_eArgError, ":cache_str must be a Integer.");
656
678
  }
657
- #else
658
- if (T_FIXNUM != rb_type(v)) {
659
- rb_raise(rb_eArgError, ":second_precision must be a Fixnum.");
679
+ n = FIX2INT(v);
680
+ if (0 >= n) {
681
+ copts->cache_str = 0;
682
+ } else {
683
+ if (32 < n) {
684
+ n = 32;
685
+ }
686
+ copts->cache_str = (char)n;
687
+ }
688
+ } else if (sec_prec_sym == k) {
689
+ int n;
690
+
691
+ if (rb_cInteger != rb_obj_class(v)) {
692
+ rb_raise(rb_eArgError, ":second_precision must be a Integer.");
660
693
  }
661
- #endif
662
694
  n = NUM2INT(v);
663
695
  if (0 > n) {
664
696
  n = 0;
@@ -670,8 +702,7 @@ void oj_parse_options(VALUE ropts, Options copts) {
670
702
  copts->sec_prec_set = true;
671
703
  }
672
704
  copts->sec_prec = n;
673
- }
674
- if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
705
+ } else if (mode_sym == k) {
675
706
  if (wab_sym == v) {
676
707
  copts->mode = WabMode;
677
708
  } else if (object_sym == v) {
@@ -687,11 +718,9 @@ void oj_parse_options(VALUE ropts, Options copts) {
687
718
  } else if (rails_sym == v) {
688
719
  copts->mode = RailsMode;
689
720
  } else {
690
- rb_raise(rb_eArgError,
691
- ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
721
+ rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
692
722
  }
693
- }
694
- if (Qnil != (v = rb_hash_lookup(ropts, time_format_sym))) {
723
+ } else if (time_format_sym == k) {
695
724
  if (unix_sym == v) {
696
725
  copts->time_format = UnixTime;
697
726
  } else if (unix_zone_sym == v) {
@@ -703,12 +732,13 @@ void oj_parse_options(VALUE ropts, Options copts) {
703
732
  } else {
704
733
  rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby.");
705
734
  }
706
- }
707
- if (Qnil != (v = rb_hash_lookup(ropts, escape_mode_sym))) {
735
+ } else if (escape_mode_sym == k) {
708
736
  if (newline_sym == v) {
709
737
  copts->escape_mode = NLEsc;
710
738
  } else if (json_sym == v) {
711
739
  copts->escape_mode = JSONEsc;
740
+ } else if (slash_sym == v) {
741
+ copts->escape_mode = SlashEsc;
712
742
  } else if (xss_safe_sym == v) {
713
743
  copts->escape_mode = XSSEsc;
714
744
  } else if (ascii_sym == v) {
@@ -716,11 +746,13 @@ void oj_parse_options(VALUE ropts, Options copts) {
716
746
  } else if (unicode_xss_sym == v) {
717
747
  copts->escape_mode = JXEsc;
718
748
  } else {
719
- rb_raise(rb_eArgError,
720
- ":encoding must be :newline, :json, :xss_safe, :unicode_xss, or :ascii.");
749
+ rb_raise(rb_eArgError, ":encoding must be :newline, :json, :xss_safe, :unicode_xss, or :ascii.");
721
750
  }
722
- }
723
- if (Qnil != (v = rb_hash_lookup(ropts, bigdecimal_load_sym))) {
751
+ } else if (bigdecimal_load_sym == k) {
752
+ if (Qnil == v) {
753
+ return ST_CONTINUE;
754
+ }
755
+
724
756
  if (bigdecimal_sym == v || Qtrue == v) {
725
757
  copts->bigdec_load = BigDec;
726
758
  } else if (float_sym == v) {
@@ -732,12 +764,12 @@ void oj_parse_options(VALUE ropts, Options copts) {
732
764
  } else {
733
765
  rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto.");
734
766
  }
735
- }
736
- if (Qnil != (v = rb_hash_lookup(ropts, compat_bigdecimal_sym))) {
767
+ } else if (compat_bigdecimal_sym == k) {
768
+ if (Qnil == v) {
769
+ return ST_CONTINUE;
770
+ }
737
771
  copts->compat_bigdec = (Qtrue == v);
738
- }
739
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_decimal_class_sym)) {
740
- v = rb_hash_lookup(ropts, oj_decimal_class_sym);
772
+ } else if (oj_decimal_class_sym == k) {
741
773
  if (rb_cFloat == v) {
742
774
  copts->compat_bigdec = false;
743
775
  } else if (oj_bigdecimal_class == v) {
@@ -745,12 +777,10 @@ void oj_parse_options(VALUE ropts, Options copts) {
745
777
  } else {
746
778
  rb_raise(rb_eArgError, ":decimal_class must be BigDecimal or Float.");
747
779
  }
748
- }
749
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, create_id_sym)) {
750
- v = rb_hash_lookup(ropts, create_id_sym);
780
+ } else if (create_id_sym == k) {
751
781
  if (Qnil == v) {
752
782
  if (oj_json_class != oj_default_options.create_id && NULL != copts->create_id) {
753
- xfree((char *)oj_default_options.create_id);
783
+ OJ_R_FREE((char *)oj_default_options.create_id);
754
784
  }
755
785
  copts->create_id = NULL;
756
786
  copts->create_id_len = 0;
@@ -759,32 +789,15 @@ void oj_parse_options(VALUE ropts, Options copts) {
759
789
 
760
790
  len = RSTRING_LEN(v);
761
791
  if (len != copts->create_id_len || 0 != strcmp(copts->create_id, str)) {
762
- copts->create_id = ALLOC_N(char, len + 1);
792
+ copts->create_id = OJ_R_ALLOC_N(char, len + 1);
763
793
  strcpy((char *)copts->create_id, str);
764
794
  copts->create_id_len = len;
765
795
  }
766
796
  } else {
767
797
  rb_raise(rb_eArgError, ":create_id must be string.");
768
798
  }
769
- }
770
- for (o = ynos; 0 != o->attr; o++) {
771
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, o->sym)) {
772
- v = rb_hash_lookup(ropts, o->sym);
773
- if (Qnil == v) {
774
- *o->attr = NotSet;
775
- } else if (Qtrue == v) {
776
- *o->attr = Yes;
777
- } else if (Qfalse == v) {
778
- *o->attr = No;
779
- } else {
780
- rb_raise(rb_eArgError,
781
- "%s must be true, false, or nil.",
782
- rb_id2name(SYM2ID(o->sym)));
783
- }
784
- }
785
- }
786
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_space_sym)) {
787
- if (Qnil == (v = rb_hash_lookup(ropts, oj_space_sym))) {
799
+ } else if (oj_space_sym == k) {
800
+ if (Qnil == v) {
788
801
  copts->dump_opts.after_size = 0;
789
802
  *copts->dump_opts.after_sep = '\0';
790
803
  } else {
@@ -797,9 +810,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
797
810
  strcpy(copts->dump_opts.after_sep, StringValuePtr(v));
798
811
  copts->dump_opts.after_size = (uint8_t)len;
799
812
  }
800
- }
801
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_space_before_sym)) {
802
- if (Qnil == (v = rb_hash_lookup(ropts, oj_space_before_sym))) {
813
+ } else if (oj_space_before_sym == k) {
814
+ if (Qnil == v) {
803
815
  copts->dump_opts.before_size = 0;
804
816
  *copts->dump_opts.before_sep = '\0';
805
817
  } else {
@@ -812,9 +824,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
812
824
  strcpy(copts->dump_opts.before_sep, StringValuePtr(v));
813
825
  copts->dump_opts.before_size = (uint8_t)len;
814
826
  }
815
- }
816
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_object_nl_sym)) {
817
- if (Qnil == (v = rb_hash_lookup(ropts, oj_object_nl_sym))) {
827
+ } else if (oj_object_nl_sym == k) {
828
+ if (Qnil == v) {
818
829
  copts->dump_opts.hash_size = 0;
819
830
  *copts->dump_opts.hash_nl = '\0';
820
831
  } else {
@@ -827,9 +838,8 @@ void oj_parse_options(VALUE ropts, Options copts) {
827
838
  strcpy(copts->dump_opts.hash_nl, StringValuePtr(v));
828
839
  copts->dump_opts.hash_size = (uint8_t)len;
829
840
  }
830
- }
831
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_array_nl_sym)) {
832
- if (Qnil == (v = rb_hash_lookup(ropts, oj_array_nl_sym))) {
841
+ } else if (oj_array_nl_sym == k) {
842
+ if (Qnil == v) {
833
843
  copts->dump_opts.array_size = 0;
834
844
  *copts->dump_opts.array_nl = '\0';
835
845
  } else {
@@ -842,8 +852,10 @@ void oj_parse_options(VALUE ropts, Options copts) {
842
852
  strcpy(copts->dump_opts.array_nl, StringValuePtr(v));
843
853
  copts->dump_opts.array_size = (uint8_t)len;
844
854
  }
845
- }
846
- if (Qnil != (v = rb_hash_lookup(ropts, nan_sym))) {
855
+ } else if (nan_sym == k) {
856
+ if (Qnil == v) {
857
+ return ST_CONTINUE;
858
+ }
847
859
  if (null_sym == v) {
848
860
  copts->dump_opts.nan_dump = NullNan;
849
861
  } else if (huge_sym == v) {
@@ -857,11 +869,10 @@ void oj_parse_options(VALUE ropts, Options copts) {
857
869
  } else {
858
870
  rb_raise(rb_eArgError, ":nan must be :null, :huge, :word, :raise, or :auto.");
859
871
  }
860
- }
861
- copts->dump_opts.use = (0 < copts->dump_opts.indent_size || 0 < copts->dump_opts.after_size ||
862
- 0 < copts->dump_opts.before_size || 0 < copts->dump_opts.hash_size ||
863
- 0 < copts->dump_opts.array_size);
864
- if (Qnil != (v = rb_hash_lookup(ropts, omit_nil_sym))) {
872
+ } else if (omit_nil_sym == k) {
873
+ if (Qnil == v) {
874
+ return ST_CONTINUE;
875
+ }
865
876
  if (Qtrue == v) {
866
877
  copts->dump_opts.omit_nil = true;
867
878
  } else if (Qfalse == v) {
@@ -869,43 +880,49 @@ void oj_parse_options(VALUE ropts, Options copts) {
869
880
  } else {
870
881
  rb_raise(rb_eArgError, ":omit_nil must be true or false.");
871
882
  }
872
- }
873
- // This is here only for backwards compatibility with the original Oj.
874
- v = rb_hash_lookup(ropts, oj_ascii_only_sym);
875
- if (Qtrue == v) {
876
- copts->escape_mode = ASCIIEsc;
877
- } else if (Qfalse == v) {
878
- copts->escape_mode = JSONEsc;
879
- }
880
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_hash_class_sym)) {
881
- if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) {
883
+ } else if (omit_null_byte_sym == k) {
884
+ if (Qnil == v) {
885
+ return ST_CONTINUE;
886
+ }
887
+ if (Qtrue == v) {
888
+ copts->dump_opts.omit_null_byte = true;
889
+ } else if (Qfalse == v) {
890
+ copts->dump_opts.omit_null_byte = false;
891
+ } else {
892
+ rb_raise(rb_eArgError, ":omit_null_byte must be true or false.");
893
+ }
894
+ } else if (oj_ascii_only_sym == k) {
895
+ // This is here only for backwards compatibility with the original Oj.
896
+ if (Qtrue == v) {
897
+ copts->escape_mode = ASCIIEsc;
898
+ } else if (Qfalse == v) {
899
+ copts->escape_mode = JSONEsc;
900
+ }
901
+ } else if (oj_hash_class_sym == k) {
902
+ if (Qnil == v) {
882
903
  copts->hash_class = Qnil;
883
904
  } else {
884
905
  rb_check_type(v, T_CLASS);
885
906
  copts->hash_class = v;
886
907
  }
887
- }
888
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_object_class_sym)) {
889
- if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) {
908
+ } else if (oj_object_class_sym == k) {
909
+ if (Qnil == v) {
890
910
  copts->hash_class = Qnil;
891
911
  } else {
892
912
  rb_check_type(v, T_CLASS);
893
913
  copts->hash_class = v;
894
914
  }
895
- }
896
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_array_class_sym)) {
897
- if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) {
915
+ } else if (oj_array_class_sym == k) {
916
+ if (Qnil == v) {
898
917
  copts->array_class = Qnil;
899
918
  } else {
900
919
  rb_check_type(v, T_CLASS);
901
920
  copts->array_class = v;
902
921
  }
903
- }
904
- oj_parse_opt_match_string(&copts->str_rx, ropts);
905
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, ignore_sym)) {
906
- xfree(copts->ignore);
922
+ } else if (ignore_sym == k) {
923
+ OJ_R_FREE(copts->ignore);
907
924
  copts->ignore = NULL;
908
- if (Qnil != (v = rb_hash_lookup(ropts, ignore_sym))) {
925
+ if (Qnil != v) {
909
926
  int cnt;
910
927
 
911
928
  rb_check_type(v, T_ARRAY);
@@ -913,16 +930,18 @@ void oj_parse_options(VALUE ropts, Options copts) {
913
930
  if (0 < cnt) {
914
931
  int i;
915
932
 
916
- copts->ignore = ALLOC_N(VALUE, cnt + 1);
933
+ copts->ignore = OJ_R_ALLOC_N(VALUE, cnt + 1);
917
934
  for (i = 0; i < cnt; i++) {
918
- copts->ignore[i] = rb_ary_entry(v, i);
935
+ copts->ignore[i] = RARRAY_AREF(v, i);
919
936
  }
920
937
  copts->ignore[i] = Qnil;
921
938
  }
922
939
  }
923
- }
924
- if (Qnil != (v = rb_hash_lookup(ropts, integer_range_sym))) {
925
- if (TYPE(v) == T_STRUCT && rb_obj_class(v) == rb_cRange) {
940
+ } else if (integer_range_sym == k) {
941
+ if (Qnil == v) {
942
+ return ST_CONTINUE;
943
+ }
944
+ if (rb_obj_class(v) == rb_cRange) {
926
945
  VALUE min = rb_funcall(v, oj_begin_id, 0);
927
946
  VALUE max = rb_funcall(v, oj_end_id, 0);
928
947
 
@@ -935,7 +954,45 @@ void oj_parse_options(VALUE ropts, Options copts) {
935
954
  } else if (Qfalse != v) {
936
955
  rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum.");
937
956
  }
957
+ } else if (symbol_keys_sym == k || oj_symbolize_names_sym == k) {
958
+ if (Qnil == v) {
959
+ return ST_CONTINUE;
960
+ }
961
+ copts->sym_key = (Qtrue == v) ? Yes : No;
962
+
963
+ } else if (oj_max_nesting_sym == k) {
964
+ if (Qtrue == v) {
965
+ copts->dump_opts.max_depth = 100;
966
+ } else if (Qfalse == v || Qnil == v) {
967
+ copts->dump_opts.max_depth = MAX_DEPTH;
968
+ } else if (T_FIXNUM == rb_type(v)) {
969
+ copts->dump_opts.max_depth = NUM2INT(v);
970
+ if (0 >= copts->dump_opts.max_depth) {
971
+ copts->dump_opts.max_depth = MAX_DEPTH;
972
+ }
973
+ }
974
+ } else if (float_format_sym == k) {
975
+ rb_check_type(v, T_STRING);
976
+ if (6 < (int)RSTRING_LEN(v)) {
977
+ rb_raise(rb_eArgError, ":float_format must be 6 bytes or less.");
978
+ }
979
+ strncpy(copts->float_fmt, RSTRING_PTR(v), (size_t)RSTRING_LEN(v));
980
+ copts->float_fmt[RSTRING_LEN(v)] = '\0';
981
+ }
982
+ return ST_CONTINUE;
983
+ }
984
+
985
+ void oj_parse_options(VALUE ropts, Options copts) {
986
+ if (T_HASH != rb_type(ropts)) {
987
+ return;
938
988
  }
989
+ rb_hash_foreach(ropts, parse_options_cb, (VALUE)copts);
990
+ oj_parse_opt_match_string(&copts->str_rx, ropts);
991
+
992
+ copts->dump_opts.use = (0 < copts->dump_opts.indent_size || 0 < copts->dump_opts.after_size ||
993
+ 0 < copts->dump_opts.before_size || 0 < copts->dump_opts.hash_size ||
994
+ 0 < copts->dump_opts.array_size);
995
+ return;
939
996
  }
940
997
 
941
998
  static int match_string_cb(VALUE key, VALUE value, VALUE rx) {
@@ -951,9 +1008,7 @@ static int match_string_cb(VALUE key, VALUE value, VALUE rx) {
951
1008
  rb_raise(rb_eArgError, "%s", rc->err);
952
1009
  }
953
1010
  break;
954
- default:
955
- rb_raise(rb_eArgError, "for :match_string, keys must either a String or RegExp.");
956
- break;
1011
+ default: rb_raise(rb_eArgError, "for :match_string, keys must either a String or RegExp."); break;
957
1012
  }
958
1013
  return ST_CONTINUE;
959
1014
  }
@@ -1086,7 +1141,7 @@ static VALUE load(int argc, VALUE *argv, VALUE self) {
1086
1141
  * Returns [_Object_|_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
1087
1142
  */
1088
1143
  static VALUE load_file(int argc, VALUE *argv, VALUE self) {
1089
- char * path;
1144
+ char *path;
1090
1145
  int fd;
1091
1146
  Mode mode = oj_default_options.mode;
1092
1147
  struct _parseInfo pi;
@@ -1094,7 +1149,7 @@ static VALUE load_file(int argc, VALUE *argv, VALUE self) {
1094
1149
  if (1 > argc) {
1095
1150
  rb_raise(rb_eArgError, "Wrong number of arguments to load().");
1096
1151
  }
1097
- Check_Type(*argv, T_STRING);
1152
+ path = StringValuePtr(*argv);
1098
1153
  parse_info_init(&pi);
1099
1154
  pi.options = oj_default_options;
1100
1155
  pi.handler = Qnil;
@@ -1121,14 +1176,21 @@ static VALUE load_file(int argc, VALUE *argv, VALUE self) {
1121
1176
  } else if (wab_sym == v) {
1122
1177
  mode = WabMode;
1123
1178
  } else {
1124
- rb_raise(
1125
- rb_eArgError,
1126
- ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
1179
+ rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
1127
1180
  }
1128
1181
  }
1129
1182
  }
1130
- path = StringValuePtr(*argv);
1131
- if (0 == (fd = open(path, O_RDONLY))) {
1183
+ #ifdef _WIN32
1184
+ {
1185
+ WCHAR *wide_path;
1186
+ wide_path = rb_w32_mbstr_to_wstr(CP_UTF8, path, -1, NULL);
1187
+ fd = rb_w32_wopen(wide_path, O_RDONLY);
1188
+ OJ_FREE(wide_path);
1189
+ }
1190
+ #else
1191
+ fd = open(path, O_RDONLY);
1192
+ #endif
1193
+ if (0 == fd) {
1132
1194
  rb_raise(rb_eIOError, "%s", strerror(errno));
1133
1195
  }
1134
1196
  switch (mode) {
@@ -1200,6 +1262,35 @@ static VALUE safe_load(VALUE self, VALUE doc) {
1200
1262
  * - *io* [_IO__|_String_] IO Object to read from
1201
1263
  */
1202
1264
 
1265
+ struct dump_arg {
1266
+ struct _out *out;
1267
+ struct _options *copts;
1268
+ int argc;
1269
+ VALUE *argv;
1270
+ };
1271
+
1272
+ static VALUE dump_body(VALUE a) {
1273
+ volatile struct dump_arg *arg = (void *)a;
1274
+ VALUE rstr;
1275
+
1276
+ oj_dump_obj_to_json_using_params(*arg->argv, arg->copts, arg->out, arg->argc - 1, arg->argv + 1);
1277
+ if (0 == arg->out->buf) {
1278
+ rb_raise(rb_eNoMemError, "Not enough memory.");
1279
+ }
1280
+ rstr = rb_str_new2(arg->out->buf);
1281
+ rstr = oj_encode(rstr);
1282
+
1283
+ return rstr;
1284
+ }
1285
+
1286
+ static VALUE dump_ensure(VALUE a) {
1287
+ volatile struct dump_arg *arg = (void *)a;
1288
+
1289
+ oj_out_free(arg->out);
1290
+
1291
+ return Qnil;
1292
+ }
1293
+
1203
1294
  /* Document-method: dump
1204
1295
  * call-seq: dump(obj, options={})
1205
1296
  *
@@ -1208,10 +1299,9 @@ static VALUE safe_load(VALUE self, VALUE doc) {
1208
1299
  * - *options* [_Hash_] same as default_options
1209
1300
  */
1210
1301
  static VALUE dump(int argc, VALUE *argv, VALUE self) {
1211
- char buf[4096];
1302
+ struct dump_arg arg;
1212
1303
  struct _out out;
1213
1304
  struct _options copts = oj_default_options;
1214
- VALUE rstr;
1215
1305
 
1216
1306
  if (1 > argc) {
1217
1307
  rb_raise(rb_eArgError, "wrong number of arguments (0 for 1).");
@@ -1225,21 +1315,17 @@ static VALUE dump(int argc, VALUE *argv, VALUE self) {
1225
1315
  if (CompatMode == copts.mode && copts.escape_mode != ASCIIEsc) {
1226
1316
  copts.escape_mode = JSONEsc;
1227
1317
  }
1228
- out.buf = buf;
1229
- out.end = buf + sizeof(buf) - 10;
1230
- out.allocated = false;
1231
- out.omit_nil = copts.dump_opts.omit_nil;
1232
- out.caller = CALLER_DUMP;
1233
- oj_dump_obj_to_json_using_params(*argv, &copts, &out, argc - 1, argv + 1);
1234
- if (0 == out.buf) {
1235
- rb_raise(rb_eNoMemError, "Not enough memory.");
1236
- }
1237
- rstr = rb_str_new2(out.buf);
1238
- rstr = oj_encode(rstr);
1239
- if (out.allocated) {
1240
- xfree(out.buf);
1241
- }
1242
- return rstr;
1318
+ arg.out = &out;
1319
+ arg.copts = &copts;
1320
+ arg.argc = argc;
1321
+ arg.argv = argv;
1322
+
1323
+ oj_out_init(arg.out);
1324
+
1325
+ arg.out->omit_nil = copts.dump_opts.omit_nil;
1326
+ arg.out->omit_null_byte = copts.dump_opts.omit_null_byte;
1327
+
1328
+ return rb_ensure(dump_body, (VALUE)&arg, dump_ensure, (VALUE)&arg);
1243
1329
  }
1244
1330
 
1245
1331
  /* Document-method: to_json
@@ -1249,17 +1335,16 @@ static VALUE dump(int argc, VALUE *argv, VALUE self) {
1249
1335
  * will be called. The mode is set to :compat.
1250
1336
  * - *obj* [_Object_] Object to serialize as an JSON document String
1251
1337
  * - *options* [_Hash_]
1252
- * - *:max_nesting* [_boolean_] It true nesting is limited to 100. The option to detect circular
1253
- * references is available but is not compatible with the json gem., default is false
1254
- * - *:allow_nan* [_boolean_] If true non JSON compliant words such as Nan and Infinity will be
1255
- * used as appropriate, default is true.
1256
- * - *:quirks_mode* [_boolean_] Allow single JSON values instead of documents, default is true
1257
- * (allow).
1258
- * - *:indent* [_String_|_nil_] String to use for indentation, overriding the indent option if not
1259
- * nil.
1338
+ * - *:max_nesting* [_Fixnum_|_boolean_] It true nesting is limited to 100.
1339
+ * If a Fixnum nesting is set to the provided value. The option to detect
1340
+ * circular references is available but is not compatible with the json gem.,
1341
+ * default is false or unlimited.
1342
+ * - *:allow_nan* [_boolean_] If true non JSON compliant words such as Nan and
1343
+ * Infinity will be used as appropriate, default is true.
1344
+ * - *:quirks_mode* [_boolean_] Allow single JSON values instead of documents, default is true (allow).
1345
+ * - *:indent* [_String_|_nil_] String to use for indentation, overriding the indent option if not nil.
1260
1346
  * - *:space* [_String_|_nil_] String to use for the space after the colon in JSON object fields.
1261
- * - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object
1262
- * fields.
1347
+ * - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object fields.
1263
1348
  * - *:object_nl* [_String_|_nil_] String to use after a JSON object field value.
1264
1349
  * - *:array_nl* [_String_|_nil_] String to use after a JSON array value.
1265
1350
  * - *:trace* [_Boolean_] If true trace is turned on.
@@ -1267,7 +1352,6 @@ static VALUE dump(int argc, VALUE *argv, VALUE self) {
1267
1352
  * Returns [_String_] the encoded JSON.
1268
1353
  */
1269
1354
  static VALUE to_json(int argc, VALUE *argv, VALUE self) {
1270
- char buf[4096];
1271
1355
  struct _out out;
1272
1356
  struct _options copts = oj_default_options;
1273
1357
  VALUE rstr;
@@ -1282,10 +1366,11 @@ static VALUE to_json(int argc, VALUE *argv, VALUE self) {
1282
1366
  }
1283
1367
  copts.mode = CompatMode;
1284
1368
  copts.to_json = Yes;
1285
- out.buf = buf;
1286
- out.end = buf + sizeof(buf) - 10;
1287
- out.allocated = false;
1288
- out.omit_nil = copts.dump_opts.omit_nil;
1369
+
1370
+ oj_out_init(&out);
1371
+
1372
+ out.omit_nil = copts.dump_opts.omit_nil;
1373
+ out.omit_null_byte = copts.dump_opts.omit_null_byte;
1289
1374
  // For obj.to_json or generate nan is not allowed but if called from dump
1290
1375
  // it is.
1291
1376
  oj_dump_obj_to_json_using_params(*argv, &copts, &out, argc - 1, argv + 1);
@@ -1295,9 +1380,9 @@ static VALUE to_json(int argc, VALUE *argv, VALUE self) {
1295
1380
  }
1296
1381
  rstr = rb_str_new2(out.buf);
1297
1382
  rstr = oj_encode(rstr);
1298
- if (out.allocated) {
1299
- xfree(out.buf);
1300
- }
1383
+
1384
+ oj_out_free(&out);
1385
+
1301
1386
  return rstr;
1302
1387
  }
1303
1388
 
@@ -1307,7 +1392,7 @@ static VALUE to_json(int argc, VALUE *argv, VALUE self) {
1307
1392
  * Dumps an Object to the specified file.
1308
1393
  * - *file* [_String_] _path file path to write the JSON document to
1309
1394
  * - *obj* [_Object_] Object to serialize as an JSON document String
1310
- * - *options* [_Hash_] formating options
1395
+ * - *options* [_Hash_] formatting options
1311
1396
  * - *:indent* [_Fixnum_] format expected
1312
1397
  * - *:circular* [_Boolean_] allow circular references, default: false
1313
1398
  */
@@ -1317,7 +1402,6 @@ static VALUE to_file(int argc, VALUE *argv, VALUE self) {
1317
1402
  if (3 == argc) {
1318
1403
  oj_parse_options(argv[2], &copts);
1319
1404
  }
1320
- Check_Type(*argv, T_STRING);
1321
1405
  oj_write_obj_to_file(argv[1], StringValuePtr(*argv), &copts);
1322
1406
 
1323
1407
  return Qnil;
@@ -1329,7 +1413,7 @@ static VALUE to_file(int argc, VALUE *argv, VALUE self) {
1329
1413
  * Dumps an Object to the specified IO stream.
1330
1414
  * - *io* [_IO_] IO stream to write the JSON document to
1331
1415
  * - *obj* [_Object_] Object to serialize as an JSON document String
1332
- * - *options* [_Hash_] formating options
1416
+ * - *options* [_Hash_] formatting options
1333
1417
  * - *:indent* [_Fixnum_] format expected
1334
1418
  * - *:circular* [_Boolean_] allow circular references, default: false
1335
1419
  */
@@ -1355,10 +1439,10 @@ static VALUE to_stream(int argc, VALUE *argv, VALUE self) {
1355
1439
  *
1356
1440
  * - *clas* [_Class__|_Module_] Class or Module to be made special
1357
1441
  * - *create_object* [_Object_] object to call the create method on
1358
- * - *create_method* [_Symbol_] method on the clas that will create a new instance of the clas when
1359
- * given all the member values in the order specified.
1360
- * - *members* [_Symbol__|_String_] methods used to get the member values from instances of the
1361
- * clas.
1442
+ * - *create_method* [_Symbol_] method on the clas that will create a new instance
1443
+ * of the clas when given all the member values in the order specified.
1444
+ * - *members* [_Symbol__|_String_] methods used to get the member values from
1445
+ * instances of the clas.
1362
1446
  */
1363
1447
  static VALUE register_odd(int argc, VALUE *argv, VALUE self) {
1364
1448
  if (3 > argc) {
@@ -1391,10 +1475,10 @@ static VALUE register_odd(int argc, VALUE *argv, VALUE self) {
1391
1475
  *
1392
1476
  * - *clas* [_Class_|_Module_] Class or Module to be made special
1393
1477
  * - *create_object* [_Object_] object to call the create method on
1394
- * - *create_method* [_Symbol_] method on the clas that will create a new instance of the clas when
1395
- *given all the member values in the order specified.
1396
- * - *dump_method* [_Symbol_|_String_] method to call on the object being serialized to generate the
1397
- *raw JSON.
1478
+ * - *create_method* [_Symbol_] method on the clas that will create a new instance
1479
+ * of the clas when given all the member values in the order specified.
1480
+ * - *dump_method* [_Symbol_|_String_] method to call on the object being
1481
+ * serialized to generate the raw JSON.
1398
1482
  */
1399
1483
  static VALUE register_odd_raw(int argc, VALUE *argv, VALUE self) {
1400
1484
  if (3 > argc) {
@@ -1620,8 +1704,8 @@ extern VALUE oj_define_mimic_json(int argc, VALUE *argv, VALUE self);
1620
1704
  * - *:space_before* [_String_] String placed before a : delimiter
1621
1705
  * - *:object_nl* [_String_] String placed after a JSON object
1622
1706
  * - *:array_nl* [_String_] String placed after a JSON array
1623
- * - *:ascii_only* [_Boolean_] if not nil or false then use only ascii characters in the output.
1624
- * Note JSON.generate does support this even if it is not documented.
1707
+ * - *:ascii_only* [_Boolean_] if not nil or false then use only ascii characters
1708
+ * in the output. Note JSON.generate does support this even if it is not documented.
1625
1709
  *
1626
1710
  * Returns [_String_]generated JSON.
1627
1711
  */
@@ -1636,13 +1720,20 @@ extern VALUE oj_optimize_rails(VALUE self);
1636
1720
 
1637
1721
  /*
1638
1722
  extern void oj_hash_test();
1639
-
1640
1723
  static VALUE
1641
1724
  hash_test(VALUE self) {
1642
1725
  oj_hash_test();
1643
1726
  return Qnil;
1644
1727
  }
1645
1728
  */
1729
+ /*
1730
+ extern void oj_hash_sizes();
1731
+ static VALUE
1732
+ hash_test(VALUE self) {
1733
+ oj_hash_sizes();
1734
+ return Qnil;
1735
+ }
1736
+ */
1646
1737
 
1647
1738
  static VALUE protect_require(VALUE x) {
1648
1739
  rb_require("time");
@@ -1650,6 +1741,18 @@ static VALUE protect_require(VALUE x) {
1650
1741
  return Qnil;
1651
1742
  }
1652
1743
 
1744
+ extern void print_all_odds(const char *label);
1745
+
1746
+ static VALUE debug_odd(VALUE self, VALUE label) {
1747
+ print_all_odds(RSTRING_PTR(label));
1748
+ return Qnil;
1749
+ }
1750
+
1751
+ static VALUE mem_report(VALUE self) {
1752
+ oj_mem_report();
1753
+ return Qnil;
1754
+ }
1755
+
1653
1756
  /* Document-module: Oj
1654
1757
  *
1655
1758
  * Optimized JSON (Oj), as the name implies was written to provide speed
@@ -1659,8 +1762,8 @@ static VALUE protect_require(VALUE x) {
1659
1762
  * global and options to methods allow additional behavior modifications. The
1660
1763
  * modes are:
1661
1764
  *
1662
- * - *:strict* mode will only allow the 7 basic JSON types to be serialized. Any other Object
1663
- * will raise an Exception.
1765
+ * - *:strict* mode will only allow the 7 basic JSON types to be serialized.
1766
+ * Any other Object will raise an Exception.
1664
1767
  *
1665
1768
  * - *:null* mode is similar to the :strict mode except any Object that is not
1666
1769
  * one of the JSON base types is replaced by a JSON null.
@@ -1678,12 +1781,19 @@ static VALUE protect_require(VALUE x) {
1678
1781
  *
1679
1782
  * - *:wab* specifically for WAB data exchange.
1680
1783
  */
1681
- void Init_oj() {
1784
+ void Init_oj(void) {
1682
1785
  int err = 0;
1683
1786
 
1787
+ #if HAVE_RB_EXT_RACTOR_SAFE
1788
+ rb_ext_ractor_safe(true);
1789
+ #endif
1684
1790
  Oj = rb_define_module("Oj");
1791
+ rb_gc_register_address(&Oj);
1685
1792
 
1686
1793
  oj_cstack_class = rb_define_class_under(Oj, "CStack", rb_cObject);
1794
+ rb_gc_register_address(&oj_cstack_class);
1795
+
1796
+ rb_undef_alloc_func(oj_cstack_class);
1687
1797
 
1688
1798
  oj_string_writer_init();
1689
1799
  oj_stream_writer_init();
@@ -1692,9 +1802,11 @@ void Init_oj() {
1692
1802
  // On Rubinius the require fails but can be done from a ruby file.
1693
1803
  rb_protect(protect_require, Qnil, &err);
1694
1804
  rb_require("stringio");
1695
- oj_utf8_encoding = rb_enc_find("UTF-8");
1805
+ oj_utf8_encoding_index = rb_enc_find_index("UTF-8");
1806
+ oj_utf8_encoding = rb_enc_from_index(oj_utf8_encoding_index);
1696
1807
 
1697
1808
  // rb_define_module_function(Oj, "hash_test", hash_test, 0);
1809
+ rb_define_module_function(Oj, "debug_odd", debug_odd, 1);
1698
1810
 
1699
1811
  rb_define_module_function(Oj, "default_options", get_def_opts, 0);
1700
1812
  rb_define_module_function(Oj, "default_options=", set_def_opts, 1);
@@ -1728,50 +1840,52 @@ void Init_oj() {
1728
1840
 
1729
1841
  rb_define_module_function(Oj, "optimize_rails", oj_optimize_rails, 0);
1730
1842
 
1731
- oj_add_value_id = rb_intern("add_value");
1732
- oj_array_append_id = rb_intern("array_append");
1733
- oj_array_end_id = rb_intern("array_end");
1734
- oj_array_start_id = rb_intern("array_start");
1735
- oj_as_json_id = rb_intern("as_json");
1736
- oj_begin_id = rb_intern("begin");
1737
- oj_bigdecimal_id = rb_intern("BigDecimal");
1738
- oj_end_id = rb_intern("end");
1739
- oj_error_id = rb_intern("error");
1740
- oj_exclude_end_id = rb_intern("exclude_end?");
1741
- oj_file_id = rb_intern("file?");
1742
- oj_fileno_id = rb_intern("fileno");
1743
- oj_ftype_id = rb_intern("ftype");
1744
- oj_has_key_id = rb_intern("has_key?");
1745
- oj_hash_end_id = rb_intern("hash_end");
1746
- oj_hash_key_id = rb_intern("hash_key");
1747
- oj_hash_set_id = rb_intern("hash_set");
1748
- oj_hash_start_id = rb_intern("hash_start");
1749
- oj_iconv_id = rb_intern("iconv");
1750
- oj_instance_variables_id = rb_intern("instance_variables");
1751
- oj_json_create_id = rb_intern("json_create");
1752
- oj_length_id = rb_intern("length");
1753
- oj_new_id = rb_intern("new");
1754
- oj_parse_id = rb_intern("parse");
1755
- oj_pos_id = rb_intern("pos");
1756
- oj_raw_json_id = rb_intern("raw_json");
1757
- oj_read_id = rb_intern("read");
1758
- oj_readpartial_id = rb_intern("readpartial");
1759
- oj_replace_id = rb_intern("replace");
1760
- oj_stat_id = rb_intern("stat");
1761
- oj_string_id = rb_intern("string");
1762
- oj_to_h_id = rb_intern("to_h");
1763
- oj_to_hash_id = rb_intern("to_hash");
1764
- oj_to_json_id = rb_intern("to_json");
1765
- oj_to_s_id = rb_intern("to_s");
1766
- oj_to_sym_id = rb_intern("to_sym");
1767
- oj_to_time_id = rb_intern("to_time");
1768
- oj_tv_nsec_id = rb_intern("tv_nsec");
1769
- oj_tv_sec_id = rb_intern("tv_sec");
1770
- oj_tv_usec_id = rb_intern("tv_usec");
1771
- oj_utc_id = rb_intern("utc");
1772
- oj_utc_offset_id = rb_intern("utc_offset");
1773
- oj_utcq_id = rb_intern("utc?");
1774
- oj_write_id = rb_intern("write");
1843
+ rb_define_module_function(Oj, "mem_report", mem_report, 0);
1844
+
1845
+ oj_add_value_id = rb_intern("add_value");
1846
+ oj_array_append_id = rb_intern("array_append");
1847
+ oj_array_end_id = rb_intern("array_end");
1848
+ oj_array_start_id = rb_intern("array_start");
1849
+ oj_as_json_id = rb_intern("as_json");
1850
+ oj_begin_id = rb_intern("begin");
1851
+ oj_bigdecimal_id = rb_intern("BigDecimal");
1852
+ oj_end_id = rb_intern("end");
1853
+ oj_eofq_id = rb_intern("eof?");
1854
+ oj_error_id = rb_intern("error");
1855
+ oj_exclude_end_id = rb_intern("exclude_end?");
1856
+ oj_file_id = rb_intern("file?");
1857
+ oj_fileno_id = rb_intern("fileno");
1858
+ oj_ftype_id = rb_intern("ftype");
1859
+ oj_hash_end_id = rb_intern("hash_end");
1860
+ oj_hash_key_id = rb_intern("hash_key");
1861
+ oj_hash_set_id = rb_intern("hash_set");
1862
+ oj_hash_start_id = rb_intern("hash_start");
1863
+ oj_iconv_id = rb_intern("iconv");
1864
+ oj_json_create_id = rb_intern("json_create");
1865
+ oj_length_id = rb_intern("length");
1866
+ oj_new_id = rb_intern("new");
1867
+ oj_parse_id = rb_intern("parse");
1868
+ oj_plus_id = rb_intern("+");
1869
+ oj_pos_id = rb_intern("pos");
1870
+ oj_raw_json_id = rb_intern("raw_json");
1871
+ oj_read_id = rb_intern("read");
1872
+ oj_readpartial_id = rb_intern("readpartial");
1873
+ oj_replace_id = rb_intern("replace");
1874
+ oj_stat_id = rb_intern("stat");
1875
+ oj_string_id = rb_intern("string");
1876
+ oj_to_h_id = rb_intern("to_h");
1877
+ oj_to_hash_id = rb_intern("to_hash");
1878
+ oj_to_json_id = rb_intern("to_json");
1879
+ oj_to_s_id = rb_intern("to_s");
1880
+ oj_to_sym_id = rb_intern("to_sym");
1881
+ oj_to_time_id = rb_intern("to_time");
1882
+ oj_tv_nsec_id = rb_intern("tv_nsec");
1883
+ oj_tv_sec_id = rb_intern("tv_sec");
1884
+ oj_tv_usec_id = rb_intern("tv_usec");
1885
+ oj_utc_id = rb_intern("utc");
1886
+ oj_utc_offset_id = rb_intern("utc_offset");
1887
+ oj_utcq_id = rb_intern("utc?");
1888
+ oj_write_id = rb_intern("write");
1775
1889
 
1776
1890
  rb_require("oj/bag");
1777
1891
  rb_require("oj/error");
@@ -1816,6 +1930,12 @@ void Init_oj() {
1816
1930
  rb_gc_register_address(&bigdecimal_load_sym);
1817
1931
  bigdecimal_sym = ID2SYM(rb_intern("bigdecimal"));
1818
1932
  rb_gc_register_address(&bigdecimal_sym);
1933
+ cache_keys_sym = ID2SYM(rb_intern("cache_keys"));
1934
+ rb_gc_register_address(&cache_keys_sym);
1935
+ cache_str_sym = ID2SYM(rb_intern("cache_str"));
1936
+ rb_gc_register_address(&cache_str_sym);
1937
+ cache_string_sym = ID2SYM(rb_intern("cache_string"));
1938
+ rb_gc_register_address(&cache_string_sym);
1819
1939
  circular_sym = ID2SYM(rb_intern("circular"));
1820
1940
  rb_gc_register_address(&circular_sym);
1821
1941
  class_cache_sym = ID2SYM(rb_intern("class_cache"));
@@ -1836,6 +1956,8 @@ void Init_oj() {
1836
1956
  rb_gc_register_address(&integer_range_sym);
1837
1957
  fast_sym = ID2SYM(rb_intern("fast"));
1838
1958
  rb_gc_register_address(&fast_sym);
1959
+ float_format_sym = ID2SYM(rb_intern("float_format"));
1960
+ rb_gc_register_address(&float_format_sym);
1839
1961
  float_prec_sym = ID2SYM(rb_intern("float_precision"));
1840
1962
  rb_gc_register_address(&float_prec_sym);
1841
1963
  float_sym = ID2SYM(rb_intern("float"));
@@ -1888,6 +2010,8 @@ void Init_oj() {
1888
2010
  rb_gc_register_address(&oj_quirks_mode_sym);
1889
2011
  oj_safe_sym = ID2SYM(rb_intern("safe"));
1890
2012
  rb_gc_register_address(&oj_safe_sym);
2013
+ omit_null_byte_sym = ID2SYM(rb_intern("omit_null_byte"));
2014
+ rb_gc_register_address(&omit_null_byte_sym);
1891
2015
  oj_space_before_sym = ID2SYM(rb_intern("space_before"));
1892
2016
  rb_gc_register_address(&oj_space_before_sym);
1893
2017
  oj_space_sym = ID2SYM(rb_intern("space"));
@@ -1904,10 +2028,14 @@ void Init_oj() {
1904
2028
  rb_gc_register_address(&ruby_sym);
1905
2029
  sec_prec_sym = ID2SYM(rb_intern("second_precision"));
1906
2030
  rb_gc_register_address(&sec_prec_sym);
2031
+ slash_sym = ID2SYM(rb_intern("slash"));
2032
+ rb_gc_register_address(&slash_sym);
1907
2033
  strict_sym = ID2SYM(rb_intern("strict"));
1908
2034
  rb_gc_register_address(&strict_sym);
1909
2035
  symbol_keys_sym = ID2SYM(rb_intern("symbol_keys"));
1910
2036
  rb_gc_register_address(&symbol_keys_sym);
2037
+ oj_symbolize_names_sym = ID2SYM(rb_intern("symbolize_names"));
2038
+ rb_gc_register_address(&oj_symbolize_names_sym);
1911
2039
  time_format_sym = ID2SYM(rb_intern("time_format"));
1912
2040
  rb_gc_register_address(&time_format_sym);
1913
2041
  unicode_xss_sym = ID2SYM(rb_intern("unicode_xss"));
@@ -1952,4 +2080,7 @@ void Init_oj() {
1952
2080
  rb_gc_register_address(&oj_cache_mutex);
1953
2081
  #endif
1954
2082
  oj_init_doc();
2083
+
2084
+ oj_parser_init();
2085
+ oj_scanner_init();
1955
2086
  }