oj 3.11.0 → 3.16.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.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1421 -0
  3. data/README.md +20 -5
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +48 -38
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +60 -62
  9. data/ext/oj/cache8.h +8 -7
  10. data/ext/oj/circarray.c +35 -35
  11. data/ext/oj/circarray.h +11 -9
  12. data/ext/oj/code.c +156 -174
  13. data/ext/oj/code.h +19 -18
  14. data/ext/oj/compat.c +140 -197
  15. data/ext/oj/custom.c +737 -879
  16. data/ext/oj/debug.c +126 -0
  17. data/ext/oj/dump.c +830 -835
  18. data/ext/oj/dump.h +65 -53
  19. data/ext/oj/dump_compat.c +566 -642
  20. data/ext/oj/dump_leaf.c +95 -182
  21. data/ext/oj/dump_object.c +518 -659
  22. data/ext/oj/dump_strict.c +301 -334
  23. data/ext/oj/encode.h +3 -4
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +27 -24
  26. data/ext/oj/err.h +38 -13
  27. data/ext/oj/extconf.rb +23 -7
  28. data/ext/oj/fast.c +1043 -1073
  29. data/ext/oj/intern.c +313 -0
  30. data/ext/oj/intern.h +22 -0
  31. data/ext/oj/mem.c +318 -0
  32. data/ext/oj/mem.h +53 -0
  33. data/ext/oj/mimic_json.c +449 -423
  34. data/ext/oj/object.c +530 -576
  35. data/ext/oj/odd.c +155 -138
  36. data/ext/oj/odd.h +24 -22
  37. data/ext/oj/oj.c +1331 -993
  38. data/ext/oj/oj.h +306 -292
  39. data/ext/oj/parse.c +934 -938
  40. data/ext/oj/parse.h +73 -70
  41. data/ext/oj/parser.c +1600 -0
  42. data/ext/oj/parser.h +101 -0
  43. data/ext/oj/rails.c +795 -845
  44. data/ext/oj/rails.h +7 -7
  45. data/ext/oj/reader.c +132 -140
  46. data/ext/oj/reader.h +67 -78
  47. data/ext/oj/resolve.c +40 -59
  48. data/ext/oj/resolve.h +3 -2
  49. data/ext/oj/rxclass.c +67 -67
  50. data/ext/oj/rxclass.h +11 -9
  51. data/ext/oj/saj.c +441 -480
  52. data/ext/oj/saj2.c +584 -0
  53. data/ext/oj/saj2.h +23 -0
  54. data/ext/oj/scp.c +78 -111
  55. data/ext/oj/sparse.c +726 -730
  56. data/ext/oj/stream_writer.c +146 -165
  57. data/ext/oj/strict.c +103 -123
  58. data/ext/oj/string_writer.c +241 -253
  59. data/ext/oj/trace.c +29 -33
  60. data/ext/oj/trace.h +41 -11
  61. data/ext/oj/usual.c +1218 -0
  62. data/ext/oj/usual.h +69 -0
  63. data/ext/oj/util.c +103 -103
  64. data/ext/oj/util.h +3 -2
  65. data/ext/oj/val_stack.c +60 -49
  66. data/ext/oj/val_stack.h +79 -85
  67. data/ext/oj/validate.c +46 -0
  68. data/ext/oj/wab.c +307 -350
  69. data/lib/oj/active_support_helper.rb +1 -3
  70. data/lib/oj/bag.rb +8 -1
  71. data/lib/oj/easy_hash.rb +9 -9
  72. data/lib/oj/error.rb +1 -2
  73. data/lib/oj/json.rb +162 -150
  74. data/lib/oj/mimic.rb +9 -19
  75. data/lib/oj/saj.rb +20 -6
  76. data/lib/oj/schandler.rb +5 -4
  77. data/lib/oj/state.rb +12 -8
  78. data/lib/oj/version.rb +1 -2
  79. data/lib/oj.rb +2 -0
  80. data/pages/Compatibility.md +1 -1
  81. data/pages/InstallOptions.md +20 -0
  82. data/pages/JsonGem.md +15 -0
  83. data/pages/Modes.md +8 -3
  84. data/pages/Options.md +43 -5
  85. data/pages/Parser.md +309 -0
  86. data/pages/Rails.md +14 -2
  87. data/test/_test_active.rb +8 -9
  88. data/test/_test_active_mimic.rb +7 -8
  89. data/test/_test_mimic_rails.rb +17 -20
  90. data/test/activerecord/result_test.rb +12 -8
  91. data/test/activesupport6/encoding_test.rb +63 -28
  92. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  93. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  94. data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
  95. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  96. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  97. data/test/files.rb +15 -15
  98. data/test/foo.rb +17 -43
  99. data/test/helper.rb +16 -3
  100. data/test/isolated/shared.rb +3 -2
  101. data/test/json_gem/json_addition_test.rb +2 -2
  102. data/test/json_gem/json_common_interface_test.rb +8 -6
  103. data/test/json_gem/json_encoding_test.rb +0 -0
  104. data/test/json_gem/json_ext_parser_test.rb +1 -0
  105. data/test/json_gem/json_fixtures_test.rb +3 -2
  106. data/test/json_gem/json_generator_test.rb +71 -41
  107. data/test/json_gem/json_generic_object_test.rb +11 -11
  108. data/test/json_gem/json_parser_test.rb +54 -47
  109. data/test/json_gem/json_string_matching_test.rb +9 -9
  110. data/test/json_gem/test_helper.rb +12 -0
  111. data/test/mem.rb +34 -0
  112. data/test/perf.rb +22 -27
  113. data/test/perf_compat.rb +31 -33
  114. data/test/perf_dump.rb +50 -0
  115. data/test/perf_fast.rb +80 -82
  116. data/test/perf_file.rb +27 -29
  117. data/test/perf_object.rb +65 -69
  118. data/test/perf_once.rb +59 -0
  119. data/test/perf_parser.rb +183 -0
  120. data/test/perf_saj.rb +46 -54
  121. data/test/perf_scp.rb +58 -69
  122. data/test/perf_simple.rb +41 -39
  123. data/test/perf_strict.rb +74 -82
  124. data/test/perf_wab.rb +67 -69
  125. data/test/prec.rb +5 -5
  126. data/test/sample/change.rb +0 -1
  127. data/test/sample/dir.rb +0 -1
  128. data/test/sample/doc.rb +0 -1
  129. data/test/sample/file.rb +0 -1
  130. data/test/sample/group.rb +0 -1
  131. data/test/sample/hasprops.rb +0 -1
  132. data/test/sample/layer.rb +0 -1
  133. data/test/sample/rect.rb +0 -1
  134. data/test/sample/shape.rb +0 -1
  135. data/test/sample/text.rb +0 -1
  136. data/test/sample.rb +16 -16
  137. data/test/sample_json.rb +8 -8
  138. data/test/test_compat.rb +97 -45
  139. data/test/test_custom.rb +73 -51
  140. data/test/test_debian.rb +7 -10
  141. data/test/test_fast.rb +135 -79
  142. data/test/test_file.rb +41 -30
  143. data/test/test_gc.rb +16 -5
  144. data/test/test_generate.rb +21 -0
  145. data/test/test_hash.rb +15 -5
  146. data/test/test_integer_range.rb +9 -9
  147. data/test/test_null.rb +20 -20
  148. data/test/test_object.rb +99 -96
  149. data/test/test_parser.rb +11 -0
  150. data/test/test_parser_debug.rb +27 -0
  151. data/test/test_parser_saj.rb +337 -0
  152. data/test/test_parser_usual.rb +251 -0
  153. data/test/test_rails.rb +2 -2
  154. data/test/test_saj.rb +10 -8
  155. data/test/test_scp.rb +38 -40
  156. data/test/test_strict.rb +40 -32
  157. data/test/test_various.rb +165 -84
  158. data/test/test_wab.rb +48 -44
  159. data/test/test_writer.rb +47 -47
  160. data/test/tests.rb +13 -5
  161. data/test/tests_mimic.rb +12 -3
  162. data/test/tests_mimic_addition.rb +12 -3
  163. metadata +75 -127
  164. data/ext/oj/hash.c +0 -135
  165. data/ext/oj/hash.h +0 -18
  166. data/ext/oj/hash_test.c +0 -484
  167. data/test/activesupport4/decoding_test.rb +0 -108
  168. data/test/activesupport4/encoding_test.rb +0 -531
  169. data/test/activesupport4/test_helper.rb +0 -41
  170. data/test/activesupport5/test_helper.rb +0 -72
  171. data/test/bar.rb +0 -35
  172. data/test/baz.rb +0 -16
  173. data/test/zoo.rb +0 -13
data/ext/oj/custom.c CHANGED
@@ -1,4 +1,5 @@
1
1
  // Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
2
3
 
3
4
  #include <stdint.h>
4
5
  #include <stdio.h>
@@ -7,7 +8,8 @@
7
8
  #include "dump.h"
8
9
  #include "encode.h"
9
10
  #include "err.h"
10
- #include "hash.h"
11
+ #include "intern.h"
12
+ #include "mem.h"
11
13
  #include "odd.h"
12
14
  #include "oj.h"
13
15
  #include "parse.h"
@@ -15,212 +17,199 @@
15
17
  #include "trace.h"
16
18
  #include "util.h"
17
19
 
18
- extern void oj_set_obj_ivar(Val parent, Val kval, VALUE value);
19
- extern VALUE oj_parse_xml_time(const char *str, int len); // from object.c
20
+ extern void oj_set_obj_ivar(Val parent, Val kval, VALUE value);
21
+ extern VALUE oj_parse_xml_time(const char *str, int len); // from object.c
20
22
 
