oj 2.18.3 → 3.13.14

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 (182) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1324 -0
  3. data/README.md +51 -204
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +49 -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 -68
  11. data/ext/oj/circarray.h +16 -42
  12. data/ext/oj/code.c +221 -0
  13. data/ext/oj/code.h +40 -0
  14. data/ext/oj/compat.c +231 -107
  15. data/ext/oj/custom.c +1125 -0
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +935 -2513
  18. data/ext/oj/dump.h +108 -0
  19. data/ext/oj/dump_compat.c +936 -0
  20. data/ext/oj/dump_leaf.c +164 -0
  21. data/ext/oj/dump_object.c +761 -0
  22. data/ext/oj/dump_strict.c +410 -0
  23. data/ext/oj/encode.h +7 -42
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -54
  26. data/ext/oj/err.h +52 -46
  27. data/ext/oj/extconf.rb +21 -30
  28. data/ext/oj/fast.c +1097 -1080
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +893 -0
  32. data/ext/oj/object.c +549 -620
  33. data/ext/oj/odd.c +155 -167
  34. data/ext/oj/odd.h +37 -63
  35. data/ext/oj/oj.c +1661 -2063
  36. data/ext/oj/oj.h +341 -270
  37. data/ext/oj/parse.c +974 -737
  38. data/ext/oj/parse.h +105 -97
  39. data/ext/oj/parser.c +1526 -0
  40. data/ext/oj/parser.h +90 -0
  41. data/ext/oj/rails.c +1504 -0
  42. data/ext/oj/rails.h +18 -0
  43. data/ext/oj/reader.c +141 -163
  44. data/ext/oj/reader.h +75 -113
  45. data/ext/oj/resolve.c +45 -93
  46. data/ext/oj/resolve.h +7 -34
  47. data/ext/oj/rxclass.c +143 -0
  48. data/ext/oj/rxclass.h +26 -0
  49. data/ext/oj/saj.c +447 -511
  50. data/ext/oj/saj2.c +348 -0
  51. data/ext/oj/scp.c +91 -138
  52. data/ext/oj/sparse.c +793 -644
  53. data/ext/oj/stream_writer.c +331 -0
  54. data/ext/oj/strict.c +145 -109
  55. data/ext/oj/string_writer.c +493 -0
  56. data/ext/oj/trace.c +72 -0
  57. data/ext/oj/trace.h +28 -0
  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 +62 -70
  62. data/ext/oj/val_stack.h +95 -129
  63. data/ext/oj/validate.c +51 -0
  64. data/ext/oj/wab.c +622 -0
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +17 -8
  67. data/lib/oj/error.rb +10 -11
  68. data/lib/oj/json.rb +176 -0
  69. data/lib/oj/mimic.rb +158 -19
  70. data/lib/oj/state.rb +132 -0
  71. data/lib/oj/version.rb +2 -2
  72. data/lib/oj.rb +1 -31
  73. data/pages/Advanced.md +22 -0
  74. data/pages/Compatibility.md +25 -0
  75. data/pages/Custom.md +23 -0
  76. data/pages/Encoding.md +65 -0
  77. data/pages/JsonGem.md +94 -0
  78. data/pages/Modes.md +161 -0
  79. data/pages/Options.md +327 -0
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +167 -0
  82. data/pages/Security.md +20 -0
  83. data/pages/WAB.md +13 -0
  84. data/test/activerecord/result_test.rb +32 -0
  85. data/test/activesupport4/decoding_test.rb +108 -0
  86. data/test/activesupport4/encoding_test.rb +531 -0
  87. data/test/activesupport4/test_helper.rb +41 -0
  88. data/test/activesupport5/abstract_unit.rb +45 -0
  89. data/test/activesupport5/decoding_test.rb +133 -0
  90. data/test/activesupport5/encoding_test.rb +500 -0
  91. data/test/activesupport5/encoding_test_cases.rb +98 -0
  92. data/test/activesupport5/test_helper.rb +72 -0
  93. data/test/activesupport5/time_zone_test_helpers.rb +39 -0
  94. data/test/activesupport6/abstract_unit.rb +44 -0
  95. data/test/activesupport6/decoding_test.rb +133 -0
  96. data/test/activesupport6/encoding_test.rb +507 -0
  97. data/test/activesupport6/encoding_test_cases.rb +98 -0
  98. data/test/activesupport6/test_common.rb +17 -0
  99. data/test/activesupport6/test_helper.rb +163 -0
  100. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  101. data/test/activesupport7/abstract_unit.rb +49 -0
  102. data/test/activesupport7/decoding_test.rb +125 -0
  103. data/test/activesupport7/encoding_test.rb +486 -0
  104. data/test/activesupport7/encoding_test_cases.rb +104 -0
  105. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  106. data/test/bar.rb +9 -0
  107. data/test/baz.rb +16 -0
  108. data/test/bug.rb +11 -46
  109. data/test/foo.rb +69 -16
  110. data/test/helper.rb +10 -1
  111. data/test/isolated/shared.rb +12 -8
  112. data/test/isolated/test_mimic_rails_after.rb +3 -3
  113. data/test/isolated/test_mimic_rails_before.rb +3 -3
  114. data/test/json_gem/json_addition_test.rb +216 -0
  115. data/test/json_gem/json_common_interface_test.rb +153 -0
  116. data/test/json_gem/json_encoding_test.rb +107 -0
  117. data/test/json_gem/json_ext_parser_test.rb +20 -0
  118. data/test/json_gem/json_fixtures_test.rb +35 -0
  119. data/test/json_gem/json_generator_test.rb +397 -0
  120. data/test/json_gem/json_generic_object_test.rb +90 -0
  121. data/test/json_gem/json_parser_test.rb +470 -0
  122. data/test/json_gem/json_string_matching_test.rb +42 -0
  123. data/test/json_gem/test_helper.rb +26 -0
  124. data/test/mem.rb +33 -0
  125. data/test/perf.rb +1 -1
  126. data/test/perf_compat.rb +30 -28
  127. data/test/perf_dump.rb +50 -0
  128. data/test/perf_object.rb +1 -1
  129. data/test/perf_once.rb +58 -0
  130. data/test/perf_parser.rb +189 -0
  131. data/test/perf_scp.rb +11 -10
  132. data/test/perf_strict.rb +30 -19
  133. data/test/perf_wab.rb +131 -0
  134. data/test/prec.rb +23 -0
  135. data/test/sample.rb +0 -1
  136. data/test/sample_json.rb +1 -1
  137. data/test/test_compat.rb +219 -102
  138. data/test/test_custom.rb +533 -0
  139. data/test/test_fast.rb +107 -35
  140. data/test/test_file.rb +19 -25
  141. data/test/test_generate.rb +21 -0
  142. data/test/test_hash.rb +11 -1
  143. data/test/test_integer_range.rb +72 -0
  144. data/test/test_null.rb +376 -0
  145. data/test/test_object.rb +357 -70
  146. data/test/test_parser.rb +27 -0
  147. data/test/test_parser_saj.rb +245 -0
  148. data/test/test_parser_usual.rb +217 -0
  149. data/test/test_rails.rb +35 -0
  150. data/test/test_saj.rb +1 -1
  151. data/test/test_scp.rb +39 -2
  152. data/test/test_strict.rb +186 -7
  153. data/test/test_various.rb +160 -774
  154. data/test/test_wab.rb +307 -0
  155. data/test/test_writer.rb +90 -2
  156. data/test/tests.rb +24 -0
  157. data/test/tests_mimic.rb +14 -0
  158. data/test/tests_mimic_addition.rb +7 -0
  159. data/test/zoo.rb +13 -0
  160. metadata +194 -56
  161. data/ext/oj/hash.c +0 -163
  162. data/ext/oj/hash.h +0 -46
  163. data/ext/oj/hash_test.c +0 -512
  164. data/test/activesupport_datetime_test.rb +0 -23
  165. data/test/bug2.rb +0 -10
  166. data/test/bug3.rb +0 -46
  167. data/test/bug_fast.rb +0 -32
  168. data/test/bug_load.rb +0 -24
  169. data/test/crash.rb +0 -111
  170. data/test/curl/curl_oj.rb +0 -46
  171. data/test/curl/get_oj.rb +0 -24
  172. data/test/curl/just_curl.rb +0 -31
  173. data/test/curl/just_oj.rb +0 -51
  174. data/test/example.rb +0 -11
  175. data/test/io.rb +0 -48
  176. data/test/isolated/test_mimic_rails_datetime.rb +0 -27
  177. data/test/mod.rb +0 -16
  178. data/test/rails.rb +0 -50
  179. data/test/russian.rb +0 -18
  180. data/test/struct.rb +0 -29
  181. data/test/test_serializer.rb +0 -59
  182. data/test/write_timebars.rb +0 -31
