oj 3.7.12

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 (156) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +96 -0
  4. data/ext/oj/buf.h +103 -0
  5. data/ext/oj/cache8.c +107 -0
  6. data/ext/oj/cache8.h +48 -0
  7. data/ext/oj/circarray.c +68 -0
  8. data/ext/oj/circarray.h +23 -0
  9. data/ext/oj/code.c +235 -0
  10. data/ext/oj/code.h +42 -0
  11. data/ext/oj/compat.c +299 -0
  12. data/ext/oj/custom.c +1188 -0
  13. data/ext/oj/dump.c +1232 -0
  14. data/ext/oj/dump.h +94 -0
  15. data/ext/oj/dump_compat.c +973 -0
  16. data/ext/oj/dump_leaf.c +252 -0
  17. data/ext/oj/dump_object.c +837 -0
  18. data/ext/oj/dump_strict.c +433 -0
  19. data/ext/oj/encode.h +45 -0
  20. data/ext/oj/err.c +57 -0
  21. data/ext/oj/err.h +70 -0
  22. data/ext/oj/extconf.rb +47 -0
  23. data/ext/oj/fast.c +1771 -0
  24. data/ext/oj/hash.c +163 -0
  25. data/ext/oj/hash.h +46 -0
  26. data/ext/oj/hash_test.c +512 -0
  27. data/ext/oj/mimic_json.c +873 -0
  28. data/ext/oj/object.c +771 -0
  29. data/ext/oj/odd.c +231 -0
  30. data/ext/oj/odd.h +44 -0
  31. data/ext/oj/oj.c +1694 -0
  32. data/ext/oj/oj.h +381 -0
  33. data/ext/oj/parse.c +1085 -0
  34. data/ext/oj/parse.h +111 -0
  35. data/ext/oj/rails.c +1485 -0
  36. data/ext/oj/rails.h +21 -0
  37. data/ext/oj/reader.c +231 -0
  38. data/ext/oj/reader.h +151 -0
  39. data/ext/oj/resolve.c +102 -0
  40. data/ext/oj/resolve.h +14 -0
  41. data/ext/oj/rxclass.c +147 -0
  42. data/ext/oj/rxclass.h +27 -0
  43. data/ext/oj/saj.c +714 -0
  44. data/ext/oj/scp.c +224 -0
  45. data/ext/oj/sparse.c +910 -0
  46. data/ext/oj/stream_writer.c +363 -0
  47. data/ext/oj/strict.c +212 -0
  48. data/ext/oj/string_writer.c +512 -0
  49. data/ext/oj/trace.c +79 -0
  50. data/ext/oj/trace.h +28 -0
  51. data/ext/oj/util.c +136 -0
  52. data/ext/oj/util.h +19 -0
  53. data/ext/oj/val_stack.c +118 -0
  54. data/ext/oj/val_stack.h +185 -0
  55. data/ext/oj/wab.c +631 -0
  56. data/lib/oj.rb +21 -0
  57. data/lib/oj/active_support_helper.rb +41 -0
  58. data/lib/oj/bag.rb +88 -0
  59. data/lib/oj/easy_hash.rb +52 -0
  60. data/lib/oj/error.rb +22 -0
  61. data/lib/oj/json.rb +176 -0
  62. data/lib/oj/mimic.rb +267 -0
  63. data/lib/oj/saj.rb +66 -0
  64. data/lib/oj/schandler.rb +142 -0
  65. data/lib/oj/state.rb +131 -0
  66. data/lib/oj/version.rb +5 -0
  67. data/pages/Advanced.md +22 -0
  68. data/pages/Compatibility.md +25 -0
  69. data/pages/Custom.md +23 -0
  70. data/pages/Encoding.md +65 -0
  71. data/pages/JsonGem.md +79 -0
  72. data/pages/Modes.md +154 -0
  73. data/pages/Options.md +266 -0
  74. data/pages/Rails.md +116 -0
  75. data/pages/Security.md +20 -0
  76. data/pages/WAB.md +13 -0
  77. data/test/_test_active.rb +76 -0
  78. data/test/_test_active_mimic.rb +96 -0
  79. data/test/_test_mimic_rails.rb +126 -0
  80. data/test/activerecord/result_test.rb +27 -0
  81. data/test/activesupport4/decoding_test.rb +108 -0
  82. data/test/activesupport4/encoding_test.rb +531 -0
  83. data/test/activesupport4/test_helper.rb +41 -0
  84. data/test/activesupport5/decoding_test.rb +125 -0
  85. data/test/activesupport5/encoding_test.rb +485 -0
  86. data/test/activesupport5/encoding_test_cases.rb +90 -0
  87. data/test/activesupport5/test_helper.rb +50 -0
  88. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  89. data/test/big.rb +15 -0
  90. data/test/files.rb +29 -0
  91. data/test/foo.rb +33 -0
  92. data/test/helper.rb +26 -0
  93. data/test/isolated/shared.rb +308 -0
  94. data/test/isolated/test_mimic_after.rb +13 -0
  95. data/test/isolated/test_mimic_alone.rb +12 -0
  96. data/test/isolated/test_mimic_as_json.rb +45 -0
  97. data/test/isolated/test_mimic_before.rb +13 -0
  98. data/test/isolated/test_mimic_define.rb +28 -0
  99. data/test/isolated/test_mimic_rails_after.rb +22 -0
  100. data/test/isolated/test_mimic_rails_before.rb +21 -0
  101. data/test/isolated/test_mimic_redefine.rb +15 -0
  102. data/test/json_gem/json_addition_test.rb +216 -0
  103. data/test/json_gem/json_common_interface_test.rb +148 -0
  104. data/test/json_gem/json_encoding_test.rb +107 -0
  105. data/test/json_gem/json_ext_parser_test.rb +20 -0
  106. data/test/json_gem/json_fixtures_test.rb +35 -0
  107. data/test/json_gem/json_generator_test.rb +383 -0
  108. data/test/json_gem/json_generic_object_test.rb +90 -0
  109. data/test/json_gem/json_parser_test.rb +470 -0
  110. data/test/json_gem/json_string_matching_test.rb +42 -0
  111. data/test/json_gem/test_helper.rb +18 -0
  112. data/test/mem.rb +35 -0
  113. data/test/perf.rb +107 -0
  114. data/test/perf_compat.rb +130 -0
  115. data/test/perf_fast.rb +164 -0
  116. data/test/perf_file.rb +64 -0
  117. data/test/perf_object.rb +138 -0
  118. data/test/perf_saj.rb +109 -0
  119. data/test/perf_scp.rb +151 -0
  120. data/test/perf_simple.rb +287 -0
  121. data/test/perf_strict.rb +145 -0
  122. data/test/perf_wab.rb +131 -0
  123. data/test/sample.rb +54 -0
  124. data/test/sample/change.rb +14 -0
  125. data/test/sample/dir.rb +19 -0
  126. data/test/sample/doc.rb +36 -0
  127. data/test/sample/file.rb +48 -0
  128. data/test/sample/group.rb +16 -0
  129. data/test/sample/hasprops.rb +16 -0
  130. data/test/sample/layer.rb +12 -0
  131. data/test/sample/line.rb +20 -0
  132. data/test/sample/oval.rb +10 -0
  133. data/test/sample/rect.rb +10 -0
  134. data/test/sample/shape.rb +35 -0
  135. data/test/sample/text.rb +20 -0
  136. data/test/sample_json.rb +37 -0
  137. data/test/test_compat.rb +509 -0
  138. data/test/test_custom.rb +406 -0
  139. data/test/test_debian.rb +53 -0
  140. data/test/test_fast.rb +470 -0
  141. data/test/test_file.rb +239 -0
  142. data/test/test_gc.rb +49 -0
  143. data/test/test_hash.rb +29 -0
  144. data/test/test_integer_range.rb +73 -0
  145. data/test/test_null.rb +376 -0
  146. data/test/test_object.rb +1018 -0
  147. data/test/test_saj.rb +186 -0
  148. data/test/test_scp.rb +433 -0
  149. data/test/test_strict.rb +410 -0
  150. data/test/test_various.rb +739 -0
  151. data/test/test_wab.rb +307 -0
  152. data/test/test_writer.rb +380 -0
  153. data/test/tests.rb +24 -0
  154. data/test/tests_mimic.rb +14 -0
  155. data/test/tests_mimic_addition.rb +7 -0
  156. metadata +359 -0
