oj 3.9.1 → 3.16.11

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