oj 2.18.5 → 3.0.0

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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -226
  3. data/ext/oj/circarray.c +0 -25
  4. data/ext/oj/circarray.h +0 -25
  5. data/ext/oj/code.c +227 -0
  6. data/ext/oj/code.h +40 -0
  7. data/ext/oj/compat.c +126 -38
  8. data/ext/oj/custom.c +1097 -0
  9. data/ext/oj/dump.c +658 -2376
  10. data/ext/oj/dump.h +92 -0
  11. data/ext/oj/dump_compat.c +937 -0
  12. data/ext/oj/dump_leaf.c +254 -0
  13. data/ext/oj/dump_object.c +810 -0
  14. data/ext/oj/dump_rails.c +329 -0
  15. data/ext/oj/dump_strict.c +416 -0
  16. data/ext/oj/err.c +0 -25
  17. data/ext/oj/err.h +8 -2
  18. data/ext/oj/fast.c +24 -24
  19. data/ext/oj/mimic_json.c +817 -0
  20. data/ext/oj/mimic_rails.c +806 -0
  21. data/ext/oj/mimic_rails.h +17 -0
  22. data/ext/oj/object.c +18 -72
  23. data/ext/oj/odd.c +0 -25
  24. data/ext/oj/odd.h +2 -27
  25. data/ext/oj/oj.c +655 -1503
  26. data/ext/oj/oj.h +93 -40
  27. data/ext/oj/parse.c +99 -46
  28. data/ext/oj/parse.h +12 -26
  29. data/ext/oj/reader.c +1 -25
  30. data/ext/oj/reader.h +3 -25
  31. data/ext/oj/resolve.c +9 -11
  32. data/ext/oj/resolve.h +2 -2
  33. data/ext/oj/rxclass.c +133 -0
  34. data/ext/oj/rxclass.h +27 -0
  35. data/ext/oj/saj.c +4 -25
  36. data/ext/oj/scp.c +3 -25
  37. data/ext/oj/sparse.c +89 -13
  38. data/ext/oj/stream_writer.c +301 -0
  39. data/ext/oj/strict.c +4 -27
  40. data/ext/oj/string_writer.c +480 -0
  41. data/ext/oj/val_stack.h +6 -2
  42. data/lib/oj.rb +1 -23
  43. data/lib/oj/easy_hash.rb +12 -4
  44. data/lib/oj/json.rb +172 -0
  45. data/lib/oj/mimic.rb +123 -18
  46. data/lib/oj/state.rb +131 -0
  47. data/lib/oj/version.rb +1 -1
  48. data/pages/Advanced.md +22 -0
  49. data/pages/Compatibility.md +25 -0
  50. data/pages/Custom.md +23 -0
  51. data/pages/Encoding.md +65 -0
  52. data/pages/JsonGem.md +79 -0
  53. data/pages/Modes.md +140 -0
  54. data/pages/Options.md +250 -0
  55. data/pages/Rails.md +60 -0
  56. data/pages/Security.md +20 -0
  57. data/test/activesupport4/decoding_test.rb +105 -0
  58. data/test/activesupport4/encoding_test.rb +531 -0
  59. data/test/activesupport4/test_helper.rb +41 -0
  60. data/test/activesupport5/decoding_test.rb +125 -0
  61. data/test/activesupport5/encoding_test.rb +483 -0
  62. data/test/activesupport5/encoding_test_cases.rb +90 -0
  63. data/test/activesupport5/test_helper.rb +50 -0
  64. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  65. data/test/json_gem/json_addition_test.rb +216 -0
  66. data/test/json_gem/json_common_interface_test.rb +143 -0
  67. data/test/json_gem/json_encoding_test.rb +109 -0
  68. data/test/json_gem/json_ext_parser_test.rb +20 -0
  69. data/test/json_gem/json_fixtures_test.rb +35 -0
  70. data/test/json_gem/json_generator_test.rb +383 -0
  71. data/test/json_gem/json_generic_object_test.rb +90 -0
  72. data/test/json_gem/json_parser_test.rb +470 -0
  73. data/test/json_gem/json_string_matching_test.rb +42 -0
  74. data/test/json_gem/test_helper.rb +18 -0
  75. data/test/perf_compat.rb +30 -28
  76. data/test/perf_object.rb +1 -1
  77. data/test/perf_strict.rb +18 -1
  78. data/test/sample.rb +0 -1
  79. data/test/test_compat.rb +169 -93
  80. data/test/test_custom.rb +355 -0
  81. data/test/test_file.rb +0 -8
  82. data/test/test_null.rb +376 -0
  83. data/test/test_object.rb +268 -3
  84. data/test/test_scp.rb +22 -1
  85. data/test/test_strict.rb +160 -4
  86. data/test/test_various.rb +52 -620
  87. data/test/tests.rb +14 -0
  88. data/test/tests_mimic.rb +14 -0
  89. data/test/tests_mimic_addition.rb +7 -0
  90. metadata +89 -47
  91. data/test/activesupport_datetime_test.rb +0 -23
  92. data/test/bug.rb +0 -51
  93. data/test/bug2.rb +0 -10
  94. data/test/bug3.rb +0 -46
  95. data/test/bug_fast.rb +0 -32
  96. data/test/bug_load.rb +0 -24
  97. data/test/crash.rb +0 -111
  98. data/test/curl/curl_oj.rb +0 -46
  99. data/test/curl/get_oj.rb +0 -24
  100. data/test/curl/just_curl.rb +0 -31
  101. data/test/curl/just_oj.rb +0 -51
  102. data/test/example.rb +0 -11
  103. data/test/foo.rb +0 -24
  104. data/test/io.rb +0 -48
  105. data/test/isolated/test_mimic_rails_datetime.rb +0 -27
  106. data/test/mod.rb +0 -16
  107. data/test/rails.rb +0 -50
  108. data/test/russian.rb +0 -18
  109. data/test/struct.rb +0 -29
  110. data/test/test_serializer.rb +0 -59
  111. data/test/write_timebars.rb +0 -31
