oj 2.18.5 → 3.16.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1452 -0
  3. data/README.md +53 -221
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +54 -72
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +61 -63
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +38 -67
  11. data/ext/oj/circarray.h +16 -42
  12. data/ext/oj/code.c +214 -0
  13. data/ext/oj/code.h +40 -0
  14. data/ext/oj/compat.c +194 -110
  15. data/ext/oj/custom.c +1074 -0
  16. data/ext/oj/debug.c +126 -0
  17. data/ext/oj/dump.c +1276 -2494
  18. data/ext/oj/dump.h +110 -0
  19. data/ext/oj/dump_compat.c +897 -0
  20. data/ext/oj/dump_leaf.c +162 -0
  21. data/ext/oj/dump_object.c +710 -0
  22. data/ext/oj/dump_strict.c +399 -0
  23. data/ext/oj/encode.h +7 -42
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +28 -53
  26. data/ext/oj/err.h +49 -46
  27. data/ext/oj/extconf.rb +33 -32
  28. data/ext/oj/fast.c +1082 -1098
  29. data/ext/oj/intern.c +313 -0
  30. data/ext/oj/intern.h +22 -0
  31. data/ext/oj/mem.c +318 -0
  32. data/ext/oj/mem.h +53 -0
  33. data/ext/oj/mimic_json.c +919 -0
  34. data/ext/oj/object.c +545 -625
  35. data/ext/oj/odd.c +158 -168
  36. data/ext/oj/odd.h +32 -58
  37. data/ext/oj/oj.c +1727 -2080
  38. data/ext/oj/oj.h +334 -259
  39. data/ext/oj/parse.c +974 -753
  40. data/ext/oj/parse.h +97 -90
  41. data/ext/oj/parser.c +1600 -0
  42. data/ext/oj/parser.h +103 -0
  43. data/ext/oj/rails.c +1478 -0
  44. data/ext/oj/rails.h +18 -0
  45. data/ext/oj/reader.c +136 -163
  46. data/ext/oj/reader.h +76 -112
  47. data/ext/oj/resolve.c +45 -94
  48. data/ext/oj/resolve.h +7 -34
  49. data/ext/oj/rxclass.c +144 -0
  50. data/ext/oj/rxclass.h +26 -0
  51. data/ext/oj/saj.c +445 -511
  52. data/ext/oj/saj2.c +584 -0
  53. data/ext/oj/saj2.h +23 -0
  54. data/ext/oj/scp.c +82 -143
  55. data/ext/oj/simd.h +10 -0
  56. data/ext/oj/sparse.c +749 -644
  57. data/ext/oj/stream_writer.c +329 -0
  58. data/ext/oj/strict.c +114 -112
  59. data/ext/oj/string_writer.c +517 -0
  60. data/ext/oj/trace.c +72 -0
  61. data/ext/oj/trace.h +55 -0
  62. data/ext/oj/usual.c +1218 -0
  63. data/ext/oj/usual.h +69 -0
  64. data/ext/oj/util.c +136 -0
  65. data/ext/oj/util.h +20 -0
  66. data/ext/oj/val_stack.c +75 -72
  67. data/ext/oj/val_stack.h +94 -127
  68. data/ext/oj/validate.c +46 -0
  69. data/ext/oj/wab.c +586 -0
  70. data/lib/oj/active_support_helper.rb +1 -3
  71. data/lib/oj/bag.rb +8 -1
  72. data/lib/oj/easy_hash.rb +21 -13
  73. data/lib/oj/error.rb +10 -12
  74. data/lib/oj/json.rb +188 -0
  75. data/lib/oj/mimic.rb +165 -26
  76. data/lib/oj/saj.rb +20 -6
  77. data/lib/oj/schandler.rb +5 -4
  78. data/lib/oj/state.rb +135 -0
  79. data/lib/oj/version.rb +2 -3
  80. data/lib/oj.rb +3 -31
  81. data/pages/Advanced.md +22 -0
  82. data/pages/Compatibility.md +25 -0
  83. data/pages/Custom.md +23 -0
  84. data/pages/Encoding.md +65 -0
  85. data/pages/InstallOptions.md +20 -0
  86. data/pages/JsonGem.md +94 -0
  87. data/pages/Modes.md +161 -0
  88. data/pages/Options.md +337 -0
  89. data/pages/Parser.md +309 -0
  90. data/pages/Rails.md +167 -0
  91. data/pages/Security.md +20 -0
  92. data/pages/WAB.md +13 -0
  93. metadata +126 -163
  94. data/ext/oj/hash.c +0 -163
  95. data/ext/oj/hash.h +0 -46
  96. data/ext/oj/hash_test.c +0 -512
  97. data/test/_test_active.rb +0 -76
  98. data/test/_test_active_mimic.rb +0 -96
  99. data/test/_test_mimic_rails.rb +0 -126
  100. data/test/activesupport_datetime_test.rb +0 -23
  101. data/test/bug.rb +0 -51
  102. data/test/bug2.rb +0 -10
  103. data/test/bug3.rb +0 -46
  104. data/test/bug_fast.rb +0 -32
  105. data/test/bug_load.rb +0 -24
  106. data/test/crash.rb +0 -111
  107. data/test/curl/curl_oj.rb +0 -46
  108. data/test/curl/get_oj.rb +0 -24
  109. data/test/curl/just_curl.rb +0 -31
  110. data/test/curl/just_oj.rb +0 -51
  111. data/test/example.rb +0 -11
  112. data/test/files.rb +0 -29
  113. data/test/foo.rb +0 -24
  114. data/test/helper.rb +0 -27
  115. data/test/io.rb +0 -48
  116. data/test/isolated/shared.rb +0 -310
  117. data/test/isolated/test_mimic_after.rb +0 -13
  118. data/test/isolated/test_mimic_alone.rb +0 -12
  119. data/test/isolated/test_mimic_as_json.rb +0 -45
  120. data/test/isolated/test_mimic_before.rb +0 -13
  121. data/test/isolated/test_mimic_define.rb +0 -28
  122. data/test/isolated/test_mimic_rails_after.rb +0 -22
  123. data/test/isolated/test_mimic_rails_before.rb +0 -21
  124. data/test/isolated/test_mimic_rails_datetime.rb +0 -27
  125. data/test/isolated/test_mimic_redefine.rb +0 -15
  126. data/test/mod.rb +0 -16
  127. data/test/perf.rb +0 -107
  128. data/test/perf_compat.rb +0 -128
  129. data/test/perf_fast.rb +0 -164
  130. data/test/perf_file.rb +0 -64
  131. data/test/perf_object.rb +0 -138
  132. data/test/perf_saj.rb +0 -109
  133. data/test/perf_scp.rb +0 -151
  134. data/test/perf_simple.rb +0 -287
  135. data/test/perf_strict.rb +0 -128
  136. data/test/rails.rb +0 -50
  137. data/test/russian.rb +0 -18
  138. data/test/sample/change.rb +0 -14
  139. data/test/sample/dir.rb +0 -19
  140. data/test/sample/doc.rb +0 -36
  141. data/test/sample/file.rb +0 -48
  142. data/test/sample/group.rb +0 -16
  143. data/test/sample/hasprops.rb +0 -16
  144. data/test/sample/layer.rb +0 -12
  145. data/test/sample/line.rb +0 -20
  146. data/test/sample/oval.rb +0 -10
  147. data/test/sample/rect.rb +0 -10
  148. data/test/sample/shape.rb +0 -35
  149. data/test/sample/text.rb +0 -20
  150. data/test/sample.rb +0 -55
  151. data/test/sample_json.rb +0 -37
  152. data/test/struct.rb +0 -29
  153. data/test/test_compat.rb +0 -398
  154. data/test/test_debian.rb +0 -53
  155. data/test/test_fast.rb +0 -458
  156. data/test/test_file.rb +0 -245
  157. data/test/test_gc.rb +0 -49
  158. data/test/test_hash.rb +0 -29
  159. data/test/test_object.rb +0 -745
  160. data/test/test_saj.rb +0 -186
  161. data/test/test_scp.rb +0 -396
  162. data/test/test_serializer.rb +0 -59
  163. data/test/test_strict.rb +0 -254
  164. data/test/test_various.rb +0 -1383
  165. data/test/test_writer.rb +0 -308
  166. data/test/write_timebars.rb +0 -31