21
- static void
22
- dump_obj_str(VALUE obj, int depth, Out out) {
23
- struct _attr attrs[] = {
24
- { "s", 1, Qnil },
25
- { NULL, 0, Qnil },
23
+ static void dump_obj_str(VALUE obj, int depth, Out out) {
24
+ struct _attr attrs[] = {
25
+ {"s", 1, Qnil},
26
+ {NULL, 0, Qnil},
26
27
  };
27
- attrs->value = rb_funcall(obj, oj_to_s_id, 0);
28
+ attrs->value = oj_safe_string_convert(obj);
28
29
 
29
30
  oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
30
31
  }
31
32
 
32
- static void
33
- dump_obj_as_str(VALUE obj, int depth, Out out) {
34
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
35
- const char *str = rb_string_value_ptr((VALUE*)&rstr);
33
+ static void dump_obj_as_str(VALUE obj, int depth, Out out) {
34
+ volatile VALUE rstr = oj_safe_string_convert(obj);
35
+ const char *str = RSTRING_PTR(rstr);
36
36
 
37
37
  oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
38
38
  }
39
39
 
40
- static void
41
- bigdecimal_dump(VALUE obj, int depth, Out out) {
42
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
43
- const char *str = rb_string_value_ptr((VALUE*)&rstr);
44
- int len = (int)RSTRING_LEN(rstr);
40
+ static void bigdecimal_dump(VALUE obj, int depth, Out out) {
41
+ volatile VALUE rstr = oj_safe_string_convert(obj);
42
+ const char *str = RSTRING_PTR(rstr);
43
+ int len = (int)RSTRING_LEN(rstr);
45
44
 
46
45
  if (0 == strcasecmp("Infinity", str)) {
47
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
48
- oj_dump_raw(str, len, out);
46
+ str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
47
+ oj_dump_raw(str, len, out);
49
48
  } else if (0 == strcasecmp("-Infinity", str)) {
50
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
51
- oj_dump_raw(str, len, out);
49
+ str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
50
+ oj_dump_raw(str, len, out);
52
51
  } else if (No == out->opts->bigdec_as_num) {
53
- oj_dump_cstr(str, len, 0, 0, out);
52
+ oj_dump_cstr(str, len, 0, 0, out);
54
53
  } else {
55
- oj_dump_raw(str, len, out);
54
+ oj_dump_raw(str, len, out);
56
55
  }
57
56
  }
58
57
 
59
- static ID real_id = 0;
60
- static ID imag_id = 0;
58
+ static ID real_id = 0;
59
+ static ID imag_id = 0;
61
60
 
62
- static void
63
- complex_dump(VALUE obj, int depth, Out out) {
61
+ static void complex_dump(VALUE obj, int depth, Out out) {
64
62
  if (NULL != out->opts->create_id) {
65
- struct _attr attrs[] = {
66
- { "real", 4, Qnil },
67
- { "imag", 4, Qnil },
68
- { NULL, 0, Qnil },
69
- };
70
- if (0 == real_id) {
71
- real_id = rb_intern("real");
72
- imag_id = rb_intern("imag");
73
- }
74
- attrs[0].value = rb_funcall(obj, real_id, 0);
75
- attrs[1].value = rb_funcall(obj, imag_id, 0);
76
-
77
- oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
63
+ struct _attr attrs[] = {
64
+ {"real", 4, Qnil},
65
+ {"imag", 4, Qnil},
66
+ {NULL, 0, Qnil},
67
+ };
68
+ if (0 == real_id) {
69
+ real_id = rb_intern("real");
70
+ imag_id = rb_intern("imag");
71
+ }
72
+ attrs[0].value = rb_funcall(obj, real_id, 0);
73
+ attrs[1].value = rb_funcall(obj, imag_id, 0);
74
+
75
+ oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
78
76
  } else {
79
- dump_obj_as_str(obj, depth, out);
77
+ dump_obj_as_str(obj, depth, out);
80
78
  }
81
79
  }
82
80
 
83
- static VALUE
84
- complex_load(VALUE clas, VALUE args) {
81
+ static VALUE complex_load(VALUE clas, VALUE args) {
85
82
  if (0 == real_id) {
86
- real_id = rb_intern("real");
87
- imag_id = rb_intern("imag");
83
+ real_id = rb_intern("real");
84
+ imag_id = rb_intern("imag");
88
85
  }
89
86
  return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)), rb_hash_aref(args, rb_id2str(imag_id)));
90
87
  }
91
88
 
92
- static void
93
- time_dump(VALUE obj, int depth, Out out) {
89
+ static void time_dump(VALUE obj, int depth, Out out) {
94
90
  if (Yes == out->opts->create_ok) {
95
- struct _attr attrs[] = {
96
- { "time", 4, Qundef, 0, Qundef },
97
- { NULL, 0, Qnil },
98
- };
99
- attrs->time = obj;
91
+ struct _attr attrs[] = {
92
+ {"time", 4, Qundef, 0, Qundef},
93
+ {NULL, 0, Qnil},
94
+ };
95
+ attrs->time = obj;
100
96
 
101
- oj_code_attrs(obj, attrs, depth, out, true);
97
+ oj_code_attrs(obj, attrs, depth, out, true);
102
98
  } else {
103
- switch (out->opts->time_format) {
104
- case RubyTime: oj_dump_ruby_time(obj, out); break;
105
- case XmlTime: oj_dump_xml_time(obj, out); break;
106
- case UnixZTime: oj_dump_time(obj, out, true); break;
107
- case UnixTime:
108
- default: oj_dump_time(obj, out, false); break;
109
- }
99
+ switch (out->opts->time_format) {
100
+ case RubyTime: oj_dump_ruby_time(obj, out); break;
101
+ case XmlTime: oj_dump_xml_time(obj, out); break;
102
+ case UnixZTime: oj_dump_time(obj, out, true); break;
103
+ case UnixTime:
104
+ default: oj_dump_time(obj, out, false); break;
105
+ }
110
106
  }
111
107
  }
112
108
 
113
- static void
114
- date_dump(VALUE obj, int depth, Out out) {
109
+ static void date_dump(VALUE obj, int depth, Out out) {
115
110
  if (Yes == out->opts->create_ok) {
116
- struct _attr attrs[] = {
117
- { "s", 1, Qnil },
118
- { NULL, 0, Qnil },
119
- };
120
- attrs->value = rb_funcall(obj, rb_intern("iso8601"), 0);
111
+ struct _attr attrs[] = {
112
+ {"s", 1, Qnil},
113
+ {NULL, 0, Qnil},
114
+ };
115
+ attrs->value = rb_funcall(obj, rb_intern("iso8601"), 0);
121
116
 
122
- oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
117
+ oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
123
118
  } else {
124
- volatile VALUE v;
125
- volatile VALUE ov;
126
-
127
- switch (out->opts->time_format) {
128
- case RubyTime:
129
- case XmlTime:
130
- v = rb_funcall(obj, rb_intern("iso8601"), 0);
131
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&v), (int)RSTRING_LEN(v), 0, 0, out);
132
- break;
133
- case UnixZTime:
134
- v = rb_funcall(obj, rb_intern("to_time"), 0);
135
- if (oj_date_class == rb_obj_class(obj)) {
136
- ov = rb_funcall(v, rb_intern("utc_offset"), 0);
137
- v = rb_funcall(v, rb_intern("utc"), 0);
138
- v = rb_funcall(v, rb_intern("+"), 1, ov);
139
- oj_dump_time(v, out, false);
140
- } else {
141
- oj_dump_time(v, out, true);
142
- }
143
- break;
144
- case UnixTime:
145
- default:
146
- v = rb_funcall(obj, rb_intern("to_time"), 0);
147
- if (oj_date_class == rb_obj_class(obj)) {
148
- ov = rb_funcall(v, rb_intern("utc_offset"), 0);
149
- v = rb_funcall(v, rb_intern("utc"), 0);
150
- v = rb_funcall(v, rb_intern("+"), 1, ov);
151
- }
152
- oj_dump_time(v, out, false);
153
- break;
154
- }
119
+ volatile VALUE v;
120
+ volatile VALUE ov;
121
+
122
+ switch (out->opts->time_format) {
123
+ case RubyTime:
124
+ case XmlTime:
125
+ v = rb_funcall(obj, rb_intern("iso8601"), 0);
126
+ oj_dump_cstr(RSTRING_PTR(v), (int)RSTRING_LEN(v), 0, 0, out);
127
+ break;
128
+ case UnixZTime:
129
+ v = rb_funcall(obj, rb_intern("to_time"), 0);
130
+ if (oj_date_class == rb_obj_class(obj)) {
131
+ ov = rb_funcall(v, rb_intern("utc_offset"), 0);
132
+ v = rb_funcall(v, rb_intern("utc"), 0);
133
+ v = rb_funcall(v, rb_intern("+"), 1, ov);
134
+ oj_dump_time(v, out, false);
135
+ } else {
136
+ oj_dump_time(v, out, true);
137
+ }
138
+ break;
139
+ case UnixTime:
140
+ default:
141
+ v = rb_funcall(obj, rb_intern("to_time"), 0);
142
+ if (oj_date_class == rb_obj_class(obj)) {
143
+ ov = rb_funcall(v, rb_intern("utc_offset"), 0);
144
+ v = rb_funcall(v, rb_intern("utc"), 0);
145
+ v = rb_funcall(v, rb_intern("+"), 1, ov);
146
+ }
147
+ oj_dump_time(v, out, false);
148
+ break;
149
+ }
155
150
  }
156
151
  }
157
152
 
158
- static VALUE
159
- date_load(VALUE clas, VALUE args) {
160
- volatile VALUE v;
153
+ static VALUE date_load(VALUE clas, VALUE args) {
154
+ volatile VALUE v;
161
155
 
162
156
  if (Qnil != (v = rb_hash_aref(args, rb_str_new2("s")))) {
163
- return rb_funcall(oj_date_class, rb_intern("parse"), 1, v);
157
+ return rb_funcall(oj_date_class, rb_intern("parse"), 1, v);
164
158
  }
165
159
  return Qnil;
166
160
  }
167
161
 
168
- static VALUE
169
- datetime_load(VALUE clas, VALUE args) {
170
- volatile VALUE v;
162
+ static VALUE datetime_load(VALUE clas, VALUE args) {
163
+ volatile VALUE v;
171
164
 
172
165
  if (Qnil != (v = rb_hash_aref(args, rb_str_new2("s")))) {
173
- return rb_funcall(oj_datetime_class, rb_intern("parse"), 1, v);
166
+ return rb_funcall(oj_datetime_class, rb_intern("parse"), 1, v);
174
167
  }
175
168
  return Qnil;
176
169
  }
177
170
 
178
- static ID table_id = 0;
171
+ static ID table_id = 0;
179
172
 
180
- static void
181
- openstruct_dump(VALUE obj, int depth, Out out) {
182
- struct _attr attrs[] = {
183
- { "table", 5, Qnil },
184
- { NULL, 0, Qnil },
173
+ static void openstruct_dump(VALUE obj, int depth, Out out) {
174
+ struct _attr attrs[] = {
175
+ {"table", 5, Qnil},
176
+ {NULL, 0, Qnil},
185
177
  };
186
178
  if (0 == table_id) {
187
- table_id = rb_intern("table");
179
+ table_id = rb_intern("table");
188
180
  }
189
181
  attrs->value = rb_funcall(obj, table_id, 0);
190
182
 
191
183
  oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
192
184
  }
193
185
 
194
- static VALUE
195
- openstruct_load(VALUE clas, VALUE args) {
186
+ static VALUE openstruct_load(VALUE clas, VALUE args) {
196
187
  if (0 == table_id) {
197
- table_id = rb_intern("table");
188
+ table_id = rb_intern("table");
198
189
  }
199
190
  return rb_funcall(clas, oj_new_id, 1, rb_hash_aref(args, rb_id2str(table_id)));
200
191
  }
201
192
 
202
- static void
203
- range_dump(VALUE obj, int depth, Out out) {
193
+ static void range_dump(VALUE obj, int depth, Out out) {
204
194
  if (NULL != out->opts->create_id) {
205
- struct _attr attrs[] = {
206
- { "begin", 5, Qnil },
207
- { "end", 3, Qnil },
208
- { "exclude", 7, Qnil },
209
- { NULL, 0, Qnil },
210
- };
211
- attrs[0].value = rb_funcall(obj, oj_begin_id, 0);
212
- attrs[1].value = rb_funcall(obj, oj_end_id, 0);
213
- attrs[2].value = rb_funcall(obj, oj_exclude_end_id, 0);
214
-
215
- oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
195
+ struct _attr attrs[] = {
196
+ {"begin", 5, Qnil},
197
+ {"end", 3, Qnil},
198
+ {"exclude", 7, Qnil},
199
+ {NULL, 0, Qnil},
200
+ };
201
+ attrs[0].value = rb_funcall(obj, oj_begin_id, 0);
202
+ attrs[1].value = rb_funcall(obj, oj_end_id, 0);
203
+ attrs[2].value = rb_funcall(obj, oj_exclude_end_id, 0);
204
+
205
+ oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
216
206
  } else {
217
- dump_obj_as_str(obj, depth, out);
207
+ dump_obj_as_str(obj, depth, out);
218
208
  }
219
209
  }
220
210
 
221
- static VALUE
222
- range_load(VALUE clas, VALUE args) {
223
- VALUE nargs[3];
211
+ static VALUE range_load(VALUE clas, VALUE args) {
212
+ VALUE nargs[3];
224
213
 
225
214
  nargs[0] = rb_hash_aref(args, rb_id2str(oj_begin_id));
226
215
  nargs[1] = rb_hash_aref(args, rb_id2str(oj_end_id));
@@ -229,985 +218,854 @@ range_load(VALUE clas, VALUE args) {
229
218
  return rb_class_new_instance(3, nargs, rb_cRange);
230
219
  }
231
220
 
232
- static ID numerator_id = 0;
233
- static ID denominator_id = 0;
221
+ static ID numerator_id = 0;
222
+ static ID denominator_id = 0;
234
223
 
235
- static void
236
- rational_dump(VALUE obj, int depth, Out out) {
224
+ static void rational_dump(VALUE obj, int depth, Out out) {
237
225
  if (NULL != out->opts->create_id) {
238
- struct _attr attrs[] = {
239
- { "numerator", 9, Qnil },
240
- { "denominator", 11, Qnil },
241
- { NULL, 0, Qnil },
242
- };
243
- if (0 == numerator_id) {
244
- numerator_id = rb_intern("numerator");
245
- denominator_id = rb_intern("denominator");
246
- }
247
- attrs[0].value = rb_funcall(obj, numerator_id, 0);
248
- attrs[1].value = rb_funcall(obj, denominator_id, 0);
249
-
250
- oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
226
+ struct _attr attrs[] = {
227
+ {"numerator", 9, Qnil},
228
+ {"denominator", 11, Qnil},
229
+ {NULL, 0, Qnil},
230
+ };
231
+ if (0 == numerator_id) {
232
+ numerator_id = rb_intern("numerator");
233
+ denominator_id = rb_intern("denominator");
234
+ }
235
+ attrs[0].value = rb_funcall(obj, numerator_id, 0);
236
+ attrs[1].value = rb_funcall(obj, denominator_id, 0);
237
+
238
+ oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
251
239
  } else {
252
- dump_obj_as_str(obj, depth, out);
240
+ dump_obj_as_str(obj, depth, out);
253
241
  }
254
242
  }
255
243
 
256
- static VALUE
257
- rational_load(VALUE clas, VALUE args) {
244
+ static VALUE rational_load(VALUE clas, VALUE args) {
258
245
  if (0 == numerator_id) {
259
- numerator_id = rb_intern("numerator");
260
- denominator_id = rb_intern("denominator");
246
+ numerator_id = rb_intern("numerator");
247
+ denominator_id = rb_intern("denominator");
261
248
  }
262
- return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)),
263
- rb_hash_aref(args, rb_id2str(denominator_id)));
249
+ return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)), rb_hash_aref(args, rb_id2str(denominator_id)));
264
250
  }
265
251
 
266
- static VALUE
267
- regexp_load(VALUE clas, VALUE args) {
268
- volatile VALUE v;
252
+ static VALUE regexp_load(VALUE clas, VALUE args) {
253
+ volatile VALUE v;
269
254
 
270
255
  if (Qnil != (v = rb_hash_aref(args, rb_str_new2("s")))) {
271
- return rb_funcall(rb_cRegexp, oj_new_id, 1, v);
256
+ return rb_funcall(rb_cRegexp, oj_new_id, 1, v);
272
257
  }
273
258
  return Qnil;
274
259
  }
275
260
 
276
- static VALUE
277
- time_load(VALUE clas, VALUE args) {
261
+ static VALUE time_load(VALUE clas, VALUE args) {
278
262
  // Value should have already been replaced in one of the hash_set_xxx
279
263
  // functions.
280
264
  return args;
281
265
  }
282
266
 
283
- static struct _code codes[] = {
284
- { "BigDecimal", Qnil, bigdecimal_dump, NULL, true },
285
- { "Complex", Qnil, complex_dump, complex_load, true },
286
- { "Date", Qnil, date_dump, date_load, true },
287
- { "DateTime", Qnil, date_dump, datetime_load, true },
288
- { "OpenStruct", Qnil, openstruct_dump, openstruct_load, true },
289
- { "Range", Qnil, range_dump, range_load, true },
290
- { "Rational", Qnil, rational_dump, rational_load, true },
291
- { "Regexp", Qnil, dump_obj_str, regexp_load, true },
292
- { "Time", Qnil, time_dump, time_load, true },
293
- { NULL, Qundef, NULL, NULL, false },
267
+ static struct _code codes[] = {
268
+ {"BigDecimal", Qnil, bigdecimal_dump, NULL, true},
269
+ {"Complex", Qnil, complex_dump, complex_load, true},
270
+ {"Date", Qnil, date_dump, date_load, true},
271
+ {"DateTime", Qnil, date_dump, datetime_load, true},
272
+ {"OpenStruct", Qnil, openstruct_dump, openstruct_load, true},
273
+ {"Range", Qnil, range_dump, range_load, true},
274
+ {"Rational", Qnil, rational_dump, rational_load, true},
275
+ {"Regexp", Qnil, dump_obj_str, regexp_load, true},
276
+ {"Time", Qnil, time_dump, time_load, true},
277
+ {NULL, Qundef, NULL, NULL, false},
294
278
  };
295
279
 
296
- static int
297
- hash_cb(VALUE key, VALUE value, VALUE ov) {
298
- Out out = (Out)ov;
299
- int depth = out->depth;
280
+ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
281
+ Out out = (Out)ov;
282
+ int depth = out->depth;
300
283
 
301
- if (oj_dump_ignore(out->opts, value)) {
302
- return ST_CONTINUE;
284
+ if (dump_ignore(out->opts, value)) {
285
+ return ST_CONTINUE;
303
286
  }
304
287
  if (out->omit_nil && Qnil == value) {
305
- return ST_CONTINUE;
288
+ return ST_CONTINUE;
306
289
  }
307
290
  if (!out->opts->dump_opts.use) {
308
- assure_size(out, depth * out->indent + 1);
309
- fill_indent(out, depth);
291
+ assure_size(out, depth * out->indent + 1);
292
+ fill_indent(out, depth);
310
293
  } else {
311
- assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
312
- if (0 < out->opts->dump_opts.hash_size) {
313
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
314
- out->cur += out->opts->dump_opts.hash_size;
315
- }
316
- if (0 < out->opts->dump_opts.indent_size) {
317
- int i;
318
-
319
- for (i = depth; 0 < i; i--) {
320
- strcpy(out->cur, out->opts->dump_opts.indent_str);
321
- out->cur += out->opts->dump_opts.indent_size;
322
- }
323
- }
294
+ assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
295
+ if (0 < out->opts->dump_opts.hash_size) {
296
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
297
+ }
298
+ if (0 < out->opts->dump_opts.indent_size) {
299
+ int i;
300
+
301
+ for (i = depth; 0 < i; i--) {
302
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
303
+ }
304
+ }
324
305
  }
325
306
  switch (rb_type(key)) {
326
- case T_STRING:
327
- oj_dump_str(key, 0, out, false);
328
- break;
329
- case T_SYMBOL:
330
- oj_dump_sym(key, 0, out, false);
331
- break;
332
- default:
333
- oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false);
334
- break;
307
+ case T_STRING: oj_dump_str(key, 0, out, false); break;
308
+ case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
309
+ default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
335
310
  }
336
311
  if (!out->opts->dump_opts.use) {
337
- *out->cur++ = ':';
312
+ *out->cur++ = ':';
338
313
  } else {
339
- assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2);
340
- if (0 < out->opts->dump_opts.before_size) {
341
- strcpy(out->cur, out->opts->dump_opts.before_sep);
342
- out->cur += out->opts->dump_opts.before_size;
343
- }
344
- *out->cur++ = ':';
345
- if (0 < out->opts->dump_opts.after_size) {
346
- strcpy(out->cur, out->opts->dump_opts.after_sep);
347
- out->cur += out->opts->dump_opts.after_size;
348
- }
314
+ assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2);
315
+ if (0 < out->opts->dump_opts.before_size) {
316
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
317
+ }
318
+ *out->cur++ = ':';
319
+ if (0 < out->opts->dump_opts.after_size) {
320
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
321
+ }
349
322
  }
350
323
  oj_dump_custom_val(value, depth, out, true);
351
- out->depth = depth;
324
+ out->depth = depth;
352
325
  *out->cur++ = ',';
353
326
 
354
327
  return ST_CONTINUE;
355
328
  }
356
329
 
357
- static void
358
- dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
359
- int cnt;
360
- long id = oj_check_circular(obj, out);
330
+ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
331
+ int cnt;
332
+ long id = oj_check_circular(obj, out);
361
333
 
362
334
  if (0 > id) {
363
- oj_dump_nil(Qnil, depth, out, false);
364
- return;
335
+ oj_dump_nil(Qnil, depth, out, false);
336
+ return;
365
337
  }
366
338
  cnt = (int)RHASH_SIZE(obj);
367
339
  assure_size(out, 2);
368
340
  if (0 == cnt) {
369
- *out->cur++ = '{';
370
- *out->cur++ = '}';
341
+ APPEND_CHARS(out->cur, "{}", 2);
371
342
  } else {
372
- *out->cur++ = '{';
373
- out->depth = depth + 1;
374
- rb_hash_foreach(obj, hash_cb, (VALUE)out);
375
- if (',' == *(out->cur - 1)) {
376
- out->cur--; // backup to overwrite last comma
377
- }
378
- if (!out->opts->dump_opts.use) {
379
- assure_size(out, depth * out->indent + 2);
380
- fill_indent(out, depth);
381
- } else {
382
- assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
383
- if (0 < out->opts->dump_opts.hash_size) {
384
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
385
- out->cur += out->opts->dump_opts.hash_size;
386
- }
387
- if (0 < out->opts->dump_opts.indent_size) {
388
- int i;
389
-
390
- for (i = depth; 0 < i; i--) {
391
- strcpy(out->cur, out->opts->dump_opts.indent_str);
392
- out->cur += out->opts->dump_opts.indent_size;
393
- }
394
- }
395
- }
396
- *out->cur++ = '}';
343
+ *out->cur++ = '{';
344
+ out->depth = depth + 1;
345
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
346
+ if (',' == *(out->cur - 1)) {
347
+ out->cur--; // backup to overwrite last comma
348
+ }
349
+ if (!out->opts->dump_opts.use) {
350
+ assure_size(out, depth * out->indent + 2);
351
+ fill_indent(out, depth);
352
+ } else {
353
+ assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
354
+ if (0 < out->opts->dump_opts.hash_size) {
355
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
356
+ }
357
+ if (0 < out->opts->dump_opts.indent_size) {
358
+ int i;
359
+
360
+ for (i = depth; 0 < i; i--) {
361
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
362
+ }
363
+ }
364
+ }
365
+ *out->cur++ = '}';
397
366
  }
398
367
  *out->cur = '\0';
399
368
  }
400
369
 
401
- static void
402
- dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
403
- ID *idp;
404
- AttrGetFunc *fp;
405
- volatile VALUE v;
406
- const char *name;
407
- size_t size;
408
- int d2 = depth + 1;
370
+ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
371
+ ID *idp;
372
+ AttrGetFunc *fp;
373
+ volatile VALUE v;
374
+ const char *name;
375
+ size_t size;
376
+ int d2 = depth + 1;
409
377
 
410
378
  assure_size(out, 2);
411
379
  *out->cur++ = '{';
412
380
  if (NULL != out->opts->create_id && Yes == out->opts->create_ok) {
413
- const char *classname = rb_class2name(clas);
414
- int clen = (int)strlen(classname);
415
- size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
416
-
417
- size = d2 * out->indent + 10 + clen + out->opts->create_id_len + sep_len;
418
- assure_size(out, size);
419
- fill_indent(out, d2);
420
- *out->cur++ = '"';
421
- memcpy(out->cur, out->opts->create_id, out->opts->create_id_len);
422
- out->cur += out->opts->create_id_len;
423
- *out->cur++ = '"';
424
- if (0 < out->opts->dump_opts.before_size) {
425
- strcpy(out->cur, out->opts->dump_opts.before_sep);
426
- out->cur += out->opts->dump_opts.before_size;
427
- }
428
- *out->cur++ = ':';
429
- if (0 < out->opts->dump_opts.after_size) {
430
- strcpy(out->cur, out->opts->dump_opts.after_sep);
431
- out->cur += out->opts->dump_opts.after_size;
432
- }
433
- *out->cur++ = '"';
434
- memcpy(out->cur, classname, clen);
435
- out->cur += clen;
436
- *out->cur++ = '"';
437
- *out->cur++ = ',';
381
+ const char *classname = rb_class2name(clas);
382
+ int clen = (int)strlen(classname);
383
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
384
+
385
+ size = d2 * out->indent + 10 + clen + out->opts->create_id_len + sep_len;
386
+ assure_size(out, size);
387
+ fill_indent(out, d2);
388
+ *out->cur++ = '"';
389
+ APPEND_CHARS(out->cur, out->opts->create_id, out->opts->create_id_len);
390
+ *out->cur++ = '"';
391
+ if (0 < out->opts->dump_opts.before_size) {
392
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
393
+ }
394
+ *out->cur++ = ':';
395
+ if (0 < out->opts->dump_opts.after_size) {
396
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
397
+ }
398
+ *out->cur++ = '"';
399
+ APPEND_CHARS(out->cur, classname, clen);
400
+ APPEND_CHARS(out->cur, "\",", 2);
438
401
  }
439
402
  if (odd->raw) {
440
- v = rb_funcall(obj, *odd->attrs, 0);
441
- if (Qundef == v || T_STRING != rb_type(v)) {
442
- rb_raise(rb_eEncodingError, "Invalid type for raw JSON.\n");
443
- } else {
444
- const char *s = rb_string_value_ptr((VALUE*)&v);
445
- int len = (int)RSTRING_LEN(v);
446
- const char *name = rb_id2name(*odd->attrs);
447
- size_t nlen = strlen(name);
448
-
449
- size = len + d2 * out->indent + nlen + 10;
450
- assure_size(out, size);
451
- fill_indent(out, d2);
452
- *out->cur++ = '"';
453
- memcpy(out->cur, name, nlen);
454
- out->cur += nlen;
455
- *out->cur++ = '"';
456
- *out->cur++ = ':';
457
- memcpy(out->cur, s, len);
458
- out->cur += len;
459
- *out->cur = '\0';
460
- }
403
+ v = rb_funcall(obj, *odd->attrs, 0);
404
+ if (Qundef == v || T_STRING != rb_type(v)) {
405
+ rb_raise(rb_eEncodingError, "Invalid type for raw JSON.\n");
406
+ } else {
407
+ const char *s = RSTRING_PTR(v);
408
+ int len = (int)RSTRING_LEN(v);
409
+ const char *name = rb_id2name(*odd->attrs);
410
+ size_t nlen = strlen(name);
411
+
412
+ size = len + d2 * out->indent + nlen + 10;
413
+ assure_size(out, size);
414
+ fill_indent(out, d2);
415
+ *out->cur++ = '"';
416
+ APPEND_CHARS(out->cur, name, nlen);
417
+ APPEND_CHARS(out->cur, "\":", 2);
418
+ APPEND_CHARS(out->cur, s, len);
419
+ *out->cur = '\0';
420
+ }
461
421
  } else {
462
- size = d2 * out->indent + 1;
463
- for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) {
464
- size_t nlen;
465
-
466
- assure_size(out, size);
467
- name = rb_id2name(*idp);
468
- nlen = strlen(name);
469
- if (0 != *fp) {
470
- v = (*fp)(obj);
471
- } else if (0 == strchr(name, '.')) {
472
- v = rb_funcall(obj, *idp, 0);
473
- } else {
474
- char nbuf[256];
475
- char *n2 = nbuf;
476
- char *n;
477
- char *end;
478
- ID i;
479
-
480
- if (sizeof(nbuf) <= nlen) {
481
- if (NULL == (n2 = strdup(name))) {
482
- rb_raise(rb_eNoMemError, "for attribute name.");
483
- }
484
- } else {
485
- strcpy(n2, name);
486
- }
487
- n = n2;
488
- v = obj;
489
- while (0 != (end = strchr(n, '.'))) {
490
- *end = '\0';
491
- i = rb_intern(n);
492
- v = rb_funcall(v, i, 0);
493
- n = end + 1;
494
- }
495
- i = rb_intern(n);
496
- v = rb_funcall(v, i, 0);
497
- if (nbuf != n2) {
498
- free(n2);
499
- }
500
- }
501
- fill_indent(out, d2);
502
- oj_dump_cstr(name, nlen, 0, 0, out);
503
- *out->cur++ = ':';
504
- oj_dump_custom_val(v, d2, out, true);
505
- assure_size(out, 2);
506
- *out->cur++ = ',';
507
- }
508
- out->cur--;
422
+ size = d2 * out->indent + 1;
423
+ for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) {
424
+ size_t nlen;
425
+
426
+ assure_size(out, size);
427
+ name = rb_id2name(*idp);
428
+ nlen = strlen(name);
429
+ if (0 != *fp) {
430
+ v = (*fp)(obj);
431
+ } else if (0 == strchr(name, '.')) {
432
+ v = rb_funcall(obj, *idp, 0);
433
+ } else {
434
+ char nbuf[256];
435
+ char *n2 = nbuf;
436
+ char *n;
437
+ char *end;
438
+ ID i;
439
+
440
+ if (sizeof(nbuf) <= nlen) {
441
+ if (NULL == (n2 = OJ_STRDUP(name))) {
442
+ rb_raise(rb_eNoMemError, "for attribute name.");
443
+ }
444
+ } else {
445
+ strcpy(n2, name);
446
+ }
447
+ n = n2;
448
+ v = obj;
449
+ while (0 != (end = strchr(n, '.'))) {
450
+ *end = '\0';
451
+ i = rb_intern(n);
452
+ v = rb_funcall(v, i, 0);
453
+ n = end + 1;
454
+ }
455
+ i = rb_intern(n);
456
+ v = rb_funcall(v, i, 0);
457
+ if (nbuf != n2) {
458
+ OJ_FREE(n2);
459
+ }
460
+ }
461
+ fill_indent(out, d2);
462
+ oj_dump_cstr(name, nlen, 0, 0, out);
463
+ *out->cur++ = ':';
464
+ oj_dump_custom_val(v, d2, out, true);
465
+ assure_size(out, 2);
466
+ *out->cur++ = ',';
467
+ }
468
+ out->cur--;
509
469
  }
510
470
  *out->cur++ = '}';
511
- *out->cur = '\0';
471
+ *out->cur = '\0';
512
472
  }
513
473
 
514
474
  // Return class if still needs dumping.
515
- static VALUE
516
- dump_common(VALUE obj, int depth, Out out) {
517
-
475
+ static VALUE dump_common(VALUE obj, int depth, Out out) {
518
476
  if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
519
- oj_dump_raw_json(obj, depth, out);
477
+ oj_dump_raw_json(obj, depth, out);
520
478
  } else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
521
- volatile VALUE rs;
522
- const char *s;
523
- int len;
524
-
525
- if (Yes == out->opts->trace) {
526
- oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
527
- }
528
- if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
529
- rs = rb_funcall(obj, oj_to_json_id, 0);
530
- } else {
531
- rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
532
- }
533
- if (Yes == out->opts->trace) {
534
- oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
535
- }
536
- s = rb_string_value_ptr((VALUE*)&rs);
537
- len = (int)RSTRING_LEN(rs);
538
-
539
- assure_size(out, len + 1);
540
- memcpy(out->cur, s, len);
541
- out->cur += len;
542
- *out->cur = '\0';
479
+ volatile VALUE rs;
480
+ const char *s;
481
+ int len;
482
+
483
+ TRACE(out->opts->trace, "to_json", obj, depth + 1, TraceRubyIn);
484
+ if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
485
+ rs = rb_funcall(obj, oj_to_json_id, 0);
486
+ } else {
487
+ rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
488
+ }
489
+ TRACE(out->opts->trace, "to_json", obj, depth + 1, TraceRubyOut);
490
+ s = RSTRING_PTR(rs);
491
+ len = (int)RSTRING_LEN(rs);
492
+
493
+ assure_size(out, len + 1);
494
+ APPEND_CHARS(out->cur, s, len);
495
+ *out->cur = '\0';
543
496
  } else if (Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
544
- volatile VALUE aj;
545
-
546
- if (Yes == out->opts->trace) {
547
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
548
- }
549
- // Some classes elect to not take an options argument so check the arity
550
- // of as_json.
551
- if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
552
- aj = rb_funcall(obj, oj_as_json_id, 0);
553
- } else {
554
- aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
555
- }
556
- if (Yes == out->opts->trace) {
557
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
558
- }
559
- // Catch the obvious brain damaged recursive dumping.
560
- if (aj == obj) {
561
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
562
-
563
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), false, false, out);
564
- } else {
565
- oj_dump_custom_val(aj, depth, out, true);
566
- }
497
+ volatile VALUE aj;
498
+
499
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyIn);
500
+ // Some classes elect to not take an options argument so check the arity
501
+ // of as_json.
502
+ if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
503
+ aj = rb_funcall(obj, oj_as_json_id, 0);
504
+ } else {
505
+ aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
506
+ }
507
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyOut);
508
+ // Catch the obvious brain damaged recursive dumping.
509
+ if (aj == obj) {
510
+ volatile VALUE rstr = oj_safe_string_convert(obj);
511
+
512
+ oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), false, false, out);
513
+ } else {
514
+ oj_dump_custom_val(aj, depth, out, true);
515
+ }
567
516
  } else if (Yes == out->opts->to_hash && rb_respond_to(obj, oj_to_hash_id)) {
568
- volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
569
-
570
- if (T_HASH != rb_type(h)) {
571
- // It seems that ActiveRecord implemented to_hash so that it returns
572
- // an Array and not a Hash. To get around that any value returned
573
- // will be dumped.
574
-
575
- //rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n", rb_class2name(rb_obj_class(obj)));
576
- oj_dump_custom_val(h, depth, out, false);
577
- } else {
578
- dump_hash(h, depth, out, true);
579
- }
517
+ volatile VALUE h = rb_funcall(obj, oj_to_hash_id, 0);
518
+
519
+ if (T_HASH != rb_type(h)) {
520
+ // It seems that ActiveRecord implemented to_hash so that it returns
521
+ // an Array and not a Hash. To get around that any value returned
522
+ // will be dumped.
523
+
524
+ // rb_raise(rb_eTypeError, "%s.to_hash() did not return a Hash.\n",
525
+ // rb_class2name(rb_obj_class(obj)));
526
+ oj_dump_custom_val(h, depth, out, false);
527
+ } else {
528
+ dump_hash(h, depth, out, true);
529
+ }
580
530
  } else if (!oj_code_dump(codes, obj, depth, out)) {
581
- VALUE clas = rb_obj_class(obj);
582
- Odd odd = oj_get_odd(clas);
531
+ VALUE clas = rb_obj_class(obj);
532
+ Odd odd = oj_get_odd(clas);
583
533
 
584
- if (NULL == odd) {
585
- return clas;
586
- }
587
- dump_odd(obj, odd, clas, depth + 1, out);
534
+ if (NULL == odd) {
535
+ return clas;
536
+ }
537
+ dump_odd(obj, odd, clas, depth + 1, out);
588
538
  }
