oj 3.9.1 → 3.16.11

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