data/ext/oj/object.c CHANGED
@@ -1,806 +1,735 @@
1
- /* object.c
2
- * Copyright (c) 2012, Peter Ohler
3
- * All rights reserved.
4
- *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
7
- *
8
- * - Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- *
11
- * - Redistributions in binary form must reproduce the above copyright notice,
12
- * this list of conditions and the following disclaimer in the documentation
13
- * and/or other materials provided with the distribution.
14
- *
15
- * - Neither the name of Peter Ohler nor the names of its contributors may be
16
- * used to endorse or promote products derived from this software without
17
- * specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
- */
1
+ // Copyright (c) 2012 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
30
3
 
4
+ #include <stdint.h>
31
5
  #include <stdio.h>
32
6
  #include <time.h>
33
7
 
34
- #include "oj.h"
8
+ #include "encode.h"
35
9
  #include "err.h"
10
+ #include "intern.h"
11
+ #include "odd.h"
12
+ #include "oj.h"
36
13
  #include "parse.h"
37
14
  #include "resolve.h"
38
- #include "hash.h"
39
- #include "odd.h"
40
- #include "encode.h"
15
+ #include "trace.h"
16
+ #include "util.h"
41
17
 
42
- inline static long
43
- read_long(const char *str, size_t len) {
44
- long n = 0;
18
+ inline static long read_long(const char *str, size_t len) {
19
+ long n = 0;
45
20
 
46
21
  for (; 0 < len; str++, len--) {
47
- if ('0' <= *str && *str <= '9') {
48
- n = n * 10 + (*str - '0');
49
- } else {
50
- return -1;
51
- }
22
+ if ('0' <= *str && *str <= '9') {
23
+ n = n * 10 + (*str - '0');
24
+ } else {
25
+ return -1;
26
+ }
52
27
  }
53
28
  return n;
54
29
  }
55
30
 
56
- static VALUE
57
- calc_hash_key(ParseInfo pi, Val kval, char k1) {
58
- volatile VALUE rkey;
31
+ static VALUE calc_hash_key(ParseInfo pi, Val kval, char k1) {
32
+ volatile VALUE rkey;
59
33
 
60
34
  if (':' == k1) {
61
- rkey = rb_str_new(kval->key + 1, kval->klen - 1);
62
- rkey = oj_encode(rkey);
63
- rkey = rb_funcall(rkey, oj_to_sym_id, 0);
64
- } else {
65
- rkey = rb_str_new(kval->key, kval->klen);
66
- rkey = oj_encode(rkey);
67
- if (Yes == pi->options.sym_key) {
68
- rkey = rb_str_intern(rkey);
69
- }
35
+ return ID2SYM(rb_intern3(kval->key + 1, kval->klen - 1, oj_utf8_encoding));
70
36
  }
37
+ if (Yes == pi->options.sym_key) {
38
+ return ID2SYM(rb_intern3(kval->key, kval->klen, oj_utf8_encoding));
39
+ }
40
+ #if HAVE_RB_ENC_INTERNED_STR
41
+ rkey = rb_enc_interned_str(kval->key, kval->klen, oj_utf8_encoding);
42
+ #else
43
+ rkey = rb_utf8_str_new(kval->key, kval->klen);
44
+ OBJ_FREEZE(rkey);
45
+ #endif
71
46
  return rkey;
72
47
  }
73
48
 
74
- static VALUE
75
- str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) {
76
- volatile VALUE rstr = Qnil;
49
+ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) {
50
+ volatile VALUE rstr = Qnil;
77
51
 
78
52
  if (':' == *orig && 0 < len) {
79
- rstr = rb_str_new(str + 1, len - 1);
80
- rstr = oj_encode(rstr);
81
- rstr = rb_funcall(rstr, oj_to_sym_id, 0);
53
+ rstr = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding));
82
54
  } else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
83
- long i = read_long(str + 2, len - 2);
55
+ long i = read_long(str + 2, len - 2);
84
56
 
85
- if (0 > i) {
86
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a valid ID number");
87
- return Qnil;
88
- }
89
- rstr = oj_circ_array_get(pi->circ_array, i);
57
+ if (0 > i) {
58
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a valid ID number");
59
+ return Qnil;
60
+ }
61
+ rstr = oj_circ_array_get(pi->circ_array, i);
90
62
  } else {
91
- rstr = rb_str_new(str, len);
92
- rstr = oj_encode(rstr);
63
+ rstr = rb_utf8_str_new(str, len);
93
64
  }
94
65
  return rstr;
95
66
  }
96
67
 
97
- #if (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
98
- static VALUE
99
- parse_xml_time(const char *str, int len) {
100
- return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(str, len));
101
- }
102
- #else
103
68
  // The much faster approach (4x faster)