589
539
  return Qnil;
590
540
  }
591
541
 
592
- static int
593
- dump_attr_cb(ID key, VALUE value, VALUE ov) {
594
- Out out = (Out)ov;
595
- int depth = out->depth;
596
- size_t size;
597
- const char *attr;
542
+ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
543
+ Out out = (Out)ov;
544
+ int depth = out->depth;
545
+ size_t size;
546
+ const char *attr;
598
547
 
599
- if (oj_dump_ignore(out->opts, value)) {
600
- return ST_CONTINUE;
548
+ if (dump_ignore(out->opts, value)) {
549
+ return ST_CONTINUE;
601
550
  }
602
551
  if (out->omit_nil && Qnil == value) {
603
- return ST_CONTINUE;
552
+ return ST_CONTINUE;
604
553
  }
605
554
  size = depth * out->indent + 1;
606
555
  attr = rb_id2name(key);
607
556
  // Some exceptions such as NoMethodError have an invisible attribute where
608
557
  // the key name is NULL. Not an empty string but NULL.
609
558
  if (NULL == attr) {
610
- attr = "";
559
+ attr = "";
611
560
  } else if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) {
612
- return ST_CONTINUE;
561
+ return ST_CONTINUE;
613
562
  }
614
563
  if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) {
615
- return ST_CONTINUE;
564
+ return ST_CONTINUE;
616
565
  }
