oj 3.7.12

Sign up to get free protection for your applications and to get access to all the features.
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
+ }