104
- static int
105
- parse_num(const char *str, const char *end, int cnt) {
106
- int n = 0;
107
- char c;
108
- int i;
69
+ static int parse_num(const char *str, const char *end, int cnt) {
70
+ int n = 0;
71
+ char c;
72
+ int i;
109
73
 
110
74
  for (i = cnt; 0 < i; i--, str++) {
111
- c = *str;
112
- if (end <= str || c < '0' || '9' < c) {
113
- return -1;
114
- }
115
- n = n * 10 + (c - '0');
75
+ c = *str;
76
+ if (end <= str || c < '0' || '9' < c) {
77
+ return -1;
78
+ }
79
+ n = n * 10 + (c - '0');
116
80
  }
117
81
  return n;
118
82
  }
119
83
 
120
- static VALUE
121
- parse_xml_time(const char *str, int len) {
122
- VALUE args[8];
123
- const char *end = str + len;
124
- int n;
84
+ VALUE
85
+ oj_parse_xml_time(const char *str, int len) {
86
+ VALUE args[8];
87
+ const char *end = str + len;
88
+ int n;
125
89
 
126
90
  // year
127
91
  if (0 > (n = parse_num(str, end, 4))) {
128
- return Qnil;
92
+ return Qnil;
129
93
  }
130
94
  str += 4;
131
95
  args[0] = LONG2NUM(n);
132
96
  if ('-' != *str++) {
133
- return Qnil;
97
+ return Qnil;
134
98
  }
135
99
  // month
136
100
  if (0 > (n = parse_num(str, end, 2))) {
137
- return Qnil;
101
+ return Qnil;
138
102
  }
139
103
  str += 2;
140
104
  args[1] = LONG2NUM(n);
141
105
  if ('-' != *str++) {
142
- return Qnil;
106
+ return Qnil;
143
107
  }
144
108
  // day
145
109
  if (0 > (n = parse_num(str, end, 2))) {
146
- return Qnil;
110
+ return Qnil;
147
111
  }
148
112
  str += 2;
149
113
  args[2] = LONG2NUM(n);
150
114
  if ('T' != *str++) {
151
- return Qnil;
115
+ return Qnil;
152
116
  }
153
117
  // hour
154
118
  if (0 > (n = parse_num(str, end, 2))) {
155
- return Qnil;
119
+ return Qnil;
156
120
  }
157
121
  str += 2;
158
122
  args[3] = LONG2NUM(n);
159
123
  if (':' != *str++) {
160
- return Qnil;
124
+ return Qnil;
161
125
  }
162
126
  // minute
163
127
  if (0 > (n = parse_num(str, end, 2))) {
164
- return Qnil;
128
+ return Qnil;
165
129
  }
166
130
  str += 2;
167
131
  args[4] = LONG2NUM(n);
168
132
  if (':' != *str++) {
169
- return Qnil;
133
+ return Qnil;
170
134
  }
171
135
  // second
172
136
  if (0 > (n = parse_num(str, end, 2))) {
173
- return Qnil;
137
+ return Qnil;
174
138
  }
175
139
  str += 2;
176
140
  if (str == end) {
177
- args[5] = LONG2NUM(n);
178
- args[6] = LONG2NUM(0);
141
+ args[5] = LONG2NUM(n);
142
+ args[6] = LONG2NUM(0);
179
143
  } else {
180
- char c = *str++;
181
-
182
- if ('.' == c) {
183
- long long nsec = 0;
184
-
185
- for (; str < end; str++) {
186
- c = *str;
187
- if (c < '0' || '9' < c) {
188
- str++;
189
- break;
190
- }
191
- nsec = nsec * 10 + (c - '0');
192
- }
193
- args[5] = rb_float_new((double)n + ((double)nsec + 0.5) / 1000000000.0);
194
- } else {
195
- args[5] = rb_ll2inum(n);
196
- }
197
- if (end < str) {
198
- args[6] = LONG2NUM(0);
199
- } else {
200
- if ('Z' == c) {
201
- return rb_funcall2(rb_cTime, oj_utc_id, 6, args);
202
- } else if ('+' == c) {
203
- int hr = parse_num(str, end, 2);
204
- int min;
205
-
206
- str += 2;
207
- if (0 > hr || ':' != *str++) {
208
- return Qnil;
209
- }
210
- min = parse_num(str, end, 2);
211
- if (0 > min) {
212
- return Qnil;
213
- }
214
- args[6] = LONG2NUM(hr * 3600 + min * 60);
215
- } else if ('-' == c) {
216
- int hr = parse_num(str, end, 2);
217
- int min;
218
-
219
- str += 2;
220
- if (0 > hr || ':' != *str++) {
221
- return Qnil;
222
- }
223
- min = parse_num(str, end, 2);
224
- if (0 > min) {
225
- return Qnil;
226
- }
227
- args[6] = LONG2NUM(-(hr * 3600 + min * 60));
228
- } else {
229
- args[6] = LONG2NUM(0);
230
- }
231
- }
144
+ char c = *str++;
145
+
146
+ if ('.' == c) {
147
+ long long nsec = 0;
148
+
149
+ for (; str < end; str++) {
150
+ c = *str;
151
+ if (c < '0' || '9' < c) {
152
+ str++;
153
+ break;
154
+ }
155
+ nsec = nsec * 10 + (c - '0');
156
+ }
157
+ args[5] = rb_float_new((double)n + ((double)nsec + 0.5) / 1000000000.0);
158
+ } else {
159
+ args[5] = rb_ll2inum(n);
160
+ }
161
+ if (end < str) {
162
+ args[6] = LONG2NUM(0);
163
+ } else {
164
+ if ('Z' == c) {
165
+ return rb_funcall2(rb_cTime, oj_utc_id, 6, args);
166
+ } else if ('+' == c) {
167
+ int hr = parse_num(str, end, 2);
168
+ int min;
169
+
170
+ str += 2;
171
+ if (0 > hr || ':' != *str++) {
172
+ return Qnil;
173
+ }
174
+ min = parse_num(str, end, 2);
175
+ if (0 > min) {
176
+ return Qnil;
177
+ }
178
+ args[6] = LONG2NUM(hr * 3600 + min * 60);
179
+ } else if ('-' == c) {
180
+ int hr = parse_num(str, end, 2);
181
+ int min;
182
+
183
+ str += 2;
184
+ if (0 > hr || ':' != *str++) {
185
+ return Qnil;
186
+ }
187
+ min = parse_num(str, end, 2);
188
+ if (0 > min) {
189
+ return Qnil;
190
+ }
191
+ args[6] = LONG2NUM(-(hr * 3600 + min * 60));
192
+ } else {
193
+ args[6] = LONG2NUM(0);
194
+ }
195
+ }
232
196
  }
233
197
  return rb_funcall2(rb_cTime, oj_new_id, 7, args);
234
198
  }
235
- #endif
236
199
 
237
- static int
238
- hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
239
- const char *key = kval->key;
240
- int klen = kval->klen;
200
+ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
201
+ const char *key = kval->key;
202
+ int klen = kval->klen;
241
203
 
242
204
  if (2 == klen) {
243
- switch (key[1]) {
244
- case 'o': // object
245
- { // name2class sets and error if the class is not found or created
246
- VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define);
247
-
248
- if (Qundef != clas) {
249
- parent->val = rb_obj_alloc(clas);
250
- }
251
- }
252
- break;
253
- case 'O': // odd object
254
- {
255
- Odd odd = oj_get_oddc(str, len);
256
-
257
- if (0 == odd) {
258
- return 0;
259
- }
260
- parent->val = odd->clas;
261
- parent->odd_args = oj_odd_alloc_args(odd);
262
- }
263
- break;
264
- case 'm':
265
- parent->val = rb_str_new(str + 1, len - 1);
266
- parent->val = oj_encode(parent->val);
267
- parent->val = rb_funcall(parent->val, oj_to_sym_id, 0);
268
- break;
269
- case 's':
270
- parent->val = rb_str_new(str, len);
271
- parent->val = oj_encode(parent->val);
272
- break;
273
- case 'c': // class
274
- {
275
- VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define);
276
-
277
- if (Qundef == clas) {
278
- return 0;
279
- } else {
280
- parent->val = clas;
281
- }
282
- }
283
- break;
284
- case 't': // time
285
- parent->val = parse_xml_time(str, len);
286
- break;
287
- default:
288
- return 0;
289
- break;
290
- }
291
- return 1; // handled
205
+ switch (key[1]) {
206
+ case 'o': // object
207
+ { // name2class sets an error if the class is not found or created
208
+ VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
209
+
210
+ if (Qundef != clas) {
211
+ parent->val = rb_obj_alloc(clas);
212
+ }
213
+ } break;
214
+ case 'O': // odd object
215
+ {
216
+ Odd odd = oj_get_oddc(str, len);
217
+
218
+ if (0 == odd) {
219
+ return 0;
220
+ }
221
+ parent->val = odd->clas;
222
+ parent->odd_args = oj_odd_alloc_args(odd);
223
+ break;
224
+ }
225
+ case 'm': parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding)); break;
226
+ case 's': parent->val = rb_utf8_str_new(str, len); break;
227
+ case 'c': // class
228
+ {
229
+ VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
230
+
231
+ if (Qundef == clas) {
232
+ return 0;
233
+ } else {
234
+ parent->val = clas;
235
+ }
236
+ break;
237
+ }
238
+ case 't': // time
239
+ parent->val = oj_parse_xml_time(str, (int)len);
240
+ break;
241
+ default: return 0; break;
242
+ }
243
+ return 1; // handled
292
244
  }
