nano-safe-gem 0.0.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 (97) hide show
  1. checksums.yaml +7 -0
  2. data/nano-safe-gem.gemspec +12 -0
  3. data/oj-3.17.3/CHANGELOG.md +1506 -0
  4. data/oj-3.17.3/LICENSE +21 -0
  5. data/oj-3.17.3/README.md +103 -0
  6. data/oj-3.17.3/RELEASE_NOTES.md +61 -0
  7. data/oj-3.17.3/ext/oj/buf.h +85 -0
  8. data/oj-3.17.3/ext/oj/cache.c +329 -0
  9. data/oj-3.17.3/ext/oj/cache.h +22 -0
  10. data/oj-3.17.3/ext/oj/cache8.c +105 -0
  11. data/oj-3.17.3/ext/oj/cache8.h +21 -0
  12. data/oj-3.17.3/ext/oj/circarray.c +64 -0
  13. data/oj-3.17.3/ext/oj/circarray.h +22 -0
  14. data/oj-3.17.3/ext/oj/code.c +214 -0
  15. data/oj-3.17.3/ext/oj/code.h +40 -0
  16. data/oj-3.17.3/ext/oj/compat.c +239 -0
  17. data/oj-3.17.3/ext/oj/custom.c +1079 -0
  18. data/oj-3.17.3/ext/oj/debug.c +126 -0
  19. data/oj-3.17.3/ext/oj/dump.c +1765 -0
  20. data/oj-3.17.3/ext/oj/dump.h +112 -0
  21. data/oj-3.17.3/ext/oj/dump_compat.c +902 -0
  22. data/oj-3.17.3/ext/oj/dump_leaf.c +162 -0
  23. data/oj-3.17.3/ext/oj/dump_object.c +715 -0
  24. data/oj-3.17.3/ext/oj/dump_strict.c +404 -0
  25. data/oj-3.17.3/ext/oj/encode.h +16 -0
  26. data/oj-3.17.3/ext/oj/encoder.c +43 -0
  27. data/oj-3.17.3/ext/oj/err.c +57 -0
  28. data/oj-3.17.3/ext/oj/err.h +67 -0
  29. data/oj-3.17.3/ext/oj/extconf.rb +72 -0
  30. data/oj-3.17.3/ext/oj/fast.c +1730 -0
  31. data/oj-3.17.3/ext/oj/intern.c +313 -0
  32. data/oj-3.17.3/ext/oj/intern.h +22 -0
  33. data/oj-3.17.3/ext/oj/mem.c +318 -0
  34. data/oj-3.17.3/ext/oj/mem.h +53 -0
  35. data/oj-3.17.3/ext/oj/mimic_json.c +922 -0
  36. data/oj-3.17.3/ext/oj/object.c +726 -0
  37. data/oj-3.17.3/ext/oj/odd.c +245 -0
  38. data/oj-3.17.3/ext/oj/odd.h +43 -0
  39. data/oj-3.17.3/ext/oj/oj.c +2332 -0
  40. data/oj-3.17.3/ext/oj/oj.h +405 -0
  41. data/oj-3.17.3/ext/oj/parse.c +1367 -0
  42. data/oj-3.17.3/ext/oj/parse.h +113 -0
  43. data/oj-3.17.3/ext/oj/parser.c +1676 -0
  44. data/oj-3.17.3/ext/oj/parser.h +103 -0
  45. data/oj-3.17.3/ext/oj/rails.c +1480 -0
  46. data/oj-3.17.3/ext/oj/rails.h +18 -0
  47. data/oj-3.17.3/ext/oj/reader.c +220 -0
  48. data/oj-3.17.3/ext/oj/reader.h +137 -0
  49. data/oj-3.17.3/ext/oj/resolve.c +80 -0
  50. data/oj-3.17.3/ext/oj/resolve.h +12 -0
  51. data/oj-3.17.3/ext/oj/rxclass.c +144 -0
  52. data/oj-3.17.3/ext/oj/rxclass.h +26 -0
  53. data/oj-3.17.3/ext/oj/safe.c +230 -0
  54. data/oj-3.17.3/ext/oj/safe.h +79 -0
  55. data/oj-3.17.3/ext/oj/saj.c +677 -0
  56. data/oj-3.17.3/ext/oj/saj2.c +584 -0
  57. data/oj-3.17.3/ext/oj/saj2.h +23 -0
  58. data/oj-3.17.3/ext/oj/scp.c +185 -0
  59. data/oj-3.17.3/ext/oj/simd.h +219 -0
  60. data/oj-3.17.3/ext/oj/sparse.c +943 -0
  61. data/oj-3.17.3/ext/oj/stream_writer.c +329 -0
  62. data/oj-3.17.3/ext/oj/strict.c +187 -0
  63. data/oj-3.17.3/ext/oj/string_writer.c +517 -0
  64. data/oj-3.17.3/ext/oj/trace.c +72 -0
  65. data/oj-3.17.3/ext/oj/trace.h +55 -0
  66. data/oj-3.17.3/ext/oj/usual.c +1231 -0
  67. data/oj-3.17.3/ext/oj/usual.h +69 -0
  68. data/oj-3.17.3/ext/oj/util.c +136 -0
  69. data/oj-3.17.3/ext/oj/util.h +20 -0
  70. data/oj-3.17.3/ext/oj/val_stack.c +101 -0
  71. data/oj-3.17.3/ext/oj/val_stack.h +151 -0
  72. data/oj-3.17.3/ext/oj/validate.c +46 -0
  73. data/oj-3.17.3/ext/oj/wab.c +586 -0
  74. data/oj-3.17.3/lib/oj/active_support_helper.rb +39 -0
  75. data/oj-3.17.3/lib/oj/bag.rb +95 -0
  76. data/oj-3.17.3/lib/oj/easy_hash.rb +52 -0
  77. data/oj-3.17.3/lib/oj/error.rb +21 -0
  78. data/oj-3.17.3/lib/oj/json.rb +188 -0
  79. data/oj-3.17.3/lib/oj/mimic.rb +301 -0
  80. data/oj-3.17.3/lib/oj/saj.rb +80 -0
  81. data/oj-3.17.3/lib/oj/schandler.rb +143 -0
  82. data/oj-3.17.3/lib/oj/state.rb +135 -0
  83. data/oj-3.17.3/lib/oj/version.rb +4 -0
  84. data/oj-3.17.3/lib/oj.rb +15 -0
  85. data/oj-3.17.3/pages/Advanced.md +22 -0
  86. data/oj-3.17.3/pages/Compatibility.md +25 -0
  87. data/oj-3.17.3/pages/Custom.md +23 -0
  88. data/oj-3.17.3/pages/Encoding.md +65 -0
  89. data/oj-3.17.3/pages/InstallOptions.md +20 -0
  90. data/oj-3.17.3/pages/JsonGem.md +94 -0
  91. data/oj-3.17.3/pages/Modes.md +161 -0
  92. data/oj-3.17.3/pages/Options.md +337 -0
  93. data/oj-3.17.3/pages/Parser.md +309 -0
  94. data/oj-3.17.3/pages/Rails.md +167 -0
  95. data/oj-3.17.3/pages/Security.md +20 -0
  96. data/oj-3.17.3/pages/WAB.md +13 -0
  97. metadata +136 -0