@@ -0,0 +1,94 @@
1
+ /* dump.h
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #ifndef OJ_DUMP_H
7
+ #define OJ_DUMP_H
8
+
9
+ #include <ruby.h>
10
+
11
+ #include "oj.h"
12
+
13
+ #define MAX_DEPTH 1000
14
+
15
+ // Extra padding at end of buffer.
16
+ #define BUFFER_EXTRA 64
17
+
18
+ extern void oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok);
19
+ extern void oj_dump_true(VALUE obj, int depth, Out out, bool as_ok);
20
+ extern void oj_dump_false(VALUE obj, int depth, Out out, bool as_ok);
21
+ extern void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok);
22
+ extern void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok);
23
+ extern void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok);
24
+ extern void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok);
25
+ extern void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok);
26
+ extern void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok);
27
+
28
+ extern void oj_dump_raw(const char *str, size_t cnt, Out out);
29
+ extern void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out);
30
+ extern void oj_dump_ruby_time(VALUE obj, Out out);
31
+ extern void oj_dump_xml_time(VALUE obj, Out out);
32
+ extern void oj_dump_time(VALUE obj, Out out, int withZone);
33
+ extern void oj_dump_obj_to_s(VALUE obj, Out out);
34
+
35
+ extern const char* oj_nan_str(VALUE obj, int opt, int mode, bool plus, int *lenp);
36
+
37
+ extern void oj_grow_out(Out out, size_t len);
38
+ extern long oj_check_circular(VALUE obj, Out out);
39
+
40
+ extern void oj_dump_strict_val(VALUE obj, int depth, Out out);
41
+ extern void oj_dump_null_val(VALUE obj, int depth, Out out);
42
+ extern void oj_dump_obj_val(VALUE obj, int depth, Out out);
43
+ extern void oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok);
44
+ extern void oj_dump_rails_val(VALUE obj, int depth, Out out);
45
+ extern void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok);
46
+ extern void oj_dump_wab_val(VALUE obj, int depth, Out out);
47
+
48
+ extern VALUE oj_add_to_json(int argc, VALUE *argv, VALUE self);
49
+ extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self);
50
+
51
+ extern int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *format);
52
+
53
+ extern bool oj_dump_ignore(Options opts, VALUE obj);
54
+ extern time_t oj_sec_from_time_hard_way(VALUE obj);
55
+
56
+ inline static void
57
+ assure_size(Out out, size_t len) {
58
+ if (out->end - out->cur <= (long)len) {
59
+ oj_grow_out(out, len);
60
+ }
61
+ }
62
+
63
+ inline static void
64
+ fill_indent(Out out, int cnt) {
65
+ if (0 < out->indent) {
66
+ cnt *= out->indent;
67
+ *out->cur++ = '\n';
68
+ for (; 0 < cnt; cnt--) {
69
+ *out->cur++ = ' ';
70
+ }
71
+ }
72
+ }
73
+
74
+ inline static void
75
+ dump_ulong(unsigned long num, Out out) {
76
+ char buf[32];
77
+ char *b = buf + sizeof(buf) - 1;
78
+
79
+ *b-- = '\0';
80
+ if (0 < num) {
81
+ for (; 0 < num; num /= 10, b--) {
82
+ *b = (num % 10) + '0';
83
+ }
84
+ b++;
85
+ } else {
86
+ *b = '0';
87
+ }
88
+ for (; '\0' != *b; b++) {
89
+ *out->cur++ = *b;
90
+ }
91
+ *out->cur = '\0';
92
+ }
93
+
94
+ #endif /* OJ_DUMP_H */
@@ -0,0 +1,973 @@
1
+ /* dump_object.c
2
+ * Copyright (c) 2012, 2017, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include "code.h"
7
+ #include "dump.h"
8
+ #include "rails.h"
9
+ #include "trace.h"
10
+
11
+ // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
12
+ #define OJ_INFINITY (1.0/0.0)
13
+
14
+ bool oj_use_hash_alt = false;
15
+ bool oj_use_array_alt = false;
16
+
17
+ static bool use_struct_alt = false;
18
+ static bool use_exception_alt = false;
19
+ static bool use_bignum_alt = false;
20
+
21
+ static void
22
+ raise_json_err(const char *msg, const char *err_classname) {
23
+ rb_raise(oj_get_json_err_class(err_classname), "%s", msg);
24
+ }
25
+
26
+ static void
27
+ dump_obj_classname(const char *classname, int depth, Out out) {
28
+ int d2 = depth + 1;
29
+ size_t len = strlen(classname);
30
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
31
+ size_t size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len;
32
+
33
+ assure_size(out, size);
34
+ *out->cur++ = '{';
35
+ fill_indent(out, d2);
36
+ *out->cur++ = '"';
37
+ memcpy(out->cur, out->opts->create_id, out->opts->create_id_len);
38
+ out->cur += out->opts->create_id_len;
39
+ *out->cur++ = '"';
40
+ if (0 < out->opts->dump_opts.before_size) {
41
+ strcpy(out->cur, out->opts->dump_opts.before_sep);
42
+ out->cur += out->opts->dump_opts.before_size;
43
+ }
44
+ *out->cur++ = ':';
45
+ if (0 < out->opts->dump_opts.after_size) {
46
+ strcpy(out->cur, out->opts->dump_opts.after_sep);
47
+ out->cur += out->opts->dump_opts.after_size;
48
+ }
49
+ *out->cur++ = '"';
50
+ memcpy(out->cur, classname, len);
51
+ out->cur += len;
52
+ *out->cur++ = '"';
53
+ }
54
+
55
+ static void
56
+ dump_values_array(VALUE *values, int depth, Out out) {
57
+ size_t size;
58
+ int d2 = depth + 1;
59
+
60
+ assure_size(out, d2 * out->indent + 3);
61
+ *out->cur++ = '[';
62
+ if (Qundef == *values) {
63
+ *out->cur++ = ']';
64
+ } else {
65
+ if (out->opts->dump_opts.use) {
66
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 2;
67
+ } else {
68
+ size = d2 * out->indent + 3;
69
+ }
70
+ if (out->opts->dump_opts.use) {
71
+ size += out->opts->dump_opts.array_size;
72
+ size += out->opts->dump_opts.indent_size;
73
+ }
74
+ for (; Qundef != *values; values++) {
75
+ assure_size(out, size);
76
+ if (out->opts->dump_opts.use) {
77
+ if (0 < out->opts->dump_opts.array_size) {
78
+ strcpy(out->cur, out->opts->dump_opts.array_nl);
79
+ out->cur += out->opts->dump_opts.array_size;
80
+ }
81
+ if (0 < out->opts->dump_opts.indent_size) {
82
+ int i;
83
+ for (i = d2; 0 < i; i--) {
84
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
85
+ out->cur += out->opts->dump_opts.indent_size;
86
+ }
87
+ }
88
+ } else {
89
+ fill_indent(out, d2);
90
+ }
91
+ oj_dump_compat_val(*values, d2, out, true);
92
+ if (Qundef != *(values + 1)) {
93
+ *out->cur++ = ',';
94
+ }
95
+ }
96
+ assure_size(out, size);
97
+ if (out->opts->dump_opts.use) {
98
+ if (0 < out->opts->dump_opts.array_size) {
99
+ strcpy(out->cur, out->opts->dump_opts.array_nl);
100
+ out->cur += out->opts->dump_opts.array_size;
101
+ }
102
+ if (0 < out->opts->dump_opts.indent_size) {
103
+ int i;
104
+
105
+ for (i = depth; 0 < i; i--) {
106
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
107
+ out->cur += out->opts->dump_opts.indent_size;
108
+ }
109
+ }
110
+ } else {
111
+ fill_indent(out, depth);
112
+ }
113
+ *out->cur++ = ']';
114
+ }
115
+ }
116
+
117
+ static void
118
+ dump_to_json(VALUE obj, Out out) {
119
+ volatile VALUE rs;
120
+ const char *s;
121
+ int len;
122
+
123
+ if (Yes == out->opts->trace) {
124
+ oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyIn);
125
+ }
126
+ if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
127
+ rs = rb_funcall(obj, oj_to_json_id, 0);
128
+ } else {
129
+ rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
130
+ }
131
+ if (Yes == out->opts->trace) {
132
+ oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyOut);
133
+ }
134
+
135
+ s = rb_string_value_ptr((VALUE*)&rs);
136
+ len = (int)RSTRING_LEN(rs);
137
+
138
+ assure_size(out, len + 1);
139
+ memcpy(out->cur, s, len);
140
+ out->cur += len;
141
+ *out->cur = '\0';
142
+ }
143
+
144
+ static void
145
+ dump_array(VALUE a, int depth, Out out, bool as_ok) {
146
+ size_t size;
147
+ int i, cnt;
148
+ int d2 = depth + 1;
149
+ long id = oj_check_circular(a, out);
150
+
151
+ if (0 > id) {
152
+ raise_json_err("Too deeply nested", "NestingError");
153
+ return;
154
+ }
155
+ if (as_ok && !oj_use_hash_alt && rb_obj_class(a) != rb_cArray && rb_respond_to(a, oj_to_json_id)) {
156
+ dump_to_json(a, out);
157
+ return;
158
+ }
159
+ cnt = (int)RARRAY_LEN(a);
160
+ *out->cur++ = '[';
161
+ assure_size(out, 2);
162
+ if (0 == cnt) {
163
+ *out->cur++ = ']';
164
+ } else {
165
+ if (out->opts->dump_opts.use) {
166
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
167
+ } else {
168
+ size = d2 * out->indent + 2;
169
+ }
170
+ cnt--;
171
+ for (i = 0; i <= cnt; i++) {
172
+ assure_size(out, size);
173
+ if (out->opts->dump_opts.use) {
174
+ if (0 < out->opts->dump_opts.array_size) {
175
+ strcpy(out->cur, out->opts->dump_opts.array_nl);
176
+ out->cur += out->opts->dump_opts.array_size;
177
+ }
178
+ if (0 < out->opts->dump_opts.indent_size) {
179
+ int i;
180
+ for (i = d2; 0 < i; i--) {
181
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
182
+ out->cur += out->opts->dump_opts.indent_size;
183
+ }
184
+ }
185
+ } else {
186
+ fill_indent(out, d2);
187
+ }
188
+ oj_dump_compat_val(rb_ary_entry(a, i), d2, out, true);
189
+ if (i < cnt) {
190
+ *out->cur++ = ',';
191
+ }
192
+ }
193
+ size = depth * out->indent + 1;
194
+ assure_size(out, size);
195
+ if (out->opts->dump_opts.use) {
196
+ if (0 < out->opts->dump_opts.array_size) {
197
+ strcpy(out->cur, out->opts->dump_opts.array_nl);
198
+ out->cur += out->opts->dump_opts.array_size;
199
+ }
200
+ if (0 < out->opts->dump_opts.indent_size) {
201
+ int i;
202
+
203
+ for (i = depth; 0 < i; i--) {
204
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
205
+ out->cur += out->opts->dump_opts.indent_size;
206
+ }
207
+ }
208
+ } else {
209
+ fill_indent(out, depth);
210
+ }
211
+ *out->cur++ = ']';
212
+ }
213
+ *out->cur = '\0';
214
+ }
215
+
216
+ static ID _dump_id = 0;
217
+
218
+ static void
219
+ bigdecimal_alt(VALUE obj, int depth, Out out) {
220
+ struct _attr attrs[] = {
221
+ { "b", 1, Qnil },
222
+ { NULL, 0, Qnil },
223
+ };
224
+
225
+ if (0 == _dump_id) {
226
+ _dump_id = rb_intern("_dump");
227
+ }
228
+ attrs[0].value = rb_funcall(obj, _dump_id, 0);
229
+
230
+ oj_code_attrs(obj, attrs, depth, out, true);
231
+ }
232
+
233
+ static ID real_id = 0;
234
+ static ID imag_id = 0;
235
+
236
+ static void
237
+ complex_alt(VALUE obj, int depth, Out out) {
238
+ struct _attr attrs[] = {
239
+ { "r", 1, Qnil },
240
+ { "i", 1, Qnil },
241
+ { NULL, 0, Qnil },
242
+ };
243
+
244
+ if (0 == real_id) {
245
+ real_id = rb_intern("real");
246
+ imag_id = rb_intern("imag");
247
+ }
248
+ attrs[0].value = rb_funcall(obj, real_id, 0);
249
+ attrs[1].value = rb_funcall(obj, imag_id, 0);
250
+
251
+ oj_code_attrs(obj, attrs, depth, out, true);
252
+ }
253
+
254
+ static ID year_id = 0;
255
+ static ID month_id = 0;
256
+ static ID day_id = 0;
257
+ static ID start_id = 0;
258
+
259
+ static void
260
+ date_alt(VALUE obj, int depth, Out out) {
261
+ struct _attr attrs[] = {
262
+ { "y", 1, Qnil },
263
+ { "m", 1, Qnil },
264
+ { "d", 1, Qnil },
265
+ { "sg", 2, Qnil },
266
+ { NULL, 0, Qnil },
267
+ };
268
+ if (0 == year_id) {
269
+ year_id = rb_intern("year");
270
+ month_id = rb_intern("month");
271
+ day_id = rb_intern("day");
272
+ start_id = rb_intern("start");
273
+ }
274
+ attrs[0].value = rb_funcall(obj, year_id, 0);
275
+ attrs[1].value = rb_funcall(obj, month_id, 0);
276
+ attrs[2].value = rb_funcall(obj, day_id, 0);
277
+ attrs[3].value = rb_funcall(obj, start_id, 0);
278
+
279
+ oj_code_attrs(obj, attrs, depth, out, true);
280
+ }
281
+
282
+ static ID hour_id = 0;
283
+ static ID min_id = 0;
284
+ static ID sec_id = 0;
285
+ static ID offset_id = 0;
286
+
287
+ static void
288
+ datetime_alt(VALUE obj, int depth, Out out) {
289
+ struct _attr attrs[] = {
290
+ { "y", 1, Qnil },
291
+ { "m", 1, Qnil },
292
+ { "d", 1, Qnil },
293
+ { "H", 1, Qnil },
294
+ { "M", 1, Qnil },
295
+ { "S", 1, Qnil },
296
+ { "of", 2, Qnil },
297
+ { "sg", 2, Qnil },
298
+ { NULL, 0, Qnil },
299
+ };
300
+ if (0 == hour_id) {
301
+ year_id = rb_intern("year");
302
+ month_id = rb_intern("month");
303
+ day_id = rb_intern("day");
304
+ hour_id = rb_intern("hour");
305
+ min_id = rb_intern("min");
306
+ sec_id = rb_intern("sec");
307
+ offset_id = rb_intern("offset");
308
+ start_id = rb_intern("start");
309
+ }
310
+ attrs[0].value = rb_funcall(obj, year_id, 0);
311
+ attrs[1].value = rb_funcall(obj, month_id, 0);
312
+ attrs[2].value = rb_funcall(obj, day_id, 0);
313
+ attrs[3].value = rb_funcall(obj, hour_id, 0);
314
+ attrs[4].value = rb_funcall(obj, min_id, 0);
315
+ attrs[5].value = rb_funcall(obj, sec_id, 0);
316
+ attrs[6].value = rb_funcall(rb_funcall(obj, offset_id, 0), oj_to_s_id, 0);
317
+ attrs[7].value = rb_funcall(obj, start_id, 0);
318
+
319
+ oj_code_attrs(obj, attrs, depth, out, true);
320
+ }
321
+
322
+ static ID message_id = 0;
323
+ static ID backtrace_id = 0;
324
+
325
+ static void
326
+ exception_alt(VALUE obj, int depth, Out out) {
327
+ int d3 = depth + 2;
328
+ size_t size = d3 * out->indent + 2;
329
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
330
+
331
+ if (0 == message_id) {
332
+ message_id = rb_intern("message");
333
+ backtrace_id = rb_intern("backtrace");
334
+ }
335
+ dump_obj_classname(rb_class2name(rb_obj_class(obj)), depth, out);
336
+
337
+ assure_size(out, size + sep_len + 6);
338
+ *out->cur++ = ',';
339
+ fill_indent(out, d3);
340
+ *out->cur++ = '"';
341
+ *out->cur++ = 'm';
342
+ *out->cur++ = '"';
343
+ if (0 < out->opts->dump_opts.before_size) {
344
+ strcpy(out->cur, out->opts->dump_opts.before_sep);
345
+ out->cur += out->opts->dump_opts.before_size;
346
+ }
347
+ *out->cur++ = ':';
348
+ if (0 < out->opts->dump_opts.after_size) {
349
+ strcpy(out->cur, out->opts->dump_opts.after_sep);
350
+ out->cur += out->opts->dump_opts.after_size;
351
+ }
352
+ oj_dump_str(rb_funcall(obj, message_id, 0), 0, out, false);
353
+ assure_size(out, size + sep_len + 6);
354
+ *out->cur++ = ',';
355
+ fill_indent(out, d3);
356
+ *out->cur++ = '"';
357
+ *out->cur++ = 'b';
358
+ *out->cur++ = '"';
359
+ if (0 < out->opts->dump_opts.before_size) {
360
+ strcpy(out->cur, out->opts->dump_opts.before_sep);
361
+ out->cur += out->opts->dump_opts.before_size;
362
+ }
363
+ *out->cur++ = ':';
364
+ if (0 < out->opts->dump_opts.after_size) {
365
+ strcpy(out->cur, out->opts->dump_opts.after_sep);
366
+ out->cur += out->opts->dump_opts.after_size;
367
+ }
368
+ dump_array(rb_funcall(obj, backtrace_id, 0), depth, out, false);
369
+ fill_indent(out, depth);
370
+ *out->cur++ = '}';
371
+ *out->cur = '\0';
372
+ }
373
+
374
+ static ID table_id = 0;
375
+
376
+ static void
377
+ openstruct_alt(VALUE obj, int depth, Out out) {
378
+ struct _attr attrs[] = {
379
+ { "t", 1, Qnil },
380
+ { NULL, 0, Qnil },
381
+ };
382
+ if (0 == table_id) {
383
+ table_id = rb_intern("table");
384
+ }
385
+ attrs[0].value = rb_funcall(obj, table_id, 0);
386
+
387
+ oj_code_attrs(obj, attrs, depth, out, true);
388
+ }
389
+
390
+ static void
391
+ range_alt(VALUE obj, int depth, Out out) {
392
+ int d3 = depth + 2;
393
+ size_t size = d3 * out->indent + 2;
394
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
395
+ VALUE args[] = { Qundef, Qundef, Qundef, Qundef };
396
+
397
+ dump_obj_classname(rb_class2name(rb_obj_class(obj)), depth, out);
398
+
399
+ assure_size(out, size + sep_len + 6);
400
+ *out->cur++ = ',';
401
+ fill_indent(out, d3);
402
+ *out->cur++ = '"';
403
+ *out->cur++ = 'a';
404
+ *out->cur++ = '"';
405
+ if (0 < out->opts->dump_opts.before_size) {
406
+ strcpy(out->cur, out->opts->dump_opts.before_sep);
407
+ out->cur += out->opts->dump_opts.before_size;
408
+ }
409
+ *out->cur++ = ':';
410
+ if (0 < out->opts->dump_opts.after_size) {
411
+ strcpy(out->cur, out->opts->dump_opts.after_sep);
412
+ out->cur += out->opts->dump_opts.after_size;
413
+ }
414
+ args[0] = rb_funcall(obj, oj_begin_id, 0);
415
+ args[1] = rb_funcall(obj, oj_end_id, 0);
416
+ args[2] = rb_funcall(obj, oj_exclude_end_id, 0);
417
+ dump_values_array(args, depth, out);
418
+ fill_indent(out, depth);
419
+ *out->cur++ = '}';
420
+ *out->cur = '\0';
421
+ }
422
+
423
+ static ID numerator_id = 0;
424
+ static ID denominator_id = 0;
425
+
426
+ static void
427
+ rational_alt(VALUE obj, int depth, Out out) {
428
+ struct _attr attrs[] = {
429
+ { "n", 1, Qnil },
430
+ { "d", 1, Qnil },
431
+ { NULL, 0, Qnil },
432
+ };
433
+ if (0 == numerator_id) {
434
+ numerator_id = rb_intern("numerator");
435
+ denominator_id = rb_intern("denominator");
436
+ }
437
+ attrs[0].value = rb_funcall(obj, numerator_id, 0);
438
+ attrs[1].value = rb_funcall(obj, denominator_id, 0);
439
+
440
+ oj_code_attrs(obj, attrs, depth, out, true);
441
+ }
442
+
443
+ static ID options_id = 0;
444
+ static ID source_id = 0;
445
+
446
+ static void
447
+ regexp_alt(VALUE obj, int depth, Out out) {
448
+ struct _attr attrs[] = {
449
+ { "o", 1, Qnil },
450
+ { "s", 1, Qnil },
451
+ { NULL, 0, Qnil },
452
+ };
453
+ if (0 == options_id) {
454
+ options_id = rb_intern("options");
455
+ source_id = rb_intern("source");
456
+ }
457
+ attrs[0].value = rb_funcall(obj, options_id, 0);
458
+ attrs[1].value = rb_funcall(obj, source_id, 0);
459
+
460
+ oj_code_attrs(obj, attrs, depth, out, true);
461
+ }
462
+
463
+ static void
464
+ time_alt(VALUE obj, int depth, Out out) {
465
+ struct _attr attrs[] = {
466
+ { "s", 1, Qundef, 0, Qundef },
467
+ { "n", 1, Qundef, 0, Qundef },
468
+ { NULL, 0, Qnil },
469
+ };
470
+ time_t sec;
471
+ long long nsec;
472
+
473
+ #ifdef HAVE_RB_TIME_TIMESPEC
474
+ if (16 <= sizeof(struct timespec)) {
475
+ struct timespec ts = rb_time_timespec(obj);
476
+
477
+ sec = (long long)ts.tv_sec;
478
+ nsec = ts.tv_nsec;
479
+ } else {
480
+ sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
481
+ nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
482
+ }
483
+ #else
484
+ sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
485
+ nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
486
+ #endif
487
+
488
+ attrs[0].num = sec;
489
+ attrs[1].num = nsec;
490
+
491
+ oj_code_attrs(obj, attrs, depth, out, true);
492
+ }
493
+
494
+ struct _code oj_compat_codes[] = {
495
+ { "BigDecimal", Qnil, bigdecimal_alt, NULL, false },
496
+ { "Complex", Qnil, complex_alt, NULL, false },
497
+ { "Date", Qnil, date_alt, false },
498
+ { "DateTime", Qnil, datetime_alt, NULL, false },
499
+ { "OpenStruct", Qnil, openstruct_alt, NULL, false },
500
+ { "Range", Qnil, range_alt, NULL, false },
501
+ { "Rational", Qnil, rational_alt, NULL, false },
502
+ { "Regexp", Qnil, regexp_alt, NULL, false },
503
+ { "Time", Qnil, time_alt, NULL, false },
504
+ // TBD the rest of the library classes
505
+ { NULL, Qundef, NULL, NULL, false },
506
+ };
507
+
508
+ VALUE
509
+ oj_add_to_json(int argc, VALUE *argv, VALUE self) {
510
+ Code a;
511
+
512
+ if (0 == argc) {
513
+ for (a = oj_compat_codes; NULL != a->name; a++) {
514
+ if (Qnil == a->clas || Qundef == a->clas) {
515
+ a->clas = rb_const_get_at(rb_cObject, rb_intern(a->name));
516
+ }
517
+ a->active = true;
518
+ }
519
+ use_struct_alt = true;
520
+ use_exception_alt = true;
521
+ use_bignum_alt = true;
522
+ oj_use_hash_alt = true;
523
+ oj_use_array_alt = true;
524
+ } else {
525
+ for (; 0 < argc; argc--, argv++) {
526
+ if (rb_cStruct == *argv) {
527
+ use_struct_alt = true;
528
+ continue;
529
+ }
530
+ if (rb_eException == *argv) {
531
+ use_exception_alt = true;
532
+ continue;
533
+ }
534
+ if (rb_cInteger == *argv) {
535
+ use_bignum_alt = true;
536
+ continue;
537
+ }
538
+ if (rb_cHash == *argv) {
539
+ oj_use_hash_alt = true;
540
+ continue;
541
+ }
542
+ if (rb_cArray == *argv) {
543
+ oj_use_array_alt = true;
544
+ continue;
545
+ }
546
+ for (a = oj_compat_codes; NULL != a->name; a++) {
547
+ if (Qnil == a->clas || Qundef == a->clas) {
548
+ a->clas = rb_const_get_at(rb_cObject, rb_intern(a->name));
549
+ }
550
+ if (*argv == a->clas) {
551
+ a->active = true;
552
+ break;
553
+ }
554
+ }
555
+ }
556
+ }
557
+ return Qnil;
558
+ }
559
+
560
+ VALUE
561
+ oj_remove_to_json(int argc, VALUE *argv, VALUE self) {
562
+ if (0 == argc) {
563
+ oj_code_set_active(oj_compat_codes, Qnil, false);
564
+ use_struct_alt = false;
565
+ use_exception_alt = false;
566
+ use_bignum_alt = false;
567
+ oj_use_hash_alt = false;
568
+ oj_use_array_alt = false;
569
+ } else {
570
+ for (; 0 < argc; argc--, argv++) {
571
+ if (rb_cStruct == *argv) {
572
+ use_struct_alt = false;
573
+ continue;
574
+ }
575
+ if (rb_eException == *argv) {
576
+ use_exception_alt = false;
577
+ continue;
578
+ }
579
+ if (rb_cInteger == *argv) {
580
+ use_bignum_alt = false;
581
+ continue;
582
+ }
583
+ if (rb_cHash == *argv) {
584
+ oj_use_hash_alt = false;
585
+ continue;
586
+ }
587
+ if (rb_cArray == *argv) {
588
+ oj_use_array_alt = false;
589
+ continue;
590
+ }
591
+ oj_code_set_active(oj_compat_codes, *argv, false);
592
+ }
593
+ }
594
+ return Qnil;
595
+ }
596
+
597
+ // The JSON gem is inconsistent with handling of infinity. Using
598
+ // JSON.dump(0.1/0) returns the string Infinity but (0.1/0).to_json raise and
599
+ // exception. Worse, for BigDecimals a quoted "Infinity" is returned.
600
+ static void
601
+ dump_float(VALUE obj, int depth, Out out, bool as_ok) {
602
+ char buf[64];
603
+ char *b;
604
+ double d = rb_num2dbl(obj);
605
+ int cnt = 0;
606
+
607
+ if (0.0 == d) {
608
+ b = buf;
609
+ *b++ = '0';
610
+ *b++ = '.';
611
+ *b++ = '0';
612
+ *b++ = '\0';
613
+ cnt = 3;
614
+ } else if (OJ_INFINITY == d) {
615
+ if (WordNan == out->opts->dump_opts.nan_dump) {
616
+ strcpy(buf, "Infinity");
617
+ } else {
618
+ raise_json_err("Infinity not allowed in JSON.", "GeneratorError");
619
+ }
620
+ } else if (-OJ_INFINITY == d) {
621
+ if (WordNan == out->opts->dump_opts.nan_dump) {
622
+ strcpy(buf, "-Infinity");
623
+ } else {
624
+ raise_json_err("-Infinity not allowed in JSON.", "GeneratorError");
625
+ }
626
+ } else if (isnan(d)) {
627
+ if (WordNan == out->opts->dump_opts.nan_dump) {
628
+ strcpy(buf, "NaN");
629
+ } else {
630
+ raise_json_err("NaN not allowed in JSON.", "GeneratorError");
631
+ }
632
+ } else if (d == (double)(long long int)d) {
633
+ cnt = snprintf(buf, sizeof(buf), "%.1f", d);
634
+ } else if (oj_rails_float_opt) {
635
+ cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g");
636
+ } else {
637
+ volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
638
+
639
+ strcpy(buf, rb_string_value_ptr((VALUE*)&rstr));
640
+ cnt = (int)RSTRING_LEN(rstr);
641
+ }
642
+ assure_size(out, cnt);
643
+ for (b = buf; '\0' != *b; b++) {
644
+ *out->cur++ = *b;
645
+ }
646
+ *out->cur = '\0';
647
+ }
648
+
649
+ static int
650
+ hash_cb(VALUE key, VALUE value, Out out) {
651
+ int depth = out->depth;
652
+
653
+ if (out->omit_nil && Qnil == value) {
654
+ return ST_CONTINUE;
655
+ }
656
+ if (!out->opts->dump_opts.use) {
657
+ assure_size(out, depth * out->indent + 1);
658
+ fill_indent(out, depth);
659
+ } else {
660
+ assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
661
+ if (0 < out->opts->dump_opts.hash_size) {
662
+ strcpy(out->cur, out->opts->dump_opts.hash_nl);
663
+ out->cur += out->opts->dump_opts.hash_size;
664
+ }
665
+ if (0 < out->opts->dump_opts.indent_size) {
666
+ int i;
667
+ for (i = depth; 0 < i; i--) {
668
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
669
+ out->cur += out->opts->dump_opts.indent_size;
670
+ }
671
+ }
672
+ }
673
+ switch (rb_type(key)) {
674
+ case T_STRING:
675
+ oj_dump_str(key, 0, out, false);
676
+ break;
677
+ case T_SYMBOL:
678
+ oj_dump_sym(key, 0, out, false);
679
+ break;
680
+ default:
681
+ /*rb_raise(rb_eTypeError, "In :compat mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));*/
682
+ oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false);
683
+ break;
684
+ }
685
+ if (!out->opts->dump_opts.use) {
686
+ *out->cur++ = ':';
687
+ } else {
688
+ assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2);
689
+ if (0 < out->opts->dump_opts.before_size) {
690
+ strcpy(out->cur, out->opts->dump_opts.before_sep);
691
+ out->cur += out->opts->dump_opts.before_size;
692
+ }
693
+ *out->cur++ = ':';
694
+ if (0 < out->opts->dump_opts.after_size) {
695
+ strcpy(out->cur, out->opts->dump_opts.after_sep);
696
+ out->cur += out->opts->dump_opts.after_size;
697
+ }
698
+ }
699
+ oj_dump_compat_val(value, depth, out, true);
700
+ out->depth = depth;
701
+ *out->cur++ = ',';
702
+
703
+ return ST_CONTINUE;
704
+ }
705
+
706
+ static void
707
+ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
708
+ int cnt;
709
+ long id = oj_check_circular(obj, out);
710
+
711
+ if (0 > id) {
712
+ raise_json_err("Too deeply nested", "NestingError");
713
+ return;
714
+ }
715
+ if (as_ok && !oj_use_hash_alt && rb_obj_class(obj) != rb_cHash && rb_respond_to(obj, oj_to_json_id)) {
716
+ dump_to_json(obj, out);
717
+ return;
718
+ }
719
+ cnt = (int)RHASH_SIZE(obj);
720
+ assure_size(out, 2);
721
+ if (0 == cnt) {
722
+ *out->cur++ = '{';
723
+ *out->cur++ = '}';
724
+ } else {
725
+ *out->cur++ = '{';
726
+ out->depth = depth + 1;
727
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
728
+ if (',' == *(out->cur - 1)) {
729
+ out->cur--; // backup to overwrite last comma
730
+ }
731
+ if (!out->opts->dump_opts.use) {
732
+ assure_size(out, depth * out->indent + 2);
733
+ fill_indent(out, depth);
734
+ } else {
735
+ assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
736
+ if (0 < out->opts->dump_opts.hash_size) {
737
+ strcpy(out->cur, out->opts->dump_opts.hash_nl);
738
+ out->cur += out->opts->dump_opts.hash_size;
739
+ }
740
+ if (0 < out->opts->dump_opts.indent_size) {
741
+ int i;
742
+
743
+ for (i = depth; 0 < i; i--) {
744
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
745
+ out->cur += out->opts->dump_opts.indent_size;
746
+ }
747
+ }
748
+ }
749
+ *out->cur++ = '}';
750
+ }
751
+ *out->cur = '\0';
752
+ }
753
+
754
+ // In compat mode only the first call check for to_json. After that to_s is
755
+ // called.
756
+ static void
757
+ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
758
+ if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
759
+ return;
760
+ }
761
+ if (use_exception_alt && rb_obj_is_kind_of(obj, rb_eException)) {
762
+ exception_alt(obj, depth, out);
763
+ return;
764
+ }
765
+ if (as_ok && rb_respond_to(obj, oj_to_json_id)) {
766
+ dump_to_json(obj, out);
767
+
768
+ return;
769
+ }
770
+ // Nothing else matched so encode as a JSON object with Ruby obj members
771
+ // as JSON object members.
772
+ oj_dump_obj_to_s(obj, out);
773
+ }
774
+
775
+ static void
776
+ dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
777
+ VALUE clas = rb_obj_class(obj);
778
+
779
+ if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
780
+ return;
781
+ }
782
+ if (rb_cRange == clas) {
783
+ *out->cur++ = '"';
784
+ oj_dump_compat_val(rb_funcall(obj, oj_begin_id, 0), 0, out, false);
785
+ assure_size(out, 3);
786
+ *out->cur++ = '.';
787
+ *out->cur++ = '.';
788
+ if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) {
789
+ *out->cur++ = '.';
790
+ }
791
+ oj_dump_compat_val(rb_funcall(obj, oj_end_id, 0), 0, out, false);
792
+ *out->cur++ = '"';
793
+
794
+ return;
795
+ }
796
+ if (as_ok && rb_respond_to(obj, oj_to_json_id)) {
797
+ dump_to_json(obj, out);
798
+
799
+ return;
800
+ }
801
+ if (use_struct_alt) {
802
+ int d3 = depth + 2;
803
+ size_t size = d3 * out->indent + 2;
804
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
805
+ const char *classname = rb_class2name(rb_obj_class(obj));
806
+ VALUE args[100];
807
+ int cnt;
808
+ int i;
809
+
810
+ if (NULL == classname || '#' == *classname) {
811
+ raise_json_err("Only named structs are supported.", "JSONError");
812
+ }
813
+ #ifdef RSTRUCT_LEN
814
+ #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
815
+ cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
816
+ #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
817
+ cnt = (int)RSTRUCT_LEN(obj);
818
+ #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
819
+ #else
820
+ // This is a bit risky as a struct in C ruby is not the same as a Struct
821
+ // class in interpreted Ruby so length() may not be defined.
822
+ cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
823
+ #endif
824
+ if (sizeof(args) / sizeof(*args) <= (size_t)cnt) {
825
+ // TBD allocate and try again
826
+ cnt = 99;
827
+ }
828
+ dump_obj_classname(rb_class2name(rb_obj_class(obj)), depth, out);
829
+
830
+ assure_size(out, size + sep_len + 6);
831
+ *out->cur++ = ',';
832
+ fill_indent(out, d3);
833
+ *out->cur++ = '"';
834
+ *out->cur++ = 'v';
835
+ *out->cur++ = '"';
836
+ if (0 < out->opts->dump_opts.before_size) {
837
+ strcpy(out->cur, out->opts->dump_opts.before_sep);
838
+ out->cur += out->opts->dump_opts.before_size;
839
+ }
840
+ *out->cur++ = ':';
841
+ if (0 < out->opts->dump_opts.after_size) {
842
+ strcpy(out->cur, out->opts->dump_opts.after_sep);
843
+ out->cur += out->opts->dump_opts.after_size;
844
+ }
845
+ for (i = 0; i < cnt; i++) {
846
+ #ifdef RSTRUCT_LEN
847
+ args[i] = RSTRUCT_GET(obj, i);
848
+ #else
849
+ args[i] = rb_struct_aref(obj, INT2FIX(i));
850
+ #endif
851
+ }
852
+ args[cnt] = Qundef;
853
+ dump_values_array(args, depth, out);
854
+ fill_indent(out, depth);
855
+ *out->cur++ = '}';
856
+ *out->cur = '\0';
857
+ } else {
858
+ oj_dump_obj_to_s(obj, out);
859
+ }
860
+ }
861
+
862
+ static void
863
+ dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
864
+ // The json gem uses to_s explicitly. to_s can be overridden while
865
+ // rb_big2str can not so unless overridden by using add_to_json(Integer)
866
+ // this must use to_s to pass the json gem unit tests.
867
+ volatile VALUE rs;
868
+ int cnt;
869
+ bool dump_as_string = false;
870
+
871
+ if (use_bignum_alt) {
872
+ rs = rb_big2str(obj, 10);
873
+ } else {
874
+ rs = rb_funcall(obj, oj_to_s_id, 0);
875
+ }
876
+ rb_check_type(rs, T_STRING);
877
+ cnt = (int)RSTRING_LEN(rs);
878
+
879
+ if (out->opts->integer_range_min != 0 || out->opts->integer_range_max != 0) {
880
+ dump_as_string = true; // Bignum cannot be inside of Fixnum range
881
+ assure_size(out, cnt + 2);
882
+ *out->cur++ = '"';
883
+ } else {
884
+ assure_size(out, cnt);
885
+ }
886
+
887
+ memcpy(out->cur, rb_string_value_ptr((VALUE*)&rs), cnt);
888
+ out->cur += cnt;
889
+
890
+ if(dump_as_string) {
891
+ *out->cur++ = '"';
892
+ }
893
+
894
+ *out->cur = '\0';
895
+ }
896
+
897
+ static DumpFunc compat_funcs[] = {
898
+ NULL, // RUBY_T_NONE = 0x00,
899
+ dump_obj, // RUBY_T_OBJECT = 0x01,
900
+ oj_dump_class, // RUBY_T_CLASS = 0x02,
901
+ oj_dump_class, // RUBY_T_MODULE = 0x03,
902
+ dump_float, // RUBY_T_FLOAT = 0x04,
903
+ oj_dump_str, // RUBY_T_STRING = 0x05,
904
+ dump_obj, // RUBY_T_REGEXP = 0x06,
905
+ dump_array, // RUBY_T_ARRAY = 0x07,
906
+ dump_hash, // RUBY_T_HASH = 0x08,
907
+ dump_struct, // RUBY_T_STRUCT = 0x09,
908
+ dump_bignum, // RUBY_T_BIGNUM = 0x0a,
909
+ NULL, // RUBY_T_FILE = 0x0b,
910
+ dump_obj, // RUBY_T_DATA = 0x0c,
911
+ NULL, // RUBY_T_MATCH = 0x0d,
912
+ dump_obj, // RUBY_T_COMPLEX = 0x0e,
913
+ dump_obj, // RUBY_T_RATIONAL = 0x0f,
914
+ NULL, // 0x10
915
+ oj_dump_nil, // RUBY_T_NIL = 0x11,
916
+ oj_dump_true, // RUBY_T_TRUE = 0x12,
917
+ oj_dump_false, // RUBY_T_FALSE = 0x13,
918
+ oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
919
+ oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
920
+ };
921
+
922
+ static void
923
+ set_state_depth(VALUE state, int depth) {
924
+ VALUE json_module = rb_const_get_at(rb_cObject, rb_intern("JSON"));
925
+ VALUE ext = rb_const_get(json_module, rb_intern("Ext"));
926
+ VALUE generator = rb_const_get(ext, rb_intern("Generator"));
927
+ VALUE state_class = rb_const_get(generator, rb_intern("State"));
928
+
929
+ if (state_class == rb_obj_class(state)) {
930
+ rb_funcall(state, rb_intern("depth="), 1, INT2NUM(depth));
931
+ }
932
+ }
933
+
934
+ void
935
+ oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
936
+ int type = rb_type(obj);
937
+
938
+ if (Yes == out->opts->trace) {
939
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
940
+ }
941
+ if (out->opts->dump_opts.max_depth <= depth) {
942
+ // When JSON.dump is called then an ArgumentError is expected and the
943
+ // limit is the depth inclusive. If JSON.generate is called then a
944
+ // NestingError is expected and the limit is inclusive. Worse than
945
+ // that there are unit tests for both.
946
+ if (CALLER_DUMP == out->caller) {
947
+ if (0 < out->argc) {
948
+ set_state_depth(*out->argv, depth);
949
+ }
950
+ rb_raise(rb_eArgError, "Too deeply nested.");
951
+ } else if (out->opts->dump_opts.max_depth < depth) {
952
+ if (0 < out->argc) {
953
+ set_state_depth(*out->argv, depth - 1);
954
+ }
955
+ raise_json_err("Too deeply nested", "NestingError");
956
+ }
957
+ }
958
+ if (0 < type && type <= RUBY_T_FIXNUM) {
959
+ DumpFunc f = compat_funcs[type];
960
+
961
+ if (NULL != f) {
962
+ f(obj, depth, out, as_ok);
963
+ if (Yes == out->opts->trace) {
964
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
965
+ }
966
+ return;
967
+ }
968
+ }
969
+ oj_dump_nil(Qnil, depth, out, false);
970
+ if (Yes == out->opts->trace) {
971
+ oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
972
+ }
973
+ }