293
245
  return 0;
294
246
  }
295
247
 
296
- static int
297
- hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
248
+ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
298
249
  if (2 == kval->klen) {
299
- switch (kval->key[1]) {
300
- case 't': // time as a float
301
- {
302
- int64_t nsec = ni->num * 1000000000LL / ni->div;
303
-
304
- if (ni->neg) {
305
- ni->i = -ni->i;
306
- if (0 < nsec) {
307
- ni->i--;
308
- nsec = 1000000000LL - nsec;
309
- }
310
- }
311
- if (86400 == ni->exp) { // UTC time
312
- #if HAS_NANO_TIME
313
- parent->val = rb_time_nano_new(ni->i, (long)nsec);
314
- #else
315
- parent->val = rb_time_new(ni->i, (long)(nsec / 1000));
316
- #endif
317
- // Since the ruby C routines alway create local time, the
318
- // offset and then a convertion to UTC keeps makes the time
319
- // match the expected value.
320
- parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
321
- } else if (ni->hasExp) {
322
- time_t t = (time_t)(ni->i + ni->exp);
323
- struct tm *st = gmtime(&t);
324
- #if RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8
325
- // The only methods that allow the UTC offset to be set in
326
- // 1.8.7 is the parse() and xmlschema() methods. The
327
- // xmlschema() method always returns a Time instance that is
328
- // UTC time. (true on some platforms anyway) Time.parse()
329
- // fails on other Ruby versions until 2.2.0.
330
- char buf[64];
331
- int z = (0 > ni->exp ? -ni->exp : ni->exp) / 60;
332
- int tzhour = z / 60;
333
- int tzmin = z - tzhour * 60;
334
- int cnt;
335
-
336
- cnt = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d",
337
- 1900 + st->tm_year, 1 + st->tm_mon, st->tm_mday,
338
- st->tm_hour, st->tm_min, st->tm_sec, (long)nsec,
339
- (0 > ni->exp ? '-' : '+'), tzhour, tzmin);
340
- parent->val = rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(buf, cnt));
341
- #else
342
- VALUE args[8];
343
-
344
- args[0] = LONG2NUM(1900 + st->tm_year);
345
- args[1] = LONG2NUM(1 + st->tm_mon);
346
- args[2] = LONG2NUM(st->tm_mday);
347
- args[3] = LONG2NUM(st->tm_hour);
348
- args[4] = LONG2NUM(st->tm_min);
349
- #if NO_TIME_ROUND_PAD
350
- args[5] = rb_float_new((double)st->tm_sec + ((double)nsec) / 1000000000.0);
351
- #else
352
- args[5] = rb_float_new((double)st->tm_sec + ((double)nsec + 0.5) / 1000000000.0);
353
- #endif
354
- args[6] = LONG2NUM(ni->exp);
355
- parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
356
- #endif
357
- } else {
358
- #if HAS_NANO_TIME
359
- parent->val = rb_time_nano_new(ni->i, (long)nsec);
360
- #else
361
- parent->val = rb_time_new(ni->i, (long)(nsec / 1000));
362
- #endif
363
- }
364
- }
365
- break;
366
- case 'i': // circular index
367
- if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
368
- if (Qnil == parent->val) {
369
- parent->val = rb_hash_new();
370
- }
371
- oj_circ_array_set(pi->circ_array, parent->val, ni->i);
372
- } else {
373
- return 0;
374
- }
375
- break;
376
- default:
377
- return 0;
378
- break;
379
- }
380
- return 1; // handled
250
+ switch (kval->key[1]) {
251
+ case 't': // time as a float
252
+ if (0 == ni->div || 9 < ni->di) {
253
+ rb_raise(rb_eArgError, "Invalid time decimal representation.");
254
+ // parent->val = rb_time_nano_new(0, 0);
255
+ } else {
256
+ int64_t nsec = ni->num * 1000000000LL / ni->div;
257
+
258
+ if (ni->neg) {
259
+ ni->i = -ni->i;
260
+ if (0 < nsec) {
261
+ ni->i--;
262
+ nsec = 1000000000LL - nsec;
263
+ }
264
+ }
265
+ if (86400 == ni->exp) { // UTC time
266
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
267
+ // Since the ruby C routines always create local time, the
268
+ // offset and then a conversion to UTC keeps makes the time
269
+ // match the expected value.
270
+ parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
271
+ } else if (ni->has_exp) {
272
+ int64_t t = (int64_t)(ni->i + ni->exp);
273
+ struct _timeInfo ti;
274
+ VALUE args[8];
275
+
276
+ sec_as_time(t, &ti);
277
+ args[0] = LONG2NUM((long)(ti.year));
278
+ args[1] = LONG2NUM(ti.mon);
279
+ args[2] = LONG2NUM(ti.day);
280
+ args[3] = LONG2NUM(ti.hour);
281
+ args[4] = LONG2NUM(ti.min);
282
+ args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
283
+ args[6] = LONG2NUM(ni->exp);
284
+ parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
285
+ } else {
286
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
287
+ }
288
+ }
289
+ break;
290
+ case 'i': // circular index
291
+ if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
292
+ if (Qnil == parent->val) {
293
+ parent->val = rb_hash_new();
294
+ }
295
+ oj_circ_array_set(pi->circ_array, parent->val, ni->i);
296
+ } else {
297
+ return 0;
298
+ }
299
+ break;
300
+ default: return 0; break;
301
+ }
302
+ return 1; // handled
381
303
  }