data/ext/oj/object.c CHANGED
@@ -1,806 +1,726 @@
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[7];
87
+ const char *end = str + len;
88
+ const char *orig = str;
89
+ int n;
125
90
 
126
91
  // year
127
92
  if (0 > (n = parse_num(str, end, 4))) {
128
- return Qnil;
93
+ return Qnil;
129
94
  }
130
95
  str += 4;
131
96
  args[0] = LONG2NUM(n);
132
97
  if ('-' != *str++) {
133
- return Qnil;
98
+ return Qnil;
134
99
  }
135
100
  // month
136
101
  if (0 > (n = parse_num(str, end, 2))) {
137
- return Qnil;
102
+ return Qnil;
138
103
  }
139
104
  str += 2;
140
105
  args[1] = LONG2NUM(n);
141
106
  if ('-' != *str++) {
142
- return Qnil;
107
+ return Qnil;
143
108
  }
144
109
  // day
145
110
  if (0 > (n = parse_num(str, end, 2))) {
146
- return Qnil;
111
+ return Qnil;
147
112
  }
148
113
  str += 2;
149
114
  args[2] = LONG2NUM(n);
150
115
  if ('T' != *str++) {
151
- return Qnil;
116
+ return Qnil;
152
117
  }
153
118
  // hour
154
119
  if (0 > (n = parse_num(str, end, 2))) {
155
- return Qnil;
120
+ return Qnil;
156
121
  }