@@ -0,0 +1,2332 @@
1
+ // Copyright (c) 2012 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #include "oj.h"
5
+
6
+ #include <errno.h>
7
+ #include <fcntl.h>
8
+ #include <stdio.h>
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+ #include <sys/types.h>
12
+ #include <unistd.h>
13
+
14
+ #include "dump.h"
15
+ #include "encode.h"
16
+ #include "intern.h"
17
+ #include "mem.h"
18
+ #include "odd.h"
19
+ #include "parse.h"
20
+ #include "rails.h"
21
+ #include "simd.h"
22
+
23
+ #define MAX_INDENT 16
24
+
25
+ typedef struct _yesNoOpt {
26
+ VALUE sym;
27
+ char *attr;
28
+ } *YesNoOpt;
29
+
30
+ void Init_oj();
31
+
32
+ VALUE Oj = Qnil;
33
+
34
+ ID oj_add_value_id;
35
+ ID oj_array_append_id;
36
+ ID oj_array_end_id;
37
+ ID oj_array_start_id;
38
+ ID oj_as_json_id;
39
+ ID oj_begin_id;
40
+ ID oj_bigdecimal_id;
41
+ ID oj_end_id;
42
+ ID oj_eofq_id;
43
+ ID oj_exclude_end_id;
44
+ ID oj_error_id;
45
+ ID oj_file_id;
46
+ ID oj_fileno_id;
47
+ ID oj_ftype_id;
48
+ ID oj_hash_end_id;
49
+ ID oj_hash_key_id;
50
+ ID oj_hash_set_id;
51
+ ID oj_hash_start_id;
52
+ ID oj_iconv_id;
53
+ ID oj_json_create_id;
54
+ ID oj_length_id;
55
+ ID oj_new_id;
56
+ ID oj_parse_id;
57
+ ID oj_plus_id;
58
+ ID oj_pos_id;
59
+ ID oj_raw_json_id;
60
+ ID oj_read_id;
61
+ ID oj_readpartial_id;
62
+ ID oj_replace_id;
63
+ ID oj_stat_id;
64
+ ID oj_string_id;
65
+ ID oj_to_h_id;
66
+ ID oj_to_hash_id;
67
+ ID oj_to_json_id;
68
+ ID oj_to_s_id;
69
+ ID oj_to_sym_id;
70
+ ID oj_to_time_id;
71
+ ID oj_tv_nsec_id;
72
+ ID oj_tv_sec_id;
73
+ ID oj_tv_usec_id;
74
+ ID oj_utc_id;
75
+ ID oj_utc_offset_id;
76
+ ID oj_utcq_id;
77
+ ID oj_write_id;
78
+
79
+ VALUE oj_bag_class;
80
+ VALUE oj_bigdecimal_class;
81
+ VALUE oj_cstack_class;
82
+ VALUE oj_date_class;
83
+ VALUE oj_datetime_class;
84
+ VALUE oj_enumerable_class;
85
+ VALUE oj_parse_error_class;
86
+ VALUE oj_stream_writer_class;
87
+ VALUE oj_string_writer_class;
88
+ VALUE oj_stringio_class;
89
+ VALUE oj_struct_class;
90
+
91
+ VALUE oj_slash_string;
92
+
93
+ VALUE oj_allow_nan_sym;
94
+ VALUE oj_array_class_sym;
95
+ VALUE oj_create_additions_sym;
96
+ VALUE oj_decimal_class_sym;
97
+ VALUE oj_hash_class_sym;
98
+ VALUE oj_indent_sym;
99
+ VALUE oj_object_class_sym;
100
+ VALUE oj_quirks_mode_sym;
101
+ VALUE oj_safe_sym;
102
+ VALUE oj_symbolize_names_sym;
103
+ VALUE oj_trace_sym;
104
+
105
+ static VALUE allow_blank_sym;
106
+ static VALUE allow_gc_sym;
107
+ static VALUE allow_invalid_unicode_sym;
108
+ static VALUE ascii_sym;
109
+ static VALUE auto_define_sym;
110
+ static VALUE auto_sym;
111
+ static VALUE bigdecimal_as_decimal_sym;
112
+ static VALUE bigdecimal_load_sym;
113
+ static VALUE bigdecimal_sym;
114
+ static VALUE cache_keys_sym;
115
+ static VALUE cache_str_sym;
116
+ static VALUE cache_string_sym;
117
+ static VALUE circular_sym;
118
+ static VALUE class_cache_sym;
119
+ static VALUE compat_bigdecimal_sym;
120
+ static VALUE compat_sym;
121
+ static VALUE create_id_sym;
122
+ static VALUE custom_sym;
123
+ static VALUE empty_string_sym;
124
+ static VALUE escape_mode_sym;
125
+ static VALUE except_sym;
126
+ static VALUE integer_range_sym;
127
+ static VALUE max_integer_digits_sym;
128
+ static VALUE fast_sym;
129
+ static VALUE float_prec_sym;
130
+ static VALUE float_format_sym;
131
+ static VALUE float_sym;
132
+ static VALUE huge_sym;
133
+ static VALUE ignore_sym;
134
+ static VALUE ignore_under_sym;
135
+ static VALUE json_sym;
136
+ static VALUE match_string_sym;
137
+ static VALUE mode_sym;
138
+ static VALUE nan_sym;
139
+ static VALUE newline_sym;
140
+ static VALUE nilnil_sym;
141
+ static VALUE null_sym;
142
+ static VALUE object_sym;
143
+ static VALUE omit_null_byte_sym;
144
+ static VALUE omit_nil_sym;
145
+ static VALUE only_sym;
146
+ static VALUE rails_sym;
147
+ static VALUE raise_sym;
148
+ static VALUE ruby_sym;
149
+ static VALUE sec_prec_sym;
150
+ static VALUE slash_sym;
151
+ static VALUE strict_sym;
152
+ static VALUE symbol_keys_sym;
153
+ static VALUE time_format_sym;
154
+ static VALUE unicode_xss_sym;
155
+ static VALUE unix_sym;
156
+ static VALUE unix_zone_sym;
157
+ static VALUE use_as_json_sym;
158
+ static VALUE use_raw_json_sym;
159
+ static VALUE use_to_hash_sym;
160
+ static VALUE use_to_json_sym;
161
+ static VALUE wab_sym;
162
+ static VALUE word_sym;
163
+ static VALUE xmlschema_sym;
164
+ static VALUE xss_safe_sym;
165
+
166
+ rb_encoding *oj_utf8_encoding = 0;
167
+ int oj_utf8_encoding_index = 0;
168
+
169
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
170
+ pthread_mutex_t oj_cache_mutex;
171
+ #else
172
+ VALUE oj_cache_mutex = Qnil;
173
+ #endif
174
+
175
+ SIMD_Implementation SIMD_Impl = SIMD_NONE;
176
+
177
+ extern void oj_parser_init();
178
+
179
+ const char oj_json_class[] = "json_class";
180
+
181
+ struct _options oj_default_options = {
182
+ 0, // indent
183
+ No, // circular
184
+ No, // auto_define
185
+ No, // sym_key
186
+ JSONEsc, // escape_mode
187
+ ObjectMode, // mode
188
+ Yes, // class_cache
189
+ UnixTime, // time_format
190
+ NotSet, // bigdec_as_num
191
+ AutoDec, // bigdec_load
192
+ false, // compat_bigdec
193
+ No, // to_hash
194
+ No, // to_json
195
+ No, // as_json
196
+ No, // raw_json
197
+ No, // nilnil
198
+ Yes, // empty_string
199
+ Yes, // allow_gc
200
+ Yes, // quirks_mode
201
+ No, // allow_invalid
202
+ No, // create_ok
203
+ Yes, // allow_nan
204
+ No, // trace
205
+ No, // safe
206
+ false, // sec_prec_set
207
+ No, // ignore_under
208
+ Yes, // cache_keys
209
+ 0, // cache_str
210
+ 0, // int_range_min
211
+ 0, // int_range_max
212
+ 0, // max_integer_digits
213
+ oj_json_class, // create_id
214
+ 10, // create_id_len
215
+ 9, // sec_prec
216
+ 16, // float_prec
217
+ "%0.15g", // float_fmt
218
+ Qnil, // hash_class
219
+ Qnil, // array_class
220
+ {
221
+ // dump_opts
222
+ false, // use
223
+ "", // indent
224
+ "", // before_sep
225
+ "", // after_sep
226
+ "", // hash_nl
227
+ "", // array_nl
228
+ 0, // indent_size
229
+ 0, // before_size
230
+ 0, // after_size
231
+ 0, // hash_size
232
+ 0, // array_size
233
+ AutoNan, // nan_dump
234
+ false, // omit_nil
235
+ false, // omit_null_byte
236
+ MAX_DEPTH, // max_depth
237
+ NULL, // only
238
+ NULL, // except
239
+ },
240
+ {
241
+ // str_rx
242
+ NULL, // head
243
+ NULL, // tail
244
+ {'\0'}, // err
245
+ },
246
+ NULL,
247
+ };
248
+
249
+ static VALUE only_array_from_string(const char *str) {
250
+ volatile VALUE a = Qnil;
251
+
252
+ if (NULL != str && 2 < strlen(str)) {
253
+ str++;
254
+ char *cp;
255
+
256
+ a = rb_ary_new();
257
+ while (NULL != (cp = strchr(str, ':'))) {
258
+ rb_ary_push(a, rb_id2sym(rb_intern2(str, cp - str)));
259
+ str = cp + 1;
260
+ }
261
+ }
262
+ return a;
263
+ }
264
+
265
+ /* Document-method: default_options()
266
+ * call-seq: default_options()
267
+ *
268
+ * Returns the default load and dump options as a Hash. The options are
269
+ * - *:indent* [_Fixnum_|_String_|_nil_] number of spaces to indent each element
270
+ * in an JSON document, zero or nil is no newline between JSON elements,
271
+ * negative indicates no newline between top level JSON elements in a stream,
272
+ * a String indicates the string should be used for indentation
273
+ * - *:circular* [_Boolean_|_nil_] support circular references while dumping as
274
+ * well as shared references
275
+ * - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist
276
+ * - *:symbol_keys* [_Boolean_|_nil_] use symbols instead of strings for hash keys
277
+ * - *:escape_mode* [_:newline_|_:json_|_:slash_|_:xss_safe_|_:ascii_|_:unicode_xss_|_nil_]
278
+ * determines the characters to escape
279
+ * - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing (if dynamically
280
+ * modifying classes or reloading classes then don't use this)
281
+ * - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_|_:wab_] load and
282
+ * dump modes to use for JSON
283
+ * - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
284
+ * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or
285
+ * as a String
286
+ * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_|_:ruby_] load decimals
287
+ * as BigDecimal instead of as a Float. :auto pick the most precise for the number
288
+ * of digits. :float should be the same as ruby. :fast may require rounding but is
289
+ * must faster.
290
+ * - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead of as
291
+ * a Float when in compat or rails mode.
292
+ * - *:create_id* [_String_|_nil_] create id for json compatible object encoding,
293
+ * default is 'json_class'
294
+ * - *:create_additions* [_Boolean_|_nil_] if true allow creation of instances using
295
+ * create_id on load.
296
+ * - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal when
297
+ * dumping the seconds portion of time
298
+ * - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping
299
+ * floats, 0 indicates use Ruby
300
+ * - *:float_format* [_String_] the C printf format string for printing floats.
301
+ * Default follows the float_precision and will be changed if float_precision is
302
+ * changed. The string can be no more than 6 bytes.
303
+ * - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false
304
+ * - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false
305
+ * - *:use_raw_json* [_Boolean_|_nil_] call raw_json() methods on dump, default is false
306
+ * - *:nilnil* [_Boolean_|_nil_] if true a nil input to load will return nil and
307
+ * not raise an Exception
308
+ * - *:empty_string* [_Boolean_|_nil_] if true an empty input will not raise an Exception
309
+ * - *:allow_gc* [_Boolean_|_nil_] allow or prohibit GC during parsing, default is true (allow)
310
+ * - *:quirks_mode* [_true,_|_false_|_nil_] Allow single JSON values instead of
311
+ * documents, default is true (allow)
312
+ * - *:allow_invalid_unicode* [_true,_|_false_|_nil_] Allow invalid unicode,
313
+ * default is false (don't allow)
314
+ * - *:allow_nan* [_true,_|_false_|_nil_] Allow Nan, Infinity, and -Infinity to
315
+ * be parsed, default is true (allow)
316
+ * - *:indent_str* [_String_|_nil_] String to use for indentation, overriding the
317
+ * indent option is not nil
318
+ * - *:space* [_String_|_nil_] String to use for the space after the colon in JSON
319
+ * object fields
320
+ * - *:space_before* [_String_|_nil_] String to use before the colon separator in
321
+ * JSON object fields
322
+ * - *:object_nl* [_String_|_nil_] String to use after a JSON object field value
323
+ * - *:array_nl* [_String_|_nil_] String to use after a JSON array value
324
+ * - *:nan* [_:null_|_:huge_|_:word_|_:raise_|_:auto_] how to dump Infinity and
325
+ * NaN. :null places a null, :huge places a huge number, :word places Infinity
326
+ * or NaN, :raise raises and exception, :auto uses default for each mode.
327
+ * - *:hash_class* [_Class_|_nil_] Class to use instead of Hash on load,
328
+ * :object_class can also be used
329
+ * - *:array_class* [_Class_|_nil_] Class to use instead of Array on load
330
+ * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil
331
+ * values are omitted
332
+ * - *:omit_null_byte* [_true_|_false_] if true null bytes in strings will be
333
+ * omitted when dumping
334
+ * - *:ignore* [_nil_|_Array_] either nil or an Array of classes to ignore when dumping
335
+ * - *:ignore_under* [_Boolean_] if true then attributes that start with _ are
336
+ * ignored when dumping in object or custom mode.
337
+ * - *:cache_keys* [_Boolean_] if true then hash keys are cached if less than 35 bytes.
338
+ * - *:cache_str* [_Fixnum_] maximum string value length to cache (strings less
339
+ * than this are cached)
340
+ * - *:integer_range* [_Range_] Dump integers outside range as strings.
341
+ * - *:max_integer_digits* [_Fixnum_] Maximum number of decimal digits allowed in a
342
+ * parsed integer. When the limit is exceeded a parse error is raised. 0 (the
343
+ * default) disables the limit. Setting a reasonable limit is recommended when
344
+ * parsing untrusted input to mitigate CPU-DoS attacks. Only applies to the
345
+ * legacy parsers (Oj.load, Oj::Doc, JSON.parse mimic); Oj::Parser is unaffected.
346
+ * - *:trace* [_true,_|_false_] Trace all load and dump calls, default is false
347
+ * (trace is off)
348
+ * - *:safe* [_true,_|_false_] Safe mimic breaks JSON mimic to be safer, default
349
+ * is false (safe is off)
350
+ * - *:only* [_nil,_|_Array_] A list of the fields to encode. All others are skipped.
351
+ * - *:except* [_nil,_|_Array_] A list of the fields to not encode. All others are encoded.
352
+ *
353
+ * Return [_Hash_] all current option settings.
354
+ */
355
+ static VALUE get_def_opts(VALUE self) {
356
+ VALUE opts = rb_hash_new();
357
+
358
+ if (0 == oj_default_options.dump_opts.indent_size) {
359
+ rb_hash_aset(opts, oj_indent_sym, INT2FIX(oj_default_options.indent));
360
+ } else {
361
+ rb_hash_aset(opts, oj_indent_sym, rb_str_new2(oj_default_options.dump_opts.indent_str));
362
+ }
363
+ rb_hash_aset(opts, sec_prec_sym, INT2FIX(oj_default_options.sec_prec));
364
+ rb_hash_aset(opts,
365
+ circular_sym,
366
+ (Yes == oj_default_options.circular) ? Qtrue : ((No == oj_default_options.circular) ? Qfalse : Qnil));
367
+ rb_hash_aset(
368
+ opts,
369
+ class_cache_sym,
370
+ (Yes == oj_default_options.class_cache) ? Qtrue : ((No == oj_default_options.class_cache) ? Qfalse : Qnil));
371
+ rb_hash_aset(
372
+ opts,
373
+ auto_define_sym,
374
+ (Yes == oj_default_options.auto_define) ? Qtrue : ((No == oj_default_options.auto_define) ? Qfalse : Qnil));
375
+ rb_hash_aset(opts,
376
+ symbol_keys_sym,
377
+ (Yes == oj_default_options.sym_key) ? Qtrue : ((No == oj_default_options.sym_key) ? Qfalse : Qnil));
378
+ rb_hash_aset(
379
+ opts,
380
+ bigdecimal_as_decimal_sym,
381
+ (Yes == oj_default_options.bigdec_as_num) ? Qtrue : ((No == oj_default_options.bigdec_as_num) ? Qfalse : Qnil));
382
+ rb_hash_aset(
383
+ opts,
384
+ oj_create_additions_sym,
385
+ (Yes == oj_default_options.create_ok) ? Qtrue : ((No == oj_default_options.create_ok) ? Qfalse : Qnil));
386
+ rb_hash_aset(opts,
387
+ use_to_json_sym,
388
+ (Yes == oj_default_options.to_json) ? Qtrue : ((No == oj_default_options.to_json) ? Qfalse : Qnil));
389
+ rb_hash_aset(opts,
390
+ use_to_hash_sym,
391
+ (Yes == oj_default_options.to_hash) ? Qtrue : ((No == oj_default_options.to_hash) ? Qfalse : Qnil));
392
+ rb_hash_aset(opts,
393
+ use_as_json_sym,
394
+ (Yes == oj_default_options.as_json) ? Qtrue : ((No == oj_default_options.as_json) ? Qfalse : Qnil));
395
+ rb_hash_aset(opts,
396
+ use_raw_json_sym,
397
+ (Yes == oj_default_options.raw_json) ? Qtrue : ((No == oj_default_options.raw_json) ? Qfalse : Qnil));
398
+ rb_hash_aset(opts,
399
+ nilnil_sym,
400
+ (Yes == oj_default_options.nilnil) ? Qtrue : ((No == oj_default_options.nilnil) ? Qfalse : Qnil));
401
+ rb_hash_aset(
402
+ opts,
403
+ empty_string_sym,
404
+ (Yes == oj_default_options.empty_string) ? Qtrue : ((No == oj_default_options.empty_string) ? Qfalse : Qnil));
405
+ rb_hash_aset(opts,
406
+ allow_gc_sym,
407
+ (Yes == oj_default_options.allow_gc) ? Qtrue : ((No == oj_default_options.allow_gc) ? Qfalse : Qnil));
408
+ rb_hash_aset(
409
+ opts,
410
+ oj_quirks_mode_sym,
411
+ (Yes == oj_default_options.quirks_mode) ? Qtrue : ((No == oj_default_options.quirks_mode) ? Qfalse : Qnil));
412
+ rb_hash_aset(
413
+ opts,
414
+ allow_invalid_unicode_sym,
415
+ (Yes == oj_default_options.allow_invalid) ? Qtrue : ((No == oj_default_options.allow_invalid) ? Qfalse : Qnil));
416
+ rb_hash_aset(
417
+ opts,
418
+ oj_allow_nan_sym,
419
+ (Yes == oj_default_options.allow_nan) ? Qtrue : ((No == oj_default_options.allow_nan) ? Qfalse : Qnil));
420
+ rb_hash_aset(opts,
421
+ oj_trace_sym,
422
+ (Yes == oj_default_options.trace) ? Qtrue : ((No == oj_default_options.trace) ? Qfalse : Qnil));
423
+ rb_hash_aset(opts,
424
+ oj_safe_sym,
425
+ (Yes == oj_default_options.safe) ? Qtrue : ((No == oj_default_options.safe) ? Qfalse : Qnil));
426
+ rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec));
427
+ rb_hash_aset(opts, float_format_sym, rb_str_new_cstr(oj_default_options.float_fmt));
428
+ rb_hash_aset(opts, cache_str_sym, INT2FIX(oj_default_options.cache_str));
429
+ rb_hash_aset(
430
+ opts,
431
+ ignore_under_sym,
432
+ (Yes == oj_default_options.ignore_under) ? Qtrue : ((No == oj_default_options.ignore_under) ? Qfalse : Qnil));
433
+ rb_hash_aset(
434
+ opts,
435
+ cache_keys_sym,
436
+ (Yes == oj_default_options.cache_keys) ? Qtrue : ((No == oj_default_options.cache_keys) ? Qfalse : Qnil));
437
+
438
+ switch (oj_default_options.mode) {
439
+ case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
440
+ case CompatMode: rb_hash_aset(opts, mode_sym, compat_sym); break;
441
+ case NullMode: rb_hash_aset(opts, mode_sym, null_sym); break;
442
+ case ObjectMode: rb_hash_aset(opts, mode_sym, object_sym); break;
443
+ case CustomMode: rb_hash_aset(opts, mode_sym, custom_sym); break;
444
+ case RailsMode: rb_hash_aset(opts, mode_sym, rails_sym); break;
445
+ case WabMode: rb_hash_aset(opts, mode_sym, wab_sym); break;
446
+ default: rb_hash_aset(opts, mode_sym, object_sym); break;
447
+ }
448
+
449
+ if (oj_default_options.int_range_max != 0 || oj_default_options.int_range_min != 0) {
450
+ VALUE range = rb_obj_alloc(rb_cRange);
451
+ VALUE min = LONG2FIX(oj_default_options.int_range_min);
452
+ VALUE max = LONG2FIX(oj_default_options.int_range_max);
453
+
454
+ rb_ivar_set(range, oj_begin_id, min);
455
+ rb_ivar_set(range, oj_end_id, max);
456
+ rb_hash_aset(opts, integer_range_sym, range);
457
+ } else {
458
+ rb_hash_aset(opts, integer_range_sym, Qnil);
459
+ }
460
+ rb_hash_aset(opts, max_integer_digits_sym, LONG2NUM((long)oj_default_options.max_integer_digits));
461
+ switch (oj_default_options.escape_mode) {
462
+ case NLEsc: rb_hash_aset(opts, escape_mode_sym, newline_sym); break;
463
+ case JSONEsc: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
464
+ case SlashEsc: rb_hash_aset(opts, escape_mode_sym, slash_sym); break;
465
+ case XSSEsc: rb_hash_aset(opts, escape_mode_sym, xss_safe_sym); break;
466
+ case ASCIIEsc: rb_hash_aset(opts, escape_mode_sym, ascii_sym); break;
467
+ case JXEsc: rb_hash_aset(opts, escape_mode_sym, unicode_xss_sym); break;
468
+ default: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
469
+ }
470
+ switch (oj_default_options.time_format) {
471
+ case XmlTime: rb_hash_aset(opts, time_format_sym, xmlschema_sym); break;
472
+ case RubyTime: rb_hash_aset(opts, time_format_sym, ruby_sym); break;
473
+ case UnixZTime: rb_hash_aset(opts, time_format_sym, unix_zone_sym); break;
474
+ case UnixTime:
475
+ default: rb_hash_aset(opts, time_format_sym, unix_sym); break;
476
+ }
477
+ switch (oj_default_options.bigdec_load) {
478
+ case BigDec: rb_hash_aset(opts, bigdecimal_load_sym, bigdecimal_sym); break;
479
+ case FloatDec: rb_hash_aset(opts, bigdecimal_load_sym, float_sym); break;
480
+ case FastDec: rb_hash_aset(opts, bigdecimal_load_sym, fast_sym); break;
481
+ case AutoDec:
482
+ default: rb_hash_aset(opts, bigdecimal_load_sym, auto_sym); break;
483
+ }
484
+ rb_hash_aset(opts, compat_bigdecimal_sym, oj_default_options.compat_bigdec ? Qtrue : Qfalse);
485
+ rb_hash_aset(opts,
486
+ create_id_sym,
487
+ (NULL == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));
488
+ rb_hash_aset(
489
+ opts,
490
+ oj_space_sym,
491
+ (0 == oj_default_options.dump_opts.after_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.after_sep));
492
+ rb_hash_aset(
493
+ opts,
494
+ oj_space_before_sym,
495
+ (0 == oj_default_options.dump_opts.before_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.before_sep));
496
+ rb_hash_aset(
497
+ opts,
498
+ oj_object_nl_sym,
499
+ (0 == oj_default_options.dump_opts.hash_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.hash_nl));
500
+ rb_hash_aset(
501
+ opts,
502
+ oj_array_nl_sym,
503
+ (0 == oj_default_options.dump_opts.array_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.array_nl));
504
+
505
+ switch (oj_default_options.dump_opts.nan_dump) {
506
+ case NullNan: rb_hash_aset(opts, nan_sym, null_sym); break;
507
+ case RaiseNan: rb_hash_aset(opts, nan_sym, raise_sym); break;
508
+ case WordNan: rb_hash_aset(opts, nan_sym, word_sym); break;
509
+ case HugeNan: rb_hash_aset(opts, nan_sym, huge_sym); break;
510
+ case AutoNan:
511
+ default: rb_hash_aset(opts, nan_sym, auto_sym); break;
512
+ }
513
+ rb_hash_aset(opts, omit_nil_sym, oj_default_options.dump_opts.omit_nil ? Qtrue : Qfalse);
514
+ rb_hash_aset(opts, omit_null_byte_sym, oj_default_options.dump_opts.omit_null_byte ? Qtrue : Qfalse);
515
+ rb_hash_aset(opts, oj_hash_class_sym, oj_default_options.hash_class);
516
+ rb_hash_aset(opts, oj_array_class_sym, oj_default_options.array_class);
517
+
518
+ rb_hash_aset(opts, only_sym, only_array_from_string(oj_default_options.dump_opts.only));
519
+ rb_hash_aset(opts, except_sym, only_array_from_string(oj_default_options.dump_opts.except));
520
+
521
+ if (NULL == oj_default_options.ignore) {
522
+ rb_hash_aset(opts, ignore_sym, Qnil);
523
+ } else {
524
+ VALUE *vp;
525
+ volatile VALUE a = rb_ary_new();
526
+
527
+ for (vp = oj_default_options.ignore; Qnil != *vp; vp++) {
528
+ rb_ary_push(a, *vp);
529
+ }
530
+ rb_hash_aset(opts, ignore_sym, a);
531
+ }
532
+ return opts;
533
+ }
534
+
535
+ /* Document-method: default_options=
536
+ * call-seq: default_options=(opts)
537
+ *
538
+ * Sets the default options for load and dump.
539
+ * - *opts* [_Hash_] options to change
540
+ * - *:indent* [_Fixnum_|_String_|_nil_] number of spaces to indent each element
541
+ * in a JSON document or the String to use for indentation.
542
+ * - :circular [_Boolean_|_nil_] support circular references while dumping.
543
+ * - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist.
544
+ * - *:symbol_keys* [_Boolean_|_nil_] convert hash keys to symbols.
545
+ * - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing.
546
+ * - *:escape* [_:newline_|_:json_|_:xss_safe_|_:ascii_|_unicode_xss_|_nil_]
547
+ * mode encodes all high-bit characters as escaped sequences if :ascii, :json
548
+ * is standand UTF-8 JSON encoding, :newline is the same as :json but newlines
549
+ * are not escaped, :unicode_xss allows unicode but escapes &, <, and >, and
550
+ * any \u20xx characters along with some others, and :xss_safe escapes &, <,
551
+ * and >, and some others.
552
+ * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal
553
+ * number or as a String.
554
+ * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_nil_] load decimals as
555
+ * BigDecimal instead of as a Float. :auto pick the most precise for the number of digits.
556
+ * - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead
557
+ * of as a Float in compat mode.
558
+ * - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_|_:wab_] load
559
+ * and dump mode to use for JSON :strict raises an exception when a non-supported
560
+ * Object is encountered. :compat attempts to extract variable values from an
561
+ * Object using to_json() or to_hash() then it walks the Object's variables if
562
+ * neither is found. The :object mode ignores to_hash() and to_json() methods
563
+ * and encodes variables using code internal to the Oj gem. The :null mode
564
+ * ignores non-supported Objects and replaces them with a null. The :custom
565
+ * mode honors all dump options. The :rails more mimics rails and Active behavior.
566
+ * - *:time_format* [_:unix_|_:xmlschema_|_:ruby_] time format when dumping in :compat
567
+ * mode :unix decimal number denoting the number of seconds since 1/1/1970,
568
+ * :unix_zone decimal number denoting the number of seconds since 1/1/1970
569
+ * plus the utc_offset in the exponent, :xmlschema date-time format taken
570
+ * from XML Schema as a String, :ruby Time.to_s formatted String.
571
+ * - *:create_id* [_String_|_nil_] create id for json compatible object encoding
572
+ * - *:create_additions* [_Boolean_|_nil_] if true allow creation of instances using create_id on load.
573
+ * - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal
574
+ * when dumping the seconds portion of time.
575
+ * - *:float_format* [_String_] the C printf format string for printing floats.
576
+ * Default follows the float_precision and will be changed if float_precision
577
+ * is changed. The string can be no more than 6 bytes.
578
+ * - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping floats, 0 indicates use Ruby.
579
+ * - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false.
580
+ * - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false.
581
+ * - *:use_to_hash* [_Boolean_|_nil_] call to_hash() methods on dump, default is false.
582
+ * - *:use_raw_json* [_Boolean_|_nil_] call raw_json() methods on dump, default is false.
583
+ * - *:nilnil* [_Boolean_|_nil_] if true a nil input to load will return nil and not raise an Exception.
584
+ * - *:allow_gc* [_Boolean_|_nil_] allow or prohibit GC during parsing, default is true (allow).
585
+ * - *:quirks_mode* [_Boolean_|_nil_] allow single JSON values instead of documents, default is true (allow).
586
+ * - *:allow_invalid_unicode* [_Boolean_|_nil_] allow invalid unicode, default is false (don't allow).
587
+ * - *:allow_nan* [_Boolean_|_nil_] allow Nan, Infinity, and -Infinity, default is true (allow).
588
+ * - *:space* [_String_|_nil_] String to use for the space after the colon in JSON object fields.
589
+ * - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object fields.
590
+ * - *:object_nl* [_String_|_nil_] String to use after a JSON object field value.
591
+ * - *:array_nl* [_String_|_nil_] String to use after a JSON array value
592
+ * - *:nan* [_:null_|_:huge_|_:word_|_:raise_] how to dump Infinity and NaN in null,
593
+ * strict, and compat mode. :null places a null, :huge places a huge number, :word
594
+ * places Infinity or NaN, :raise raises and exception, :auto uses default for each mode.
595
+ * - *:hash_class* [_Class_|_nil_] Class to use instead of Hash on load, :object_class can also be used.
596
+ * - *:array_class* [_Class_|_nil_] Class to use instead of Array on load.
597
+ * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted.
598
+ * - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
599
+ * - *:ignore_under* [_Boolean_] if true then attributes that start with _ are
600
+ * ignored when dumping in object or custom mode.
601
+ * - *:cache_keys* [_Boolean_] if true then hash keys are cached
602
+ * - *:cache_str* [_Fixnum_] maximum string value length to cache (strings less than this are cached)
603
+ * - *:integer_range* [_Range_] Dump integers outside range as strings.
604
+ * - *:max_integer_digits* [_Fixnum_] Maximum decimal digits in a parsed integer
605
+ * (0 = unlimited). Use to mitigate CPU-DoS via huge integer values in JSON.
606
+ * - *:trace* [_Boolean_] turn trace on or off.
607
+ * - *:safe* [_Boolean_] turn safe mimic on or off.
608
+ */
609
+ static VALUE set_def_opts(VALUE self, VALUE opts) {
610
+ Check_Type(opts, T_HASH);
611
+ oj_parse_options(opts, &oj_default_options);
612
+
613
+ return Qnil;
614
+ }
615
+
616
+ bool oj_hash_has_key(VALUE hash, VALUE key) {
617
+ if (Qundef == rb_hash_lookup2(hash, key, Qundef)) {
618
+ return false;
619
+ }
620
+ return true;
621
+ }
622
+
623
+ bool set_yesno_options(VALUE key, VALUE value, Options copts) {
624
+ struct _yesNoOpt ynos[] = {{circular_sym, &copts->circular},
625
+ {auto_define_sym, &copts->auto_define},
626
+ {symbol_keys_sym, &copts->sym_key},
627
+ {class_cache_sym, &copts->class_cache},
628
+ {bigdecimal_as_decimal_sym, &copts->bigdec_as_num},
629
+ {use_to_hash_sym, &copts->to_hash},
630
+ {use_to_json_sym, &copts->to_json},
631
+ {use_as_json_sym, &copts->as_json},
632
+ {use_raw_json_sym, &copts->raw_json},
633
+ {nilnil_sym, &copts->nilnil},
634
+ {allow_blank_sym, &copts->nilnil}, // same as nilnil
635
+ {empty_string_sym, &copts->empty_string},
636
+ {allow_gc_sym, &copts->allow_gc},
637
+ {oj_quirks_mode_sym, &copts->quirks_mode},
638
+ {allow_invalid_unicode_sym, &copts->allow_invalid},
639
+ {oj_allow_nan_sym, &copts->allow_nan},
640
+ {oj_trace_sym, &copts->trace},
641
+ {oj_safe_sym, &copts->safe},
642
+ {ignore_under_sym, &copts->ignore_under},
643
+ {oj_create_additions_sym, &copts->create_ok},
644
+ {cache_keys_sym, &copts->cache_keys},
645
+ {Qnil, 0}};
646
+ YesNoOpt o;
647
+
648
+ for (o = ynos; 0 != o->attr; o++) {
649
+ if (key == o->sym) {
650
+ if (Qnil == value) {
651
+ *o->attr = NotSet;
652
+ } else if (Qtrue == value) {
653
+ *o->attr = Yes;
654
+ } else if (Qfalse == value) {
655
+ *o->attr = No;
656
+ } else {
657
+ rb_raise(rb_eArgError, "%s must be true, false, or nil.", rb_id2name(key));
658
+ }
659
+ return true;
660
+ }
661
+ }
662
+ return false;
663
+ }
664
+
665
+ static const char *make_only_value(VALUE v) {
666
+ switch (rb_type(v)) {
667
+ case RUBY_T_NIL:
668
+ case RUBY_T_NONE: return NULL;
669
+ case RUBY_T_ARRAY: {
670
+ long len = rb_array_len(v);
671
+ long i;
672
+ long size = 0;
673
+ char *buf;
674
+ char *bp;
675
+
676
+ for (i = 0; i < len; i++) {
677
+ VALUE x = rb_ary_entry(v, i);
678
+
679
+ switch (rb_type(x)) {
680
+ case RUBY_T_SYMBOL:
681
+ size += strlen(rb_id2name(rb_sym2id(x)));
682
+ size++;
683
+ break;
684
+ case RUBY_T_STRING:
685
+ size += strlen(StringValueCStr(x));
686
+ size++;
687
+ break;
688
+ default: rb_raise(rb_eArgError, ":only and :except must be nil, symbol, string, or array."); break;
689
+ }
690
+ }
691
+ if (0 == size) {
692
+ return NULL;
693
+ }
694
+ buf = OJ_R_ALLOC_N(char, size + 2);
695
+ bp = buf;
696
+ *bp++ = ':';
697
+ for (i = 0; i < len; i++) {
698
+ VALUE x = rb_ary_entry(v, i);
699
+ const char *str;
700
+
701
+ switch (rb_type(x)) {
702
+ case RUBY_T_SYMBOL:
703
+ str = rb_id2name(rb_sym2id(x));
704
+ size = strlen(str);
705
+ memcpy(bp, str, size);
706
+ bp += size;
707
+ *bp++ = ':';
708
+ break;
709
+ case RUBY_T_STRING:
710
+ str = StringValueCStr(x);
711
+ size = strlen(str);
712
+ memcpy(bp, str, size);
713
+ bp += size;
714
+ *bp++ = ':';
715
+ break;
716
+ default:
717
+ // ignore
718
+ break;
719
+ }
720
+ }
721
+ *bp = '\0';
722
+
723
+ return buf;
724
+ }
725
+ case RUBY_T_STRING: {
726
+ const char *str = StringValueCStr(v);
727
+ size_t size = strlen(str);
728
+ char *buf = OJ_R_ALLOC_N(char, size + 3);
729
+
730
+ buf[0] = ':';
731
+ strcpy(buf + 1, str);
732
+ buf[size + 1] = ':';
733
+ buf[size + 2] = '\0';
734
+
735
+ return buf;
736
+ }
737
+ case RUBY_T_SYMBOL: {
738
+ const char *str = rb_id2name(rb_sym2id(v));
739
+ size_t size = strlen(str);
740
+ char *buf = OJ_R_ALLOC_N(char, size + 3);
741
+
742
+ buf[0] = ':';
743
+ strcpy(buf + 1, str);
744
+ buf[size + 1] = ':';
745
+ buf[size + 2] = '\0';
746
+
747
+ return buf;
748
+ }
749
+ default: rb_raise(rb_eArgError, ":only and zzz :except must be nil, symbol, string, or array."); break;
750
+ }
751
+ return NULL;
752
+ }
753
+
754
+ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
755
+ Options copts = (Options)opts;
756
+ size_t len;
757
+
758
+ if (set_yesno_options(k, v, copts)) {
759
+ return ST_CONTINUE;
760
+ }
761
+ if (oj_indent_sym == k) {
762
+ switch (rb_type(v)) {
763
+ case T_NIL:
764
+ copts->dump_opts.indent_size = 0;
765
+ *copts->dump_opts.indent_str = '\0';
766
+ copts->indent = 0;
767
+ break;
768
+ case T_FIXNUM:
769
+ copts->dump_opts.indent_size = 0;
770
+ *copts->dump_opts.indent_str = '\0';
771
+ if (MAX_INDENT < FIX2INT(v)) {
772
+ rb_raise(rb_eArgError, "indent is limited to %d characters.", MAX_INDENT);
773
+ }
774
+ copts->indent = FIX2INT(v);
775
+ break;
776
+ case T_STRING:
777
+ if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) {
778
+ rb_raise(rb_eArgError,
779
+ "indent string is limited to %lu characters.",
780
+ (unsigned long)sizeof(copts->dump_opts.indent_str));
781
+ }
782
+ strcpy(copts->dump_opts.indent_str, StringValuePtr(v));
783
+ copts->dump_opts.indent_size = (uint8_t)len;
784
+ copts->indent = 0;
785
+ break;
786
+ default: rb_raise(rb_eTypeError, "indent must be a Fixnum, String, or nil."); break;
787
+ }
788
+ } else if (float_prec_sym == k) {
789
+ int n;
790
+
791
+ if (rb_cInteger != rb_obj_class(v)) {
792
+ rb_raise(rb_eArgError, ":float_precision must be a Integer.");
793
+ }
794
+ n = FIX2INT(v);
795
+ if (0 >= n) {
796
+ *copts->float_fmt = '\0';
797
+ copts->float_prec = 0;
798
+ } else {
799
+ if (20 < n) {
800
+ n = 20;
801
+ }
802
+ sprintf(copts->float_fmt, "%%0.%dg", n);
803
+ copts->float_prec = n;
804
+ }
805
+ } else if (cache_str_sym == k || cache_string_sym == k) {
806
+ int n;
807
+
808
+ if (rb_cInteger != rb_obj_class(v)) {
809
+ rb_raise(rb_eArgError, ":cache_str must be a Integer.");
810
+ }
811
+ n = FIX2INT(v);
812
+ if (0 >= n) {
813
+ copts->cache_str = 0;
814
+ } else {
815
+ if (32 < n) {
816
+ n = 32;
817
+ }
818
+ copts->cache_str = (char)n;
819
+ }
820
+ } else if (sec_prec_sym == k) {
821
+ int n;
822
+
823
+ if (rb_cInteger != rb_obj_class(v)) {
824
+ rb_raise(rb_eArgError, ":second_precision must be a Integer.");
825
+ }
826
+ n = NUM2INT(v);
827
+ if (0 > n) {
828
+ n = 0;
829
+ copts->sec_prec_set = false;
830
+ } else if (9 < n) {
831
+ n = 9;
832
+ copts->sec_prec_set = true;
833
+ } else {
834
+ copts->sec_prec_set = true;
835
+ }
836
+ copts->sec_prec = n;
837
+ } else if (mode_sym == k) {
838
+ if (wab_sym == v) {
839
+ copts->mode = WabMode;
840
+ } else if (object_sym == v) {
841
+ copts->mode = ObjectMode;
842
+ } else if (strict_sym == v) {
843
+ copts->mode = StrictMode;
844
+ } else if (compat_sym == v || json_sym == v) {
845
+ copts->mode = CompatMode;
846
+ } else if (null_sym == v) {
847
+ copts->mode = NullMode;
848
+ } else if (custom_sym == v) {
849
+ copts->mode = CustomMode;
850
+ } else if (rails_sym == v) {
851
+ copts->mode = RailsMode;
852
+ } else {
853
+ rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
854
+ }
855
+ } else if (time_format_sym == k) {
856
+ if (unix_sym == v) {
857
+ copts->time_format = UnixTime;
858
+ } else if (unix_zone_sym == v) {
859
+ copts->time_format = UnixZTime;
860
+ } else if (xmlschema_sym == v) {
861
+ copts->time_format = XmlTime;
862
+ } else if (ruby_sym == v) {
863
+ copts->time_format = RubyTime;
864
+ } else {
865
+ rb_raise(rb_eArgError, ":time_format must be :unix, :unix_zone, :xmlschema, or :ruby.");
866
+ }
867
+ } else if (escape_mode_sym == k) {
868
+ if (newline_sym == v) {
869
+ copts->escape_mode = NLEsc;
870
+ } else if (json_sym == v) {
871
+ copts->escape_mode = JSONEsc;
872
+ } else if (slash_sym == v) {
873
+ copts->escape_mode = SlashEsc;
874
+ } else if (xss_safe_sym == v) {
875
+ copts->escape_mode = XSSEsc;
876
+ } else if (ascii_sym == v) {
877
+ copts->escape_mode = ASCIIEsc;
878
+ } else if (unicode_xss_sym == v) {
879
+ copts->escape_mode = JXEsc;
880
+ } else {
881
+ rb_raise(rb_eArgError, ":encoding must be :newline, :json, :xss_safe, :unicode_xss, or :ascii.");
882
+ }
883
+ } else if (bigdecimal_load_sym == k) {
884
+ if (Qnil == v) {
885
+ return ST_CONTINUE;
886
+ }
887
+
888
+ if (bigdecimal_sym == v || Qtrue == v) {
889
+ copts->bigdec_load = BigDec;
890
+ } else if (float_sym == v) {
891
+ copts->bigdec_load = FloatDec;
892
+ } else if (fast_sym == v) {
893
+ copts->bigdec_load = FastDec;
894
+ } else if (auto_sym == v || Qfalse == v) {
895
+ copts->bigdec_load = AutoDec;
896
+ } else {
897
+ rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto.");
898
+ }
899
+ } else if (compat_bigdecimal_sym == k) {
900
+ if (Qnil == v) {
901
+ return ST_CONTINUE;
902
+ }
903
+ copts->compat_bigdec = (Qtrue == v);
904
+ } else if (oj_decimal_class_sym == k) {
905
+ if (rb_cFloat == v) {
906
+ copts->compat_bigdec = false;
907
+ } else if (oj_bigdecimal_class == v) {
908
+ copts->compat_bigdec = true;
909
+ } else {
910
+ rb_raise(rb_eArgError, ":decimal_class must be BigDecimal or Float.");
911
+ }
912
+ } else if (create_id_sym == k) {
913
+ if (Qnil == v) {
914
+ if (oj_json_class != oj_default_options.create_id && NULL != copts->create_id) {
915
+ OJ_R_FREE((char *)oj_default_options.create_id);
916
+ }
917
+ copts->create_id = NULL;
918
+ copts->create_id_len = 0;
919
+ } else if (T_STRING == rb_type(v)) {
920
+ const char *str = StringValuePtr(v);
921
+
922
+ len = RSTRING_LEN(v);
923
+ if (len != copts->create_id_len || 0 != strcmp(copts->create_id, str)) {
924
+ copts->create_id = OJ_R_ALLOC_N(char, len + 1);
925
+ strcpy((char *)copts->create_id, str);
926
+ copts->create_id_len = len;
927
+ }
928
+ } else {
929
+ rb_raise(rb_eArgError, ":create_id must be string.");
930
+ }
931
+ } else if (oj_space_sym == k) {
932
+ if (Qnil == v) {
933
+ copts->dump_opts.after_size = 0;
934
+ *copts->dump_opts.after_sep = '\0';
935
+ } else {
936
+ rb_check_type(v, T_STRING);
937
+ if (sizeof(copts->dump_opts.after_sep) <= (len = RSTRING_LEN(v))) {
938
+ rb_raise(rb_eArgError,
939
+ "space string is limited to %lu characters.",
940
+ (unsigned long)sizeof(copts->dump_opts.after_sep));
941
+ }
942
+ strcpy(copts->dump_opts.after_sep, StringValuePtr(v));
943
+ copts->dump_opts.after_size = (uint8_t)len;
944
+ }
945
+ } else if (oj_space_before_sym == k) {
946
+ if (Qnil == v) {
947
+ copts->dump_opts.before_size = 0;
948
+ *copts->dump_opts.before_sep = '\0';
949
+ } else {
950
+ rb_check_type(v, T_STRING);
951
+ if (sizeof(copts->dump_opts.before_sep) <= (len = RSTRING_LEN(v))) {
952
+ rb_raise(rb_eArgError,
953
+ "sapce_before string is limited to %lu characters.",
954
+ (unsigned long)sizeof(copts->dump_opts.before_sep));
955
+ }
956
+ strcpy(copts->dump_opts.before_sep, StringValuePtr(v));
957
+ copts->dump_opts.before_size = (uint8_t)len;
958
+ }
959
+ } else if (oj_object_nl_sym == k) {
960
+ if (Qnil == v) {
961
+ copts->dump_opts.hash_size = 0;
962
+ *copts->dump_opts.hash_nl = '\0';
963
+ } else {
964
+ rb_check_type(v, T_STRING);
965
+ if (sizeof(copts->dump_opts.hash_nl) <= (len = RSTRING_LEN(v))) {
966
+ rb_raise(rb_eArgError,
967
+ "object_nl string is limited to %lu characters.",
968
+ (unsigned long)sizeof(copts->dump_opts.hash_nl));
969
+ }
970
+ strcpy(copts->dump_opts.hash_nl, StringValuePtr(v));
971
+ copts->dump_opts.hash_size = (uint8_t)len;
972
+ }
973
+ } else if (oj_array_nl_sym == k) {
974
+ if (Qnil == v) {
975
+ copts->dump_opts.array_size = 0;
976
+ *copts->dump_opts.array_nl = '\0';
977
+ } else {
978
+ rb_check_type(v, T_STRING);
979
+ if (sizeof(copts->dump_opts.array_nl) <= (len = RSTRING_LEN(v))) {
980
+ rb_raise(rb_eArgError,
981
+ "array_nl string is limited to %lu characters.",
982
+ (unsigned long)sizeof(copts->dump_opts.array_nl));
983
+ }
984
+ strcpy(copts->dump_opts.array_nl, StringValuePtr(v));
985
+ copts->dump_opts.array_size = (uint8_t)len;
986
+ }
987
+ } else if (nan_sym == k) {
988
+ if (Qnil == v) {
989
+ return ST_CONTINUE;
990
+ }
991
+ if (null_sym == v) {
992
+ copts->dump_opts.nan_dump = NullNan;
993
+ } else if (huge_sym == v) {
994
+ copts->dump_opts.nan_dump = HugeNan;
995
+ } else if (word_sym == v) {
996
+ copts->dump_opts.nan_dump = WordNan;
997
+ } else if (raise_sym == v) {
998
+ copts->dump_opts.nan_dump = RaiseNan;
999
+ } else if (auto_sym == v) {
1000
+ copts->dump_opts.nan_dump = AutoNan;
1001
+ } else {
1002
+ rb_raise(rb_eArgError, ":nan must be :null, :huge, :word, :raise, or :auto.");
1003
+ }
1004
+ } else if (omit_nil_sym == k) {
1005
+ if (Qnil == v) {
1006
+ return ST_CONTINUE;
1007
+ }
1008
+ if (Qtrue == v) {
1009
+ copts->dump_opts.omit_nil = true;
1010
+ } else if (Qfalse == v) {
1011
+ copts->dump_opts.omit_nil = false;
1012
+ } else {
1013
+ rb_raise(rb_eArgError, ":omit_nil must be true or false.");
1014
+ }
1015
+ } else if (omit_null_byte_sym == k) {
1016
+ if (Qnil == v) {
1017
+ return ST_CONTINUE;
1018
+ }
1019
+ if (Qtrue == v) {
1020
+ copts->dump_opts.omit_null_byte = true;
1021
+ } else if (Qfalse == v) {
1022
+ copts->dump_opts.omit_null_byte = false;
1023
+ } else {
1024
+ rb_raise(rb_eArgError, ":omit_null_byte must be true or false.");
1025
+ }
1026
+ } else if (oj_ascii_only_sym == k) {
1027
+ // This is here only for backwards compatibility with the original Oj.
1028
+ if (Qtrue == v) {
1029
+ copts->escape_mode = ASCIIEsc;
1030
+ } else if (Qfalse == v) {
1031
+ copts->escape_mode = JSONEsc;
1032
+ }
1033
+ } else if (oj_hash_class_sym == k) {
1034
+ if (Qnil == v) {
1035
+ copts->hash_class = Qnil;
1036
+ } else {
1037
+ rb_check_type(v, T_CLASS);
1038
+ copts->hash_class = v;
1039
+ }
1040
+ } else if (oj_object_class_sym == k) {
1041
+ if (Qnil == v) {
1042
+ copts->hash_class = Qnil;
1043
+ } else {
1044
+ rb_check_type(v, T_CLASS);
1045
+ copts->hash_class = v;
1046
+ }
1047
+ } else if (oj_array_class_sym == k) {
1048
+ if (Qnil == v) {
1049
+ copts->array_class = Qnil;
1050
+ } else {
1051
+ rb_check_type(v, T_CLASS);
1052
+ copts->array_class = v;
1053
+ }
1054
+ } else if (ignore_sym == k) {
1055
+ OJ_R_FREE(copts->ignore);
1056
+ copts->ignore = NULL;
1057
+ if (Qnil != v) {
1058
+ size_t cnt;
1059
+
1060
+ rb_check_type(v, T_ARRAY);
1061
+ cnt = RARRAY_LEN(v);
1062
+ if (0 < cnt) {
1063
+ size_t i;
1064
+
1065
+ copts->ignore = OJ_R_ALLOC_N(VALUE, cnt + 1);
1066
+ for (i = 0; i < cnt; i++) {
1067
+ copts->ignore[i] = RARRAY_AREF(v, i);
1068
+ }
1069
+ copts->ignore[i] = Qnil;
1070
+ }
1071
+ }
1072
+ } else if (integer_range_sym == k) {
1073
+ if (Qnil == v) {
1074
+ return ST_CONTINUE;
1075
+ }
1076
+ if (rb_obj_class(v) == rb_cRange) {
1077
+ VALUE min = rb_funcall(v, oj_begin_id, 0);
1078
+ VALUE max = rb_funcall(v, oj_end_id, 0);
1079
+
1080
+ if (TYPE(min) != T_FIXNUM || TYPE(max) != T_FIXNUM) {
1081
+ rb_raise(rb_eArgError, ":integer_range range bounds is not Fixnum.");
1082
+ }
1083
+
1084
+ copts->int_range_min = FIX2LONG(min);
1085
+ copts->int_range_max = FIX2LONG(max);
1086
+ } else if (Qfalse != v) {
1087
+ rb_raise(rb_eArgError, ":integer_range must be a range of Fixnum.");
1088
+ }
1089
+ } else if (max_integer_digits_sym == k) {
1090
+ if (Qnil == v || Qfalse == v) {
1091
+ copts->max_integer_digits = 0;
1092
+ } else if (T_FIXNUM == rb_type(v)) {
1093
+ long n = FIX2LONG(v);
1094
+
1095
+ if (n < 0) {
1096
+ rb_raise(rb_eArgError, ":max_integer_digits must be >= 0.");
1097
+ }
1098
+
1099
+ copts->max_integer_digits = (size_t)n;
1100
+ } else {
1101
+ rb_raise(rb_eArgError, ":max_integer_digits must be a non-negative Integer.");
1102
+ }
1103
+ } else if (symbol_keys_sym == k || oj_symbolize_names_sym == k) {
1104
+ if (Qnil == v) {
1105
+ return ST_CONTINUE;
1106
+ }
1107
+ copts->sym_key = (Qtrue == v) ? Yes : No;
1108
+
1109
+ } else if (oj_max_nesting_sym == k) {
1110
+ if (Qtrue == v) {
1111
+ copts->dump_opts.max_depth = 100;
1112
+ } else if (Qfalse == v || Qnil == v) {
1113
+ copts->dump_opts.max_depth = MAX_DEPTH;
1114
+ } else if (T_FIXNUM == rb_type(v)) {
1115
+ copts->dump_opts.max_depth = NUM2INT(v);
1116
+ if (0 >= copts->dump_opts.max_depth) {
1117
+ copts->dump_opts.max_depth = MAX_DEPTH;
1118
+ }
1119
+ }
1120
+ } else if (float_format_sym == k) {
1121
+ rb_check_type(v, T_STRING);
1122
+ if (6 < RSTRING_LEN(v)) {
1123
+ rb_raise(rb_eArgError, ":float_format must be 6 bytes or less.");
1124
+ }
1125
+ strncpy(copts->float_fmt, RSTRING_PTR(v), (size_t)RSTRING_LEN(v));
1126
+ copts->float_fmt[RSTRING_LEN(v)] = '\0';
1127
+ } else if (only_sym == k) {
1128
+ if (NULL != copts->dump_opts.only) {
1129
+ OJ_R_FREE((void *)copts->dump_opts.only);
1130
+ copts->dump_opts.only = NULL;
1131
+ }
1132
+ copts->dump_opts.only = make_only_value(v);
1133
+ } else if (except_sym == k) {
1134
+ if (NULL != copts->dump_opts.except) {
1135
+ OJ_R_FREE((void *)copts->dump_opts.except);
1136
+ copts->dump_opts.except = NULL;
1137
+ }
1138
+ copts->dump_opts.except = make_only_value(v);
1139
+ }
1140
+ return ST_CONTINUE;
1141
+ }
1142
+
1143
+ void oj_parse_options(VALUE ropts, Options copts) {
1144
+ if (T_HASH != rb_type(ropts)) {
1145
+ return;
1146
+ }
1147
+ rb_hash_foreach(ropts, parse_options_cb, (VALUE)copts);
1148
+ oj_parse_opt_match_string(&copts->str_rx, ropts);
1149
+
1150
+ copts->dump_opts.use = (0 < copts->dump_opts.indent_size || 0 < copts->dump_opts.after_size ||
1151
+ 0 < copts->dump_opts.before_size || 0 < copts->dump_opts.hash_size ||
1152
+ 0 < copts->dump_opts.array_size);
1153
+ return;
1154
+ }
1155
+
1156
+ static int match_string_cb(VALUE key, VALUE value, VALUE rx) {
1157
+ RxClass rc = (RxClass)rx;
1158
+
1159
+ if (T_CLASS != rb_type(value)) {
1160
+ rb_raise(rb_eArgError, "for :match_string, the hash values must be a Class.");
1161
+ }
1162
+ switch (rb_type(key)) {
1163
+ case T_REGEXP: oj_rxclass_rappend(rc, key, value); break;
1164
+ case T_STRING:
1165
+ if (0 != oj_rxclass_append(rc, StringValuePtr(key), value)) {
1166
+ rb_raise(rb_eArgError, "%s", rc->err);
1167
+ }
1168
+ break;
1169
+ default: rb_raise(rb_eArgError, "for :match_string, keys must either a String or RegExp."); break;
1170
+ }
1171
+ return ST_CONTINUE;
1172
+ }
1173
+
1174
+ void oj_parse_opt_match_string(RxClass rc, VALUE ropts) {
1175
+ VALUE v;
1176
+
1177
+ if (Qnil != (v = rb_hash_lookup(ropts, match_string_sym))) {
1178
+ rb_check_type(v, T_HASH);
1179
+ // Zero out rc. Pattern are not appended but override.
1180
+ rc->head = NULL;
1181
+ rc->tail = NULL;
1182
+ *rc->err = '\0';
1183
+ rb_hash_foreach(v, match_string_cb, (VALUE)rc);
1184
+ }
1185
+ }
1186
+
1187
+ /* Document-method: load
1188
+ * call-seq: load(json, options={}) { _|_obj, start, len_|_ }
1189
+ *
1190
+ * Parses a JSON document String into a Object, Hash, Array, String, Fixnum,
1191
+ * Float, true, false, or nil according to the default mode or the mode
1192
+ * specified. Raises an exception if the JSON is malformed or the classes
1193
+ * specified are not valid. If the string input is not a valid JSON document (an
1194
+ * empty string is not a valid JSON document) an exception is raised.
1195
+ *
1196
+ * When used with a document that has multiple JSON elements the block, if
1197
+ * any, will be yielded to. If no block then the last element read will be
1198
+ * returned.
1199
+ *
1200
+ * This parser operates on string and will attempt to load files into memory if
1201
+ * a file object is passed as the first argument. A stream input will be parsed
1202
+ * using a stream parser but others use the slightly faster string parser.
1203
+ *
1204
+ * A block can be provided with a single argument. That argument will be the
1205
+ * parsed JSON document. This is useful when parsing a string that includes
1206
+ * multiple JSON documents. The block can take up to 3 arguments, the parsed
1207
+ * object, the position in the string or stream of the start of the JSON for
1208
+ * that object, and the length of the JSON for that object plus trailing
1209
+ * whitespace.
1210
+ *
1211
+ * - *json* [_String_|_IO_] JSON String or an Object that responds to read()
1212
+ * - *options* [_Hash_] load options (same as default_options)
1213
+ * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1214
+ * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1215
+ * - *len* [_optional, _Integer_] length of parsed JSON for obj.
1216
+ *
1217
+ * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
1218
+ */
1219
+ static VALUE load(int argc, VALUE *argv, VALUE self) {
1220
+ Mode mode = oj_default_options.mode;
1221
+
1222
+ if (1 > argc) {
1223
+ rb_raise(rb_eArgError, "Wrong number of arguments to load().");
1224
+ }
1225
+ if (2 <= argc) {
1226
+ VALUE ropts = argv[1];
1227
+ VALUE v;
1228
+
1229
+ if (Qnil != ropts || CompatMode != mode) {
1230
+ Check_Type(ropts, T_HASH);
1231
+ if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
1232
+ if (object_sym == v) {
1233
+ mode = ObjectMode;
1234
+ } else if (strict_sym == v) {
1235
+ mode = StrictMode;
1236
+ } else if (compat_sym == v || json_sym == v) {
1237
+ mode = CompatMode;
1238
+ } else if (null_sym == v) {
1239
+ mode = NullMode;
1240
+ } else if (custom_sym == v) {
1241
+ mode = CustomMode;
1242
+ } else if (rails_sym == v) {
1243
+ mode = RailsMode;
1244
+ } else if (wab_sym == v) {
1245
+ mode = WabMode;
1246
+ } else {
1247
+ rb_raise(rb_eArgError,
1248
+ ":mode must be :object, :strict, :compat, :null, :custom, :rails, or "
1249
+ ":wab.");
1250
+ }
1251
+ }
1252
+ }
1253
+ }
1254
+ switch (mode) {
1255
+ case StrictMode:
1256
+ case NullMode: return oj_strict_parse(argc, argv, self);
1257
+ case CompatMode:
1258
+ case RailsMode: return oj_compat_parse(argc, argv, self);
1259
+ case CustomMode: return oj_custom_parse(argc, argv, self);
1260
+ case WabMode: return oj_wab_parse(argc, argv, self);
1261
+ case ObjectMode:
1262
+ default: break;
1263
+ }
1264
+ return oj_object_parse(argc, argv, self);
1265
+ }
1266
+
1267
+ /* Document-method: load_file
1268
+ * call-seq: load_file(path, options={}) { _|_obj, start, len_|_ }
1269
+ *
1270
+ * Parses a JSON document String into a Object, Hash, Array, String, Fixnum,
1271
+ * Float, true, false, or nil according to the default mode or the mode
1272
+ * specified. Raises an exception if the JSON is malformed or the classes
1273
+ * specified are not valid. If the string input is not a valid JSON document (an
1274
+ * empty string is not a valid JSON document) an exception is raised.
1275
+ *
1276
+ * When used with a document that has multiple JSON elements the block, if
1277
+ * any, will be yielded to. If no block then the last element read will be
1278
+ * returned.
1279
+ *
1280
+ * If the input file is not a valid JSON document (an empty file is not a valid
1281
+ * JSON document) an exception is raised.
1282
+ *
1283
+ * This is a stream based parser which allows a large or huge file to be loaded
1284
+ * without pulling the whole file into memory.
1285
+ *
1286
+ * A block can be provided with a single argument. That argument will be the
1287
+ * parsed JSON document. This is useful when parsing a string that includes
1288
+ * multiple JSON documents. The block can take up to 3 arguments, the parsed
1289
+ * object, the position in the string or stream of the start of the JSON for
1290
+ * that object, and the length of the JSON for that object plus trailing
1291
+ * whitespace.
1292
+ *
1293
+ * - *path* [_String_] to a file containing a JSON document
1294
+ * - *options* [_Hash_] load options (same as default_options)
1295
+ * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1296
+ * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1297
+ * - *len* [_optional, _Integer_] length of parsed JSON for obj.
1298
+ *
1299
+ * Returns [_Object_|_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
1300
+ */
1301
+ static VALUE load_file(int argc, VALUE *argv, VALUE self) {
1302
+ char *path;
1303
+ int fd;
1304
+ Mode mode = oj_default_options.mode;
1305
+ struct _parseInfo pi;
1306
+
1307
+ if (1 > argc) {
1308
+ rb_raise(rb_eArgError, "Wrong number of arguments to load().");
1309
+ }
1310
+ path = StringValuePtr(*argv);
1311
+ parse_info_init(&pi);
1312
+ pi.options = oj_default_options;
1313
+ pi.handler = Qnil;
1314
+ pi.err_class = Qnil;
1315
+ pi.max_depth = 0;
1316
+ if (2 <= argc) {
1317
+ VALUE ropts = argv[1];
1318
+ VALUE v;
1319
+
1320
+ Check_Type(ropts, T_HASH);
1321
+ if (Qnil != (v = rb_hash_lookup(ropts, mode_sym))) {
1322
+ if (object_sym == v) {
1323
+ mode = ObjectMode;
1324
+ } else if (strict_sym == v) {
1325
+ mode = StrictMode;
1326
+ } else if (compat_sym == v || json_sym == v) {
1327
+ mode = CompatMode;
1328
+ } else if (null_sym == v) {
1329
+ mode = NullMode;
1330
+ } else if (custom_sym == v) {
1331
+ mode = CustomMode;
1332
+ } else if (rails_sym == v) {
1333
+ mode = RailsMode;
1334
+ } else if (wab_sym == v) {
1335
+ mode = WabMode;
1336
+ } else {
1337
+ rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, :null, :custom, :rails, or :wab.");
1338
+ }
1339
+ }
1340
+ }
1341
+ #ifdef _WIN32
1342
+ {
1343
+ WCHAR *wide_path;
1344
+ wide_path = rb_w32_mbstr_to_wstr(CP_UTF8, path, -1, NULL);
1345
+ fd = rb_w32_wopen(wide_path, O_RDONLY);
1346
+ OJ_FREE(wide_path);
1347
+ }
1348
+ #else
1349
+ fd = open(path, O_RDONLY);
1350
+ #endif
1351
+ if (0 == fd) {
1352
+ rb_raise(rb_eIOError, "%s", strerror(errno));
1353
+ }
1354
+ switch (mode) {
1355
+ case StrictMode:
1356
+ case NullMode: oj_set_strict_callbacks(&pi); return oj_pi_sparse(argc, argv, &pi, fd);
1357
+ case CustomMode: oj_set_custom_callbacks(&pi); return oj_pi_sparse(argc, argv, &pi, fd);
1358
+ case CompatMode:
1359
+ case RailsMode: oj_set_compat_callbacks(&pi); return oj_pi_sparse(argc, argv, &pi, fd);
1360
+ case WabMode: oj_set_wab_callbacks(&pi); return oj_pi_sparse(argc, argv, &pi, fd);
1361
+ case ObjectMode:
1362
+ default: break;
1363
+ }
1364
+ oj_set_object_callbacks(&pi);
1365
+
1366
+ return oj_pi_sparse(argc, argv, &pi, fd);
1367
+ }
1368
+
1369
+ /* Document-method: safe_load
1370
+ * call-seq: safe_load(doc)
1371
+ *
1372
+ * Loads a JSON document in strict mode with :auto_define and :symbol_keys
1373
+ * turned off. This function should be safe to use with JSON received on an
1374
+ * unprotected public interface.
1375
+ *
1376
+ * - *doc* [_String__|_IO_] JSON String or IO to load.
1377
+ *
1378
+ * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Bignum_|_BigDecimal_|_nil_|_True_|_False_]
1379
+ */
1380
+ static VALUE safe_load(VALUE self, VALUE doc) {
1381
+ struct _parseInfo pi;
1382
+ VALUE args[1];
1383
+
1384
+ parse_info_init(&pi);
1385
+ pi.err_class = Qnil;
1386
+ pi.max_depth = 0;
1387
+ pi.options = oj_default_options;
1388
+ pi.options.auto_define = No;
1389
+ pi.options.sym_key = No;
1390
+ pi.options.mode = StrictMode;
1391
+ oj_set_strict_callbacks(&pi);
1392
+ *args = doc;
1393
+
1394
+ return oj_pi_parse(1, args, &pi, 0, 0, 1);
1395
+ }
1396
+
1397
+ /* Document-method: saj_parse
1398
+ * call-seq: saj_parse(handler, io)
1399
+ *
1400
+ * Parses an IO stream or file containing a JSON document. Raises an exception
1401
+ * if the JSON is malformed. This is a callback parser that calls the methods in
1402
+ * the handler if they exist. A sample is the Oj::Saj class which can be used as
1403
+ * a base class for the handler.
1404
+ *
1405
+ * - *handler* [_Oj::Saj_] responds to Oj::Saj methods
1406
+ * - *io* [_IO_|_String_] IO Object to read from
1407
+ */
1408
+
1409
+ /* Document-method: sc_parse
1410
+ * call-seq: sc_parse(handler, io)
1411
+ *
1412
+ * Parses an IO stream or file containing a JSON document. Raises an exception
1413
+ * if the JSON is malformed. This is a callback parser (Simple Callback Parser)
1414
+ * that calls the methods in the handler if they exist. A sample is the
1415
+ * Oj::ScHandler class which can be used as a base class for the handler. This
1416
+ * callback parser is slightly more efficient than the Saj callback parser and
1417
+ * requires less argument checking.
1418
+ *
1419
+ * - *handler* [_Oj_::ScHandler_] responds to Oj::ScHandler methods
1420
+ * - *io* [_IO__|_String_] IO Object to read from
1421
+ */
1422
+
1423
+ struct dump_arg {
1424
+ struct _out *out;
1425
+ struct _options *copts;
1426
+ int argc;
1427
+ VALUE *argv;
1428
+ };
1429
+
1430
+ static VALUE dump_body(VALUE a) {
1431
+ volatile struct dump_arg *arg = (void *)a;
1432
+ VALUE rstr;
1433
+
1434
+ oj_dump_obj_to_json_using_params(*arg->argv, arg->copts, arg->out, arg->argc - 1, arg->argv + 1);
1435
+ if (0 == arg->out->buf) {
1436
+ rb_raise(rb_eNoMemError, "Not enough memory.");
1437
+ }
1438
+ rstr = rb_utf8_str_new_cstr(arg->out->buf);
1439
+
1440
+ return rstr;
1441
+ }
1442
+
1443
+ static VALUE dump_ensure(VALUE a) {
1444
+ volatile struct dump_arg *arg = (void *)a;
1445
+
1446
+ oj_out_free(arg->out);
1447
+
1448
+ return Qnil;
1449
+ }
1450
+
1451
+ /* Document-method: dump
1452
+ * call-seq: dump(obj, options={})
1453
+ *
1454
+ * Dumps an Object (obj) to a string.
1455
+ * - *obj* [_Object_] Object to serialize as an JSON document String
1456
+ * - *options* [_Hash_] same as default_options
1457
+ */
1458
+ static VALUE dump(int argc, VALUE *argv, VALUE self) {
1459
+ struct dump_arg arg;
1460
+ struct _out out;
1461
+ struct _options copts = oj_default_options;
1462
+
1463
+ if (1 > argc) {
1464
+ rb_raise(rb_eArgError, "wrong number of arguments (0 for 1).");
1465
+ }
1466
+ if (CompatMode == copts.mode) {
1467
+ copts.dump_opts.nan_dump = WordNan;
1468
+ }
1469
+ if (2 == argc) {
1470
+ oj_parse_options(argv[1], &copts);
1471
+ }
1472
+ if (CompatMode == copts.mode && copts.escape_mode != ASCIIEsc) {
1473
+ copts.escape_mode = JSONEsc;
1474
+ }
1475
+ arg.out = &out;
1476
+ arg.copts = &copts;
1477
+ arg.argc = argc;
1478
+ arg.argv = argv;
1479
+
1480
+ oj_out_init(arg.out);
1481
+
1482
+ arg.out->omit_nil = copts.dump_opts.omit_nil;
1483
+ arg.out->omit_null_byte = copts.dump_opts.omit_null_byte;
1484
+
1485
+ return rb_ensure(dump_body, (VALUE)&arg, dump_ensure, (VALUE)&arg);
1486
+ }
1487
+
1488
+ /* Document-method: to_json
1489
+ * call-seq: to_json(obj, options)
1490
+ *
1491
+ * Dumps an Object (obj) to a string. If the object has a to_json method that
1492
+ * will be called. The mode is set to :compat.
1493
+ * - *obj* [_Object_] Object to serialize as an JSON document String
1494
+ * - *options* [_Hash_]
1495
+ * - *:max_nesting* [_Fixnum_|_boolean_] It true nesting is limited to 100.
1496
+ * If a Fixnum nesting is set to the provided value. The option to detect
1497
+ * circular references is available but is not compatible with the json gem.,
1498
+ * default is false or unlimited.
1499
+ * - *:allow_nan* [_boolean_] If true non JSON compliant words such as Nan and
1500
+ * Infinity will be used as appropriate, default is true.
1501
+ * - *:quirks_mode* [_boolean_] Allow single JSON values instead of documents, default is true (allow).
1502
+ * - *:indent* [_String_|_nil_] String to use for indentation, overriding the indent option if not nil.
1503
+ * - *:space* [_String_|_nil_] String to use for the space after the colon in JSON object fields.
1504
+ * - *:space_before* [_String_|_nil_] String to use before the colon separator in JSON object fields.
1505
+ * - *:object_nl* [_String_|_nil_] String to use after a JSON object field value.
1506
+ * - *:array_nl* [_String_|_nil_] String to use after a JSON array value.
1507
+ * - *:trace* [_Boolean_] If true trace is turned on.
1508
+ *
1509
+ * Returns [_String_] the encoded JSON.
1510
+ */
1511
+ static VALUE to_json(int argc, VALUE *argv, VALUE self) {
1512
+ struct _out out;
1513
+ struct _options copts = oj_default_options;
1514
+ VALUE rstr;
1515
+
1516
+ if (1 > argc) {
1517
+ rb_raise(rb_eArgError, "wrong number of arguments (0 for 1).");
1518
+ }
1519
+ copts.escape_mode = JXEsc;
1520
+ copts.dump_opts.nan_dump = RaiseNan;
1521
+ if (2 == argc) {
1522
+ oj_parse_mimic_dump_options(argv[1], &copts);
1523
+ }
1524
+ copts.mode = CompatMode;
1525
+ copts.to_json = Yes;
1526
+
1527
+ oj_out_init(&out);
1528
+
1529
+ out.omit_nil = copts.dump_opts.omit_nil;
1530
+ out.omit_null_byte = copts.dump_opts.omit_null_byte;
1531
+ // For obj.to_json or generate nan is not allowed but if called from dump
1532
+ // it is.
1533
+ oj_dump_obj_to_json_using_params(*argv, &copts, &out, argc - 1, argv + 1);
1534
+
1535
+ if (0 == out.buf) {
1536
+ rb_raise(rb_eNoMemError, "Not enough memory.");
1537
+ }
1538
+ rstr = rb_utf8_str_new_cstr(out.buf);
1539
+
1540
+ oj_out_free(&out);
1541
+
1542
+ return rstr;
1543
+ }
1544
+
1545
+ /* Document-method: to_file
1546
+ * call-seq: to_file(file_path, obj, options={})
1547
+ *
1548
+ * Dumps an Object to the specified file.
1549
+ * - *file* [_String_] _path file path to write the JSON document to
1550
+ * - *obj* [_Object_] Object to serialize as an JSON document String
1551
+ * - *options* [_Hash_] formatting options
1552
+ * - *:indent* [_Fixnum_] format expected
1553
+ * - *:circular* [_Boolean_] allow circular references, default: false
1554
+ */
1555
+ static VALUE to_file(int argc, VALUE *argv, VALUE self) {
1556
+ struct _options copts = oj_default_options;
1557
+
1558
+ if (3 == argc) {
1559
+ oj_parse_options(argv[2], &copts);
1560
+ }
1561
+ oj_write_obj_to_file(argv[1], StringValuePtr(*argv), &copts);
1562
+
1563
+ return Qnil;
1564
+ }
1565
+
1566
+ /* Document-method: to_stream
1567
+ * call-seq: to_stream(io, obj, options={})
1568
+ *
1569
+ * Dumps an Object to the specified IO stream.
1570
+ * - *io* [_IO_] IO stream to write the JSON document to
1571
+ * - *obj* [_Object_] Object to serialize as an JSON document String
1572
+ * - *options* [_Hash_] formatting options
1573
+ * - *:indent* [_Fixnum_] format expected
1574
+ * - *:circular* [_Boolean_] allow circular references, default: false
1575
+ */
1576
+ static VALUE to_stream(int argc, VALUE *argv, VALUE self) {
1577
+ struct _options copts = oj_default_options;
1578
+
1579
+ if (3 == argc) {
1580
+ oj_parse_options(argv[2], &copts);
1581
+ }
1582
+ oj_write_obj_to_stream(argv[1], *argv, &copts);
1583
+
1584
+ return Qnil;
1585
+ }
1586
+
1587
+ /* Document-method: register_odd
1588
+ * call-seq: register_odd(clas, create_object, create_method, *members)
1589
+ *
1590
+ * Registers a class as special. This is useful for working around subclasses of
1591
+ * primitive types as is done with ActiveSupport classes. The use of this
1592
+ * function should be limited to just classes that can not be handled in the
1593
+ * normal way. It is not intended as a hook for changing the output of all
1594
+ * classes as it is not optimized for large numbers of classes.
1595
+ *
1596
+ * - *clas* [_Class__|_Module_] Class or Module to be made special
1597
+ * - *create_object* [_Object_] object to call the create method on
1598
+ * - *create_method* [_Symbol_] method on the clas that will create a new instance
1599
+ * of the clas when given all the member values in the order specified.
1600
+ * - *members* [_Symbol__|_String_] methods used to get the member values from
1601
+ * instances of the clas.
1602
+ */
1603
+ static VALUE register_odd(int argc, VALUE *argv, VALUE self) {
1604
+ if (3 > argc) {
1605
+ rb_raise(rb_eArgError, "incorrect number of arguments.");
1606
+ }
1607
+ switch (rb_type(*argv)) {
1608
+ case T_CLASS:
1609
+ case T_MODULE: break;
1610
+ default: rb_raise(rb_eTypeError, "expected a class or module."); break;
1611
+ }
1612
+ Check_Type(argv[2], T_SYMBOL);
1613
+ if (MAX_ODD_ARGS < argc - 2) {
1614
+ rb_raise(rb_eArgError, "too many members.");
1615
+ }
1616
+ oj_reg_odd(argv[0], argv[1], argv[2], argc - 3, argv + 3, false);
1617
+
1618
+ return Qnil;
1619
+ }
1620
+
1621
+ /* Document-method: register_odd_raw
1622
+ * call-seq: register_odd_raw(clas, create_object, create_method, dump_method)
1623
+ *
1624
+ * Registers a class as special and expect the output to be a string that can be
1625
+ * included in the dumped JSON directly. This is useful for working around
1626
+ * subclasses of primitive types as is done with ActiveSupport classes. The use
1627
+ * of this function should be limited to just classes that can not be handled in
1628
+ * the normal way. It is not intended as a hook for changing the output of all
1629
+ * classes as it is not optimized for large numbers of classes. Be careful with
1630
+ * this option as the JSON may be incorrect if invalid JSON is returned.
1631
+ *
1632
+ * - *clas* [_Class_|_Module_] Class or Module to be made special
1633
+ * - *create_object* [_Object_] object to call the create method on
1634
+ * - *create_method* [_Symbol_] method on the clas that will create a new instance
1635
+ * of the clas when given all the member values in the order specified.
1636
+ * - *dump_method* [_Symbol_|_String_] method to call on the object being
1637
+ * serialized to generate the raw JSON.
1638
+ */
1639
+ static VALUE register_odd_raw(int argc, VALUE *argv, VALUE self) {
1640
+ if (3 > argc) {
1641
+ rb_raise(rb_eArgError, "incorrect number of arguments.");
1642
+ }
1643
+ switch (rb_type(*argv)) {
1644
+ case T_CLASS:
1645
+ case T_MODULE: break;
1646
+ default: rb_raise(rb_eTypeError, "expected a class or module."); break;
1647
+ }
1648
+ Check_Type(argv[2], T_SYMBOL);
1649
+ if (MAX_ODD_ARGS < argc - 2) {
1650
+ rb_raise(rb_eArgError, "too many members.");
1651
+ }
1652
+ oj_reg_odd(argv[0], argv[1], argv[2], 1, argv + 3, true);
1653
+
1654
+ return Qnil;
1655
+ }
1656
+
1657
+ ////////////////////////////////////////////////////////////////////////////////
1658
+ // RDoc entries must be in the same file as the rb_define_method and must be
1659
+ // directly above the C method function. The extern declaration is enough to
1660
+ // get it to work.
1661
+ ////////////////////////////////////////////////////////////////////////////////
1662
+
1663
+ /* Document-method: strict_load
1664
+ * call-seq: strict_load(json, options) { _|_obj, start, len_|_ }
1665
+ *
1666
+ * Parses a JSON document String into an Hash, Array, String, Fixnum, Float,
1667
+ * true, false, or nil. It parses using a mode that is strict in that it maps
1668
+ * each primitive JSON type to a similar Ruby type. The :create_id is not
1669
+ * honored in this mode. Note that a Ruby Hash is used to represent the JSON
1670
+ * Object type. These two are not the same since the JSON Object type can have
1671
+ * repeating entries with the same key and Ruby Hash can not.
1672
+ *
1673
+ * When used with a document that has multiple JSON elements the block, if
1674
+ * any, will be yielded to. If no block then the last element read will be
1675
+ * returned.
1676
+ *
1677
+ * Raises an exception if the JSON is malformed or the classes specified are not
1678
+ * valid. If the input is not a valid JSON document (an empty string is not a
1679
+ * valid JSON document) an exception is raised.
1680
+ *
1681
+ * A block can be provided with a single argument. That argument will be the
1682
+ * parsed JSON document. This is useful when parsing a string that includes
1683
+ * multiple JSON documents. The block can take up to 3 arguments, the parsed
1684
+ * object, the position in the string or stream of the start of the JSON for
1685
+ * that object, and the length of the JSON for that object plus trailing
1686
+ * whitespace.
1687
+ *
1688
+ * - *json* [_String_|_IO_] JSON String or an Object that responds to read().
1689
+ * - *options* [_Hash_] load options (same as default_options).
1690
+ * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1691
+ * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1692
+ * - *len* [_optional, _Integer_] length of parsed JSON for obj.
1693
+ *
1694
+ * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
1695
+ */
1696
+ extern VALUE oj_strict_parse(int argc, VALUE *argv, VALUE self);
1697
+
1698
+ /* Document-method: compat_load
1699
+ * call-seq: compat_load(json, options) { _|_obj, start, len_|_ }
1700
+ *
1701
+ * Parses a JSON document String into an Object, Hash, Array, String, Fixnum,
1702
+ * Float, true, false, or nil. It parses using a mode that is generally
1703
+ * compatible with other Ruby JSON parsers in that it will create objects based
1704
+ * on the :create_id value. It is not compatible in every way to every other
1705
+ * parser though as each parser has it's own variations.
1706
+ *
1707
+ * When used with a document that has multiple JSON elements the block, if
1708
+ * any, will be yielded to. If no block then the last element read will be
1709
+ * returned.
1710
+ *
1711
+ * Raises an exception if the JSON is malformed or the classes specified are not
1712
+ * valid. If the input is not a valid JSON document (an empty string is not a
1713
+ * valid JSON document) an exception is raised.
1714
+ *
1715
+ * A block can be provided with a single argument. That argument will be the
1716
+ * parsed JSON document. This is useful when parsing a string that includes
1717
+ * multiple JSON documents. The block can take up to 3 arguments, the parsed
1718
+ * object, the position in the string or stream of the start of the JSON for
1719
+ * that object, and the length of the JSON for that object plus trailing
1720
+ * whitespace.
1721
+ *
1722
+ * - *json* [_String_|_IO_] JSON String or an Object that responds to read().
1723
+ * - *options* [_Hash_] load options (same as default_options).
1724
+ * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1725
+ * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1726
+ * - *len* [_optional, _Integer_] length of parsed JSON for obj.
1727
+ *
1728
+ * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
1729
+ */
1730
+ extern VALUE oj_compat_parse(int argc, VALUE *argv, VALUE self);
1731
+
1732
+ /* Document-method: object_load
1733
+ * call-seq: object_load(json, options) { _|_obj, start, len_|_ }
1734
+ *
1735
+ * Parses a JSON document String into an Object, Hash, Array, String, Fixnum,
1736
+ * Float, true, false, or nil. In the :object mode the JSON should have been
1737
+ * generated by Oj.dump(). The parser will reconstitute the original marshalled
1738
+ * or dumped Object. The :auto_define and :circular options have meaning with
1739
+ * this parsing mode.
1740
+ *
1741
+ * Raises an exception if the JSON is malformed or the classes specified are not
1742
+ * valid. If the input is not a valid JSON document (an empty string is not a
1743
+ * valid JSON document) an exception is raised.
1744
+ *
1745
+ * A block can be provided with a single argument. That argument will be the
1746
+ * parsed JSON document. This is useful when parsing a string that includes
1747
+ * multiple JSON documents. The block can take up to 3 arguments, the parsed
1748
+ * object, the position in the string or stream of the start of the JSON for
1749
+ * that object, and the length of the JSON for that object plus trailing
1750
+ * whitespace.
1751
+ *
1752
+ * - *json* [_String_|_IO_] JSON String or an Object that responds to read().
1753
+ * - *options* [_Hash_] load options (same as default_options).
1754
+ * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1755
+ * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1756
+ * - *len* [_optional, _Integer_] length of parsed JSON for obj.
1757
+ *
1758
+ * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
1759
+ */
1760
+ extern VALUE oj_object_parse(int argc, VALUE *argv, VALUE self);
1761
+
1762
+ /* Document-method: wab_load
1763
+ * call-seq: wab_load(json, options) { _|_obj, start, len_|_ }
1764
+ *
1765
+ * Parses a JSON document String into an Hash, Array, String, Fixnum, Float,
1766
+ * true, false, or nil. It parses using a mode that is :wab in that it maps
1767
+ * each primitive JSON type to a similar Ruby type. The :create_id is not
1768
+ * honored in this mode. Note that a Ruby Hash is used to represent the JSON
1769
+ * Object type. These two are not the same since the JSON Object type can have
1770
+ * repeating entries with the same key and Ruby Hash can not.
1771
+ *
1772
+ * When used with a document that has multiple JSON elements the block, if
1773
+ * any, will be yielded to. If no block then the last element read will be
1774
+ * returned.
1775
+ *
1776
+ * Raises an exception if the JSON is malformed or the classes specified are not
1777
+ * valid. If the input is not a valid JSON document (an empty string is not a
1778
+ * valid JSON document) an exception is raised.
1779
+ *
1780
+ * A block can be provided with a single argument. That argument will be the
1781
+ * parsed JSON document. This is useful when parsing a string that includes
1782
+ * multiple JSON documents. The block can take up to 3 arguments, the parsed
1783
+ * object, the position in the string or stream of the start of the JSON for
1784
+ * that object, and the length of the JSON for that object plus trailing
1785
+ * whitespace.
1786
+ *
1787
+ * - *json* [_String_|_IO_] JSON String or an Object that responds to read().
1788
+ * - *options* [_Hash_] load options (same as default_options).
1789
+ * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1790
+ * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1791
+ * - *len* [_optional, _Integer_] length of parsed JSON for obj.
1792
+ *
1793
+ * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
1794
+ */
1795
+ extern VALUE oj_wab_parse(int argc, VALUE *argv, VALUE self);
1796
+
1797
+ /* Document-method: add_to_json
1798
+ * call-seq: add_to_json(*args)
1799
+ *
1800
+ * Override simple to_s dump behavior in :compat mode to instead use an
1801
+ * optimized dump that includes the classname and attributes so that the
1802
+ * object can be re-created on load. The format is the same as the json gem
1803
+ * but does not use the ruby methods for encoding.
1804
+ *
1805
+ * The classes supported for optimization are: Array, BigDecimal, Complex,
1806
+ * Date, DateTime, Exception, Hash, Integer, OpenStruct, Range, Rational,
1807
+ * Regexp, Struct, and Time. Providing no classes will result in all those
1808
+ * classes being optimized.q
1809
+ *
1810
+ * - *args( [_Class_] zero or more classes to optimize.
1811
+ */
1812
+ extern VALUE oj_add_to_json(int argc, VALUE *argv, VALUE self);
1813
+
1814
+ /* @!method remove_to_json(*args)
1815
+ *
1816
+ * Reverts back to the to_s dump behavior in :compat mode to instead use an
1817
+ * optimized dump that includes the classname and attributes so that the
1818
+ * object can be re-created on load. The format is the same as the json gem
1819
+ * but does not use the ruby methods for encoding.
1820
+ *
1821
+ * The classes supported for optimization are: Array, BigDecimal, Complex,
1822
+ * Date, DateTime, Exception, Hash, Integer, OpenStruct, Range, Rational,
1823
+ * Regexp, Struct, and Time. Providing no classes will result in all those
1824
+ * classes being reverted from the optimized mode.
1825
+ *
1826
+ * - *args* [_Class_] zero or more classes to optimize.
1827
+ */
1828
+ extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self);
1829
+
1830
+ /* Document-method: mimic_JSON
1831
+ * call-seq: mimic_JSON()
1832
+ *
1833
+ * Creates the JSON module with methods and classes to mimic the JSON gem. After
1834
+ * this method is invoked calls that expect the JSON module will use Oj instead
1835
+ * and be faster than the original JSON. Most options that could be passed to
1836
+ * the JSON methods are supported. The calls to set parser or generator will not
1837
+ * raise an Exception but will not have any effect. The method can also be
1838
+ * called after the json gem is loaded. The necessary methods on the json gem
1839
+ * will be replaced with Oj methods.
1840
+ *
1841
+ * Note that this also sets the default options of :mode to :compat and
1842
+ * :encoding to :unicode_xss.
1843
+ *
1844
+ * Returns [_Module_] the JSON module.
1845
+ */
1846
+ extern VALUE oj_define_mimic_json(int argc, VALUE *argv, VALUE self);
1847
+
1848
+ /* Document-method: generate
1849
+ * call-seq: generate(obj, opts=nil)
1850
+ *
1851
+ * Encode obj as a JSON String. The obj argument must be a Hash, Array, or
1852
+ * respond to to_h or to_json. Options other than those listed such as
1853
+ * +:allow_nan+ or +:max_nesting+ are ignored. Calling this method will call
1854
+ * Oj.mimic_JSON if it is not already called.
1855
+ *
1856
+ * - *obj* [_Object__|_Hash_|_Array_] object to convert to a JSON String
1857
+ * - *opts* [_Hash_] options
1858
+ * - *:indent* [_String_] String to use for indentation.
1859
+ * - *:space* [_String_] String placed after a , or : delimiter
1860
+ * - *:space_before* [_String_] String placed before a : delimiter
1861
+ * - *:object_nl* [_String_] String placed after a JSON object
1862
+ * - *:array_nl* [_String_] String placed after a JSON array
1863
+ * - *:ascii_only* [_Boolean_] if not nil or false then use only ascii characters
1864
+ * in the output. Note JSON.generate does support this even if it is not documented.
1865
+ *
1866
+ * Returns [_String_]generated JSON.
1867
+ */
1868
+ extern VALUE oj_mimic_generate(int argc, VALUE *argv, VALUE self);
1869
+
1870
+ /* Document-module: Oj.optimize_rails()
1871
+ *
1872
+ * Sets the Oj as the Rails encoder and decoder. Oj::Rails.optimize is also
1873
+ * called.
1874
+ */
1875
+ extern VALUE oj_optimize_rails(VALUE self);
1876
+
1877
+ /*
1878
+ extern void oj_hash_test();
1879
+ static VALUE
1880
+ hash_test(VALUE self) {
1881
+ oj_hash_test();
1882
+ return Qnil;
1883
+ }
1884
+ */
1885
+ /*
1886
+ extern void oj_hash_sizes();
1887
+ static VALUE
1888
+ hash_test(VALUE self) {
1889
+ oj_hash_sizes();
1890
+ return Qnil;
1891
+ }
1892
+ */
1893
+
1894
+ static VALUE protect_require(VALUE x) {
1895
+ rb_require("time");
1896
+ rb_require("bigdecimal");
1897
+ return Qnil;
1898
+ }
1899
+
1900
+ extern void print_all_odds(const char *label);
1901
+
1902
+ static VALUE debug_odd(VALUE self, VALUE label) {
1903
+ print_all_odds(RSTRING_PTR(label));
1904
+ return Qnil;
1905
+ }
1906
+
1907
+ static VALUE mem_report(VALUE self) {
1908
+ oj_mem_report();
1909
+ return Qnil;
1910
+ }
1911
+
1912
+ /* Document-module: Oj
1913
+ *
1914
+ * Optimized JSON (Oj), as the name implies was written to provide speed
1915
+ * optimized JSON handling.
1916
+ *
1917
+ * Oj uses modes to control how object are encoded and decoded. In addition
1918
+ * global and options to methods allow additional behavior modifications. The
1919
+ * modes are:
1920
+ *
1921
+ * - *:strict* mode will only allow the 7 basic JSON types to be serialized.
1922
+ * Any other Object will raise an Exception.
1923
+ *
1924
+ * - *:null* mode is similar to the :strict mode except any Object that is not
1925
+ * one of the JSON base types is replaced by a JSON null.
1926
+ *
1927
+ * - *:object* mode will dump any Object as a JSON Object with keys that match
1928
+ * the Ruby Object's variable names without the '@' character. This is the
1929
+ * highest performance mode.
1930
+ *
1931
+ * - *:compat* or *:json* mode is the compatible mode for the json gem. It mimics
1932
+ * the json gem including the options, defaults, and restrictions.
1933
+ *
1934
+ * - *:rails* is the compatibility mode for Rails or Active support.
1935
+ *
1936
+ * - *:custom* is the most configurable mode.
1937
+ *
1938
+ * - *:wab* specifically for WAB data exchange.
1939
+ */
1940
+
1941
+ // =============================================================================
1942
+ // Runtime SIMD CPU detection
1943
+ // Cross-platform support for Windows (MSVC), Linux, and macOS (GCC/Clang)
1944
+ // =============================================================================
1945
+ SIMD_Implementation oj_get_simd_implementation(void) {
1946
+ #ifdef HAVE_SIMD_X86
1947
+ // x86/x86_64 runtime detection
1948
+
1949
+ #if defined(_MSC_VER)
1950
+ // MSVC: Use __cpuid intrinsic
1951
+ int cpu_info[4];
1952
+ __cpuid(cpu_info, 1);
1953
+
1954
+ // Check for SSE4.2 (bit 20 of ECX)
1955
+ if (cpu_info[2] & (1 << 20)) {
1956
+ return SIMD_SSE42;
1957
+ }
1958
+ // Check for SSE2 (bit 26 of EDX)
1959
+ if (cpu_info[3] & (1 << 26)) {
1960
+ return SIMD_SSE2;
1961
+ }
1962
+
1963
+ #elif defined(__GNUC__) || defined(__clang__)
1964
+ // GCC/Clang: Use __builtin_cpu_supports if available
1965
+ #if defined(__has_builtin)
1966
+ #if __has_builtin(__builtin_cpu_supports)
1967
+ #define OJ_HAS_BUILTIN_CPU_SUPPORTS 1
1968
+ #endif
1969
+ #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
1970
+ // GCC 4.8+ has __builtin_cpu_supports
1971
+ #define OJ_HAS_BUILTIN_CPU_SUPPORTS 1
1972
+ #endif
1973
+
1974
+ #ifdef OJ_HAS_BUILTIN_CPU_SUPPORTS
1975
+ #ifdef HAVE_SIMD_SSE4_2
1976
+ if (__builtin_cpu_supports("sse4.2")) {
1977
+ return SIMD_SSE42;
1978
+ }
1979
+ #endif
1980
+ #ifdef HAVE_SIMD_SSE2
1981
+ if (__builtin_cpu_supports("sse2")) {
1982
+ return SIMD_SSE2;
1983
+ }
1984
+ #endif
1985
+ #else
1986
+ // Fallback: Use CPUID instruction directly
1987
+ unsigned int eax, ebx, ecx, edx;
1988
+ if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
1989
+ // Check for SSE4.2 (bit 20 of ECX)
1990
+ if (ecx & (1 << 20)) {
1991
+ return SIMD_SSE42;
1992
+ }
1993
+ // Check for SSE2 (bit 26 of EDX)
1994
+ if (edx & (1 << 26)) {
1995
+ return SIMD_SSE2;
1996
+ }
1997
+ }
1998
+ #endif // OJ_HAS_BUILTIN_CPU_SUPPORTS
1999
+
2000
+ #endif // _MSC_VER vs GCC/Clang
2001
+
2002
+ #endif // HAVE_SIMD_X86
2003
+
2004
+ #ifdef HAVE_SIMD_NEON
2005
+ // ARM NEON is always available on ARM64 and detected at compile time
2006
+ return SIMD_NEON;
2007
+ #endif
2008
+
2009
+ return SIMD_NONE;
2010
+ }
2011
+
2012
+ void Init_oj(void) {
2013
+ int err = 0;
2014
+
2015
+ #if HAVE_RB_EXT_RACTOR_SAFE
2016
+ rb_ext_ractor_safe(true);
2017
+ #endif
2018
+ Oj = rb_define_module("Oj");
2019
+ rb_gc_register_address(&Oj);
2020
+
2021
+ oj_cstack_class = rb_define_class_under(Oj, "CStack", rb_cObject);
2022
+ rb_gc_register_address(&oj_cstack_class);
2023
+
2024
+ rb_undef_alloc_func(oj_cstack_class);
2025
+
2026
+ oj_string_writer_init();
2027
+ oj_stream_writer_init();
2028
+
2029
+ rb_require("date");
2030
+ // On Rubinius the require fails but can be done from a ruby file.
2031
+ rb_protect(protect_require, Qnil, &err);
2032
+ rb_require("stringio");
2033
+ oj_utf8_encoding_index = rb_enc_find_index("UTF-8");
2034
+ oj_utf8_encoding = rb_enc_from_index(oj_utf8_encoding_index);
2035
+
2036
+ // rb_define_module_function(Oj, "hash_test", hash_test, 0);
2037
+ rb_define_module_function(Oj, "debug_odd", debug_odd, 1);
2038
+
2039
+ rb_define_module_function(Oj, "default_options", get_def_opts, 0);
2040
+ rb_define_module_function(Oj, "default_options=", set_def_opts, 1);
2041
+
2042
+ rb_define_module_function(Oj, "mimic_JSON", oj_define_mimic_json, -1);
2043
+ rb_define_module_function(Oj, "load", load, -1);
2044
+ rb_define_module_function(Oj, "load_file", load_file, -1);
2045
+ rb_define_module_function(Oj, "safe_load", safe_load, 1);
2046
+ rb_define_module_function(Oj, "strict_load", oj_strict_parse, -1);
2047
+ rb_define_module_function(Oj, "compat_load", oj_compat_parse, -1);
2048
+ rb_define_module_function(Oj, "object_load", oj_object_parse, -1);
2049
+ rb_define_module_function(Oj, "wab_load", oj_wab_parse, -1);
2050
+
2051
+ rb_define_module_function(Oj, "dump", dump, -1);
2052
+
2053
+ rb_define_module_function(Oj, "to_file", to_file, -1);
2054
+ rb_define_module_function(Oj, "to_stream", to_stream, -1);
2055
+ // JSON gem compatibility
2056
+ rb_define_module_function(Oj, "to_json", to_json, -1);
2057
+ rb_define_module_function(Oj, "generate", oj_mimic_generate, -1);
2058
+ rb_define_module_function(Oj, "fast_generate", oj_mimic_generate, -1);
2059
+
2060
+ rb_define_module_function(Oj, "add_to_json", oj_add_to_json, -1);
2061
+ rb_define_module_function(Oj, "remove_to_json", oj_remove_to_json, -1);
2062
+
2063
+ rb_define_module_function(Oj, "register_odd", register_odd, -1);
2064
+ rb_define_module_function(Oj, "register_odd_raw", register_odd_raw, -1);
2065
+
2066
+ rb_define_module_function(Oj, "saj_parse", oj_saj_parse, -1);
2067
+ rb_define_module_function(Oj, "sc_parse", oj_sc_parse, -1);
2068
+
2069
+ rb_define_module_function(Oj, "optimize_rails", oj_optimize_rails, 0);
2070
+
2071
+ rb_define_module_function(Oj, "mem_report", mem_report, 0);
2072
+
2073
+ oj_add_value_id = rb_intern("add_value");
2074
+ oj_array_append_id = rb_intern("array_append");
2075
+ oj_array_end_id = rb_intern("array_end");
2076
+ oj_array_start_id = rb_intern("array_start");
2077
+ oj_as_json_id = rb_intern("as_json");
2078
+ oj_begin_id = rb_intern("begin");
2079
+ oj_bigdecimal_id = rb_intern("BigDecimal");
2080
+ oj_end_id = rb_intern("end");
2081
+ oj_eofq_id = rb_intern("eof?");
2082
+ oj_error_id = rb_intern("error");
2083
+ oj_exclude_end_id = rb_intern("exclude_end?");
2084
+ oj_file_id = rb_intern("file?");
2085
+ oj_fileno_id = rb_intern("fileno");
2086
+ oj_ftype_id = rb_intern("ftype");
2087
+ oj_hash_end_id = rb_intern("hash_end");
2088
+ oj_hash_key_id = rb_intern("hash_key");
2089
+ oj_hash_set_id = rb_intern("hash_set");
2090
+ oj_hash_start_id = rb_intern("hash_start");
2091
+ oj_iconv_id = rb_intern("iconv");
2092
+ oj_json_create_id = rb_intern("json_create");
2093
+ oj_length_id = rb_intern("length");
2094
+ oj_new_id = rb_intern("new");
2095
+ oj_parse_id = rb_intern("parse");
2096
+ oj_plus_id = rb_intern("+");
2097
+ oj_pos_id = rb_intern("pos");
2098
+ oj_raw_json_id = rb_intern("raw_json");
2099
+ oj_read_id = rb_intern("read");
2100
+ oj_readpartial_id = rb_intern("readpartial");
2101
+ oj_replace_id = rb_intern("replace");
2102
+ oj_stat_id = rb_intern("stat");
2103
+ oj_string_id = rb_intern("string");
2104
+ oj_to_h_id = rb_intern("to_h");
2105
+ oj_to_hash_id = rb_intern("to_hash");
2106
+ oj_to_json_id = rb_intern("to_json");
2107
+ oj_to_s_id = rb_intern("to_s");
2108
+ oj_to_sym_id = rb_intern("to_sym");
2109
+ oj_to_time_id = rb_intern("to_time");
2110
+ oj_tv_nsec_id = rb_intern("tv_nsec");
2111
+ oj_tv_sec_id = rb_intern("tv_sec");
2112
+ oj_tv_usec_id = rb_intern("tv_usec");
2113
+ oj_utc_id = rb_intern("utc");
2114
+ oj_utc_offset_id = rb_intern("utc_offset");
2115
+ oj_utcq_id = rb_intern("utc?");
2116
+ oj_write_id = rb_intern("write");
2117
+
2118
+ rb_require("oj/bag");
2119
+ rb_require("oj/error");
2120
+ rb_require("oj/mimic");
2121
+ rb_require("oj/saj");
2122
+ rb_require("oj/schandler");
2123
+
2124
+ oj_bag_class = rb_const_get_at(Oj, rb_intern("Bag"));
2125
+ rb_gc_register_mark_object(oj_bag_class);
2126
+ oj_bigdecimal_class = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
2127
+ rb_gc_register_mark_object(oj_bigdecimal_class);
2128
+ oj_date_class = rb_const_get(rb_cObject, rb_intern("Date"));
2129
+ rb_gc_register_mark_object(oj_date_class);
2130
+ oj_datetime_class = rb_const_get(rb_cObject, rb_intern("DateTime"));
2131
+ rb_gc_register_mark_object(oj_datetime_class);
2132
+ oj_enumerable_class = rb_const_get(rb_cObject, rb_intern("Enumerable"));
2133
+ rb_gc_register_mark_object(oj_enumerable_class);
2134
+ oj_parse_error_class = rb_const_get_at(Oj, rb_intern("ParseError"));
2135
+ rb_gc_register_mark_object(oj_parse_error_class);
2136
+ oj_stringio_class = rb_const_get(rb_cObject, rb_intern("StringIO"));
2137
+ rb_gc_register_mark_object(oj_stringio_class);
2138
+ oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
2139
+ rb_gc_register_mark_object(oj_struct_class);
2140
+ oj_json_parser_error_class = rb_eEncodingError; // replaced if mimic is called
2141
+ oj_json_generator_error_class = rb_eEncodingError; // replaced if mimic is called
2142
+
2143
+ allow_blank_sym = ID2SYM(rb_intern("allow_blank"));
2144
+ rb_gc_register_address(&allow_blank_sym);
2145
+ allow_gc_sym = ID2SYM(rb_intern("allow_gc"));
2146
+ rb_gc_register_address(&allow_gc_sym);
2147
+ allow_invalid_unicode_sym = ID2SYM(rb_intern("allow_invalid_unicode"));
2148
+ rb_gc_register_address(&allow_invalid_unicode_sym);
2149
+ ascii_sym = ID2SYM(rb_intern("ascii"));
2150
+ rb_gc_register_address(&ascii_sym);
2151
+ auto_define_sym = ID2SYM(rb_intern("auto_define"));
2152
+ rb_gc_register_address(&auto_define_sym);
2153
+ auto_sym = ID2SYM(rb_intern("auto"));
2154
+ rb_gc_register_address(&auto_sym);
2155
+ bigdecimal_as_decimal_sym = ID2SYM(rb_intern("bigdecimal_as_decimal"));
2156
+ rb_gc_register_address(&bigdecimal_as_decimal_sym);
2157
+ bigdecimal_load_sym = ID2SYM(rb_intern("bigdecimal_load"));
2158
+ rb_gc_register_address(&bigdecimal_load_sym);
2159
+ bigdecimal_sym = ID2SYM(rb_intern("bigdecimal"));
2160
+ rb_gc_register_address(&bigdecimal_sym);
2161
+ cache_keys_sym = ID2SYM(rb_intern("cache_keys"));
2162
+ rb_gc_register_address(&cache_keys_sym);
2163
+ cache_str_sym = ID2SYM(rb_intern("cache_str"));
2164
+ rb_gc_register_address(&cache_str_sym);
2165
+ cache_string_sym = ID2SYM(rb_intern("cache_string"));
2166
+ rb_gc_register_address(&cache_string_sym);
2167
+ circular_sym = ID2SYM(rb_intern("circular"));
2168
+ rb_gc_register_address(&circular_sym);
2169
+ class_cache_sym = ID2SYM(rb_intern("class_cache"));
2170
+ rb_gc_register_address(&class_cache_sym);
2171
+ compat_bigdecimal_sym = ID2SYM(rb_intern("compat_bigdecimal"));
2172
+ rb_gc_register_address(&compat_bigdecimal_sym);
2173
+ compat_sym = ID2SYM(rb_intern("compat"));
2174
+ rb_gc_register_address(&compat_sym);
2175
+ create_id_sym = ID2SYM(rb_intern("create_id"));
2176
+ rb_gc_register_address(&create_id_sym);
2177
+ custom_sym = ID2SYM(rb_intern("custom"));
2178
+ rb_gc_register_address(&custom_sym);
2179
+ empty_string_sym = ID2SYM(rb_intern("empty_string"));
2180
+ rb_gc_register_address(&empty_string_sym);
2181
+ escape_mode_sym = ID2SYM(rb_intern("escape_mode"));
2182
+ rb_gc_register_address(&escape_mode_sym);
2183
+ integer_range_sym = ID2SYM(rb_intern("integer_range"));
2184
+ rb_gc_register_address(&integer_range_sym);
2185
+ max_integer_digits_sym = ID2SYM(rb_intern("max_integer_digits"));
2186
+ rb_gc_register_address(&max_integer_digits_sym);
2187
+ fast_sym = ID2SYM(rb_intern("fast"));
2188
+ rb_gc_register_address(&fast_sym);
2189
+ float_format_sym = ID2SYM(rb_intern("float_format"));
2190
+ rb_gc_register_address(&float_format_sym);
2191
+ float_prec_sym = ID2SYM(rb_intern("float_precision"));
2192
+ rb_gc_register_address(&float_prec_sym);
2193
+ float_sym = ID2SYM(rb_intern("float"));
2194
+ rb_gc_register_address(&float_sym);
2195
+ huge_sym = ID2SYM(rb_intern("huge"));
2196
+ rb_gc_register_address(&huge_sym);
2197
+ ignore_sym = ID2SYM(rb_intern("ignore"));
2198
+ rb_gc_register_address(&ignore_sym);
2199
+ ignore_under_sym = ID2SYM(rb_intern("ignore_under"));
2200
+ rb_gc_register_address(&ignore_under_sym);
2201
+ json_sym = ID2SYM(rb_intern("json"));
2202
+ rb_gc_register_address(&json_sym);
2203
+ match_string_sym = ID2SYM(rb_intern("match_string"));
2204
+ rb_gc_register_address(&match_string_sym);
2205
+ mode_sym = ID2SYM(rb_intern("mode"));
2206
+ rb_gc_register_address(&mode_sym);
2207
+ nan_sym = ID2SYM(rb_intern("nan"));
2208
+ rb_gc_register_address(&nan_sym);
2209
+ newline_sym = ID2SYM(rb_intern("newline"));
2210
+ rb_gc_register_address(&newline_sym);
2211
+ nilnil_sym = ID2SYM(rb_intern("nilnil"));
2212
+ rb_gc_register_address(&nilnil_sym);
2213
+ null_sym = ID2SYM(rb_intern("null"));
2214
+ rb_gc_register_address(&null_sym);
2215
+ object_sym = ID2SYM(rb_intern("object"));
2216
+ rb_gc_register_address(&object_sym);
2217
+ oj_allow_nan_sym = ID2SYM(rb_intern("allow_nan"));
2218
+ rb_gc_register_address(&oj_allow_nan_sym);
2219
+ oj_array_class_sym = ID2SYM(rb_intern("array_class"));
2220
+ rb_gc_register_address(&oj_array_class_sym);
2221
+ oj_array_nl_sym = ID2SYM(rb_intern("array_nl"));
2222
+ rb_gc_register_address(&oj_array_nl_sym);
2223
+ oj_ascii_only_sym = ID2SYM(rb_intern("ascii_only"));
2224
+ rb_gc_register_address(&oj_ascii_only_sym);
2225
+ oj_create_additions_sym = ID2SYM(rb_intern("create_additions"));
2226
+ rb_gc_register_address(&oj_create_additions_sym);
2227
+ oj_decimal_class_sym = ID2SYM(rb_intern("decimal_class"));
2228
+ rb_gc_register_address(&oj_decimal_class_sym);
2229
+ oj_hash_class_sym = ID2SYM(rb_intern("hash_class"));
2230
+ rb_gc_register_address(&oj_hash_class_sym);
2231
+ oj_indent_sym = ID2SYM(rb_intern("indent"));
2232
+ rb_gc_register_address(&oj_indent_sym);
2233
+ oj_max_nesting_sym = ID2SYM(rb_intern("max_nesting"));
2234
+ rb_gc_register_address(&oj_max_nesting_sym);
2235
+ oj_object_class_sym = ID2SYM(rb_intern("object_class"));
2236
+ rb_gc_register_address(&oj_object_class_sym);
2237
+ oj_object_nl_sym = ID2SYM(rb_intern("object_nl"));
2238
+ rb_gc_register_address(&oj_object_nl_sym);
2239
+ oj_quirks_mode_sym = ID2SYM(rb_intern("quirks_mode"));
2240
+ rb_gc_register_address(&oj_quirks_mode_sym);
2241
+ oj_safe_sym = ID2SYM(rb_intern("safe"));
2242
+ rb_gc_register_address(&oj_safe_sym);
2243
+ omit_null_byte_sym = ID2SYM(rb_intern("omit_null_byte"));
2244
+ rb_gc_register_address(&omit_null_byte_sym);
2245
+ oj_space_before_sym = ID2SYM(rb_intern("space_before"));
2246
+ rb_gc_register_address(&oj_space_before_sym);
2247
+ oj_space_sym = ID2SYM(rb_intern("space"));
2248
+ rb_gc_register_address(&oj_space_sym);
2249
+ oj_trace_sym = ID2SYM(rb_intern("trace"));
2250
+ rb_gc_register_address(&oj_trace_sym);
2251
+ omit_nil_sym = ID2SYM(rb_intern("omit_nil"));
2252
+ rb_gc_register_address(&omit_nil_sym);
2253
+ rails_sym = ID2SYM(rb_intern("rails"));
2254
+ rb_gc_register_address(&rails_sym);
2255
+ raise_sym = ID2SYM(rb_intern("raise"));
2256
+ rb_gc_register_address(&raise_sym);
2257
+ ruby_sym = ID2SYM(rb_intern("ruby"));
2258
+ rb_gc_register_address(&ruby_sym);
2259
+ sec_prec_sym = ID2SYM(rb_intern("second_precision"));
2260
+ rb_gc_register_address(&sec_prec_sym);
2261
+ slash_sym = ID2SYM(rb_intern("slash"));
2262
+ rb_gc_register_address(&slash_sym);
2263
+ strict_sym = ID2SYM(rb_intern("strict"));
2264
+ rb_gc_register_address(&strict_sym);
2265
+ symbol_keys_sym = ID2SYM(rb_intern("symbol_keys"));
2266
+ rb_gc_register_address(&symbol_keys_sym);
2267
+ oj_symbolize_names_sym = ID2SYM(rb_intern("symbolize_names"));
2268
+ rb_gc_register_address(&oj_symbolize_names_sym);
2269
+ time_format_sym = ID2SYM(rb_intern("time_format"));
2270
+ rb_gc_register_address(&time_format_sym);
2271
+ unicode_xss_sym = ID2SYM(rb_intern("unicode_xss"));
2272
+ rb_gc_register_address(&unicode_xss_sym);
2273
+ unix_sym = ID2SYM(rb_intern("unix"));
2274
+ rb_gc_register_address(&unix_sym);
2275
+ unix_zone_sym = ID2SYM(rb_intern("unix_zone"));
2276
+ rb_gc_register_address(&unix_zone_sym);
2277
+ use_as_json_sym = ID2SYM(rb_intern("use_as_json"));
2278
+ rb_gc_register_address(&use_as_json_sym);
2279
+ use_raw_json_sym = ID2SYM(rb_intern("use_raw_json"));
2280
+ rb_gc_register_address(&use_raw_json_sym);
2281
+ use_to_hash_sym = ID2SYM(rb_intern("use_to_hash"));
2282
+ rb_gc_register_address(&use_to_hash_sym);
2283
+ use_to_json_sym = ID2SYM(rb_intern("use_to_json"));
2284
+ rb_gc_register_address(&use_to_json_sym);
2285
+ wab_sym = ID2SYM(rb_intern("wab"));
2286
+ rb_gc_register_address(&wab_sym);
2287
+ word_sym = ID2SYM(rb_intern("word"));
2288
+ rb_gc_register_address(&word_sym);
2289
+ xmlschema_sym = ID2SYM(rb_intern("xmlschema"));
2290
+ rb_gc_register_address(&xmlschema_sym);
2291
+ xss_safe_sym = ID2SYM(rb_intern("xss_safe"));
2292
+ rb_gc_register_address(&xss_safe_sym);
2293
+ only_sym = ID2SYM(rb_intern("only"));
2294
+ rb_gc_register_address(&only_sym);
2295
+ except_sym = ID2SYM(rb_intern("except"));
2296
+ rb_gc_register_address(&except_sym);
2297
+
2298
+ oj_slash_string = rb_str_new2("/");
2299
+ rb_gc_register_address(&oj_slash_string);
2300
+ OBJ_FREEZE(oj_slash_string);
2301
+
2302
+ oj_default_options.mode = ObjectMode;
2303
+
2304
+ oj_hash_init();
2305
+ oj_odd_init();
2306
+ oj_mimic_rails_init();
2307
+
2308
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
2309
+ if (0 != (err = pthread_mutex_init(&oj_cache_mutex, 0))) {
2310
+ rb_raise(rb_eException, "failed to initialize a mutex. %s", strerror(err));
2311
+ }
2312
+ #else
2313
+ oj_cache_mutex = rb_mutex_new();
2314
+ rb_gc_register_address(&oj_cache_mutex);
2315
+ #endif
2316
+ oj_init_doc();
2317
+
2318
+ SIMD_Impl = oj_get_simd_implementation();
2319
+
2320
+ oj_parser_init();
2321
+ oj_scanner_init();
2322
+
2323
+ #ifdef HAVE_SIMD_NEON
2324
+ initialize_neon();
2325
+ #endif /* HAVE_SIMD_NEON */
2326
+
2327
+ #ifdef HAVE_SIMD_SSE4_2
2328
+ if (SIMD_Impl == SIMD_SSE42) {
2329
+ initialize_sse42();
2330
+ }
2331
+ #endif /* HAVE_SIMD_SSE4_2 */
2332
+ }