617
566
  assure_size(out, size);
618
567
  fill_indent(out, depth);
619
568
  if ('@' == *attr) {
620
- attr++;
621
- oj_dump_cstr(attr, strlen(attr), 0, 0, out);
569
+ attr++;
570
+ oj_dump_cstr(attr, strlen(attr), 0, 0, out);
622
571
  } else {
623
- char buf[32];
572
+ char buf[32];
624
573
 
625
- *buf = '~';
626
- strncpy(buf + 1, attr, sizeof(buf) - 2);
627
- buf[sizeof(buf) - 1] = '\0';
628
- oj_dump_cstr(buf, strlen(buf), 0, 0, out);
574
+ *buf = '~';
575
+ strncpy(buf + 1, attr, sizeof(buf) - 2);
576
+ buf[sizeof(buf) - 1] = '\0';
577
+ oj_dump_cstr(buf, strlen(buf), 0, 0, out);
629
578
  }
630
579
  *out->cur++ = ':';
631
580
  oj_dump_custom_val(value, depth, out, true);
632
- out->depth = depth;
581
+ out->depth = depth;
633
582
  *out->cur++ = ',';
634
583
 
635
584
  return ST_CONTINUE;
636
585
  }
637
586
 
638
- static void
639
- dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
640
- size_t size = 0;
641
- int d2 = depth + 1;
642
- int cnt;
643
- bool class_written = false;
587
+ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
588
+ size_t size = 0;
589
+ int d2 = depth + 1;
590
+ int cnt;
591
+ bool class_written = false;
644
592
 