@@ -0,0 +1,329 @@
1
+ /* dump_object.c
2
+ * Copyright (c) 2012, 2017, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include "dump.h"
7
+ #include "encode.h"
8
+ #include "mimic_rails.h"
9
+
10
+ #define OJ_INFINITY (1.0/0.0)
11
+
12
+ bool oj_rails_hash_opt = false;
13
+ bool oj_rails_array_opt = false;
14
+
15
+ static void
16
+ dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
17
+ volatile VALUE ja;
18
+
19
+ if (0 < out->argc) {
20
+ ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
21
+ } else {
22
+ ja = rb_funcall(obj, oj_as_json_id, 0);
23
+ }
24
+ if (ja == obj || !as_ok) {
25
+ // Once as_json is call it should never be called again on the same
26
+ // object with as_ok.
27
+ oj_dump_rails_val(ja, depth, out, false);
28
+ } else {
29
+ int type = rb_type(ja);
30
+
31
+ if (T_HASH == type || T_ARRAY == type) {
32
+ oj_dump_rails_val(ja, depth, out, false);
33
+ } else {
34
+ oj_dump_rails_val(ja, depth, out, true);
35
+ }
36
+ }
37
+ }
38
+
39
+ static void
40
+ dump_to_hash(VALUE obj, int depth, Out out) {
41
+ oj_dump_rails_val(rb_funcall(obj, oj_to_hash_id, 0), depth, out, false);
42
+ }
43
+
44
+ static void
45
+ dump_float(VALUE obj, int depth, Out out, bool as_ok) {
46
+ char buf[64];
47
+ char *b;
48
+ double d = rb_num2dbl(obj);
49
+ int cnt = 0;
50
+
51
+ if (0.0 == d) {
52
+ b = buf;
53
+ *b++ = '0';
54
+ *b++ = '.';
55
+ *b++ = '0';
56
+ *b++ = '\0';
57
+ cnt = 3;
58
+ } else {
59
+ if (isnan(d) || OJ_INFINITY == d || -OJ_INFINITY == d) {
60
+ strcpy(buf, "null");
61
+ cnt = 4;
62
+ } else if (d == (double)(long long int)d) {
63
+ cnt = snprintf(buf, sizeof(buf), "%.1f", d);
64
+ } else {
65
+ cnt = snprintf(buf, sizeof(buf), "%0.16g", d);
66
+ }
67
+ }
68
+ assure_size(out, cnt);
69
+ for (b = buf; '\0' != *b; b++) {
70
+ *out->cur++ = *b;
71
+ }
72
+ *out->cur = '\0';
73
+ }
74
+
75
+ static void
76
+ dump_array(VALUE a, int depth, Out out, bool as_ok) {
77
+ size_t size;
78
+ int i, cnt;
79
+ int d2 = depth + 1;
80
+
81
+ if (Yes == out->opts->circular) {
82
+ if (0 > oj_check_circular(a, out)) {
83
+ oj_dump_nil(Qnil, 0, out, false);
84
+ return;
85
+ }
86
+ }
87
+ if (as_ok && !oj_rails_array_opt && rb_respond_to(a, oj_as_json_id)) {
88
+ dump_as_json(a, depth, out, false);
89
+ return;
90
+ }
91
+ cnt = (int)RARRAY_LEN(a);
92
+ *out->cur++ = '[';
93
+ size = 2;
94
+ assure_size(out, size);
95
+ if (0 == cnt) {
96
+ *out->cur++ = ']';
97
+ } else {
98
+ if (out->opts->dump_opts.use) {
99
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
100
+ } else {
101
+ size = d2 * out->indent + 2;
102
+ }
103
+ cnt--;
104
+ for (i = 0; i <= cnt; i++) {
105
+ assure_size(out, size);
106
+ if (out->opts->dump_opts.use) {
107
+ if (0 < out->opts->dump_opts.array_size) {
108
+ strcpy(out->cur, out->opts->dump_opts.array_nl);
109
+ out->cur += out->opts->dump_opts.array_size;
110
+ }
111
+ if (0 < out->opts->dump_opts.indent_size) {
112
+ int i;
113
+ for (i = d2; 0 < i; i--) {
114
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
115
+ out->cur += out->opts->dump_opts.indent_size;
116
+ }
117
+ }
118
+ } else {
119
+ fill_indent(out, d2);
120
+ }
121
+ oj_dump_rails_val(rb_ary_entry(a, i), d2, out, as_ok);
122
+ if (i < cnt) {
123
+ *out->cur++ = ',';
124
+ }
125
+ }
126
+ size = depth * out->indent + 1;
127
+ assure_size(out, size);
128
+ if (out->opts->dump_opts.use) {
129
+ if (0 < out->opts->dump_opts.array_size) {
130
+ strcpy(out->cur, out->opts->dump_opts.array_nl);
131
+ out->cur += out->opts->dump_opts.array_size;
132
+ }
133
+ if (0 < out->opts->dump_opts.indent_size) {
134
+ int i;
135
+
136
+ for (i = depth; 0 < i; i--) {
137
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
138
+ out->cur += out->opts->dump_opts.indent_size;
139
+ }
140
+ }
141
+ } else {
142
+ fill_indent(out, depth);
143
+ }
144
+ *out->cur++ = ']';
145
+ }
146
+ *out->cur = '\0';
147
+ }
148
+
149
+ static int
150
+ hash_cb(VALUE key, VALUE value, Out out) {
151
+ int depth = out->depth;
152
+ long size;
153
+ int rtype = rb_type(key);
154
+
155
+ if (rtype != T_STRING && rtype != T_SYMBOL) {
156
+ key = rb_funcall(key, oj_to_s_id, 0);
157
+ rtype = rb_type(key);
158
+ }
159
+ if (!out->opts->dump_opts.use) {
160
+ size = depth * out->indent + 1;
161
+ assure_size(out, size);
162
+ fill_indent(out, depth);
163
+ if (rtype == T_STRING) {
164
+ oj_dump_str(key, 0, out, false);
165
+ } else {
166
+ oj_dump_sym(key, 0, out, false);
167
+ }
168
+ *out->cur++ = ':';
169
+ } else {
170
+ size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
171
+ assure_size(out, size);
172
+ if (0 < out->opts->dump_opts.hash_size) {
173
+ strcpy(out->cur, out->opts->dump_opts.hash_nl);
174
+ out->cur += out->opts->dump_opts.hash_size;
175
+ }
176
+ if (0 < out->opts->dump_opts.indent_size) {
177
+ int i;
178
+ for (i = depth; 0 < i; i--) {
179
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
180
+ out->cur += out->opts->dump_opts.indent_size;
181
+ }
182
+ }
183
+ if (rtype == T_STRING) {
184
+ oj_dump_str(key, 0, out, false);
185
+ } else {
186
+ oj_dump_sym(key, 0, out, false);
187
+ }
188
+ size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
189
+ assure_size(out, size);
190
+ if (0 < out->opts->dump_opts.before_size) {
191
+ strcpy(out->cur, out->opts->dump_opts.before_sep);
192
+ out->cur += out->opts->dump_opts.before_size;
193
+ }
194
+ *out->cur++ = ':';
195
+ if (0 < out->opts->dump_opts.after_size) {
196
+ strcpy(out->cur, out->opts->dump_opts.after_sep);
197
+ out->cur += out->opts->dump_opts.after_size;
198
+ }
199
+ }
200
+ oj_dump_rails_val(value, depth, out, false);
201
+ out->depth = depth;
202
+ *out->cur++ = ',';
203
+
204
+ return ST_CONTINUE;
205
+ }
206
+
207
+ static void
208
+ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
209
+ int cnt;
210
+ size_t size;
211
+
212
+ if (Yes == out->opts->circular) {
213
+ if (0 > oj_check_circular(obj, out)) {
214
+ oj_dump_nil(Qnil, 0, out, false);
215
+ return;
216
+ }
217
+ }
218
+ if (as_ok && !oj_rails_hash_opt && rb_respond_to(obj, oj_as_json_id)) {
219
+ dump_as_json(obj, depth, out, false);
220
+ return;
221
+ }
222
+ cnt = (int)RHASH_SIZE(obj);
223
+ size = depth * out->indent + 2;
224
+ assure_size(out, 2);
225
+ *out->cur++ = '{';
226
+ if (0 == cnt) {
227
+ *out->cur++ = '}';
228
+ } else {
229
+ out->depth = depth + 1;
230
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
231
+ if (',' == *(out->cur - 1)) {
232
+ out->cur--; // backup to overwrite last comma
233
+ }
234
+ if (!out->opts->dump_opts.use) {
235
+ assure_size(out, size);
236
+ fill_indent(out, depth);
237
+ } else {
238
+ size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
239
+ assure_size(out, size);
240
+ if (0 < out->opts->dump_opts.hash_size) {
241
+ strcpy(out->cur, out->opts->dump_opts.hash_nl);
242
+ out->cur += out->opts->dump_opts.hash_size;
243
+ }
244
+ if (0 < out->opts->dump_opts.indent_size) {
245
+ int i;
246
+
247
+ for (i = depth; 0 < i; i--) {
248
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
249
+ out->cur += out->opts->dump_opts.indent_size;
250
+ }
251
+ }
252
+ }
253
+ *out->cur++ = '}';
254
+ }
255
+ *out->cur = '\0';
256
+ }
257
+
258
+ static void
259
+ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
260
+ if (as_ok) {
261
+ ROpt ro;
262
+
263
+ if (NULL != (ro = oj_rails_get_opt(out->ropts, rb_obj_class(obj))) && ro->on) {
264
+ ro->dump(obj, depth, out, as_ok);
265
+ } else if (rb_respond_to(obj, oj_as_json_id)) {
266
+ dump_as_json(obj, depth, out, true);
267
+ } else if (rb_respond_to(obj, oj_to_hash_id)) {
268
+ dump_to_hash(obj, depth, out);
269
+ } else {
270
+ oj_dump_obj_to_s(obj, out);
271
+ }
272
+ } else if (rb_respond_to(obj, oj_to_hash_id)) {
273
+ // Always attempt to_hash.
274
+ dump_to_hash(obj, depth, out);
275
+ } else {
276
+ oj_dump_obj_to_s(obj, out);
277
+ }
278
+ }
279
+
280
+ static void
281
+ dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
282
+ oj_dump_obj_to_s(obj, out);
283
+ }
284
+
285
+ static DumpFunc rails_funcs[] = {
286
+ NULL, // RUBY_T_NONE = 0x00,
287
+ dump_obj, // RUBY_T_OBJECT = 0x01,
288
+ oj_dump_class, // RUBY_T_CLASS = 0x02,
289
+ oj_dump_class, // RUBY_T_MODULE = 0x03,
290
+ dump_float, // RUBY_T_FLOAT = 0x04,
291
+ oj_dump_str, // RUBY_T_STRING = 0x05,
292
+ dump_as_string, // RUBY_T_REGEXP = 0x06,
293
+ dump_array, // RUBY_T_ARRAY = 0x07,
294
+ dump_hash, // RUBY_T_HASH = 0x08,
295
+ dump_obj, // RUBY_T_STRUCT = 0x09,
296
+ oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
297
+ NULL, // RUBY_T_FILE = 0x0b,
298
+ dump_obj, // RUBY_T_DATA = 0x0c,
299
+ NULL, // RUBY_T_MATCH = 0x0d,
300
+ // Rails raises a stack error on Complex and Rational. It also corrupts
301
+ // something whic causes a segfault on the next call. Oj will not mimic
302
+ // that behavior.
303
+ dump_as_string, // RUBY_T_COMPLEX = 0x0e,
304
+ dump_as_string, // RUBY_T_RATIONAL = 0x0f,
305
+ NULL, // 0x10
306
+ oj_dump_nil, // RUBY_T_NIL = 0x11,
307
+ oj_dump_true, // RUBY_T_TRUE = 0x12,
308
+ oj_dump_false, // RUBY_T_FALSE = 0x13,
309
+ oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
310
+ oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
311
+ };
312
+
313
+ void
314
+ oj_dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
315
+ int type = rb_type(obj);
316
+
317
+ if (MAX_DEPTH < depth) {
318
+ rb_raise(rb_eNoMemError, "Too deeply nested.\n");
319
+ }
320
+ if (0 < type && type <= RUBY_T_FIXNUM) {
321
+ DumpFunc f = rails_funcs[type];
322
+
323
+ if (NULL != f) {
324
+ f(obj, depth, out, as_ok);
325
+ return;
326
+ }
327
+ }
328
+ oj_dump_nil(Qnil, depth, out, false);
329
+ }
@@ -0,0 +1,416 @@
1
+ /* dump_strict.c
2
+ * Copyright (c) 2012, 2017, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include <stdlib.h>
7
+ #include <time.h>
8
+ #include <stdio.h>
9
+ #include <string.h>
10
+ #include <math.h>
11
+ #include <unistd.h>
12
+ #include <errno.h>
13
+
14
+ #include "dump.h"
15
+
16
+ #if !HAS_ENCODING_SUPPORT || defined(RUBINIUS_RUBY)
17
+ #define rb_eEncodingError rb_eException
18
+ #endif
19
+
20
+ // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
21
+ #define OJ_INFINITY (1.0/0.0)
22
+
23
+ // Extra padding at end of buffer.
24
+ #define BUFFER_EXTRA 10
25
+
26
+ typedef unsigned long ulong;
27
+
28
+ static const char inf_val[] = INF_VAL;
29
+ static const char ninf_val[] = NINF_VAL;
30
+ static const char nan_val[] = NAN_VAL;
31
+
32
+ static void
33
+ raise_strict(VALUE obj) {
34
+ rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in strict mode.\n", rb_class2name(rb_obj_class(obj)));
35
+ }
36
+
37
+ // Removed dependencies on math due to problems with CentOS 5.4.
38
+ static void
39
+ dump_float(VALUE obj, int depth, Out out, bool as_ok) {
40
+ char buf[64];
41
+ char *b;
42
+ double d = rb_num2dbl(obj);
43
+ int cnt = 0;
44
+
45
+ if (0.0 == d) {
46
+ b = buf;
47
+ *b++ = '0';
48
+ *b++ = '.';
49
+ *b++ = '0';
50
+ *b++ = '\0';
51
+ cnt = 3;
52
+ } else {
53
+ NanDump nd = out->opts->dump_opts.nan_dump;
54
+
55
+ if (AutoNan == nd) {
56
+ nd = RaiseNan;
57
+ }
58
+ if (OJ_INFINITY == d) {
59
+ switch (nd) {
60
+ case RaiseNan:
61
+ case WordNan:
62
+ raise_strict(obj);
63
+ break;
64
+ case NullNan:
65
+ strcpy(buf, "null");
66
+ cnt = 4;
67
+ break;
68
+ case HugeNan:
69
+ default:
70
+ strcpy(buf, inf_val);
71
+ cnt = sizeof(inf_val) - 1;
72
+ break;
73
+ }
74
+ } else if (-OJ_INFINITY == d) {
75
+ switch (nd) {
76
+ case RaiseNan:
77
+ case WordNan:
78
+ raise_strict(obj);
79
+ break;
80
+ case NullNan:
81
+ strcpy(buf, "null");
82
+ cnt = 4;
83
+ break;
84
+ case HugeNan:
85
+ default:
86
+ strcpy(buf, ninf_val);
87
+ cnt = sizeof(ninf_val) - 1;
88
+ break;
89
+ }
90
+ } else if (isnan(d)) {
91
+ switch (nd) {
92
+ case RaiseNan:
93
+ case WordNan:
94
+ raise_strict(obj);
95
+ break;
96
+ case NullNan:
97
+ strcpy(buf, "null");
98
+ cnt = 4;
99
+ break;
100
+ case HugeNan:
101
+ default:
102
+ strcpy(buf, nan_val);
103
+ cnt = sizeof(nan_val) - 1;
104
+ break;
105
+ }
106
+ } else if (d == (double)(long long int)d) {
107
+ cnt = snprintf(buf, sizeof(buf), "%.1f", d);
108
+ } else if (0 == out->opts->float_prec) {
109
+ volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
110
+
111
+ cnt = RSTRING_LEN(rstr);
112
+ if ((int)sizeof(buf) <= cnt) {
113
+ cnt = sizeof(buf) - 1;
114
+ }
115
+ strncpy(buf, rb_string_value_ptr((VALUE*)&rstr), cnt);
116
+ buf[cnt] = '\0';
117
+ } else {
118
+ cnt = snprintf(buf, sizeof(buf), out->opts->float_fmt, d);
119
+ }
120
+ }
121
+ assure_size(out, cnt);
122
+ for (b = buf; '\0' != *b; b++) {
123
+ *out->cur++ = *b;
124
+ }
125
+ *out->cur = '\0';
126
+ }
127
+
128
+ static void
129
+ dump_array(VALUE a, int depth, Out out, bool as_ok) {
130
+ size_t size;
131
+ int i, cnt;
132
+ int d2 = depth + 1;
133
+
134
+ if (Yes == out->opts->circular) {
135
+ if (0 > oj_check_circular(a, out)) {
136
+ oj_dump_nil(Qnil, 0, out, false);
137
+ return;
138
+ }
139
+ }
140
+ cnt = (int)RARRAY_LEN(a);
141
+ *out->cur++ = '[';
142
+ size = 2;
143
+ assure_size(out, size);
144
+ if (0 == cnt) {
145
+ *out->cur++ = ']';
146
+ } else {
147
+ if (out->opts->dump_opts.use) {
148
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
149
+ } else {
150
+ size = d2 * out->indent + 2;
151
+ }
152
+ cnt--;
153
+ for (i = 0; i <= cnt; i++) {
154
+ assure_size(out, size);
155
+ if (out->opts->dump_opts.use) {
156
+ if (0 < out->opts->dump_opts.array_size) {
157
+ strcpy(out->cur, out->opts->dump_opts.array_nl);
158
+ out->cur += out->opts->dump_opts.array_size;
159
+ }
160
+ if (0 < out->opts->dump_opts.indent_size) {
161
+ int i;
162
+ for (i = d2; 0 < i; i--) {
163
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
164
+ out->cur += out->opts->dump_opts.indent_size;
165
+ }
166
+ }
167
+ } else {
168
+ fill_indent(out, d2);
169
+ }
170
+ oj_dump_strict_val(rb_ary_entry(a, i), d2, out);
171
+ if (i < cnt) {
172
+ *out->cur++ = ',';
173
+ }
174
+ }
175
+ size = depth * out->indent + 1;
176
+ assure_size(out, size);
177
+ if (out->opts->dump_opts.use) {
178
+ //printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size, out->opts->dump_opts->indent);
179
+ if (0 < out->opts->dump_opts.array_size) {
180
+ strcpy(out->cur, out->opts->dump_opts.array_nl);
181
+ out->cur += out->opts->dump_opts.array_size;
182
+ }
183
+ if (0 < out->opts->dump_opts.indent_size) {
184
+ int i;
185
+
186
+ for (i = depth; 0 < i; i--) {
187
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
188
+ out->cur += out->opts->dump_opts.indent_size;
189
+ }
190
+ }
191
+ } else {
192
+ fill_indent(out, depth);
193
+ }
194
+ *out->cur++ = ']';
195
+ }
196
+ *out->cur = '\0';
197
+ }
198
+
199
+ static int
200
+ hash_cb(VALUE key, VALUE value, Out out) {
201
+ int depth = out->depth;
202
+ long size;
203
+ int rtype = rb_type(key);
204
+
205
+ if (rtype != T_STRING && rtype != T_SYMBOL) {
206
+ rb_raise(rb_eTypeError, "In :strict mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));
207
+ }
208
+ if (out->omit_nil && Qnil == value) {
209
+ return ST_CONTINUE;
210
+ }
211
+ if (!out->opts->dump_opts.use) {
212
+ size = depth * out->indent + 1;
213
+ assure_size(out, size);
214
+ fill_indent(out, depth);
215
+ if (rtype == T_STRING) {
216
+ oj_dump_str(key, 0, out, false);
217
+ } else {
218
+ oj_dump_sym(key, 0, out, false);
219
+ }
220
+ *out->cur++ = ':';
221
+ } else {
222
+ size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
223
+ assure_size(out, size);
224
+ if (0 < out->opts->dump_opts.hash_size) {
225
+ strcpy(out->cur, out->opts->dump_opts.hash_nl);
226
+ out->cur += out->opts->dump_opts.hash_size;
227
+ }
228
+ if (0 < out->opts->dump_opts.indent_size) {
229
+ int i;
230
+ for (i = depth; 0 < i; i--) {
231
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
232
+ out->cur += out->opts->dump_opts.indent_size;
233
+ }
234
+ }
235
+ if (rtype == T_STRING) {
236
+ oj_dump_str(key, 0, out, false);
237
+ } else {
238
+ oj_dump_sym(key, 0, out, false);
239
+ }
240
+ size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
241
+ assure_size(out, size);
242
+ if (0 < out->opts->dump_opts.before_size) {
243
+ strcpy(out->cur, out->opts->dump_opts.before_sep);
244
+ out->cur += out->opts->dump_opts.before_size;
245
+ }
246
+ *out->cur++ = ':';
247
+ if (0 < out->opts->dump_opts.after_size) {
248
+ strcpy(out->cur, out->opts->dump_opts.after_sep);
249
+ out->cur += out->opts->dump_opts.after_size;
250
+ }
251
+ }
252
+ oj_dump_strict_val(value, depth, out);
253
+ out->depth = depth;
254
+ *out->cur++ = ',';
255
+
256
+ return ST_CONTINUE;
257
+ }
258
+
259
+ static void
260
+ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
261
+ int cnt;
262
+ size_t size;
263
+
264
+ if (Yes == out->opts->circular) {
265
+ if (0 > oj_check_circular(obj, out)) {
266
+ oj_dump_nil(Qnil, 0, out, false);
267
+ return;
268
+ }
269
+ }
270
+ cnt = (int)RHASH_SIZE(obj);
271
+ size = depth * out->indent + 2;
272
+ assure_size(out, 2);
273
+ *out->cur++ = '{';
274
+ if (0 == cnt) {
275
+ *out->cur++ = '}';
276
+ } else {
277
+ out->depth = depth + 1;
278
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
279
+ if (',' == *(out->cur - 1)) {
280
+ out->cur--; // backup to overwrite last comma
281
+ }
282
+ if (!out->opts->dump_opts.use) {
283
+ assure_size(out, size);
284
+ fill_indent(out, depth);
285
+ } else {
286
+ size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
287
+ assure_size(out, size);
288
+ if (0 < out->opts->dump_opts.hash_size) {
289
+ strcpy(out->cur, out->opts->dump_opts.hash_nl);
290
+ out->cur += out->opts->dump_opts.hash_size;
291
+ }
292
+ if (0 < out->opts->dump_opts.indent_size) {
293
+ int i;
294
+
295
+ for (i = depth; 0 < i; i--) {
296
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
297
+ out->cur += out->opts->dump_opts.indent_size;
298
+ }
299
+ }
300
+ }
301
+ *out->cur++ = '}';
302
+ }
303
+ *out->cur = '\0';
304
+ }
305
+
306
+ static void
307
+ dump_data_strict(VALUE obj, int depth, Out out, bool as_ok) {
308
+ VALUE clas = rb_obj_class(obj);
309
+
310
+ if (oj_bigdecimal_class == clas) {
311
+ volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
312
+
313
+ oj_dump_raw(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), out);
314
+ } else {
315
+ raise_strict(obj);
316
+ }
317
+ }
318
+
319
+ static void
320
+ dump_data_null(VALUE obj, int depth, Out out, bool as_ok) {
321
+ VALUE clas = rb_obj_class(obj);
322
+
323
+ if (oj_bigdecimal_class == clas) {
324
+ volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
325
+
326
+ oj_dump_raw(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), out);
327
+ } else {
328
+ oj_dump_nil(Qnil, depth, out, false);
329
+ }
330
+ }
331
+
332
+ static DumpFunc strict_funcs[] = {
333
+ NULL, // RUBY_T_NONE = 0x00,
334
+ dump_data_strict, // RUBY_T_OBJECT = 0x01,
335
+ NULL, // RUBY_T_CLASS = 0x02,
336
+ NULL, // RUBY_T_MODULE = 0x03,
337
+ dump_float, // RUBY_T_FLOAT = 0x04,
338
+ oj_dump_str, // RUBY_T_STRING = 0x05,
339
+ NULL, // RUBY_T_REGEXP = 0x06,
340
+ dump_array, // RUBY_T_ARRAY = 0x07,
341
+ dump_hash, // RUBY_T_HASH = 0x08,
342
+ NULL, // RUBY_T_STRUCT = 0x09,
343
+ oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
344
+ NULL, // RUBY_T_FILE = 0x0b,
345
+ dump_data_strict, // RUBY_T_DATA = 0x0c,
346
+ NULL, // RUBY_T_MATCH = 0x0d,
347
+ NULL, // RUBY_T_COMPLEX = 0x0e,
348
+ NULL, // RUBY_T_RATIONAL = 0x0f,
349
+ NULL, // 0x10
350
+ oj_dump_nil, // RUBY_T_NIL = 0x11,
351
+ oj_dump_true, // RUBY_T_TRUE = 0x12,
352
+ oj_dump_false, // RUBY_T_FALSE = 0x13,
353
+ oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
354
+ oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
355
+ };
356
+
357
+ void
358
+ oj_dump_strict_val(VALUE obj, int depth, Out out) {
359
+ int type = rb_type(obj);
360
+
361
+ if (MAX_DEPTH < depth) {
362
+ rb_raise(rb_eNoMemError, "Too deeply nested.\n");
363
+ }
364
+ if (0 < type && type <= RUBY_T_FIXNUM) {
365
+ DumpFunc f = strict_funcs[type];
366
+
367
+ if (NULL != f) {
368
+ f(obj, depth, out, false);
369
+ return;
370
+ }
371
+ }
372
+ raise_strict(obj);
373
+ }
374
+
375
+ static DumpFunc null_funcs[] = {
376
+ NULL, // RUBY_T_NONE = 0x00,
377
+ dump_data_null, // RUBY_T_OBJECT = 0x01,
378
+ NULL, // RUBY_T_CLASS = 0x02,
379
+ NULL, // RUBY_T_MODULE = 0x03,
380
+ dump_float, // RUBY_T_FLOAT = 0x04,
381
+ oj_dump_str, // RUBY_T_STRING = 0x05,
382
+ NULL, // RUBY_T_REGEXP = 0x06,
383
+ dump_array, // RUBY_T_ARRAY = 0x07,
384
+ dump_hash, // RUBY_T_HASH = 0x08,
385
+ NULL, // RUBY_T_STRUCT = 0x09,
386
+ oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
387
+ NULL, // RUBY_T_FILE = 0x0b,
388
+ dump_data_null, // RUBY_T_DATA = 0x0c,
389
+ NULL, // RUBY_T_MATCH = 0x0d,
390
+ NULL, // RUBY_T_COMPLEX = 0x0e,
391
+ NULL, // RUBY_T_RATIONAL = 0x0f,
392
+ NULL, // 0x10
393
+ oj_dump_nil, // RUBY_T_NIL = 0x11,
394
+ oj_dump_true, // RUBY_T_TRUE = 0x12,
395
+ oj_dump_false, // RUBY_T_FALSE = 0x13,
396
+ oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
397
+ oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
398
+ };
399
+
400
+ void
401
+ oj_dump_null_val(VALUE obj, int depth, Out out) {
402
+ int type = rb_type(obj);
403
+
404
+ if (MAX_DEPTH < depth) {
405
+ rb_raise(rb_eNoMemError, "Too deeply nested.\n");
406
+ }
407
+ if (0 < type && type <= RUBY_T_FIXNUM) {
408
+ DumpFunc f = null_funcs[type];
409
+
410
+ if (NULL != f) {
411
+ f(obj, depth, out, false);
412
+ return;
413
+ }
414
+ }
415
+ oj_dump_nil(Qnil, depth, out, false);
416
+ }