oj 2.18.4 → 2.18.5

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