645
593
  assure_size(out, 2);
646
594
  *out->cur++ = '{';
647
595
  if (Qundef != clas && NULL != out->opts->create_id && Yes == out->opts->create_ok) {
648
- size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
649
- const char *classname = rb_obj_classname(obj);
650
- size_t len = strlen(classname);
651
-
652
- size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len;
653
- assure_size(out, size);
654
- fill_indent(out, d2);
655
- *out->cur++ = '"';
656
- memcpy(out->cur, out->opts->create_id, out->opts->create_id_len);
657
- out->cur += out->opts->create_id_len;
658
- *out->cur++ = '"';
659
- if (0 < out->opts->dump_opts.before_size) {
660
- strcpy(out->cur, out->opts->dump_opts.before_sep);
661
- out->cur += out->opts->dump_opts.before_size;
662
- }
663
- *out->cur++ = ':';
664
- if (0 < out->opts->dump_opts.after_size) {
665
- strcpy(out->cur, out->opts->dump_opts.after_sep);
666
- out->cur += out->opts->dump_opts.after_size;
667
- }
668
- *out->cur++ = '"';
669
- memcpy(out->cur, classname, len);
670
- out->cur += len;
671
- *out->cur++ = '"';
672
- class_written = true;
596
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
597
+ const char *classname = rb_obj_classname(obj);
598
+ size_t len = strlen(classname);
599
+
600
+ size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len;
601
+ assure_size(out, size);
602
+ fill_indent(out, d2);
603
+ *out->cur++ = '"';
604
+ APPEND_CHARS(out->cur, out->opts->create_id, out->opts->create_id_len);
605
+ *out->cur++ = '"';
606
+ if (0 < out->opts->dump_opts.before_size) {
607
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
608
+ }
609
+ *out->cur++ = ':';
610
+ if (0 < out->opts->dump_opts.after_size) {
611
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
612
+ }
613
+ *out->cur++ = '"';
614
+ APPEND_CHARS(out->cur, classname, len);
615
+ *out->cur++ = '"';
616
+ class_written = true;
673
617
  }
674
618
  cnt = (int)rb_ivar_count(obj);
675
619
  if (class_written) {
676
- *out->cur++ = ',';
620
+ *out->cur++ = ',';
677
621
  }
678
622
  if (0 == cnt && Qundef == clas) {
679
- // Might be something special like an Enumerable.
680
- if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) {
681
- out->cur--;
682
- oj_dump_custom_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out, false);
683
- return;
684
- }
623
+ // Might be something special like an Enumerable.
624
+ if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) {
625
+ out->cur--;
626
+ oj_dump_custom_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out, false);
627
+ return;
628
+ }
685
629
  }
686
630
  out->depth = depth + 1;
687
631
  rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
688
632
  if (',' == *(out->cur - 1)) {
689
- out->cur--; // backup to overwrite last comma
633
+ out->cur--; // backup to overwrite last comma
690
634
  }