157
122
  str += 2;
158
123
  args[3] = LONG2NUM(n);
159
124
  if (':' != *str++) {
160
- return Qnil;
125
+ return Qnil;
161
126
  }
162
127
  // minute
163
128
  if (0 > (n = parse_num(str, end, 2))) {
164
- return Qnil;
129
+ return Qnil;
165
130
  }
166
131
  str += 2;
167
132
  args[4] = LONG2NUM(n);
168
133
  if (':' != *str++) {
169
- return Qnil;
134
+ return Qnil;
170
135
  }
171
136
  // second
172
137
  if (0 > (n = parse_num(str, end, 2))) {
173
- return Qnil;
138
+ return Qnil;
174
139
  }
175
140
  str += 2;
176
141
  if (str == end) {
177
- args[5] = LONG2NUM(n);
178
- args[6] = LONG2NUM(0);
142
+ args[5] = LONG2NUM(n);
143
+ args[6] = LONG2NUM(0);
179
144
  } 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
- }
145
+ char c = *str++;
146
+
147
+ if ('.' == c) {
148
+ unsigned long long num = 0;
149
+ unsigned long long den = 1;
150
+ const unsigned long long last_den_limit = ULLONG_MAX / 10;
151
+
152
+ for (; str < end; str++) {
153
+ c = *str;
154
+ if (c < '0' || '9' < c) {
155
+ str++;
156
+ break;
157
+ }
158
+ if (den > last_den_limit) {
159
+ // bail to Time.parse if there are more fractional digits than a ULLONG rational can hold
160
+ return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(orig, len));
161
+ }
162
+ num = num * 10 + (c - '0');
163
+ den *= 10;
164
+ }
165
+ args[5] = rb_funcall(INT2NUM(n), oj_plus_id, 1, rb_rational_new(ULL2NUM(num), ULL2NUM(den)));
166
+ } else {
167
+ args[5] = rb_ll2inum(n);
168
+ }
169
+ if (end < str) {
170
+ args[6] = LONG2NUM(0);
171
+ } else {
172
+ if ('Z' == c) {
173
+ return rb_funcall2(rb_cTime, oj_utc_id, 6, args);
174
+ } else if ('+' == c) {
175
+ int hr = parse_num(str, end, 2);
176
+ int min;
177
+
178
+ str += 2;
179
+ if (0 > hr || ':' != *str++) {
180
+ return Qnil;
181
+ }
182
+ min = parse_num(str, end, 2);
183
+ if (0 > min) {
184
+ return Qnil;
185
+ }
186
+ args[6] = LONG2NUM(hr * 3600 + min * 60);
187
+ } else if ('-' == c) {
188
+ int hr = parse_num(str, end, 2);
189
+ int min;
190
+
191
+ str += 2;
192
+ if (0 > hr || ':' != *str++) {
193
+ return Qnil;
194
+ }
195
+ min = parse_num(str, end, 2);
196
+ if (0 > min) {
197
+ return Qnil;
198
+ }
199
+ args[6] = LONG2NUM(-(hr * 3600 + min * 60));
200
+ } else {
201
+ args[6] = LONG2NUM(0);
202
+ }
203
+ }
232
204
  }
