oj 2.18.5 → 3.0.0

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