691
635
  if (rb_obj_is_kind_of(obj, rb_eException)) {
692
- volatile VALUE rv;
693
-
694
- if (',' != *(out->cur - 1)) {
695
- *out->cur++ = ',';
696
- }
697
- // message
698
- assure_size(out, 2);
699
- fill_indent(out, d2);
700
- oj_dump_cstr("~mesg", 5, 0, 0, out);
701
- *out->cur++ = ':';
702
- rv = rb_funcall2(obj, rb_intern("message"), 0, 0);
703
- oj_dump_custom_val(rv, d2, out, true);
704
- assure_size(out, size + 2);
705
- *out->cur++ = ',';
706
- // backtrace
707
- fill_indent(out, d2);
708
- oj_dump_cstr("~bt", 3, 0, 0, out);
709
- *out->cur++ = ':';
710
- rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0);
711
- oj_dump_custom_val(rv, d2, out, true);
712
- assure_size(out, 2);
636
+ volatile VALUE rv;
637
+
638
+ if (',' != *(out->cur - 1)) {
639
+ *out->cur++ = ',';
640
+ }
641
+ // message
642
+ assure_size(out, 2);
643
+ fill_indent(out, d2);
644
+ oj_dump_cstr("~mesg", 5, 0, 0, out);
645
+ *out->cur++ = ':';
646
+ rv = rb_funcall2(obj, rb_intern("message"), 0, 0);
647
+ oj_dump_custom_val(rv, d2, out, true);
648
+ assure_size(out, size + 2);
649
+ *out->cur++ = ',';
650
+ // backtrace
651
+ fill_indent(out, d2);
652
+ oj_dump_cstr("~bt", 3, 0, 0, out);
653
+ *out->cur++ = ':';
654
+ rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0);
655
+ oj_dump_custom_val(rv, d2, out, true);
656
+ assure_size(out, 2);
713
657
  }
714
658
  out->depth = depth;
715
659
 
716
660
  fill_indent(out, depth);
717
661
  *out->cur++ = '}';
718
- *out->cur = '\0';
662
+ *out->cur = '\0';
719
663
  }
720
664
 
721
- static void
722
- dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
723
- long id = oj_check_circular(obj, out);
724
- VALUE clas;
665
+ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
666
+ long id = oj_check_circular(obj, out);
667
+ VALUE clas;
725
668
 
726
669
  if (0 > id) {
727
- oj_dump_nil(Qnil, depth, out, false);
670
+ oj_dump_nil(Qnil, depth, out, false);
728
671
  } else if (Qnil != (clas = dump_common(obj, depth, out))) {
729
- dump_obj_attrs(obj, clas, 0, depth, out);
672
+ dump_obj_attrs(obj, clas, 0, depth, out);
730
673
  }
731
674
  *out->cur = '\0';
732
675
  }
733
676
 
734
- static void
735
- dump_array(VALUE a, int depth, Out out, bool as_ok) {
736
- size_t size;
737
- int i, cnt;
738
- int d2 = depth + 1;
739
- long id = oj_check_circular(a, out);
677
+ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
678
+ size_t size;
679
+ int i, cnt;
680
+ int d2 = depth + 1;
681
+ long id = oj_check_circular(a, out);
740
682
 
741
683
  if (0 > id) {
742
- oj_dump_nil(Qnil, depth, out, false);
743
- return;
684
+ oj_dump_nil(Qnil, depth, out, false);
685
+ return;
744
686
  }
745
- cnt = (int)RARRAY_LEN(a);
687
+ cnt = (int)RARRAY_LEN(a);
746
688
  *out->cur++ = '[';
747
689
  assure_size(out, 2);
748
690
  if (0 == cnt) {
749
- *out->cur++ = ']';
691
+ *out->cur++ = ']';
750
692
  } else {
751
- if (out->opts->dump_opts.use) {
752
- size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
753
- } else {
754
- size = d2 * out->indent + 2;
755
- }
756
- cnt--;
757
- for (i = 0; i <= cnt; i++) {
758
- assure_size(out, size);
759
- if (out->opts->dump_opts.use) {
760
- if (0 < out->opts->dump_opts.array_size) {
761
- strcpy(out->cur, out->opts->dump_opts.array_nl);
762
- out->cur += out->opts->dump_opts.array_size;
763
- }
764
- if (0 < out->opts->dump_opts.indent_size) {
765
- int i;
766
- for (i = d2; 0 < i; i--) {
767
- strcpy(out->cur, out->opts->dump_opts.indent_str);
768
- out->cur += out->opts->dump_opts.indent_size;
769
- }
770
- }
771
- } else {
772
- fill_indent(out, d2);
773
- }
774
- oj_dump_custom_val(rb_ary_entry(a, i), d2, out, true);
775
- if (i < cnt) {
776
- *out->cur++ = ',';
777
- }
778
- }
779
- size = depth * out->indent + 1;
780
- assure_size(out, size);
781
- if (out->opts->dump_opts.use) {
782
- if (0 < out->opts->dump_opts.array_size) {
783
- strcpy(out->cur, out->opts->dump_opts.array_nl);
784
- out->cur += out->opts->dump_opts.array_size;
785
- }
786
- if (0 < out->opts->dump_opts.indent_size) {
787
- int i;
788
-
789
- for (i = depth; 0 < i; i--) {
790
- strcpy(out->cur, out->opts->dump_opts.indent_str);
791
- out->cur += out->opts->dump_opts.indent_size;
792
- }
793
- }
794
- } else {
795
- fill_indent(out, depth);
796
- }
797
- *out->cur++ = ']';
693
+ if (out->opts->dump_opts.use) {
694
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
695
+ } else {
696
+ size = d2 * out->indent + 2;
697
+ }
698
+ assure_size(out, size * cnt);
699
+ cnt--;
700
+ for (i = 0; i <= cnt; i++) {
701
+ if (out->opts->dump_opts.use) {
702
+ if (0 < out->opts->dump_opts.array_size) {
703
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
704
+ }
705
+ if (0 < out->opts->dump_opts.indent_size) {
706
+ int i;
707
+ for (i = d2; 0 < i; i--) {
708
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
709
+ }
710
+ }
711
+ } else {
712
+ fill_indent(out, d2);
713
+ }
714
+ oj_dump_custom_val(RARRAY_AREF(a, i), d2, out, true);
715
+ if (i < cnt) {
716
+ *out->cur++ = ',';
717
+ }
718
+ }
719
+ size = depth * out->indent + 1;
720
+ assure_size(out, size);
721
+ if (out->opts->dump_opts.use) {
722
+ if (0 < out->opts->dump_opts.array_size) {
723
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
724
+ }
725
+ if (0 < out->opts->dump_opts.indent_size) {
726
+ int i;
727
+
728
+ for (i = depth; 0 < i; i--) {
729
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
730
+ }
731
+ }
732
+ } else {
733
+ fill_indent(out, depth);
734
+ }
735
+ *out->cur++ = ']';
798
736
  }
799
737
  *out->cur = '\0';
800
738
  }
801
739
 
802
- static void
803
- dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
804
- long id = oj_check_circular(obj, out);
805
- VALUE clas;
740
+ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
741
+ long id = oj_check_circular(obj, out);
742
+ VALUE clas;
806
743
 
807
744
  if (0 > id) {
808
- oj_dump_nil(Qnil, depth, out, false);
745
+ oj_dump_nil(Qnil, depth, out, false);
809
746
  } else if (Qnil != (clas = dump_common(obj, depth, out))) {
810
- VALUE ma = Qnil;
811
- VALUE v;
812
- char num_id[32];
813
- int i;
814
- int d2 = depth + 1;
815
- int d3 = d2 + 1;
816
- size_t size = d2 * out->indent + d3 * out->indent + 3;
817
- const char *name;
818
- int cnt;
819
- size_t len;
820
-
821
- assure_size(out, size);
822
- if (clas == rb_cRange) {
823
- *out->cur++ = '"';
824
- oj_dump_custom_val(rb_funcall(obj, oj_begin_id, 0), d3, out, false);
825
- assure_size(out, 3);
826
- *out->cur++ = '.';
827
- *out->cur++ = '.';
828
- if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) {
829
- *out->cur++ = '.';
830
- }
831
- oj_dump_custom_val(rb_funcall(obj, oj_end_id, 0), d3, out, false);
832
- *out->cur++ = '"';
833
-
834
- return;
835
- }
836
- *out->cur++ = '{';
837
- fill_indent(out, d2);
838
- size = d3 * out->indent + 2;
839
- ma = rb_struct_s_members(clas);
747
+ VALUE ma = Qnil;
748
+ VALUE v;
749
+ char num_id[32];
750
+ int i;
751
+ int d2 = depth + 1;
752
+ int d3 = d2 + 1;
753
+ size_t size = d2 * out->indent + d3 * out->indent + 3;
754
+ const char *name;
755
+ int cnt;
756
+ size_t len;
757
+
758
+ assure_size(out, size);
759
+ if (clas == rb_cRange) {
760
+ *out->cur++ = '"';
761
+ oj_dump_custom_val(rb_funcall(obj, oj_begin_id, 0), d3, out, false);
762
+ assure_size(out, 3);
763
+ APPEND_CHARS(out->cur, "..", 2);
764
+ if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) {
765
+ *out->cur++ = '.';
766
+ }
767
+ oj_dump_custom_val(rb_funcall(obj, oj_end_id, 0), d3, out, false);
768
+ *out->cur++ = '"';
769
+
770
+ return;
771
+ }
772
+ *out->cur++ = '{';
773
+ fill_indent(out, d2);
774
+ size = d3 * out->indent + 2;
775
+ ma = rb_struct_s_members(clas);
840
776
 
841
777
  #ifdef RSTRUCT_LEN
842
778
  #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
843
- cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
844
- #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
845
- cnt = (int)RSTRUCT_LEN(obj);
846
- #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
779
+ cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
780
+ #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
781
+ cnt = (int)RSTRUCT_LEN(obj);
782
+ #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
847
783
  #else
848
- // This is a bit risky as a struct in C ruby is not the same as a Struct
849
- // class in interpreted Ruby so length() may not be defined.
850
- cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
784
+ // This is a bit risky as a struct in C ruby is not the same as a Struct
785
+ // class in interpreted Ruby so length() may not be defined.
786
+ cnt = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
851
787
  #endif
