oj 3.7.4 → 3.13.21

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