oj 3.7.4 → 3.13.23

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