233
205
  return rb_funcall2(rb_cTime, oj_new_id, 7, args);
234
206
  }
235
- #endif
236
207
 
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;
208
+ static int hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
209
+ const char *key = kval->key;
210
+ int klen = kval->klen;
241
211
 
242
212
  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
213
+ switch (key[1]) {
214
+ case 'o': // object
215
+ { // name2class sets an error if the class is not found or created
216
+ VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
217
+
218
+ if (Qundef != clas) {
219
+ parent->val = rb_obj_alloc(clas);
220
+ }
221
+ } break;
222
+ case 'O': // odd object
223
+ {
224
+ Odd odd = oj_get_oddc(str, len);
225
+
226
+ if (0 == odd) {
227
+ return 0;
228
+ }
229
+ parent->val = odd->clas;
230
+ parent->odd_args = oj_odd_alloc_args(odd);
231
+ break;
232
+ }
233
+ case 'm': parent->val = ID2SYM(rb_intern3(str + 1, len - 1, oj_utf8_encoding)); break;
234
+ case 's': parent->val = rb_utf8_str_new(str, len); break;
235
+ case 'c': // class
236
+ {
237
+ VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
238
+
239
+ if (Qundef == clas) {
240
+ return 0;
241
+ } else {
242
+ parent->val = clas;
243
+ }
244
+ break;
245
+ }
246
+ case 't': // time
247
+ parent->val = oj_parse_xml_time(str, (int)len);
248
+ break;
249
+ default: return 0; break;
250
+ }
251
+ return 1; // handled
292
252
  }
293
253
  return 0;
294
254
  }
295
255
 
296
- static int
297
- hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
256
+ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
298
257
  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
258
+ switch (kval->key[1]) {
259
+ case 't': // time as a float
260
+ if (0 == ni->div || 9 < ni->di) {
261
+ rb_raise(rb_eArgError, "Invalid time decimal representation.");
262
+ // parent->val = rb_time_nano_new(0, 0);
263
+ } else {
264
+ int64_t nsec = ni->num * 1000000000LL / ni->div;
265
+
266
+ if (ni->neg) {
267
+ ni->i = -ni->i;
268
+ if (0 < nsec) {
269
+ ni->i--;
270
+ nsec = 1000000000LL - nsec;
271
+ }
272
+ }
273
+ if (86400 == ni->exp) { // UTC time
274
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
275
+ // Since the ruby C routines always create local time, the
276
+ // offset and then a conversion to UTC keeps makes the time
277
+ // match the expected value.
278
+ parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
279
+ } else if (ni->has_exp) {
280
+ struct timespec ts;
281
+ ts.tv_sec = ni->i;
282
+ ts.tv_nsec = nsec;
283
+ parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
284
+ } else {
285
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
286
+ }
287
+ }
288
+ break;
289
+ case 'i': // circular index
290
+ if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
291
+ if (Qnil == parent->val) {
292
+ parent->val = rb_hash_new();
293
+ }
294
+ oj_circ_array_set(pi->circ_array, parent->val, ni->i);
295
+ } else {
296
+ return 0;
297
+ }
298
+ break;
299
+ default: return 0; break;
300
+ }
301
+ return 1; // handled
381
302
  }
