oj 2.18.4 → 2.18.5

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.
@@ -1,759 +0,0 @@
1
- /* dump_object.c
2
- * Copyright (c) 2012, 2017, Peter Ohler
3
- * All rights reserved.
4
- */
5
-
6
- #include "dump.h"
7
-
8
- static void
9
- dump_time(VALUE obj, Out out) {
10
- switch (out->opts->time_format) {
11
- case RubyTime: oj_dump_obj_to_s(obj, out); break;
12
- case XmlTime: oj_dump_xml_time(obj, out); break;
13
- case UnixZTime: oj_dump_time(obj, out, 1); break;
14
- case UnixTime:
15
- default: oj_dump_time(obj, out, 0); break;
16
- }
17
- }
18
-
19
- static int
20
- hash_cb(VALUE key, VALUE value, Out out) {
21
- int depth = out->depth;
22
-
23
- if (out->omit_nil && Qnil == value) {
24
- return ST_CONTINUE;
25
- }
26
- if (!out->opts->dump_opts.use) {
27
- assure_size(out, depth * out->indent + 1);
28
- fill_indent(out, depth);
29
- } else {
30
- assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
31
- if (0 < out->opts->dump_opts.hash_size) {
32
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
33
- out->cur += out->opts->dump_opts.hash_size;
34
- }
35
- if (0 < out->opts->dump_opts.indent_size) {
36
- int i;
37
- for (i = depth; 0 < i; i--) {
38
- strcpy(out->cur, out->opts->dump_opts.indent_str);
39
- out->cur += out->opts->dump_opts.indent_size;
40
- }
41
- }
42
- }
43
- switch (rb_type(key)) {
44
- case T_STRING:
45
- oj_dump_str(key, 0, out, false);
46
- break;
47
- case T_SYMBOL:
48
- oj_dump_sym(key, 0, out, false);
49
- break;
50
- default:
51
- /*rb_raise(rb_eTypeError, "In :compat mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));*/
52
- oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false);
53
- break;
54
- }
55
- if (!out->opts->dump_opts.use) {
56
- *out->cur++ = ':';
57
- } else {
58
- assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2);
59
- if (0 < out->opts->dump_opts.before_size) {
60
- strcpy(out->cur, out->opts->dump_opts.before_sep);
61
- out->cur += out->opts->dump_opts.before_size;
62
- }
63
- *out->cur++ = ':';
64
- if (0 < out->opts->dump_opts.after_size) {
65
- strcpy(out->cur, out->opts->dump_opts.after_sep);
66
- out->cur += out->opts->dump_opts.after_size;
67
- }
68
- }
69
- oj_dump_compat_val(value, depth, out, true);
70
- out->depth = depth;
71
- *out->cur++ = ',';
72
-
73
- return ST_CONTINUE;
74
- }
75
-
76
- static void
77
- dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
78
- int cnt;
79
- size_t size;
80
-
81
- cnt = (int)RHASH_SIZE(obj);
82
- size = depth * out->indent + 2;
83
- assure_size(out, 2);
84
- if (0 == cnt) {
85
- *out->cur++ = '{';
86
- *out->cur++ = '}';
87
- } else {
88
- long id = oj_check_circular(obj, out);
89
-
90
- if (0 > id) {
91
- return;
92
- }
93
- *out->cur++ = '{';
94
- if (0 < id) {
95
- assure_size(out, size + 16);
96
- fill_indent(out, depth + 1);
97
- *out->cur++ = '"';
98
- *out->cur++ = '^';
99
- *out->cur++ = 'i';
100
- *out->cur++ = '"';
101
- *out->cur++ = ':';
102
- dump_ulong(id, out);
103
- *out->cur++ = ',';
104
- }
105
- out->depth = depth + 1;
106
- rb_hash_foreach(obj, hash_cb, (VALUE)out);
107
- if (',' == *(out->cur - 1)) {
108
- out->cur--; // backup to overwrite last comma
109
- }
110
- if (!out->opts->dump_opts.use) {
111
- assure_size(out, size);
112
- fill_indent(out, depth);
113
- } else {
114
- size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
115
- assure_size(out, size);
116
- if (0 < out->opts->dump_opts.hash_size) {
117
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
118
- out->cur += out->opts->dump_opts.hash_size;
119
- }
120
- if (0 < out->opts->dump_opts.indent_size) {
121
- int i;
122
-
123
- for (i = depth; 0 < i; i--) {
124
- strcpy(out->cur, out->opts->dump_opts.indent_str);
125
- out->cur += out->opts->dump_opts.indent_size;
126
- }
127
- }
128
- }
129
- *out->cur++ = '}';
130
- }
131
- *out->cur = '\0';
132
- }
133
-
134
- static void
135
- dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
136
- dump_hash_class(obj, rb_obj_class(obj), depth, out);
137
- }
138
-
139
- #if HAS_IVAR_HELPERS
140
- static int
141
- dump_attr_cb(ID key, VALUE value, Out out) {
142
- int depth = out->depth;
143
- size_t size = depth * out->indent + 1;
144
- const char *attr = rb_id2name(key);
145
-
146
- if (out->omit_nil && Qnil == value) {
147
- return ST_CONTINUE;
148
- }
149
- #if HAS_EXCEPTION_MAGIC
150
- if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) {
151
- return ST_CONTINUE;
152
- }
153
- #endif
154
- assure_size(out, size);
155
- fill_indent(out, depth);
156
- if ('@' == *attr) {
157
- attr++;
158
- oj_dump_cstr(attr, strlen(attr), 0, 0, out);
159
- } else {
160
- char buf[32];
161
-
162
- *buf = '~';
163
- strncpy(buf + 1, attr, sizeof(buf) - 2);
164
- buf[sizeof(buf) - 1] = '\0';
165
- oj_dump_cstr(buf, strlen(buf), 0, 0, out);
166
- }
167
- *out->cur++ = ':';
168
- oj_dump_comp_val(value, depth, out, 0, 0, true);
169
- out->depth = depth;
170
- *out->cur++ = ',';
171
-
172
- return ST_CONTINUE;
173
- }
174
- #endif
175
-
176
- static void
177
- dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
178
- size_t size = 0;
179
- int d2 = depth + 1;
180
- int cnt;
181
-
182
- assure_size(out, 2);
183
- *out->cur++ = '{';
184
- {
185
- #if HAS_IVAR_HELPERS
186
- cnt = (int)rb_ivar_count(obj);
187
- #else
188
- volatile VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0);
189
- VALUE *np = RARRAY_PTR(vars);
190
- ID vid;
191
- const char *attr;
192
- int i;
193
- int first = 1;
194
-
195
- cnt = (int)RARRAY_LEN(vars);
196
- #endif
197
- if (Qundef != clas && 0 < cnt) {
198
- *out->cur++ = ',';
199
- }
200
- if (0 == cnt && Qundef == clas) {
201
- // Might be something special like an Enumerable.
202
- if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) {
203
- out->cur--;
204
- oj_dump_compat_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out, false);
205
- return;
206
- }
207
- }
208
- out->depth = depth + 1;
209
- #if HAS_IVAR_HELPERS
210
- rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
211
- if (',' == *(out->cur - 1)) {
212
- out->cur--; // backup to overwrite last comma
213
- }
214
- #else
215
- size = d2 * out->indent + 1;
216
- for (i = cnt; 0 < i; i--, np++) {
217
- VALUE value;
218
-
219
- vid = rb_to_id(*np);
220
- attr = rb_id2name(vid);
221
- value = rb_ivar_get(obj, vid);
222
- if (out->omit_nil && Qnil == value) {
223
- continue;
224
- }
225
- if (first) {
226
- first = 0;
227
- } else {
228
- *out->cur++ = ',';
229
- }
230
- assure_size(out, size);
231
- fill_indent(out, d2);
232
- if ('@' == *attr) {
233
- attr++;
234
- oj_dump_cstr(attr, strlen(attr), 0, 0, out);
235
- } else {
236
- char buf[32];
237
-
238
- *buf = '~';
239
- strncpy(buf + 1, attr, sizeof(buf) - 2);
240
- buf[sizeof(buf) - 1] = '\0';
241
- oj_dump_cstr(buf, strlen(attr) + 1, 0, 0, out);
242
- }
243
- *out->cur++ = ':';
244
- oj_dump_compat_val(value, d2, out, 0, 0, true);
245
- assure_size(out, 2);
246
- }
247
- #endif
248
- #if HAS_EXCEPTION_MAGIC
249
- if (rb_obj_is_kind_of(obj, rb_eException)) {
250
- volatile VALUE rv;
251
-
252
- if (',' != *(out->cur - 1)) {
253
- *out->cur++ = ',';
254
- }
255
- // message
256
- assure_size(out, 2);
257
- fill_indent(out, d2);
258
- oj_dump_cstr("~mesg", 5, 0, 0, out);
259
- *out->cur++ = ':';
260
- rv = rb_funcall2(obj, rb_intern("message"), 0, 0);
261
- oj_dump_compat_val(rv, d2, out, true);
262
- assure_size(out, size + 2);
263
- *out->cur++ = ',';
264
- // backtrace
265
- fill_indent(out, d2);
266
- oj_dump_cstr("~bt", 3, 0, 0, out);
267
- *out->cur++ = ':';
268
- rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0);
269
- oj_dump_compat_val(rv, d2, out, true);
270
- assure_size(out, 2);
271
- }
272
- #endif
273
- out->depth = depth;
274
- }
275
- fill_indent(out, depth);
276
- *out->cur++ = '}';
277
- *out->cur = '\0';
278
- }
279
-
280
- static void
281
- dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
282
- if (as_ok && Yes == out->opts->to_json && rb_respond_to(obj, oj_to_hash_id)) {
283
- volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
284
-
285
- if (T_HASH != rb_type(h)) {
286
- // It seems that ActiveRecord implemented to_hash so that it returns
287
- // an Array and not a Hash. To get around that any value returned
288
- // will be dumped.
289
-
290
- //rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
291
- oj_dump_compat_val(h, depth, out, false);
292
- } else {
293
- dump_hash_class(h, Qundef, depth, out);
294
- }
295
- } else if (as_ok && Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
296
- volatile VALUE aj;
297
-
298
- #if HAS_METHOD_ARITY
299
- // Some classes elect to not take an options argument so check the arity
300
- // of as_json.
301
- switch (rb_obj_method_arity(obj, oj_as_json_id)) {
302
- case 0:
303
- aj = rb_funcall2(obj, oj_as_json_id, 0, 0);
304
- break;
305
- case 1:
306
- if (1 <= out->argc) {
307
- aj = rb_funcall2(obj, oj_as_json_id, 1, (VALUE*)out->argv);
308
- } else {
309
- VALUE nothing [1];
310
-
311
- nothing[0] = Qnil;
312
- aj = rb_funcall2(obj, oj_as_json_id, 1, nothing);
313
- }
314
- break;
315
- default:
316
- aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
317
- break;
318
- }
319
- #else
320
- aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
321
- #endif
322
- // Catch the obvious brain damaged recursive dumping.
323
- if (aj == obj) {
324
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
325
-
326
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), false, false, out);
327
- } else {
328
- oj_dump_compat_val(aj, depth, out, false);
329
- }
330
- } else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
331
- volatile VALUE rs;
332
- const char *s;
333
- int len;
334
-
335
- rs = rb_funcall(obj, oj_to_json_id, 0);
336
- s = rb_string_value_ptr((VALUE*)&rs);
337
- len = (int)RSTRING_LEN(rs);
338
-
339
- assure_size(out, len + 1);
340
- memcpy(out->cur, s, len);
341
- out->cur += len;
342
- *out->cur = '\0';
343
- } else {
344
- VALUE clas = rb_obj_class(obj);
345
-
346
- if (oj_bigdecimal_class == clas) {
347
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
348
- const char *str = rb_string_value_ptr((VALUE*)&rstr);
349
- int len = RSTRING_LEN(rstr);
350
-
351
- if (Yes == out->opts->bigdec_as_num) {
352
- oj_dump_raw(str, len, out);
353
- } else if (0 == strcasecmp("Infinity", str)) {
354
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
355
- oj_dump_raw(str, len, out);
356
- } else if (0 == strcasecmp("-Infinity", str)) {
357
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
358
- oj_dump_raw(str, len, out);
359
- } else {
360
- oj_dump_cstr(str, len, 0, 0, out);
361
- }
362
- #if (defined T_RATIONAL && defined RRATIONAL)
363
- } else if (oj_datetime_class == clas || oj_date_class == clas || rb_cRational == clas) {
364
- #else
365
- } else if (oj_datetime_class == clas || oj_date_class == clas) {
366
- #endif
367
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
368
-
369
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
370
- } else {
371
- dump_obj_attrs(obj, Qundef, 0, depth, out);
372
- }
373
- }
374
- *out->cur = '\0';
375
- }
376
-
377
- static void
378
- dump_array(VALUE a, int depth, Out out, bool as_ok) {
379
- size_t size;
380
- int i, cnt;
381
- int d2 = depth + 1;
382
- long id = oj_check_circular(a, out);
383
-
384
- if (id < 0) {
385
- return;
386
- }
387
- cnt = (int)RARRAY_LEN(a);
388
- *out->cur++ = '[';
389
- if (0 < id) {
390
- oj_dump_nil(Qnil, 0, out, false);
391
- }
392
- size = 2;
393
- assure_size(out, size);
394
- if (0 == cnt) {
395
- *out->cur++ = ']';
396
- } else {
397
- if (0 < id) {
398
- *out->cur++ = ',';
399
- }
400
- if (out->opts->dump_opts.use) {
401
- size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
402
- } else {
403
- size = d2 * out->indent + 2;
404
- }
405
- cnt--;
406
- for (i = 0; i <= cnt; i++) {
407
- assure_size(out, size);
408
- if (out->opts->dump_opts.use) {
409
- if (0 < out->opts->dump_opts.array_size) {
410
- strcpy(out->cur, out->opts->dump_opts.array_nl);
411
- out->cur += out->opts->dump_opts.array_size;
412
- }
413
- if (0 < out->opts->dump_opts.indent_size) {
414
- int i;
415
- for (i = d2; 0 < i; i--) {
416
- strcpy(out->cur, out->opts->dump_opts.indent_str);
417
- out->cur += out->opts->dump_opts.indent_size;
418
- }
419
- }
420
- } else {
421
- fill_indent(out, d2);
422
- }
423
- oj_dump_comp_val(rb_ary_entry(a, i), d2, out, 0, 0, true);
424
- if (i < cnt) {
425
- *out->cur++ = ',';
426
- }
427
- }
428
- size = depth * out->indent + 1;
429
- assure_size(out, size);
430
- if (out->opts->dump_opts.use) {
431
- //printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size, out->opts->dump_opts->indent);
432
- if (0 < out->opts->dump_opts.array_size) {
433
- strcpy(out->cur, out->opts->dump_opts.array_nl);
434
- out->cur += out->opts->dump_opts.array_size;
435
- }
436
- if (0 < out->opts->dump_opts.indent_size) {
437
- int i;
438
-
439
- for (i = depth; 0 < i; i--) {
440
- strcpy(out->cur, out->opts->dump_opts.indent_str);
441
- out->cur += out->opts->dump_opts.indent_size;
442
- }
443
- }
444
- } else {
445
- fill_indent(out, depth);
446
- }
447
- *out->cur++ = ']';
448
- }
449
- *out->cur = '\0';
450
- }
451
-
452
- static void
453
- dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
454
- if (as_ok && Yes == out->opts->to_json && rb_respond_to(obj, oj_to_hash_id)) {
455
- volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
456
-
457
- if (T_HASH != rb_type(h)) {
458
- // It seems that ActiveRecord implemented to_hash so that it
459
- // returns an Array and not a Hash. To get around that any value
460
- // returned will be dumped.
461
-
462
- //rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
463
- oj_dump_comp_val(h, depth, out, 0, 0, false);
464
- }
465
- dump_hash_class(h, Qundef, depth, out);
466
- } else if (as_ok && Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
467
- volatile VALUE aj;
468
-
469
- #if HAS_METHOD_ARITY
470
- // Some classes elect to not take an options argument so check the arity
471
- // of as_json.
472
- switch (rb_obj_method_arity(obj, oj_as_json_id)) {
473
- case 0:
474
- aj = rb_funcall2(obj, oj_as_json_id, 0, 0);
475
- break;
476
- case 1:
477
- if (1 <= out->argc) {
478
- aj = rb_funcall2(obj, oj_as_json_id, 1, out->argv);
479
- } else {
480
- VALUE nothing [1];
481
-
482
- nothing[0] = Qnil;
483
- aj = rb_funcall2(obj, oj_as_json_id, 1, nothing);
484
- }
485
- break;
486
- default:
487
- aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
488
- break;
489
- }
490
- #else
491
- aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
492
- #endif
493
- // Catch the obvious brain damaged recursive dumping.
494
- if (aj == obj) {
495
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
496
-
497
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), false, false, out);
498
- } else {
499
- oj_dump_compat_val(aj, depth, out, false);
500
- }
501
- } else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
502
- volatile VALUE rs = rb_funcall(obj, oj_to_json_id, 0);
503
- const char *s;
504
- int len;
505
-
506
- s = rb_string_value_ptr((VALUE*)&rs);
507
- len = (int)RSTRING_LEN(rs);
508
- assure_size(out, len);
509
- memcpy(out->cur, s, len);
510
- out->cur += len;
511
- } else {
512
- VALUE clas = rb_obj_class(obj);
513
- VALUE ma = Qnil;
514
- VALUE v;
515
- char num_id[32];
516
- int i;
517
- int d2 = depth + 1;
518
- int d3 = d2 + 1;
519
- size_t size = d2 * out->indent + d3 * out->indent + 3;
520
- const char *name;
521
- int cnt;
522
- size_t len;
523
-
524
- assure_size(out, size);
525
- if (clas == rb_cRange) {
526
- *out->cur++ = '"';
527
- oj_dump_comp_val(rb_funcall(obj, oj_begin_id, 0), d3, out, 0, 0, false);
528
- assure_size(out, 3);
529
- *out->cur++ = '.';
530
- *out->cur++ = '.';
531
- if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) {
532
- *out->cur++ = '.';
533
- }
534
- oj_dump_comp_val(rb_funcall(obj, oj_end_id, 0), d3, out, 0, 0, false);
535
- *out->cur++ = '"';
536
-
537
- return;
538
- }
539
- *out->cur++ = '{';
540
- fill_indent(out, d2);
541
- size = d3 * out->indent + 2;
542
- #if HAS_STRUCT_MEMBERS
543
- ma = rb_struct_s_members(clas);
544
- #endif
545
-
546
- #ifdef RSTRUCT_LEN
547
- #if UNIFY_FIXNUM_AND_BIGNUM
548
- cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
549
- #else // UNIFY_FIXNUM_AND_INTEGER
550
- cnt = (int)RSTRUCT_LEN(obj);
551
- #endif // UNIFY_FIXNUM_AND_INTEGER
552
- #else
553
- // This is a bit risky as a struct in C ruby is not the same as a Struct
554
- // class in interpreted Ruby so length() may not be defined.
555
- cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
556
- #endif
557
- for (i = 0; i < cnt; i++) {
558
- #ifdef RSTRUCT_LEN
559
- v = RSTRUCT_GET(obj, i);
560
- #else
561
- v = rb_struct_aref(obj, INT2FIX(i));
562
- #endif
563
- if (ma != Qnil) {
564
- name = rb_id2name(SYM2ID(rb_ary_entry(ma, i)));
565
- len = strlen(name);
566
- } else {
567
- len = snprintf(num_id, sizeof(num_id), "%d", i);
568
- name = num_id;
569
- }
570
- assure_size(out, size + len + 3);
571
- fill_indent(out, d3);
572
- *out->cur++ = '"';
573
- memcpy(out->cur, name, len);
574
- out->cur += len;
575
- *out->cur++ = '"';
576
- *out->cur++ = ':';
577
- oj_dump_comp_val(v, d3, out, 0, 0, true);
578
- *out->cur++ = ',';
579
- }
580
- out->cur--;
581
- *out->cur++ = '}';
582
- *out->cur = '\0';
583
- }
584
- }
585
-
586
- static void
587
- dump_data(VALUE obj, int depth, Out out, bool as_ok) {
588
- VALUE clas = rb_obj_class(obj);
589
-
590
- if (as_ok && Yes == out->opts->to_json && rb_respond_to(obj, oj_to_hash_id)) {
591
- volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
592
-
593
- if (T_HASH != rb_type(h)) {
594
- // It seems that ActiveRecord implemented to_hash so that it returns
595
- // an Array and not a Hash. To get around that any value returned
596
- // will be dumped.
597
-
598
- //rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
599
- oj_dump_compat_val(h, depth, out, false);
600
- }
601
- dump_hash_class(h, Qundef, depth, out);
602
- } else if (Yes == out->opts->bigdec_as_num && oj_bigdecimal_class == clas) {
603
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
604
- const char *str = rb_string_value_ptr((VALUE*)&rstr);
605
- int len = RSTRING_LEN(rstr);
606
-
607
- if (0 == strcasecmp("Infinity", str)) {
608
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
609
- oj_dump_raw(str, len, out);
610
- } else if (0 == strcasecmp("-Infinity", str)) {
611
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
612
- oj_dump_raw(str, len, out);
613
- } else {
614
- oj_dump_raw(str, len, out);
615
- }
616
- } else if (as_ok && Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
617
- volatile VALUE aj;
618
-
619
- #if HAS_METHOD_ARITY
620
- // Some classes elect to not take an options argument so check the arity
621
- // of as_json.
622
- switch (rb_obj_method_arity(obj, oj_as_json_id)) {
623
- case 0:
624
- aj = rb_funcall2(obj, oj_as_json_id, 0, 0);
625
- break;
626
- case 1:
627
- if (1 <= out->argc) {
628
- aj = rb_funcall2(obj, oj_as_json_id, 1, out->argv);
629
- } else {
630
- VALUE nothing [1];
631
-
632
- nothing[0] = Qnil;
633
- aj = rb_funcall2(obj, oj_as_json_id, 1, nothing);
634
- }
635
- break;
636
- default:
637
- aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
638
- break;
639
- }
640
- #else
641
- aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
642
- #endif
643
- // Catch the obvious brain damaged recursive dumping.
644
- if (aj == obj) {
645
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
646
-
647
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
648
- } else {
649
- oj_dump_comp_val(aj, depth, out, 0, 0, false);
650
- }
651
- } else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
652
- volatile VALUE rs;
653
- const char *s;
654
- int len;
655
-
656
- rs = rb_funcall(obj, oj_to_json_id, 0);
657
- s = rb_string_value_ptr((VALUE*)&rs);
658
- len = (int)RSTRING_LEN(rs);
659
-
660
- assure_size(out, len + 1);
661
- memcpy(out->cur, s, len);
662
- out->cur += len;
663
- *out->cur = '\0';
664
- } else {
665
- if (rb_cTime == clas) {
666
- dump_time(obj, out);
667
- } else if (oj_bigdecimal_class == clas) {
668
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
669
- const char *str = rb_string_value_ptr((VALUE*)&rstr);
670
- int len = RSTRING_LEN(rstr);
671
-
672
- if (0 == strcasecmp("Infinity", str)) {
673
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
674
- oj_dump_raw(str, len, out);
675
- } else if (0 == strcasecmp("-Infinity", str)) {
676
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
677
- oj_dump_raw(str, len, out);
678
- } else {
679
- oj_dump_cstr(str, len, 0, 0, out);
680
- }
681
- } else if (oj_datetime_class == clas) {
682
- volatile VALUE rstr;
683
-
684
- switch (out->opts->time_format) {
685
- case XmlTime:
686
- rstr = rb_funcall(obj, rb_intern("xmlschema"), 1, INT2FIX(out->opts->sec_prec));
687
- break;
688
- case UnixZTime:
689
- case UnixTime:
690
- case RubyTime:
691
- default:
692
- rstr = rb_funcall(obj, oj_to_s_id, 0);
693
- }
694
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
695
- } else {
696
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
697
-
698
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), RSTRING_LEN(rstr), 0, 0, out);
699
- }
700
- }
701
- }
702
-
703
- static void
704
- dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
705
- oj_dump_obj_to_s(obj, out);
706
- }
707
-
708
- static void
709
- dump_complex(VALUE obj, int depth, Out out, bool as_ok) {
710
- oj_dump_obj_to_s(obj, out);
711
- }
712
-
713
- static void
714
- dump_rational(VALUE obj, int depth, Out out, bool as_ok) {
715
- oj_dump_obj_to_s(obj, out);
716
- }
717
-
718
- static DumpFunc custom_funcs[] = {
719
- NULL, // RUBY_T_NONE = 0x00,
720
- dump_obj, // RUBY_T_OBJECT = 0x01,
721
- oj_dump_class, // RUBY_T_CLASS = 0x02,
722
- oj_dump_class, // RUBY_T_MODULE = 0x03,
723
- oj_dump_float, // RUBY_T_FLOAT = 0x04,
724
- oj_dump_str, // RUBY_T_STRING = 0x05,
725
- dump_regexp, // RUBY_T_REGEXP = 0x06,
726
- dump_array, // RUBY_T_ARRAY = 0x07,
727
- dump_hash, // RUBY_T_HASH = 0x08,
728
- dump_struct, // RUBY_T_STRUCT = 0x09,
729
- oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
730
- NULL, // RUBY_T_FILE = 0x0b,
731
- dump_data, // RUBY_T_DATA = 0x0c,
732
- NULL, // RUBY_T_MATCH = 0x0d,
733
- dump_complex, // RUBY_T_COMPLEX = 0x0e,
734
- dump_rational, // RUBY_T_RATIONAL = 0x0f,
735
- NULL, // 0x10
736
- oj_dump_nil, // RUBY_T_NIL = 0x11,
737
- oj_dump_true, // RUBY_T_TRUE = 0x12,
738
- oj_dump_false, // RUBY_T_FALSE = 0x13,
739
- oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
740
- oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
741
- };
742
-
743
- void
744
- oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
745
- int type = rb_type(obj);
746
-
747
- if (MAX_DEPTH < depth) {
748
- rb_raise(rb_eNoMemError, "Too deeply nested.\n");
749
- }
750
- if (0 < type && type <= RUBY_T_FIXNUM) {
751
- DumpFunc f = custom_funcs[type];
752
-
753
- if (NULL != f) {
754
- f(obj, depth, out, true);
755
- return;
756
- }
757
- }
758
- oj_dump_nil(Qnil, depth, out, false);
759
- }