852
- for (i = 0; i < cnt; i++) {
788
+ for (i = 0; i < cnt; i++) {
853
789
  #ifdef RSTRUCT_LEN
854
- v = RSTRUCT_GET(obj, i);
790
+ v = RSTRUCT_GET(obj, i);
855
791
  #else
856
- v = rb_struct_aref(obj, INT2FIX(i));
792
+ v = rb_struct_aref(obj, INT2FIX(i));
857
793
  #endif
858
- if (ma != Qnil) {
859
- volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
860
-
861
- name = rb_string_value_ptr((VALUE*)&s);
862
- len = (int)RSTRING_LEN(s);
863
- } else {
864
- len = snprintf(num_id, sizeof(num_id), "%d", i);
865
- name = num_id;
866
- }
867
- assure_size(out, size + len + 3);
868
- fill_indent(out, d3);
869
- *out->cur++ = '"';
870
- memcpy(out->cur, name, len);
871
- out->cur += len;
872
- *out->cur++ = '"';
873
- *out->cur++ = ':';
874
- oj_dump_custom_val(v, d3, out, true);
875
- *out->cur++ = ',';
876
- }
877
- out->cur--;
878
- *out->cur++ = '}';
879
- *out->cur = '\0';
794
+ if (ma != Qnil) {
795
+ volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
796
+
797
+ name = RSTRING_PTR(s);
798
+ len = (int)RSTRING_LEN(s);
799
+ } else {
800
+ len = snprintf(num_id, sizeof(num_id), "%d", i);
801
+ name = num_id;
802
+ }
803
+ assure_size(out, size + len + 3);
804
+ fill_indent(out, d3);
805
+ *out->cur++ = '"';
806
+ APPEND_CHARS(out->cur, name, len);
807
+ APPEND_CHARS(out->cur, "\":", 2);
808
+ oj_dump_custom_val(v, d3, out, true);
809
+ *out->cur++ = ',';
810
+ }
811
+ out->cur--;
812
+ *out->cur++ = '}';
813
+ *out->cur = '\0';
880
814
  }
881
815
  }
882
816
 
883
- static void
884
- dump_data(VALUE obj, int depth, Out out, bool as_ok) {
885
- long id = oj_check_circular(obj, out);
886
- VALUE clas;
817
+ static void dump_data(VALUE obj, int depth, Out out, bool as_ok) {
818
+ long id = oj_check_circular(obj, out);
819
+ VALUE clas;
887
820
 
888
821
  if (0 > id) {
889
- oj_dump_nil(Qnil, depth, out, false);
822
+ oj_dump_nil(Qnil, depth, out, false);
890
823
  } else if (Qnil != (clas = dump_common(obj, depth, out))) {
891
- dump_obj_attrs(obj, clas, id, depth, out);
824
+ dump_obj_attrs(obj, clas, id, depth, out);
892
825
  }
893
826
  }
894
827
 
895
- static void
896
- dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
828
+ static void dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
897
829
  if (NULL != out->opts->create_id) {
898
- dump_obj_str(obj, depth, out);
830
+ dump_obj_str(obj, depth, out);
899
831
  } else {
900
- dump_obj_as_str(obj, depth, out);
832
+ dump_obj_as_str(obj, depth, out);
901
833
  }
902
834
  }
903
835
 
904
- static void
905
- dump_complex(VALUE obj, int depth, Out out, bool as_ok) {
836
+ static void dump_complex(VALUE obj, int depth, Out out, bool as_ok) {
906
837
  complex_dump(obj, depth, out);
907
838
  }
908
839
 
909
- static void
910
- dump_rational(VALUE obj, int depth, Out out, bool as_ok) {
840
+ static void dump_rational(VALUE obj, int depth, Out out, bool as_ok) {
911
841
  rational_dump(obj, depth, out);
912
842
  }
913
843
 
914
- static DumpFunc custom_funcs[] = {
915
- NULL, // RUBY_T_NONE = 0x00,
916
- dump_obj, // RUBY_T_OBJECT = 0x01,
917
- oj_dump_class, // RUBY_T_CLASS = 0x02,
918
- oj_dump_class, // RUBY_T_MODULE = 0x03,
919
- oj_dump_float, // RUBY_T_FLOAT = 0x04,
920
- oj_dump_str, // RUBY_T_STRING = 0x05,
921
- dump_regexp, // RUBY_T_REGEXP = 0x06,
922
- dump_array, // RUBY_T_ARRAY = 0x07,
923
- dump_hash, // RUBY_T_HASH = 0x08,
924
- dump_struct, // RUBY_T_STRUCT = 0x09,
925
- oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
926
- NULL, // RUBY_T_FILE = 0x0b,
927
- dump_data, // RUBY_T_DATA = 0x0c,
928
- NULL, // RUBY_T_MATCH = 0x0d,
929
- dump_complex, // RUBY_T_COMPLEX = 0x0e,
930
- dump_rational, // RUBY_T_RATIONAL = 0x0f,
931
- NULL, // 0x10
932
- oj_dump_nil, // RUBY_T_NIL = 0x11,
933
- oj_dump_true, // RUBY_T_TRUE = 0x12,
934
- oj_dump_false, // RUBY_T_FALSE = 0x13,
935
- oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
936
- oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
844
+ static DumpFunc custom_funcs[] = {
845
+ NULL, // RUBY_T_NONE = 0x00,
846
+ dump_obj, // RUBY_T_OBJECT = 0x01,
847
+ oj_dump_class, // RUBY_T_CLASS = 0x02,
848
+ oj_dump_class, // RUBY_T_MODULE = 0x03,
849
+ oj_dump_float, // RUBY_T_FLOAT = 0x04,
850
+ oj_dump_str, // RUBY_T_STRING = 0x05,
851
+ dump_regexp, // RUBY_T_REGEXP = 0x06,
852
+ dump_array, // RUBY_T_ARRAY = 0x07,
853
+ dump_hash, // RUBY_T_HASH = 0x08,
854
+ dump_struct, // RUBY_T_STRUCT = 0x09,
855
+ oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
856
+ NULL, // RUBY_T_FILE = 0x0b,
857
+ dump_data, // RUBY_T_DATA = 0x0c,
858
+ NULL, // RUBY_T_MATCH = 0x0d,
859
+ dump_complex, // RUBY_T_COMPLEX = 0x0e,
860
+ dump_rational, // RUBY_T_RATIONAL = 0x0f,
861
+ NULL, // 0x10
862
+ oj_dump_nil, // RUBY_T_NIL = 0x11,
863
+ oj_dump_true, // RUBY_T_TRUE = 0x12,
864
+ oj_dump_false, // RUBY_T_FALSE = 0x13,
865
+ oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
866
+ oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
937
867
  };
938
868
 
939
- void
940
- oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
941
- int type = rb_type(obj);
869
+ void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
870
+ int type = rb_type(obj);
942
871
 
943
- if (Yes == out->opts->trace) {
944
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
945
- }
872
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
946
873
  if (MAX_DEPTH < depth) {
947
- rb_raise(rb_eNoMemError, "Too deeply nested.\n");
874
+ rb_raise(rb_eNoMemError, "Too deeply nested.\n");
948
875
  }
949
876
  if (0 < type && type <= RUBY_T_FIXNUM) {
950
- DumpFunc f = custom_funcs[type];
951
-
952
- if (NULL != f) {
953
- f(obj, depth, out, true);
954
- if (Yes == out->opts->trace) {
955
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
956
- }
957
- return;
958
- }
877
+ DumpFunc f = custom_funcs[type];
878
+
879
+ if (NULL != f) {
880
+ f(obj, depth, out, true);
881
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
882
+ return;
883
+ }
959
884
  }
960
885
  oj_dump_nil(Qnil, depth, out, false);
961
- if (Yes == out->opts->trace) {
962
- oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
963
- }
886
+ TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
964
887
  }
965
888
 
966
889
  ///// load functions /////
967
890
 
968
- static void
969
- hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
970
- const char *key = kval->key;
971
- int klen = kval->klen;
972
- Val parent = stack_peek(&pi->stack);
973
- volatile VALUE rkey = kval->key_val;
974
-
975
- if (Qundef == rkey &&
976
- Yes == pi->options.create_ok &&
977
- NULL != pi->options.create_id &&
978
- *pi->options.create_id == *key &&
979
- (int)pi->options.create_id_len == klen &&
980
- 0 == strncmp(pi->options.create_id, key, klen)) {
981
-
982
- parent->clas = oj_name2class(pi, str, len, false, rb_eArgError);
983
- if (2 == klen && '^' == *key && 'o' == key[1]) {
984
- if (Qundef != parent->clas) {
985
- if (!oj_code_has(codes, parent->clas, false)) {
986
- parent->val = rb_obj_alloc(parent->clas);
987
- }
988
- }
989
- }
891
+ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
892
+ const char *key = kval->key;
893
+ int klen = kval->klen;
894
+ Val parent = stack_peek(&pi->stack);
895
+
896
+ if (Qundef == kval->key_val && Yes == pi->options.create_ok && NULL != pi->options.create_id &&
897
+ *pi->options.create_id == *key && (int)pi->options.create_id_len == klen &&
898
+ 0 == strncmp(pi->options.create_id, key, klen)) {
899
+ parent->clas = oj_name2class(pi, str, len, false, rb_eArgError);
900
+ if (2 == klen && '^' == *key && 'o' == key[1]) {
901
+ if (Qundef != parent->clas) {
902
+ if (!oj_code_has(codes, parent->clas, false)) {
903
+ parent->val = rb_obj_alloc(parent->clas);
904
+ }
905
+ }
906
+ }
990
907
  } else {
991
- volatile VALUE rstr = rb_str_new(str, len);
992
-
993
- if (Qundef == rkey) {
994
- rkey = rb_str_new(key, klen);
995
- rstr = oj_encode(rstr);
996
- rkey = oj_encode(rkey);
997
- if (Yes == pi->options.sym_key) {
998
- rkey = rb_str_intern(rkey);
999
- }
1000
- }
1001
- if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
1002
- VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
1003
-
1004
- if (Qnil != clas) {
1005
- rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
1006
- }
1007
- }
1008
- switch (rb_type(parent->val)) {
1009
- case T_OBJECT:
1010
- oj_set_obj_ivar(parent, kval, rstr);
1011
- break;
1012
- case T_HASH:
1013
- if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 == strncmp("time", parent->key, 4)) {
1014
- if (Qnil == (parent->val = oj_parse_xml_time(str, (int)len))) {
1015
- parent->val = rb_funcall(rb_cTime, rb_intern("parse"), 1, rb_str_new(str, len));
1016
- }
1017
- } else {
1018
- rb_hash_aset(parent->val, rkey, rstr);
1019
- }
1020
- break;
1021
- default:
1022
- break;
1023
- }
1024
- if (Yes == pi->options.trace) {
1025
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
1026
- }
908
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
909
+ volatile VALUE rkey = oj_calc_hash_key(pi, kval);
910
+
911
+ if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
912
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
913
+
914
+ if (Qnil != clas) {
915
+ rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
916
+ }
917
+ }
918
+ switch (rb_type(parent->val)) {
919
+ case T_OBJECT: oj_set_obj_ivar(parent, kval, rstr); break;
920
+ case T_HASH:
921
+ if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas &&
922
+ 0 == strncmp("time", parent->key, 4)) {
923
+ if (Qnil == (parent->val = oj_parse_xml_time(str, (int)len))) {
924
+ parent->val = rb_funcall(rb_cTime, rb_intern("parse"), 1, rb_str_new(str, len));
925
+ }
926
+ } else {
927
+ rb_hash_aset(parent->val, rkey, rstr);
928
+ }
929
+ break;
930
+ default: break;
931
+ }
932
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rstr);
1027
933
  }