382
303
  return 0;
383
304
  }
384
305
 
385
- static int
386
- hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) {
306
+ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) {
387
307
  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
- }
415
- // Create a properly initialized struct instance without calling the initialize method.
416
- parent->val = rb_obj_alloc(sc);
417
- // If the JSON array has more entries than the struct class allows, we record an error.
308
+ size_t len = RARRAY_LEN(value);
309
+
310
+ if (2 == klen && 'u' == key[1]) {
311
+ volatile VALUE sc;
312
+ volatile VALUE e1;
313
+ int slen;
314
+
315
+ if (0 == len) {
316
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
317
+ return 1;
318
+ }
319
+ e1 = *RARRAY_CONST_PTR(value);
320
+ // check for anonymous Struct
321
+ if (T_ARRAY == rb_type(e1)) {
322
+ VALUE args[1024];
323
+ volatile VALUE rstr;
324
+ size_t i;
325
+ size_t cnt = 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, (int)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_CONST_PTR(value), rb_eArgError);
335
+ }
336
+ if (sc == rb_cRange) {
337
+ parent->val = rb_class_new_instance((int)(len - 1), RARRAY_CONST_PTR(value) + 1, rb_cRange);
338
+ } else {
339
+ // Create a properly initialized struct instance without calling the initialize method.
340
+ parent->val = rb_obj_alloc(sc);
341
+ // If the JSON array has more entries than the struct class allows, we record an error.
418
342
  #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
343
+ #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
344
+ slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
345
+ #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
346
+ slen = (int)RSTRUCT_LEN(parent->val);
347
+ #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
424
348
  #else
425
- slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
349
+ slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
426
350
  #endif
427
- // MRI >= 1.9
428
- if (len - 1 > slen) {
429
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
430
- } else {
431
- int i;
351
+ // MRI >= 1.9
352
+ if (len - 1 > (size_t)slen) {
353
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
354
+ } else {
355
+ size_t i;
356
+
357
+ for (i = 0; i < len - 1; i++) {
358
+ rb_struct_aset(parent->val, INT2FIX(i), RARRAY_CONST_PTR(value)[i + 1]);
359
+ }
360
+ }
361
+ }
362
+ return 1;
363
+ } else if (3 <= klen && '#' == key[1]) {
364
+ volatile const VALUE *a;
432
365
 
433
- for (i = 0; i < slen; i++) {
434
- rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
435
- }
366
+ if (2 != len) {
367
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
368
+ return 1;
436
369
  }
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
- }
370
+ parent->val = rb_hash_new();
371
+ a = RARRAY_CONST_PTR(value);
372
+ rb_hash_aset(parent->val, *a, a[1]);
373
+
374
+ return 1;
375
+ }
451
376
  }
452
377
  return 0;
453
378
  }
454
379
 
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
- }
380
+ void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
381
+ if (kval->klen == 5 && strncmp("~mesg", kval->key, 5) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
382
+ parent->val = rb_funcall(parent->val, rb_intern("exception"), 1, value);
383
+ } else if (kval->klen == 3 && strncmp("~bt", kval->key, 3) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
384
+ rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
385
+ } else {
386
+ rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
469
387
  }
470
388
  }
471
389
 
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);
531
- }
390
+ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
391
+ const char *key = kval->key;
392
+ int klen = kval->klen;
393
+ Val parent = stack_peek(&pi->stack);
394
+ volatile VALUE rval = Qnil;
532
395
 
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);
538
-
539
- WHICH_TYPE:
396
+ WHICH_TYPE:
540
397
  switch (rb_type(parent->val)) {
541
398
  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;
399
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
400
+ if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) {
401
+ parent->val = rb_hash_new();
402
+ goto WHICH_TYPE;
403
+ }
404
+ break;
548
405
  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;
406
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
407
+ break;
551
408
  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;