382
304
  return 0;
383
305
  }
384
306
 
385
- static int
386
- hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) {
307
+ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) {
387
308
  if (T_ARRAY == rb_type(value)) {
388
- int len = (int)RARRAY_LEN(value);
389
-
390
- if (2 == klen && 'u' == key[1]) {
391
- volatile VALUE sc;
392
- volatile VALUE e1;
393
- int slen;
394
-
395
- if (0 == len) {
396
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
397
- return 1;
398
- }
399
- e1 = *RARRAY_PTR(value);
400
- // check for anonymous Struct
401
- if (T_ARRAY == rb_type(e1)) {
402
- VALUE args[1024];
403
- volatile VALUE rstr;
404
- int i, cnt = (int)RARRAY_LEN(e1);
405
-
406
- for (i = 0; i < cnt; i++) {
407
- rstr = rb_ary_entry(e1, i);
408
- args[i] = rb_funcall(rstr, oj_to_sym_id, 0);
409
- }
410
- sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args);
411
- } else {
412
- // If struct is not defined then we let this fail and raise an exception.
413
- sc = oj_name2struct(pi, *RARRAY_PTR(value));
414
- }
309
+ int len = (int)RARRAY_LEN(value);
310
+
311
+ if (2 == klen && 'u' == key[1]) {
312
+ volatile VALUE sc;
313
+ volatile VALUE e1;
314
+ int slen;
315
+
316
+ if (0 == len) {
317
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
318
+ return 1;
319
+ }
320
+ e1 = *RARRAY_PTR(value);
321
+ // check for anonymous Struct
322
+ if (T_ARRAY == rb_type(e1)) {
323
+ VALUE args[1024];
324
+ volatile VALUE rstr;
325
+ int i, cnt = (int)RARRAY_LEN(e1);
326
+
327
+ for (i = 0; i < cnt; i++) {
328
+ rstr = RARRAY_AREF(e1, i);
329
+ args[i] = rb_funcall(rstr, oj_to_sym_id, 0);
330
+ }
331
+ sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args);
332
+ } else {
333
+ // If struct is not defined then we let this fail and raise an exception.
334
+ sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
335
+ }
415
336
  // Create a properly initialized struct instance without calling the initialize method.
416
337
  parent->val = rb_obj_alloc(sc);
417
338
  // If the JSON array has more entries than the struct class allows, we record an error.
418
339
  #ifdef RSTRUCT_LEN
419
- #if UNIFY_FIXNUM_AND_BIGNUM
420
- slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
421
- #else // UNIFY_FIXNUM_AND_INTEGER
422
- slen = (int)RSTRUCT_LEN(parent->val);
423
- #endif // UNIFY_FIXNUM_AND_INTEGER
340
+ #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
341
+ slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
342
+ #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
343
+ slen = (int)RSTRUCT_LEN(parent->val);
344
+ #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
424
345
  #else
425
- slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
346
+ slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
426
347
  #endif
427
348
  // MRI >= 1.9
428
349
  if (len - 1 > slen) {
429
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
350
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
430
351
  } else {
431
- int i;
352
+ int i;
432
353
 
433
- for (i = 0; i < slen; i++) {
434
- rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
435
- }
354
+ for (i = 0; i < len - 1; i++) {
355
+ rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
356
+ }
436
357
  }
437
- return 1;
438
- } else if (3 <= klen && '#' == key[1]) {
439
- volatile VALUE *a;
440
-
441
- if (2 != len) {
442
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
443
- return 1;
444
- }
445
- parent->val = rb_hash_new();
446
- a = RARRAY_PTR(value);
447
- rb_hash_aset(parent->val, *a, a[1]);
448
-
449
- return 1;
450
- }
451
- }
452
- return 0;
453
- }
358
+ return 1;
359
+ } else if (3 <= klen && '#' == key[1]) {
360
+ volatile VALUE *a;
361
+
362
+ if (2 != len) {
363
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
364
+ return 1;
365
+ }
366
+ parent->val = rb_hash_new();
367
+ a = RARRAY_PTR(value);
368
+ rb_hash_aset(parent->val, *a, a[1]);
454
369
 
455
- static void
456
- copy_ivars(VALUE target, VALUE src) {
457
- volatile VALUE vars = rb_funcall(src, oj_instance_variables_id, 0);
458
- volatile VALUE *np = RARRAY_PTR(vars);
459
- ID vid;
460
- int i, cnt = (int)RARRAY_LEN(vars);
461
- const char *attr;
462
-
463
- for (i = cnt; 0 < i; i--, np++) {
464
- vid = rb_to_id(*np);
465
- attr = rb_id2name(vid);
466
- if ('@' == *attr) {
467
- rb_ivar_set(target, vid, rb_ivar_get(src, vid));
468
- }
370
+ return 1;
371
+ }
469
372
  }
373
+ return 0;
470
374
  }
471
375
 