1028
934
  }
1029
935
 
1030
- static void
1031
- end_hash(struct _parseInfo *pi) {
1032
- Val parent = stack_peek(&pi->stack);
936
+ static void end_hash(struct _parseInfo *pi) {
937
+ Val parent = stack_peek(&pi->stack);
1033
938
 
1034
939
  if (Qundef != parent->clas && parent->clas != rb_obj_class(parent->val)) {
1035
- volatile VALUE obj = oj_code_load(codes, parent->clas, parent->val);
1036
-
1037
- if (Qnil != obj) {
1038
- parent->val = obj;
1039
- } else {
1040
- parent->val = rb_funcall(parent->clas, oj_json_create_id, 1, parent->val);
1041
- }
1042
- parent->clas = Qundef;
1043
- }
1044
- if (Yes == pi->options.trace) {
1045
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
940
+ volatile VALUE obj = oj_code_load(codes, parent->clas, parent->val);
941
+
942
+ if (Qnil != obj) {
943
+ parent->val = obj;
944
+ } else {
945
+ parent->val = rb_funcall(parent->clas, oj_json_create_id, 1, parent->val);
946
+ }
947
+ parent->clas = Qundef;
1046
948
  }
949
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
1047
950
  }
1048
951
 
1049
- static VALUE
1050
- calc_hash_key(ParseInfo pi, Val parent) {
1051
- volatile VALUE rkey = parent->key_val;
1052
-
1053
- if (Qundef == rkey) {
1054
- rkey = rb_str_new(parent->key, parent->klen);
1055
- }
1056
- rkey = oj_encode(rkey);
1057
- if (Yes == pi->options.sym_key) {
1058
- rkey = rb_str_intern(rkey);
1059
- }
1060
- return rkey;
1061
- }
1062
-
1063
- static void
1064
- hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
1065
- Val parent = stack_peek(&pi->stack);
1066
- volatile VALUE rval = oj_num_as_value(ni);
952
+ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
953
+ Val parent = stack_peek(&pi->stack);
954
+ volatile VALUE rval = oj_num_as_value(ni);
1067
955
 
1068
956
  switch (rb_type(parent->val)) {
1069
- case T_OBJECT:
1070
- oj_set_obj_ivar(parent, kval, rval);
1071
- break;
957
+ case T_OBJECT: oj_set_obj_ivar(parent, kval, rval); break;
1072
958
  case T_HASH:
1073
- if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 != ni->div && 0 == strncmp("time", parent->key, 4)) {
1074
- int64_t nsec = ni->num * 1000000000LL / ni->div;
1075
-
1076
- if (ni->neg) {
1077
- ni->i = -ni->i;
1078
- if (0 < nsec) {
1079
- ni->i--;
1080
- nsec = 1000000000LL - nsec;
1081
- }
1082
- }
1083
- if (86400 == ni->exp) { // UTC time
1084
- parent->val = rb_time_nano_new(ni->i, (long)nsec);
1085
- // Since the ruby C routines alway create local time, the
1086
- // offset and then a conversion to UTC keeps makes the time
1087
- // match the expected value.
1088
- parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
1089
- } else if (ni->has_exp) {
1090
- int64_t t = (int64_t)(ni->i + ni->exp);
1091
- struct _timeInfo ti;
1092
- VALUE args[8];
1093
-
1094
- sec_as_time(t, &ti);
1095
-
1096
- args[0] = LONG2NUM(ti.year);
1097
- args[1] = LONG2NUM(ti.mon);
1098
- args[2] = LONG2NUM(ti.day);
1099
- args[3] = LONG2NUM(ti.hour);
1100
- args[4] = LONG2NUM(ti.min);
1101
- args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
1102
- args[6] = LONG2NUM(ni->exp);
1103
- parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
1104
- } else {
1105
- parent->val = rb_time_nano_new(ni->i, (long)nsec);
1106
- }
1107
- rval = parent->val;
1108
- } else {
1109
- rb_hash_aset(parent->val, calc_hash_key(pi, kval), rval);
1110
- }
1111
- break;
1112
- default:
1113
- break;
1114
- }
1115
- if (Yes == pi->options.trace) {
1116
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
959
+ if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 != ni->div &&
960
+ 0 == strncmp("time", parent->key, 4)) {
961
+ int64_t nsec = ni->num * 1000000000LL / ni->div;
962
+
963
+ if (ni->neg) {
964
+ ni->i = -ni->i;
965
+ if (0 < nsec) {
966
+ ni->i--;
967
+ nsec = 1000000000LL - nsec;
968
+ }
969
+ }
970
+ if (86400 == ni->exp) { // UTC time
971
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
972
+ // Since the ruby C routines always create local time, the
973
+ // offset and then a conversion to UTC keeps makes the time
974
+ // match the expected value.
975
+ parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
976
+ } else if (ni->has_exp) {
977
+ struct timespec ts;
978
+ ts.tv_sec = ni->i;
979
+ ts.tv_nsec = nsec;
980
+ parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
981
+ } else {
982
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
983
+ }
984
+ rval = parent->val;
985
+ } else {
986
+ rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), rval);
987
+ }
988
+ break;
989
+ default: break;
1117
990
  }
991
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rval);
1118
992
  }
1119
993
 
1120
- static void
1121
- hash_set_value(ParseInfo pi, Val kval, VALUE value) {
1122
- Val parent = stack_peek(&pi->stack);
994
+ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
995
+ Val parent = stack_peek(&pi->stack);
1123
996
 
1124
997
  switch (rb_type(parent->val)) {
1125
- case T_OBJECT:
1126
- oj_set_obj_ivar(parent, kval, value);
1127
- break;
1128
- case T_HASH:
1129
- rb_hash_aset(parent->val, calc_hash_key(pi, kval), value);
1130
- break;
1131
- default:
1132
- break;
1133
- }
1134
- if (Yes == pi->options.trace) {
1135
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
998
+ case T_OBJECT: oj_set_obj_ivar(parent, kval, value); break;
999
+ case T_HASH: rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), value); break;
1000
+ default: break;
1136
1001
  }
1002
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
1137
1003
  }
1138
1004
 
1139
- static void
1140
- array_append_num(ParseInfo pi, NumInfo ni) {
1141
- Val parent = stack_peek(&pi->stack);
1142
- volatile VALUE rval = oj_num_as_value(ni);
1005
+ static void array_append_num(ParseInfo pi, NumInfo ni) {
1006
+ Val parent = stack_peek(&pi->stack);
1007
+ volatile VALUE rval = oj_num_as_value(ni);
1143
1008
 
1144
1009
  rb_ary_push(parent->val, rval);
1145
- if (Yes == pi->options.trace) {
1146
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
1147
- }
1010
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
1148
1011
  }
1149
1012
 
1150
- static void
1151
- array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
1152
- volatile VALUE rstr = rb_str_new(str, len);
1013
+ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
1014
+ volatile VALUE rstr = rb_utf8_str_new(str, len);
1153
1015
 
1154
- rstr = oj_encode(rstr);
1155
1016
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
1156
- VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
1017
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
1157
1018
 
1158
- if (Qnil != clas) {
1159
- rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
1160
- return;
1161
- }
1019
+ if (Qnil != clas) {
1020
+ rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
1021
+ return;
1022
+ }
1162
1023
  }
1163
1024
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
1164
- if (Yes == pi->options.trace) {
1165
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
1166
- }
1025
+ TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rstr);
1167
1026
  }
1168
1027
 
1169
- void
1170
- oj_set_custom_callbacks(ParseInfo pi) {
1028
+ void oj_set_custom_callbacks(ParseInfo pi) {
1171
1029
  oj_set_compat_callbacks(pi);
1172
- pi->hash_set_cstr = hash_set_cstr;
1173
- pi->end_hash = end_hash;
1174
- pi->hash_set_num = hash_set_num;
1175
- pi->hash_set_value = hash_set_value;
1030
+ pi->hash_set_cstr = hash_set_cstr;
1031
+ pi->end_hash = end_hash;
1032
+ pi->hash_set_num = hash_set_num;
1033
+ pi->hash_set_value = hash_set_value;
1176
1034
  pi->array_append_cstr = array_append_cstr;
1177
- pi->array_append_num = array_append_num;
1035
+ pi->array_append_num = array_append_num;
1178
1036
  }
1179
1037
 
1180
1038
  VALUE
1181
1039
  oj_custom_parse(int argc, VALUE *argv, VALUE self) {
1182
- struct _parseInfo pi;
1040
+ struct _parseInfo pi;
1183
1041
 
1184
1042
  parse_info_init(&pi);
1185
- pi.options = oj_default_options;
1186
- pi.handler = Qnil;
1187
- pi.err_class = Qnil;
1188
- pi.max_depth = 0;
1043
+ pi.options = oj_default_options;
1044
+ pi.handler = Qnil;
1045
+ pi.err_class = Qnil;
1046
+ pi.max_depth = 0;
1189
1047
  pi.options.allow_nan = Yes;
1190
- pi.options.nilnil = Yes;
1048
+ pi.options.nilnil = Yes;
1191
1049
  oj_set_custom_callbacks(&pi);
1192
1050
 
1193
1051
  if (T_STRING == rb_type(*argv)) {
1194
- return oj_pi_parse(argc, argv, &pi, 0, 0, false);
1052
+ return oj_pi_parse(argc, argv, &pi, 0, 0, false);
1195
1053
  } else {
1196
- return oj_pi_sparse(argc, argv, &pi, 0);
1054
+ return oj_pi_sparse(argc, argv, &pi, 0);
1197
1055
  }
1198
1056
  }
1199
1057
 
1200
1058
  VALUE
1201
1059
  oj_custom_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
1202
- struct _parseInfo pi;
1060
+ struct _parseInfo pi;
1203
1061
 
1204
1062
  parse_info_init(&pi);
1205
- pi.options = oj_default_options;
1206
- pi.handler = Qnil;
1207
- pi.err_class = Qnil;
1208
- pi.max_depth = 0;
1063
+ pi.options = oj_default_options;
1064
+ pi.handler = Qnil;
1065
+ pi.err_class = Qnil;
1066
+ pi.max_depth = 0;
1209
1067
  pi.options.allow_nan = Yes;
1210
- pi.options.nilnil = Yes;
1068
+ pi.options.nilnil = Yes;
1211
1069
  oj_set_custom_callbacks(&pi);
1212
1070
  pi.end_hash = end_hash;
1213
1071