409
+ rval = str_to_value(pi, str, len, orig);
410
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
411
+ rb_funcall(parent->val, oj_replace_id, 1, rval);
412
+ } else {
413
+ oj_set_obj_ivar(parent, kval, rval);
414
+ }
415
+ break;
558
416
  case T_OBJECT:
559
- set_obj_ivar(parent, kval, str_to_value(pi, str, len, orig));
560
- break;
417
+ rval = str_to_value(pi, str, len, orig);
418
+ oj_set_obj_ivar(parent, kval, rval);
419
+ break;
561
420
  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;
421
+ if (NULL == parent->odd_args) {
422
+ oj_set_error_at(pi,
423
+ oj_parse_error_class,
424
+ __FILE__,
425
+ __LINE__,
426
+ "%s is not an odd class",
427
+ rb_class2name(rb_obj_class(parent->val)));
428
+ return;
429
+ } else {
430
+ rval = str_to_value(pi, str, len, orig);
431
+ if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) {
432
+ char buf[256];
433
+
434
+ if ((int)sizeof(buf) - 1 <= klen) {
435
+ klen = sizeof(buf) - 2;
436
+ }
437
+ memcpy(buf, key, klen);
438
+ buf[klen] = '\0';
439
+ oj_set_error_at(pi,
440
+ oj_parse_error_class,
441
+ __FILE__,
442
+ __LINE__,
443
+ "%s is not an attribute of %s",
444
+ buf,
445
+ rb_class2name(rb_obj_class(parent->val)));
446
+ }
447
+ }
448
+ break;
576
449
  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;
450
+ oj_set_error_at(pi,
451
+ oj_parse_error_class,
452
+ __FILE__,
453
+ __LINE__,
454
+ "can not add attributes to a %s",
455
+ rb_class2name(rb_obj_class(parent->val)));
456
+ return;
579
457
  }
458
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rval);
580
459
  }
581
460
 
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);
461
+ static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
462
+ const char *key = kval->key;
463
+ int klen = kval->klen;
464
+ Val parent = stack_peek(&pi->stack);
465
+ volatile VALUE rval = Qnil;
587
466
 
588
- WHICH_TYPE:
467
+ WHICH_TYPE:
589
468
  switch (rb_type(parent->val)) {
590
469
  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;
470
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
471
+ if ('^' != *key || !hat_num(pi, parent, kval, ni)) {
472
+ parent->val = rb_hash_new();
473
+ goto WHICH_TYPE;
474
+ }
475
+ break;
597
476
  case T_HASH:
598
- rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), oj_num_as_value(ni));
599
- break;
477
+ rval = oj_num_as_value(ni);
478
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
479
+ break;
600
480
  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;
481
+ if (2 == klen && '^' == *key && 'i' == key[1] && !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp &&
482
+ 0 != pi->circ_array) { // fixnum
483
+ oj_circ_array_set(pi->circ_array, parent->val, ni->i);
484
+ } else {
485
+ rval = oj_num_as_value(ni);
486
+ oj_set_obj_ivar(parent, kval, rval);
487
+ }
488
+ break;
608
489
  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;
490
+ if (NULL == parent->odd_args) {
491
+ oj_set_error_at(pi,
492
+ oj_parse_error_class,
493
+ __FILE__,
494
+ __LINE__,
495
+ "%s is not an odd class",
496
+ rb_class2name(rb_obj_class(parent->val)));
497
+ return;
498
+ } else {
499
+ rval = oj_num_as_value(ni);
500
+ if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) {
501
+ char buf[256];
502
+
503
+ if ((int)sizeof(buf) - 1 <= klen) {
504
+ klen = sizeof(buf) - 2;
505
+ }
506
+ memcpy(buf, key, klen);
507
+ buf[klen] = '\0';
508
+ oj_set_error_at(pi,
509
+ oj_parse_error_class,
510
+ __FILE__,
511
+ __LINE__,
512
+ "%s is not an attribute of %s",
513
+ buf,
514
+ rb_class2name(rb_obj_class(parent->val)));
515
+ }
516
+ }
517
+ break;
623
518
  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;