472
- static void
473
- set_obj_ivar(Val parent, Val kval, VALUE value) {
474
- const char *key = kval->key;
475
- int klen = kval->klen;
476
- ID var_id;
477
- ID *slot;
478
-
479
- if ('~' == *key && Qtrue == rb_obj_is_kind_of(parent->val, rb_eException)) {
480
- if (5 == klen && 0 == strncmp("~mesg", key, klen)) {
481
- VALUE args[1];
482
- volatile VALUE prev = parent->val;
483
-
484
- args[0] = value;
485
- parent->val = rb_class_new_instance(1, args, rb_class_of(parent->val));
486
- copy_ivars(parent->val, prev);
487
- } else if (3 == klen && 0 == strncmp("~bt", key, klen)) {
488
- rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
489
- }
490
- }
491
- #if USE_PTHREAD_MUTEX
492
- pthread_mutex_lock(&oj_cache_mutex);
493
- #elif USE_RB_MUTEX
494
- rb_mutex_lock(oj_cache_mutex);
495
- #endif
496
- if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
497
- char attr[256];
498
-
499
- if ((int)sizeof(attr) <= klen + 2) {
500
- char *buf = ALLOC_N(char, klen + 2);
501
-
502
- if ('~' == *key) {
503
- strncpy(buf, key + 1, klen - 1);
504
- buf[klen - 1] = '\0';
505
- } else {
506
- *buf = '@';
507
- strncpy(buf + 1, key, klen);
508
- buf[klen + 1] = '\0';
509
- }
510
- var_id = rb_intern(buf);
511
- xfree(buf);
512
- } else {
513
- if ('~' == *key) {
514
- strncpy(attr, key + 1, klen - 1);
515
- attr[klen - 1] = '\0';
516
- } else {
517
- *attr = '@';
518
- strncpy(attr + 1, key, klen);
519
- attr[klen + 1] = '\0';
520
- }
521
- var_id = rb_intern(attr);
522
- }
523
- *slot = var_id;
524
- }
525
- #if USE_PTHREAD_MUTEX
526
- pthread_mutex_unlock(&oj_cache_mutex);
527
- #elif USE_RB_MUTEX
528
- rb_mutex_unlock(oj_cache_mutex);
529
- #endif
530
- rb_ivar_set(parent->val, var_id, value);
376
+ void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
377
+ rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
531
378
  }
532
379
 
533
- static void
534
- hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
535
- const char *key = kval->key;
536
- int klen = kval->klen;
537
- Val parent = stack_peek(&pi->stack);
380
+ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
381
+ const char * key = kval->key;
382
+ int klen = kval->klen;
383
+ Val parent = stack_peek(&pi->stack);
384
+ volatile VALUE rval = Qnil;
538
385
 
539
- WHICH_TYPE:
386
+ WHICH_TYPE:
540
387
  switch (rb_type(parent->val)) {
541
388
  case T_NIL:
542
- parent->odd_args = 0; // make sure it is 0 in case not odd
543
- if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) {
544
- parent->val = rb_hash_new();
545
- goto WHICH_TYPE;
546
- }
547
- break;
389
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
390
+ if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) {
391
+ parent->val = rb_hash_new();
392
+ goto WHICH_TYPE;
393
+ }
394
+ break;
548
395
  case T_HASH:
549
- rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
550
- break;
396
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
397
+ break;
551
398
  case T_STRING:
552
- if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
553
- rb_funcall(parent->val, oj_replace_id, 1, str_to_value(pi, str, len, orig));
554
- } else {
555
- set_obj_ivar(parent, kval, str_to_value(pi, str, len, orig));
556
- }
557
- break;
399
+ rval = str_to_value(pi, str, len, orig);
400
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
401
+ rb_funcall(parent->val, oj_replace_id, 1, rval);
402
+ } else {
403
+ oj_set_obj_ivar(parent, kval, rval);
404
+ }
405
+ break;
558
406
  case T_OBJECT:
559
- set_obj_ivar(parent, kval, str_to_value(pi, str, len, orig));
560
- break;
407
+ rval = str_to_value(pi, str, len, orig);
408
+ oj_set_obj_ivar(parent, kval, rval);
409
+ break;
561
410
  case T_CLASS:
562
- if (0 == parent->odd_args) {
563
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
564
- return;
565
- } else if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, str_to_value(pi, str, len, orig))) {
566
- char buf[256];
567
-
568
- if ((int)sizeof(buf) - 1 <= klen) {
569
- klen = sizeof(buf) - 2;
570
- }
571
- memcpy(buf, key, klen);
572
- buf[klen] = '\0';
573
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
574
- }
575
- break;
411
+ if (NULL == parent->odd_args) {
412
+ oj_set_error_at(pi,
413
+ oj_parse_error_class,
414
+ __FILE__,
415
+ __LINE__,
416
+ "%s is not an odd class",
417
+ rb_class2name(rb_obj_class(parent->val)));
418
+ return;
419
+ } else {
420
+ rval = str_to_value(pi, str, len, orig);
421
+ if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) {
422
+ char buf[256];
423
+
424
+ if ((int)sizeof(buf) - 1 <= klen) {
425
+ klen = sizeof(buf) - 2;
426
+ }
427
+ memcpy(buf, key, klen);
428
+ buf[klen] = '\0';
429
+ oj_set_error_at(pi,
430
+ oj_parse_error_class,
431
+ __FILE__,
432
+ __LINE__,
433
+ "%s is not an attribute of %s",
434
+ buf,
435
+ rb_class2name(rb_obj_class(parent->val)));
436
+ }
437
+ }
438
+ break;
576
439
  default:
577
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
578
- return;
440
+ oj_set_error_at(pi,
441
+ oj_parse_error_class,
442
+ __FILE__,
443
+ __LINE__,
444
+ "can not add attributes to a %s",
445
+ rb_class2name(rb_obj_class(parent->val)));
446
+ return;
447
+ }
448
+ if (Yes == pi->options.trace) {
449
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
579
450
  }
580
451
  }
581
452
 
582
- static void
583
- hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
584
- const char *key = kval->key;
585
- int klen = kval->klen;
586
- Val parent = stack_peek(&pi->stack);
453
+ static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
454
+ const char * key = kval->key;
455
+ int klen = kval->klen;
456
+ Val parent = stack_peek(&pi->stack);
457
+ volatile VALUE rval = Qnil;
587
458
 
588
- WHICH_TYPE:
459
+ WHICH_TYPE:
589
460
  switch (rb_type(parent->val)) {
590
461
  case T_NIL:
591
- parent->odd_args = 0; // make sure it is 0 in case not odd
592
- if ('^' != *key || !hat_num(pi, parent, kval, ni)) {
593
- parent->val = rb_hash_new();
594
- goto WHICH_TYPE;
595
- }
596
- break;
462
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
463
+ if ('^' != *key || !hat_num(pi, parent, kval, ni)) {
464
+ parent->val = rb_hash_new();
465
+ goto WHICH_TYPE;
466
+ }
467
+ break;
597
468
  case T_HASH:
598
- rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), oj_num_as_value(ni));
599
- break;
469
+ rval = oj_num_as_value(ni);
470
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
471
+ break;
600
472
  case T_OBJECT:
601
- if (2 == klen && '^' == *key && 'i' == key[1] &&
602
- !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
603
- oj_circ_array_set(pi->circ_array, parent->val, ni->i);
604
- } else {
605
- set_obj_ivar(parent, kval, oj_num_as_value(ni));
606
- }
607
- break;
473
+ if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp &&
474
+ 0 != pi->circ_array) { // fixnum
475
+ oj_circ_array_set(pi->circ_array, parent->val, ni->i);
476
+ } else {
477
+ rval = oj_num_as_value(ni);
478
+ oj_set_obj_ivar(parent, kval, rval);
479
+ }
480
+ break;
608
481
  case T_CLASS:
609
- if (0 == parent->odd_args) {
610
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
611
- return;
612
- } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, oj_num_as_value(ni))) {
613
- char buf[256];
614
-
615
- if ((int)sizeof(buf) - 1 <= klen) {
616
- klen = sizeof(buf) - 2;
617
- }
618
- memcpy(buf, key, klen);
619
- buf[klen] = '\0';
620
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
621
- }
622
- break;
482
+ if (NULL == parent->odd_args) {
483
+ oj_set_error_at(pi,
484
+ oj_parse_error_class,
485
+ __FILE__,
486
+ __LINE__,
487
+ "%s is not an odd class",
488
+ rb_class2name(rb_obj_class(parent->val)));
489
+ return;
490
+ } else {
491
+ rval = oj_num_as_value(ni);
492
+ if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) {
493
+ char buf[256];
494
+
495
+ if ((int)sizeof(buf) - 1 <= klen) {
496
+ klen = sizeof(buf) - 2;
497
+ }
498
+ memcpy(buf, key, klen);
499
+ buf[klen] = '\0';
500
+ oj_set_error_at(pi,
501
+ oj_parse_error_class,
502
+ __FILE__,
503
+ __LINE__,
504
+ "%s is not an attribute of %s",
505
+ buf,
506
+ rb_class2name(rb_obj_class(parent->val)));
507
+ }
508
+ }
509
+ break;
623
510
  default:
624
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
625
- return;
511
+ oj_set_error_at(pi,
512
+ oj_parse_error_class,
513
+ __FILE__,
514
+ __LINE__,
515
+ "can not add attributes to a %s",
516
+ rb_class2name(rb_obj_class(parent->val)));
517
+ return;
518
+ }
519
+ if (Yes == pi->options.trace) {
520
+ oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
626
521
  }
627
522
  }
628
523
 
629
- static void
630
- hash_set_value(ParseInfo pi, Val kval, VALUE value) {
631
- const char *key = kval->key;
632
- int klen = kval->klen;
633
- Val parent = stack_peek(&pi->stack);
524
+ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
525
+ const char *key = kval->key;
526
+ int klen = kval->klen;
527
+ Val parent = stack_peek(&pi->stack);
634
528
 
635
- WHICH_TYPE:
529
+ WHICH_TYPE:
636
530
  switch (rb_type(parent->val)) {
637
531
  case T_NIL:
638
- parent->odd_args = 0; // make sure it is 0 in case not odd
639
- if ('^' != *key || !hat_value(pi, parent, key, klen, value)) {
640
- parent->val = rb_hash_new();
641
- goto WHICH_TYPE;
642
- }
643
- break;
532
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
533
+ if ('^' != *key || !hat_value(pi, parent, key, klen, value)) {
534
+ parent->val = rb_hash_new();
535
+ goto WHICH_TYPE;
536
+ }
537
+ break;
644
538
  case T_HASH:
645
- if (rb_cHash != rb_obj_class(parent->val)) {
646
- if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
647
- rb_funcall(parent->val, oj_replace_id, 1, value);
648
- } else {
649
- set_obj_ivar(parent, kval, value);
650
- }
651
- } else {
652
- if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
653
- long len = RARRAY_LEN(value);
654
- volatile VALUE *a = RARRAY_PTR(value);
655
-
656
- if (2 != len) {
657
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
658
- return;
659
- }
660
- rb_hash_aset(parent->val, *a, a[1]);
661
- } else {
662
- rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), value);
663
- }
664
- }
665
- break;
539
+ if (rb_cHash != rb_obj_class(parent->val)) {
540
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
541
+ rb_funcall(parent->val, oj_replace_id, 1, value);
542
+ } else {
543
+ oj_set_obj_ivar(parent, kval, value);
544
+ }
545
+ } else {
546
+ if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
547
+ long len = RARRAY_LEN(value);
548
+ volatile VALUE *a = RARRAY_PTR(value);
549
+
550
+ if (2 != len) {
551
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
552
+ return;
553
+ }
554
+ rb_hash_aset(parent->val, *a, a[1]);
555
+ } else {
556
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), value);
557
+ }
558
+ }
559
+ break;
666
560
  case T_ARRAY:
667
- if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
668
- rb_funcall(parent->val, oj_replace_id, 1, value);
669
- } else {
670
- set_obj_ivar(parent, kval, value);
671
- }
672
- break;
673
- case T_STRING: // for subclassed strings
674
- case T_OBJECT:
675
- set_obj_ivar(parent, kval, value);
676
- break;
561
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
562
+ rb_funcall(parent->val, oj_replace_id, 1, value);
563
+ } else {
564
+ oj_set_obj_ivar(parent, kval, value);
565
+ }
566
+ break;
567
+ case T_STRING: // for subclassed strings
568
+ case T_OBJECT: oj_set_obj_ivar(parent, kval, value); break;
677
569
  case T_MODULE:
678
570
  case T_CLASS:
679
- if (0 == parent->odd_args) {
680
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
681
- return;
682
- } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
683
- char buf[256];
684
-
685
- if ((int)sizeof(buf) - 1 <= klen) {
686
- klen = sizeof(buf) - 2;
687
- }
688
- memcpy(buf, key, klen);
689
- buf[klen] = '\0';
690
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
691
- }
692
- break;
571
+ if (NULL == parent->odd_args) {
572
+ oj_set_error_at(pi,
573
+ oj_parse_error_class,
574
+ __FILE__,
575
+ __LINE__,
576
+ "%s is not an odd class",
577
+ rb_class2name(rb_obj_class(parent->val)));
578
+ return;
579
+ } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
580
+ char buf[256];
581
+
582
+ if ((int)sizeof(buf) - 1 <= klen) {
583
+ klen = sizeof(buf) - 2;
584
+ }
585
+ memcpy(buf, key, klen);
586
+ buf[klen] = '\0';
587
+ oj_set_error_at(pi,
588
+ oj_parse_error_class,
589
+ __FILE__,
590
+ __LINE__,
591
+ "%s is not an attribute of %s",
592
+ buf,
593
+ rb_class2name(rb_obj_class(parent->val)));
594
+ }
595
+ break;
693
596
  default:
694
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
695
- return;
597
+ oj_set_error_at(pi,
598
+ oj_parse_error_class,
599
+ __FILE__,
600
+ __LINE__,
601
+ "can not add attributes to a %s",
602
+ rb_class2name(rb_obj_class(parent->val)));
603
+ return;
604
+ }
605
+ if (Yes == pi->options.trace) {
606
+ oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
696
607
  }
697
608
  }
698
609
 