519
+ oj_set_error_at(pi,
520
+ oj_parse_error_class,
521
+ __FILE__,
522
+ __LINE__,
523
+ "can not add attributes to a %s",
524
+ rb_class2name(rb_obj_class(parent->val)));
525
+ return;
626
526
  }
527
+ TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, rval);
627
528
  }
628
529
 
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);
530
+ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
531
+ const char *key = kval->key;
532
+ int klen = kval->klen;
533
+ Val parent = stack_peek(&pi->stack);
634
534
 
635
- WHICH_TYPE:
535
+ WHICH_TYPE:
636
536
  switch (rb_type(parent->val)) {
637
537
  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;
538
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
539
+ if ('^' != *key || !hat_value(pi, parent, key, klen, value)) {
540
+ parent->val = rb_hash_new();
541
+ goto WHICH_TYPE;
542
+ }
543
+ break;
644
544
  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;
545
+ if (rb_cHash != rb_obj_class(parent->val)) {
546
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
547
+ rb_funcall(parent->val, oj_replace_id, 1, value);
548
+ } else {
549
+ oj_set_obj_ivar(parent, kval, value);
550
+ }
551
+ } else {
552
+ if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
553
+ long len = RARRAY_LEN(value);
554
+ volatile const VALUE *a = RARRAY_CONST_PTR(value);
555
+
556
+ if (2 != len) {
557
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
558
+ return;
559
+ }
560
+ rb_hash_aset(parent->val, *a, a[1]);
561
+ } else {
562
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), value);
563
+ }
564
+ }
565
+ break;
666
566
  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;
567
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
568
+ rb_funcall(parent->val, oj_replace_id, 1, value);
569
+ } else {
570
+ oj_set_obj_ivar(parent, kval, value);
571
+ }
572
+ break;
573
+ case T_STRING: // for subclassed strings
574
+ case T_OBJECT: oj_set_obj_ivar(parent, kval, value); break;
677
575
  case T_MODULE:
678
576
  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;
577
+ if (NULL == parent->odd_args) {
578
+ oj_set_error_at(pi,
579
+ oj_parse_error_class,
580
+ __FILE__,
581
+ __LINE__,
582
+ "%s is not an odd class",
583
+ rb_class2name(rb_obj_class(parent->val)));
584
+ return;
585
+ } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
586
+ char buf[256];
587
+
588
+ if ((int)sizeof(buf) - 1 <= klen) {
589
+ klen = sizeof(buf) - 2;
590
+ }
591
+ memcpy(buf, key, klen);
592
+ buf[klen] = '\0';
593
+ oj_set_error_at(pi,
594
+ oj_parse_error_class,
595
+ __FILE__,
596
+ __LINE__,
597
+ "%s is not an attribute of %s",
598
+ buf,
599
+ rb_class2name(rb_obj_class(parent->val)));
600
+ }
601
+ break;
693
602
  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;
603
+ oj_set_error_at(pi,
604
+ oj_parse_error_class,
605
+ __FILE__,
606
+ __LINE__,
607
+ "can not add attributes to a %s",
608
+ rb_class2name(rb_obj_class(parent->val)));
609
+ return;
696
610
  }
611
+ TRACE_PARSE_CALL(pi->options.trace, "add_value", pi, value);
697
612
  }
698
613
 
699
- static VALUE
700
- start_hash(ParseInfo pi) {
614
+ static VALUE start_hash(ParseInfo pi) {
615
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
701
616
  return Qnil;
702
617
  }
703
618
 
704
- static void
705
- end_hash(struct _ParseInfo *pi) {
706
- Val parent = stack_peek(&pi->stack);
619
+ static void end_hash(ParseInfo pi) {
620
+ Val parent = stack_peek(&pi->stack);
707
621
 
708
622
  if (Qnil == parent->val) {
709
- parent->val = rb_hash_new();
710
- } else if (0 != parent->odd_args) {
711
- OddArgs oa = parent->odd_args;
623
+ parent->val = rb_hash_new();
624
+ } else if (NULL != parent->odd_args) {
625
+ OddArgs oa = parent->odd_args;
712
626
 
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;
627
+ parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
628
+ oj_odd_free(oa);
629
+ parent->odd_args = NULL;
716
630
  }
631
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
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
- }
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
+ }
738
654
  }
739
- rb_ary_push(stack_peek(&pi->stack)->val, str_to_value(pi, str, len, orig));
655
+ rval = str_to_value(pi, str, len, orig);
656
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
657
+ TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rval);
740
658
  }
741
659
 
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));
660
+ static void array_append_num(ParseInfo pi, NumInfo ni) {
661
+ volatile VALUE rval = oj_num_as_value(ni);
662
+
663
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
664
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
745
665
  }
746
666
 
747
- static void
748
- add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
667
+ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
749
668
  pi->stack.head->val = str_to_value(pi, str, len, orig);
669
+ TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, pi->stack.head->val);
750
670
  }
751
671
 
752
- static void
753
- add_num(ParseInfo pi, NumInfo ni) {
672
+ static void add_num(ParseInfo pi, NumInfo ni) {
754
673
  pi->stack.head->val = oj_num_as_value(ni);
674
+ TRACE_PARSE_CALL(pi->options.trace, "add_num", pi, pi->stack.head->val);
755
675
  }
756
676
 
757
- void
758
- oj_set_object_callbacks(ParseInfo pi) {
677
+ void oj_set_object_callbacks(ParseInfo pi) {
759
678
  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;
679
+ pi->end_hash = end_hash;
680
+ pi->start_hash = start_hash;
681
+ pi->hash_set_cstr = hash_set_cstr;
682
+ pi->hash_set_num = hash_set_num;
683
+ pi->hash_set_value = hash_set_value;
684
+ pi->add_cstr = add_cstr;
685
+ pi->add_num = add_num;
767
686
  pi->array_append_cstr = array_append_cstr;
768
- pi->array_append_num = array_append_num;
687
+ pi->array_append_num = array_append_num;
769
688
  }
770
689
 
771
690
  VALUE
772
691
  oj_object_parse(int argc, VALUE *argv, VALUE self) {
773
- struct _ParseInfo pi;
692
+ struct _parseInfo pi;
774
693
 
775
- pi.options = oj_default_options;
776
- pi.handler = Qnil;
694
+ parse_info_init(&pi);
695
+ pi.options = oj_default_options;
696
+ pi.handler = Qnil;
777
697
  pi.err_class = Qnil;
778
698
  oj_set_object_callbacks(&pi);
779
699
 
780
700
  if (T_STRING == rb_type(*argv)) {
781
- return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
782
- } else {
783
- return oj_pi_sparse(argc, argv, &pi, 0);
701
+ return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
784
702
  }
703
+ return oj_pi_sparse(argc, argv, &pi, 0);
785
704
  }
786
705
 
787
706
  VALUE
788
707
  oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
789
- struct _ParseInfo pi;
708
+ struct _parseInfo pi;
790
709
 
791
- pi.options = oj_default_options;
792
- pi.handler = Qnil;
710
+ parse_info_init(&pi);
711
+ pi.options = oj_default_options;
712
+ pi.handler = Qnil;
793
713
  pi.err_class = Qnil;
794
714
  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;
715
+ pi.end_hash = end_hash;
716
+ pi.start_hash = start_hash;
717
+ pi.hash_set_cstr = hash_set_cstr;
718
+ pi.hash_set_num = hash_set_num;
719
+ pi.hash_set_value = hash_set_value;
720
+ pi.add_cstr = add_cstr;
721
+ pi.add_num = add_num;
802
722
  pi.array_append_cstr = array_append_cstr;
803
- pi.array_append_num = array_append_num;
723
+ pi.array_append_num = array_append_num;
804
724
 
805
725
  return oj_pi_parse(argc, argv, &pi, json, len, 1);
806
726
  }