699
- static VALUE
700
- start_hash(ParseInfo pi) {
610
+ static VALUE start_hash(ParseInfo pi) {
611
+ if (Yes == pi->options.trace) {
612
+ oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
613
+ }
701
614
  return Qnil;
702
615
  }
703
616
 
704
- static void
705
- end_hash(struct _ParseInfo *pi) {
706
- Val parent = stack_peek(&pi->stack);
617
+ static void end_hash(ParseInfo pi) {
618
+ Val parent = stack_peek(&pi->stack);
707
619
 
708
620
  if (Qnil == parent->val) {
709
- parent->val = rb_hash_new();
710
- } else if (0 != parent->odd_args) {
711
- OddArgs oa = parent->odd_args;
621
+ parent->val = rb_hash_new();
622
+ } else if (NULL != parent->odd_args) {
623
+ OddArgs oa = parent->odd_args;
712
624
 
713
- parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
714
- oj_odd_free(oa);
715
- parent->odd_args = 0;
625
+ parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
626
+ oj_odd_free(oa);
627
+ parent->odd_args = NULL;
628
+ }
629
+ if (Yes == pi->options.trace) {
630
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
716
631
  }
717
632
  }
718
633
 
719
- static void
720
- array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
721
- if (3 <= len && 0 != pi->circ_array) {
722
- if ('i' == str[1]) {
723
- long i = read_long(str + 2, len - 2);
724
-
725
- if (0 < i) {
726
- oj_circ_array_set(pi->circ_array, stack_peek(&pi->stack)->val, i);
727
- return;
728
- }
729
- } else if ('r' == str[1]) {
730
- long i = read_long(str + 2, len - 2);
731
-
732
- if (0 < i) {
733
- rb_ary_push(stack_peek(&pi->stack)->val, oj_circ_array_get(pi->circ_array, i));
734
- return;
735
- }
736
-
737
- }
738
- }
739
- rb_ary_push(stack_peek(&pi->stack)->val, str_to_value(pi, str, len, orig));
634
+ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
635
+ volatile VALUE rval = Qnil;
636
+
637
+ // orig lets us know whether the string was ^r1 or \u005er1
638
+ if (3 <= len && 0 != pi->circ_array && '^' == orig[0] && 0 == rb_array_len(stack_peek(&pi->stack)->val)) {
639
+ if ('i' == str[1]) {
640
+ long i = read_long(str + 2, len - 2);
641
+
642
+ if (0 < i) {
643
+ oj_circ_array_set(pi->circ_array, stack_peek(&pi->stack)->val, i);
644
+ return;
645
+ }
646
+ } else if ('r' == str[1]) {
647
+ long i = read_long(str + 2, len - 2);
648
+
649
+ if (0 < i) {
650
+ rb_ary_push(stack_peek(&pi->stack)->val, oj_circ_array_get(pi->circ_array, i));
651
+ return;
652
+ }
653
+ }
654
+ }
655
+ rval = str_to_value(pi, str, len, orig);
656
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
657
+ if (Yes == pi->options.trace) {
658
+ oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
659
+ }
740
660
  }
741
661
 
742
- static void
743
- array_append_num(ParseInfo pi, NumInfo ni) {
744
- rb_ary_push(stack_peek(&pi->stack)->val, oj_num_as_value(ni));
662
+ static void array_append_num(ParseInfo pi, NumInfo ni) {
663
+ volatile VALUE rval = oj_num_as_value(ni);
664
+
665
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
666
+ if (Yes == pi->options.trace) {
667
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
668
+ }
745
669
  }
746
670
 
747
- static void
748
- add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
671
+ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
749
672
  pi->stack.head->val = str_to_value(pi, str, len, orig);
673
+ if (Yes == pi->options.trace) {
674
+ oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
675
+ }
750
676
  }
751
677
 
752
- static void
753
- add_num(ParseInfo pi, NumInfo ni) {
678
+ static void add_num(ParseInfo pi, NumInfo ni) {
754
679
  pi->stack.head->val = oj_num_as_value(ni);
680
+ if (Yes == pi->options.trace) {
681
+ oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
682
+ }
755
683
  }
756
684
 
757
- void
758
- oj_set_object_callbacks(ParseInfo pi) {
685
+ void oj_set_object_callbacks(ParseInfo pi) {
759
686
  oj_set_strict_callbacks(pi);
760
- pi->end_hash = end_hash;
761
- pi->start_hash = start_hash;
762
- pi->hash_set_cstr = hash_set_cstr;
763
- pi->hash_set_num = hash_set_num;
764
- pi->hash_set_value = hash_set_value;
765
- pi->add_cstr = add_cstr;
766
- pi->add_num = add_num;
687
+ pi->end_hash = end_hash;
688
+ pi->start_hash = start_hash;
689
+ pi->hash_set_cstr = hash_set_cstr;
690
+ pi->hash_set_num = hash_set_num;
691
+ pi->hash_set_value = hash_set_value;
692
+ pi->add_cstr = add_cstr;
693
+ pi->add_num = add_num;
767
694
  pi->array_append_cstr = array_append_cstr;
768
- pi->array_append_num = array_append_num;
695
+ pi->array_append_num = array_append_num;
769
696
  }
770
697
 
771
698
  VALUE
772
699
  oj_object_parse(int argc, VALUE *argv, VALUE self) {
773
- struct _ParseInfo pi;
700
+ struct _parseInfo pi;
774
701
 
775
- pi.options = oj_default_options;
776
- pi.handler = Qnil;
702
+ parse_info_init(&pi);
703
+ pi.options = oj_default_options;
704
+ pi.handler = Qnil;
777
705
  pi.err_class = Qnil;
778
706
  oj_set_object_callbacks(&pi);
779
707
 
780
708
  if (T_STRING == rb_type(*argv)) {
781
- return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
709
+ return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
782
710
  } else {
783
- return oj_pi_sparse(argc, argv, &pi, 0);
711
+ return oj_pi_sparse(argc, argv, &pi, 0);
784
712
  }
785
713
  }
786
714
 
787
715
  VALUE
788
716
  oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
789
- struct _ParseInfo pi;
717
+ struct _parseInfo pi;
790
718
 
791
- pi.options = oj_default_options;
792
- pi.handler = Qnil;
719
+ parse_info_init(&pi);
720
+ pi.options = oj_default_options;
721
+ pi.handler = Qnil;
793
722
  pi.err_class = Qnil;
794
723
  oj_set_strict_callbacks(&pi);
795
- pi.end_hash = end_hash;
796
- pi.start_hash = start_hash;
797
- pi.hash_set_cstr = hash_set_cstr;
798
- pi.hash_set_num = hash_set_num;
799
- pi.hash_set_value = hash_set_value;
800
- pi.add_cstr = add_cstr;
801
- pi.add_num = add_num;
724
+ pi.end_hash = end_hash;
725
+ pi.start_hash = start_hash;
726
+ pi.hash_set_cstr = hash_set_cstr;
727
+ pi.hash_set_num = hash_set_num;
728
+ pi.hash_set_value = hash_set_value;
729
+ pi.add_cstr = add_cstr;
730
+ pi.add_num = add_num;
802
731
  pi.array_append_cstr = array_append_cstr;
803
- pi.array_append_num = array_append_num;
732
+ pi.array_append_num = array_append_num;
804
733
 
805
734
  return oj_pi_parse(argc, argv, &pi, json, len, 1);
806
735
  }