oj 2.18.3 → 3.13.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (182) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1324 -0
  3. data/README.md +51 -204
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +49 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -68
  11. data/ext/oj/circarray.h +16 -42
  12. data/ext/oj/code.c +221 -0
  13. data/ext/oj/code.h +40 -0
  14. data/ext/oj/compat.c +231 -107
  15. data/ext/oj/custom.c +1125 -0
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +935 -2513
  18. data/ext/oj/dump.h +108 -0
  19. data/ext/oj/dump_compat.c +936 -0
  20. data/ext/oj/dump_leaf.c +164 -0
  21. data/ext/oj/dump_object.c +761 -0
  22. data/ext/oj/dump_strict.c +410 -0
  23. data/ext/oj/encode.h +7 -42
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -54
  26. data/ext/oj/err.h +52 -46
  27. data/ext/oj/extconf.rb +21 -30
  28. data/ext/oj/fast.c +1097 -1080
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +893 -0
  32. data/ext/oj/object.c +549 -620
  33. data/ext/oj/odd.c +155 -167
  34. data/ext/oj/odd.h +37 -63
  35. data/ext/oj/oj.c +1661 -2063
  36. data/ext/oj/oj.h +341 -270
  37. data/ext/oj/parse.c +974 -737
  38. data/ext/oj/parse.h +105 -97
  39. data/ext/oj/parser.c +1526 -0
  40. data/ext/oj/parser.h +90 -0
  41. data/ext/oj/rails.c +1504 -0
  42. data/ext/oj/rails.h +18 -0
  43. data/ext/oj/reader.c +141 -163
  44. data/ext/oj/reader.h +75 -113
  45. data/ext/oj/resolve.c +45 -93
  46. data/ext/oj/resolve.h +7 -34
  47. data/ext/oj/rxclass.c +143 -0
  48. data/ext/oj/rxclass.h +26 -0
  49. data/ext/oj/saj.c +447 -511
  50. data/ext/oj/saj2.c +348 -0
  51. data/ext/oj/scp.c +91 -138
  52. data/ext/oj/sparse.c +793 -644
  53. data/ext/oj/stream_writer.c +331 -0
  54. data/ext/oj/strict.c +145 -109
  55. data/ext/oj/string_writer.c +493 -0
  56. data/ext/oj/trace.c +72 -0
  57. data/ext/oj/trace.h +28 -0
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +62 -70
  62. data/ext/oj/val_stack.h +95 -129
  63. data/ext/oj/validate.c +51 -0
  64. data/ext/oj/wab.c +622 -0
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +17 -8
  67. data/lib/oj/error.rb +10 -11
  68. data/lib/oj/json.rb +176 -0
  69. data/lib/oj/mimic.rb +158 -19
  70. data/lib/oj/state.rb +132 -0
  71. data/lib/oj/version.rb +2 -2
  72. data/lib/oj.rb +1 -31
  73. data/pages/Advanced.md +22 -0
  74. data/pages/Compatibility.md +25 -0
  75. data/pages/Custom.md +23 -0
  76. data/pages/Encoding.md +65 -0
  77. data/pages/JsonGem.md +94 -0
  78. data/pages/Modes.md +161 -0
  79. data/pages/Options.md +327 -0
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +167 -0
  82. data/pages/Security.md +20 -0
  83. data/pages/WAB.md +13 -0
  84. data/test/activerecord/result_test.rb +32 -0
  85. data/test/activesupport4/decoding_test.rb +108 -0
  86. data/test/activesupport4/encoding_test.rb +531 -0
  87. data/test/activesupport4/test_helper.rb +41 -0
  88. data/test/activesupport5/abstract_unit.rb +45 -0
  89. data/test/activesupport5/decoding_test.rb +133 -0
  90. data/test/activesupport5/encoding_test.rb +500 -0
  91. data/test/activesupport5/encoding_test_cases.rb +98 -0
  92. data/test/activesupport5/test_helper.rb +72 -0
  93. data/test/activesupport5/time_zone_test_helpers.rb +39 -0
  94. data/test/activesupport6/abstract_unit.rb +44 -0
  95. data/test/activesupport6/decoding_test.rb +133 -0
  96. data/test/activesupport6/encoding_test.rb +507 -0
  97. data/test/activesupport6/encoding_test_cases.rb +98 -0
  98. data/test/activesupport6/test_common.rb +17 -0
  99. data/test/activesupport6/test_helper.rb +163 -0
  100. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  101. data/test/activesupport7/abstract_unit.rb +49 -0
  102. data/test/activesupport7/decoding_test.rb +125 -0
  103. data/test/activesupport7/encoding_test.rb +486 -0
  104. data/test/activesupport7/encoding_test_cases.rb +104 -0
  105. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  106. data/test/bar.rb +9 -0
  107. data/test/baz.rb +16 -0
  108. data/test/bug.rb +11 -46
  109. data/test/foo.rb +69 -16
  110. data/test/helper.rb +10 -1
  111. data/test/isolated/shared.rb +12 -8
  112. data/test/isolated/test_mimic_rails_after.rb +3 -3
  113. data/test/isolated/test_mimic_rails_before.rb +3 -3
  114. data/test/json_gem/json_addition_test.rb +216 -0
  115. data/test/json_gem/json_common_interface_test.rb +153 -0
  116. data/test/json_gem/json_encoding_test.rb +107 -0
  117. data/test/json_gem/json_ext_parser_test.rb +20 -0
  118. data/test/json_gem/json_fixtures_test.rb +35 -0
  119. data/test/json_gem/json_generator_test.rb +397 -0
  120. data/test/json_gem/json_generic_object_test.rb +90 -0
  121. data/test/json_gem/json_parser_test.rb +470 -0
  122. data/test/json_gem/json_string_matching_test.rb +42 -0
  123. data/test/json_gem/test_helper.rb +26 -0
  124. data/test/mem.rb +33 -0
  125. data/test/perf.rb +1 -1
  126. data/test/perf_compat.rb +30 -28
  127. data/test/perf_dump.rb +50 -0
  128. data/test/perf_object.rb +1 -1
  129. data/test/perf_once.rb +58 -0
  130. data/test/perf_parser.rb +189 -0
  131. data/test/perf_scp.rb +11 -10
  132. data/test/perf_strict.rb +30 -19
  133. data/test/perf_wab.rb +131 -0
  134. data/test/prec.rb +23 -0
  135. data/test/sample.rb +0 -1
  136. data/test/sample_json.rb +1 -1
  137. data/test/test_compat.rb +219 -102
  138. data/test/test_custom.rb +533 -0
  139. data/test/test_fast.rb +107 -35
  140. data/test/test_file.rb +19 -25
  141. data/test/test_generate.rb +21 -0
  142. data/test/test_hash.rb +11 -1
  143. data/test/test_integer_range.rb +72 -0
  144. data/test/test_null.rb +376 -0
  145. data/test/test_object.rb +357 -70
  146. data/test/test_parser.rb +27 -0
  147. data/test/test_parser_saj.rb +245 -0
  148. data/test/test_parser_usual.rb +217 -0
  149. data/test/test_rails.rb +35 -0
  150. data/test/test_saj.rb +1 -1
  151. data/test/test_scp.rb +39 -2
  152. data/test/test_strict.rb +186 -7
  153. data/test/test_various.rb +160 -774
  154. data/test/test_wab.rb +307 -0
  155. data/test/test_writer.rb +90 -2
  156. data/test/tests.rb +24 -0
  157. data/test/tests_mimic.rb +14 -0
  158. data/test/tests_mimic_addition.rb +7 -0
  159. data/test/zoo.rb +13 -0
  160. metadata +194 -56
  161. data/ext/oj/hash.c +0 -163
  162. data/ext/oj/hash.h +0 -46
  163. data/ext/oj/hash_test.c +0 -512
  164. data/test/activesupport_datetime_test.rb +0 -23
  165. data/test/bug2.rb +0 -10
  166. data/test/bug3.rb +0 -46
  167. data/test/bug_fast.rb +0 -32
  168. data/test/bug_load.rb +0 -24
  169. data/test/crash.rb +0 -111
  170. data/test/curl/curl_oj.rb +0 -46
  171. data/test/curl/get_oj.rb +0 -24
  172. data/test/curl/just_curl.rb +0 -31
  173. data/test/curl/just_oj.rb +0 -51
  174. data/test/example.rb +0 -11
  175. data/test/io.rb +0 -48
  176. data/test/isolated/test_mimic_rails_datetime.rb +0 -27
  177. data/test/mod.rb +0 -16
  178. data/test/rails.rb +0 -50
  179. data/test/russian.rb +0 -18
  180. data/test/struct.rb +0 -29
  181. data/test/test_serializer.rb +0 -59
  182. data/test/write_timebars.rb +0 -31
data/ext/oj/sparse.c CHANGED
@@ -1,747 +1,854 @@
1
- /* parse.c
2
- * Copyright (c) 2013, 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) 2013 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
30
3
 
31
- #include <stdlib.h>
4
+ #include <math.h>
32
5
  #include <stdio.h>
6
+ #include <stdlib.h>
33
7
  #include <string.h>
34
8
  #include <unistd.h>
35
- #include <math.h>
36
9
 
10
+ #include "buf.h"
11
+ #include "encode.h"
12
+ #include "intern.h" // for oj_strndup()
37
13
  #include "oj.h"
38
14
  #include "parse.h"
39
- #include "buf.h"
40
- #include "hash.h" // for oj_strndup()
41
15
  #include "val_stack.h"
42
16
 
43
17
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
44
- #define OJ_INFINITY (1.0/0.0)
18
+ #define OJ_INFINITY (1.0 / 0.0)
45
19
 
46
20
  #ifdef RUBINIUS_RUBY
47
- #define NUM_MAX 0x07FFFFFF
21
+ #define NUM_MAX 0x07FFFFFF
48
22
  #else
49
- #define NUM_MAX (FIXNUM_MAX >> 8)
23
+ #define NUM_MAX (FIXNUM_MAX >> 8)
50
24
  #endif
51
- #define EXP_MAX 100000
52
- #define DEC_MAX 15
25
+ #define EXP_MAX 100000
26
+ #define DEC_MAX 15
53
27
 
54
- static void
55
- skip_comment(ParseInfo pi) {
56
- char c = reader_get(&pi->rd);
28
+ static void skip_comment(ParseInfo pi) {
29
+ char c = reader_get(&pi->rd);
57
30
 
58
31
  if ('*' == c) {
59
- while ('\0' != (c = reader_get(&pi->rd))) {
60
- if ('*' == c) {
61
- c = reader_get(&pi->rd);
62
- if ('/' == c) {
63
- return;
64
- }
65
- }
66
- }
32
+ while ('\0' != (c = reader_get(&pi->rd))) {
33
+ if ('*' == c) {
34
+ c = reader_get(&pi->rd);
35
+ if ('/' == c) {
36
+ return;
37
+ }
38
+ }
39
+ }
67
40
  } else if ('/' == c) {
68
- while ('\0' != (c = reader_get(&pi->rd))) {
69
- switch (c) {
70
- case '\n':
71
- case '\r':
72
- case '\f':
73
- case '\0':
74
- return;
75
- default:
76
- break;
77
- }
78
- }
41
+ while ('\0' != (c = reader_get(&pi->rd))) {
42
+ switch (c) {
43
+ case '\n':
44
+ case '\r':
45
+ case '\f':
46
+ case '\0': return;
47
+ default: break;
48
+ }
49
+ }
79
50
  } else {
80
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
51
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
81
52
  }
82
53
  if ('\0' == c) {
83
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
84
- return;
54
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
55
+ return;
85
56
  }
86
57
  }
87
58
 
88
- static void
89
- add_value(ParseInfo pi, VALUE rval) {
90
- Val parent = stack_peek(&pi->stack);
59
+ static void add_value(ParseInfo pi, VALUE rval) {
60
+ Val parent = stack_peek(&pi->stack);
91
61
 
92
- if (0 == parent) { // simple add
93
- pi->add_value(pi, rval);
62
+ if (0 == parent) { // simple add
63
+ pi->add_value(pi, rval);
94
64
  } else {
95
- switch (parent->next) {
96
- case NEXT_ARRAY_NEW:
97
- case NEXT_ARRAY_ELEMENT:
98
- pi->array_append_value(pi, rval);
99
- parent->next = NEXT_ARRAY_COMMA;
100
- break;
101
- case NEXT_HASH_VALUE:
102
- pi->hash_set_value(pi, parent, rval);
103
- if (parent->kalloc) {
104
- xfree((char*)parent->key);
105
- }
106
- parent->key = 0;
107
- parent->kalloc = 0;
108
- parent->next = NEXT_HASH_COMMA;
109
- break;
110
- case NEXT_HASH_NEW:
111
- case NEXT_HASH_KEY:
112
- case NEXT_HASH_COMMA:
113
- case NEXT_NONE:
114
- case NEXT_ARRAY_COMMA:
115
- case NEXT_HASH_COLON:
116
- default:
117
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next));
118
- break;
119
- }
65
+ switch (parent->next) {
66
+ case NEXT_ARRAY_NEW:
67
+ case NEXT_ARRAY_ELEMENT:
68
+ pi->array_append_value(pi, rval);
69
+ parent->next = NEXT_ARRAY_COMMA;
70
+ break;
71
+ case NEXT_HASH_VALUE:
72
+ pi->hash_set_value(pi, parent, rval);
73
+ if (parent->kalloc) {
74
+ xfree((char *)parent->key);
75
+ }
76
+ parent->key = 0;
77
+ parent->kalloc = 0;
78
+ parent->next = NEXT_HASH_COMMA;
79
+ break;
80
+ case NEXT_HASH_NEW:
81
+ case NEXT_HASH_KEY:
82
+ case NEXT_HASH_COMMA:
83
+ case NEXT_NONE:
84
+ case NEXT_ARRAY_COMMA:
85
+ case NEXT_HASH_COLON:
86
+ default:
87
+ oj_set_error_at(pi,
88
+ oj_parse_error_class,
89
+ __FILE__,
90
+ __LINE__,
91
+ "expected %s",
92
+ oj_stack_next_string(parent->next));
93
+ break;
94
+ }
120
95
  }
121
96
  }
122
97
 
123
- static void
124
- add_num_value(ParseInfo pi, NumInfo ni) {
125
- Val parent = stack_peek(&pi->stack);
98
+ static void add_num_value(ParseInfo pi, NumInfo ni) {
99
+ Val parent = stack_peek(&pi->stack);
126
100
 
127
101
  if (0 == parent) {
128
- pi->add_num(pi, ni);
102
+ pi->add_num(pi, ni);
129
103
  } else {
130
- switch (parent->next) {
131
- case NEXT_ARRAY_NEW:
132
- case NEXT_ARRAY_ELEMENT:
133
- pi->array_append_num(pi, ni);
134
- parent->next = NEXT_ARRAY_COMMA;
135
- break;
136
- case NEXT_HASH_VALUE:
137
- pi->hash_set_num(pi, parent, ni);
138
- if (parent->kalloc) {
139
- xfree((char*)parent->key);
140
- }
141
- parent->key = 0;
142
- parent->kalloc = 0;
143
- parent->next = NEXT_HASH_COMMA;
144
- break;
145
- default:
146
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next));
147
- break;
148
- }
104
+ switch (parent->next) {
105
+ case NEXT_ARRAY_NEW:
106
+ case NEXT_ARRAY_ELEMENT:
107
+ pi->array_append_num(pi, ni);
108
+ parent->next = NEXT_ARRAY_COMMA;
109
+ break;
110
+ case NEXT_HASH_VALUE:
111
+ pi->hash_set_num(pi, parent, ni);
112
+ if (parent->kalloc) {
113
+ xfree((char *)parent->key);
114
+ }
115
+ parent->key = 0;
116
+ parent->kalloc = 0;
117
+ parent->next = NEXT_HASH_COMMA;
118
+ break;
119
+ default:
120
+ oj_set_error_at(pi,
121
+ oj_parse_error_class,
122
+ __FILE__,
123
+ __LINE__,
124
+ "expected %s",
125
+ oj_stack_next_string(parent->next));
126
+ break;
127
+ }
149
128
  }
150
129
  }
151
130
 
152
- static void
153
- read_true(ParseInfo pi) {
131
+ static void read_true(ParseInfo pi) {
154
132
  if (0 == reader_expect(&pi->rd, "rue")) {
155
- add_value(pi, Qtrue);
133
+ add_value(pi, Qtrue);
156
134
  } else {
157
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
135
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
158
136
  }
159
137
  }
160
138
 
161
- static void
162
- read_false(ParseInfo pi) {
139
+ static void read_false(ParseInfo pi) {
163
140
  if (0 == reader_expect(&pi->rd, "alse")) {
164
- add_value(pi, Qfalse);
141
+ add_value(pi, Qfalse);
165
142
  } else {
166
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
143
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
167
144
  }
168
145
  }
169
146
 
170
- static uint32_t
171
- read_hex(ParseInfo pi) {
172
- uint32_t b = 0;
173
- int i;
174
- char c;
147
+ static uint32_t read_hex(ParseInfo pi) {
148
+ uint32_t b = 0;
149
+ int i;
150
+ char c;
175
151
 
176
152
  for (i = 0; i < 4; i++) {
177
- c = reader_get(&pi->rd);
178
- b = b << 4;
179
- if ('0' <= c && c <= '9') {
180
- b += c - '0';
181
- } else if ('A' <= c && c <= 'F') {
182
- b += c - 'A' + 10;
183
- } else if ('a' <= c && c <= 'f') {
184
- b += c - 'a' + 10;
185
- } else {
186
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character");
187
- return 0;
188
- }
153
+ c = reader_get(&pi->rd);
154
+ b = b << 4;
155
+ if ('0' <= c && c <= '9') {
156
+ b += c - '0';
157
+ } else if ('A' <= c && c <= 'F') {
158
+ b += c - 'A' + 10;
159
+ } else if ('a' <= c && c <= 'f') {
160
+ b += c - 'a' + 10;
161
+ } else {
162
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character");
163
+ return 0;
164
+ }
189
165
  }
190
166
  return b;
191
167
  }
192
168
 
193
- static void
194
- unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
169
+ static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
195
170
  if (0x0000007F >= code) {
196
- buf_append(buf, (char)code);
171
+ buf_append(buf, (char)code);
197
172
  } else if (0x000007FF >= code) {
198
- buf_append(buf, 0xC0 | (code >> 6));
199
- buf_append(buf, 0x80 | (0x3F & code));
173
+ buf_append(buf, 0xC0 | (code >> 6));
174
+ buf_append(buf, 0x80 | (0x3F & code));
200
175
  } else if (0x0000FFFF >= code) {
201
- buf_append(buf, 0xE0 | (code >> 12));
202
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
203
- buf_append(buf, 0x80 | (0x3F & code));
176
+ buf_append(buf, 0xE0 | (code >> 12));
177
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
178
+ buf_append(buf, 0x80 | (0x3F & code));
204
179
  } else if (0x001FFFFF >= code) {
205
- buf_append(buf, 0xF0 | (code >> 18));
206
- buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
207
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
208
- buf_append(buf, 0x80 | (0x3F & code));
180
+ buf_append(buf, 0xF0 | (code >> 18));
181
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
182
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
183
+ buf_append(buf, 0x80 | (0x3F & code));
209
184
  } else if (0x03FFFFFF >= code) {
210
- buf_append(buf, 0xF8 | (code >> 24));
211
- buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
212
- buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
213
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
214
- buf_append(buf, 0x80 | (0x3F & code));
185
+ buf_append(buf, 0xF8 | (code >> 24));
186
+ buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
187
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
188
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
189
+ buf_append(buf, 0x80 | (0x3F & code));
215
190
  } else if (0x7FFFFFFF >= code) {
216
- buf_append(buf, 0xFC | (code >> 30));
217
- buf_append(buf, 0x80 | ((code >> 24) & 0x3F));
218
- buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
219
- buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
220
- buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
221
- buf_append(buf, 0x80 | (0x3F & code));
191
+ buf_append(buf, 0xFC | (code >> 30));
192
+ buf_append(buf, 0x80 | ((code >> 24) & 0x3F));
193
+ buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
194
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
195
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
196
+ buf_append(buf, 0x80 | (0x3F & code));
222
197
  } else {
223
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
198
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
224
199
  }
225
200
  }
226
201
 
227
202
  // entered at backslash
228
- static void
229
- read_escaped_str(ParseInfo pi) {
230
- struct _Buf buf;
231
- char c;
232
- uint32_t code;
233
- Val parent = stack_peek(&pi->stack);
203
+ static void read_escaped_str(ParseInfo pi) {
204
+ struct _buf buf;
205
+ char c;
206
+ uint32_t code;
207
+ Val parent = stack_peek(&pi->stack);
234
208
 
235
209
  buf_init(&buf);
236
210
  if (pi->rd.str < pi->rd.tail) {
237
- buf_append_string(&buf, pi->rd.str, pi->rd.tail - pi->rd.str);
211
+ buf_append_string(&buf, pi->rd.str, pi->rd.tail - pi->rd.str);
238
212
  }
239
213
  while ('\"' != (c = reader_get(&pi->rd))) {
240
- if ('\0' == c) {
241
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
242
- buf_cleanup(&buf);
243
- return;
244
- } else if ('\\' == c) {
245
- c = reader_get(&pi->rd);
246
- switch (c) {
247
- case 'n': buf_append(&buf, '\n'); break;
248
- case 'r': buf_append(&buf, '\r'); break;
249
- case 't': buf_append(&buf, '\t'); break;
250
- case 'f': buf_append(&buf, '\f'); break;
251
- case 'b': buf_append(&buf, '\b'); break;
252
- case '"': buf_append(&buf, '"'); break;
253
- case '/': buf_append(&buf, '/'); break;
254
- case '\\': buf_append(&buf, '\\'); break;
255
- case 'u':
256
- if (0 == (code = read_hex(pi)) && err_has(&pi->err)) {
257
- buf_cleanup(&buf);
258
- return;
259
- }
260
- if (0x0000D800 <= code && code <= 0x0000DFFF) {
261
- uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
262
- uint32_t c2;
263
- char ch2;
264
-
265
- c = reader_get(&pi->rd);
266
- ch2 = reader_get(&pi->rd);
267
- if ('\\' != c || 'u' != ch2) {
268
- if (Yes == pi->options.allow_invalid) {
269
- unicode_to_chars(pi, &buf, code);
270
- reader_backup(&pi->rd);
271
- reader_backup(&pi->rd);
272
- break;
273
- }
274
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
275
- buf_cleanup(&buf);
276
- return;
277
- }
278
- if (0 == (c2 = read_hex(pi)) && err_has(&pi->err)) {
279
- buf_cleanup(&buf);
280
- return;
281
- }
282
- c2 = (c2 - 0x0000DC00) & 0x000003FF;
283
- code = ((c1 << 10) | c2) + 0x00010000;
284
- }
285
- unicode_to_chars(pi, &buf, code);
286
- if (err_has(&pi->err)) {
287
- buf_cleanup(&buf);
288
- return;
289
- }
290
- break;
291
- default:
292
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
293
- buf_cleanup(&buf);
294
- return;
295
- }
296
- } else {
297
- buf_append(&buf, c);
298
- }
214
+ if ('\0' == c) {
215
+ oj_set_error_at(pi,
216
+ oj_parse_error_class,
217
+ __FILE__,
218
+ __LINE__,
219
+ "quoted string not terminated");
220
+ buf_cleanup(&buf);
221
+ return;
222
+ } else if ('\\' == c) {
223
+ c = reader_get(&pi->rd);
224
+ switch (c) {
225
+ case 'n': buf_append(&buf, '\n'); break;
226
+ case 'r': buf_append(&buf, '\r'); break;
227
+ case 't': buf_append(&buf, '\t'); break;
228
+ case 'f': buf_append(&buf, '\f'); break;
229
+ case 'b': buf_append(&buf, '\b'); break;
230
+ case '"': buf_append(&buf, '"'); break;
231
+ case '/': buf_append(&buf, '/'); break;
232
+ case '\\': buf_append(&buf, '\\'); break;
233
+ case 'u':
234
+ if (0 == (code = read_hex(pi)) && err_has(&pi->err)) {
235
+ buf_cleanup(&buf);
236
+ return;
237
+ }
238
+ if (0x0000D800 <= code && code <= 0x0000DFFF) {
239
+ uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
240
+ uint32_t c2;
241
+ char ch2;
242
+
243
+ c = reader_get(&pi->rd);
244
+ ch2 = reader_get(&pi->rd);
245
+ if ('\\' != c || 'u' != ch2) {
246
+ if (Yes == pi->options.allow_invalid) {
247
+ unicode_to_chars(pi, &buf, code);
248
+ reader_backup(&pi->rd);
249
+ reader_backup(&pi->rd);
250
+ break;
251
+ }
252
+ oj_set_error_at(pi,
253
+ oj_parse_error_class,
254
+ __FILE__,
255
+ __LINE__,
256
+ "invalid escaped character");
257
+ buf_cleanup(&buf);
258
+ return;
259
+ }
260
+ if (0 == (c2 = read_hex(pi)) && err_has(&pi->err)) {
261
+ buf_cleanup(&buf);
262
+ return;
263
+ }
264
+ c2 = (c2 - 0x0000DC00) & 0x000003FF;
265
+ code = ((c1 << 10) | c2) + 0x00010000;
266
+ }
267
+ unicode_to_chars(pi, &buf, code);
268
+ if (err_has(&pi->err)) {
269
+ buf_cleanup(&buf);
270
+ return;
271
+ }
272
+ break;
273
+ default:
274
+ // The json gem claims this is not an error despite the
275
+ // ECMA-404 indicating it is not valid.
276
+ if (CompatMode == pi->options.mode) {
277
+ buf_append(&buf, c);
278
+ break;
279
+ }
280
+ oj_set_error_at(pi,
281
+ oj_parse_error_class,
282
+ __FILE__,
283
+ __LINE__,
284
+ "invalid escaped character");
285
+ buf_cleanup(&buf);
286
+ return;
287
+ }
288
+ } else {
289
+ buf_append(&buf, c);
290
+ }
299
291
  }
300
292
  if (0 == parent) {
301
- pi->add_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
293
+ pi->add_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
302
294
  } else {
303
- switch (parent->next) {
304
- case NEXT_ARRAY_NEW:
305
- case NEXT_ARRAY_ELEMENT:
306
- pi->array_append_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
307
- parent->next = NEXT_ARRAY_COMMA;
308
- break;
309
- case NEXT_HASH_NEW:
310
- case NEXT_HASH_KEY:
311
- if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
312
- parent->key = strdup(buf.head);
313
- parent->klen = buf_len(&buf);
314
- } else {
315
- parent->key = "";
316
- parent->klen = 0;
317
- }
318
- parent->k1 = *pi->rd.str;
319
- parent->next = NEXT_HASH_COLON;
320
- break;
321
- case NEXT_HASH_VALUE:
322
- pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), pi->rd.str);
323
- if (parent->kalloc) {
324
- xfree((char*)parent->key);
325
- }
326
- parent->key = 0;
327
- parent->kalloc = 0;
328
- parent->next = NEXT_HASH_COMMA;
329
- break;
330
- case NEXT_HASH_COMMA:
331
- case NEXT_NONE:
332
- case NEXT_ARRAY_COMMA:
333
- case NEXT_HASH_COLON:
334
- default:
335
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next));
336
- break;
337
- }
295
+ switch (parent->next) {
296
+ case NEXT_ARRAY_NEW:
297
+ case NEXT_ARRAY_ELEMENT:
298
+ pi->array_append_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
299
+ parent->next = NEXT_ARRAY_COMMA;
300
+ break;
301
+ case NEXT_HASH_NEW:
302
+ case NEXT_HASH_KEY:
303
+ if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
304
+ parent->klen = buf_len(&buf);
305
+ parent->key = malloc(parent->klen + 1);
306
+ memcpy((char *)parent->key, buf.head, parent->klen);
307
+ *(char *)(parent->key + parent->klen) = '\0';
308
+ } else {
309
+ parent->key = "";
310
+ parent->klen = 0;
311
+ }
312
+ parent->k1 = *pi->rd.str;
313
+ parent->next = NEXT_HASH_COLON;
314
+ break;
315
+ case NEXT_HASH_VALUE:
316
+ pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), pi->rd.str);
317
+ if (parent->kalloc) {
318
+ xfree((char *)parent->key);
319
+ }
320
+ parent->key = 0;
321
+ parent->kalloc = 0;
322
+ parent->next = NEXT_HASH_COMMA;
323
+ break;
324
+ case NEXT_HASH_COMMA:
325
+ case NEXT_NONE:
326
+ case NEXT_ARRAY_COMMA:
327
+ case NEXT_HASH_COLON:
328
+ default:
329
+ oj_set_error_at(pi,
330
+ oj_parse_error_class,
331
+ __FILE__,
332
+ __LINE__,
333
+ "expected %s, not a string",
334
+ oj_stack_next_string(parent->next));
335
+ break;
336
+ }
338
337
  }
339
338
  buf_cleanup(&buf);
340
339
  }
341
340
 
342
- static void
343
- read_str(ParseInfo pi) {
344
- Val parent = stack_peek(&pi->stack);
345
- char c;
341
+ static void read_str(ParseInfo pi) {
342
+ Val parent = stack_peek(&pi->stack);
343
+ char c;
346
344
 
347
345
  reader_protect(&pi->rd);
348
346
  while ('\"' != (c = reader_get(&pi->rd))) {
349
- if ('\0' == c) {
350
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
351
- return;
352
- } else if ('\\' == c) {
353
- reader_backup(&pi->rd);
354
- read_escaped_str(pi);
355
- reader_release(&pi->rd);
356
- return;
357
- }
358
- }
359
- if (0 == parent) { // simple add
360
- pi->add_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
347
+ if ('\0' == c) {
348
+ oj_set_error_at(pi,
349
+ oj_parse_error_class,
350
+ __FILE__,
351
+ __LINE__,
352
+ "quoted string not terminated");
353
+ return;
354
+ } else if ('\\' == c) {
355
+ reader_backup(&pi->rd);
356
+ read_escaped_str(pi);
357
+ reader_release(&pi->rd);
358
+ return;
359
+ }
360
+ }
361
+ if (0 == parent) { // simple add
362
+ pi->add_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
361
363
  } else {
362
- switch (parent->next) {
363
- case NEXT_ARRAY_NEW:
364
- case NEXT_ARRAY_ELEMENT:
365
- pi->array_append_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
366
- parent->next = NEXT_ARRAY_COMMA;
367
- break;
368
- case NEXT_HASH_NEW:
369
- case NEXT_HASH_KEY:
370
- parent->klen = pi->rd.tail - pi->rd.str - 1;
371
- if (sizeof(parent->karray) <= parent->klen) {
372
- parent->key = oj_strndup(pi->rd.str, parent->klen);
373
- parent->kalloc = 1;
374
- } else {
375
- memcpy(parent->karray, pi->rd.str, parent->klen);
376
- parent->karray[parent->klen] = '\0';
377
- parent->key = parent->karray;
378
- parent->kalloc = 0;
379
- }
380
- parent->key_val = pi->hash_key(pi, parent->key, parent->klen);
381
- parent->k1 = *pi->rd.str;
382
- parent->next = NEXT_HASH_COLON;
383
- break;
384
- case NEXT_HASH_VALUE:
385
- pi->hash_set_cstr(pi, parent, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
386
- if (parent->kalloc) {
387
- xfree((char*)parent->key);
388
- }
389
- parent->key = 0;
390
- parent->kalloc = 0;
391
- parent->next = NEXT_HASH_COMMA;
392
- break;
393
- case NEXT_HASH_COMMA:
394
- case NEXT_NONE:
395
- case NEXT_ARRAY_COMMA:
396
- case NEXT_HASH_COLON:
397
- default:
398
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next));
399
- break;
400
- }
364
+ switch (parent->next) {
365
+ case NEXT_ARRAY_NEW:
366
+ case NEXT_ARRAY_ELEMENT:
367
+ pi->array_append_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
368
+ parent->next = NEXT_ARRAY_COMMA;
369
+ break;
370
+ case NEXT_HASH_NEW:
371
+ case NEXT_HASH_KEY:
372
+ parent->klen = pi->rd.tail - pi->rd.str - 1;
373
+ if (sizeof(parent->karray) <= parent->klen) {
374
+ parent->key = oj_strndup(pi->rd.str, parent->klen);
375
+ parent->kalloc = 1;
376
+ } else {
377
+ memcpy(parent->karray, pi->rd.str, parent->klen);
378
+ parent->karray[parent->klen] = '\0';
379
+ parent->key = parent->karray;
380
+ parent->kalloc = 0;
381
+ }
382
+ parent->key_val = pi->hash_key(pi, parent->key, parent->klen);
383
+ parent->k1 = *pi->rd.str;
384
+ parent->next = NEXT_HASH_COLON;
385
+ break;
386
+ case NEXT_HASH_VALUE:
387
+ pi->hash_set_cstr(pi, parent, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
388
+ if (parent->kalloc) {
389
+ xfree((char *)parent->key);
390
+ }
391
+ parent->key = 0;
392
+ parent->kalloc = 0;
393
+ parent->next = NEXT_HASH_COMMA;
394
+ break;
395
+ case NEXT_HASH_COMMA:
396
+ case NEXT_NONE:
397
+ case NEXT_ARRAY_COMMA:
398
+ case NEXT_HASH_COLON:
399
+ default:
400
+ oj_set_error_at(pi,
401
+ oj_parse_error_class,
402
+ __FILE__,
403
+ __LINE__,
404
+ "expected %s, not a string",
405
+ oj_stack_next_string(parent->next));
406
+ break;
407
+ }
401
408
  }
402
409
  reader_release(&pi->rd);
403
410
  }
404
411
 
405
- static void
406
- read_num(ParseInfo pi) {
407
- struct _NumInfo ni;
408
- char c;
412
+ static void read_num(ParseInfo pi) {
413
+ struct _numInfo ni;
414
+ char c;
409
415
 
410
416
  reader_protect(&pi->rd);
411
- ni.i = 0;
412
- ni.num = 0;
413
- ni.div = 1;
414
- ni.di = 0;
415
- ni.len = 0;
416
- ni.exp = 0;
417
- ni.big = 0;
417
+ ni.i = 0;
418
+ ni.num = 0;
419
+ ni.div = 1;
420
+ ni.di = 0;
421
+ ni.len = 0;
422
+ ni.exp = 0;
423
+ ni.big = 0;
418
424
  ni.infinity = 0;
419
- ni.nan = 0;
420
- ni.neg = 0;
421
- ni.hasExp = 0;
422
- ni.no_big = (FloatDec == pi->options.bigdec_load);
425
+ ni.nan = 0;
426
+ ni.neg = 0;
427
+ ni.has_exp = 0;
428
+ if (CompatMode == pi->options.mode) {
429
+ ni.no_big = !pi->options.compat_bigdec;
430
+ ni.bigdec_load = pi->options.compat_bigdec;
431
+ } else {
432
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
433
+ RubyDec == pi->options.bigdec_load);
434
+ ni.bigdec_load = pi->options.bigdec_load;
435
+ }
436
+
423
437
  c = reader_get(&pi->rd);
424
438
  if ('-' == c) {
425
- c = reader_get(&pi->rd);
426
- ni.neg = 1;
439
+ c = reader_get(&pi->rd);
440
+ ni.neg = 1;
427
441
  } else if ('+' == c) {
428
- c = reader_get(&pi->rd);
442
+ c = reader_get(&pi->rd);
429
443
  }
430
444
  if ('I' == c) {
431
- if (0 != reader_expect(&pi->rd, "nfinity")) {
432
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
433
- return;
434
- }
435
- ni.infinity = 1;
445
+ if (No == pi->options.allow_nan) {
446
+ oj_set_error_at(pi,
447
+ oj_parse_error_class,
448
+ __FILE__,
449
+ __LINE__,
450
+ "not a number or other value");
451
+ return;
452
+ } else if (0 != reader_expect(&pi->rd, "nfinity")) {
453
+ oj_set_error_at(pi,
454
+ oj_parse_error_class,
455
+ __FILE__,
456
+ __LINE__,
457
+ "not a number or other value");
458
+ return;
459
+ }
460
+ ni.infinity = 1;
436
461
  } else {
437
- int dec_cnt = 0;
438
-
439
- for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
440
- if (0 < ni.i) {
441
- dec_cnt++;
442
- }
443
- if (ni.big) {
444
- ni.big++;
445
- } else {
446
- int d = (c - '0');
447
-
448
- ni.i = ni.i * 10 + d;
449
- if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
450
- ni.big = 1;
451
- }
452
- }
453
- }
454
- if ('.' == c) {
455
- c = reader_get(&pi->rd);
456
- for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
457
- int d = (c - '0');
458
-
459
- if (0 < ni.num || 0 < ni.i) {
460
- dec_cnt++;
461
- }
462
- ni.num = ni.num * 10 + d;
463
- ni.div *= 10;
464
- ni.di++;
465
- if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
466
- ni.big = 1;
467
- }
468
- }
469
- }
470
- if ('e' == c || 'E' == c) {
471
- int eneg = 0;
472
-
473
- ni.hasExp = 1;
474
- c = reader_get(&pi->rd);
475
- if ('-' == c) {
476
- c = reader_get(&pi->rd);
477
- eneg = 1;
478
- } else if ('+' == c) {
479
- c = reader_get(&pi->rd);
480
- }
481
- for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
482
- ni.exp = ni.exp * 10 + (c - '0');
483
- if (EXP_MAX <= ni.exp) {
484
- ni.big = 1;
485
- }
486
- }
487
- if (eneg) {
488
- ni.exp = -ni.exp;
489
- }
490
- }
491
- ni.len = pi->rd.tail - pi->rd.str;
492
- if (0 != c) {
493
- reader_backup(&pi->rd);
494
- }
462
+ int dec_cnt = 0;
463
+ bool zero1 = false;
464
+
465
+ for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
466
+ if (0 == ni.i && '0' == c) {
467
+ zero1 = true;
468
+ }
469
+ if (0 < ni.i) {
470
+ dec_cnt++;
471
+ }
472
+ if (ni.big) {
473
+ ni.big++;
474
+ } else {
475
+ int d = (c - '0');
476
+
477
+ if (0 < d) {
478
+ if (zero1 && CompatMode == pi->options.mode) {
479
+ oj_set_error_at(pi,
480
+ oj_parse_error_class,
481
+ __FILE__,
482
+ __LINE__,
483
+ "not a number");
484
+ return;
485
+ }
486
+ zero1 = false;
487
+ }
488
+ ni.i = ni.i * 10 + d;
489
+ if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
490
+ ni.big = 1;
491
+ }
492
+ }
493
+ }
494
+ if ('.' == c) {
495
+ c = reader_get(&pi->rd);
496
+ // A trailing . is not a valid decimal but if encountered allow it
497
+ // except when mimicking the JSON gem.
498
+ if (CompatMode == pi->options.mode) {
499
+ if (c < '0' || '9' < c) {
500
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
501
+ }
502
+ }
503
+ for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
504
+ int d = (c - '0');
505
+
506
+ if (0 < ni.num || 0 < ni.i) {
507
+ dec_cnt++;
508
+ }
509
+ if (INT64_MAX <= ni.div) {
510
+ if (!ni.no_big) {
511
+ ni.big = true;
512
+ }
513
+ } else {
514
+ ni.num = ni.num * 10 + d;
515
+ ni.div *= 10;
516
+ ni.di++;
517
+ if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
518
+ if (!ni.no_big) {
519
+ ni.big = true;
520
+ }
521
+ }
522
+ }
523
+ }
524
+ }
525
+ if ('e' == c || 'E' == c) {
526
+ int eneg = 0;
527
+
528
+ ni.has_exp = 1;
529
+ c = reader_get(&pi->rd);
530
+ if ('-' == c) {
531
+ c = reader_get(&pi->rd);
532
+ eneg = 1;
533
+ } else if ('+' == c) {
534
+ c = reader_get(&pi->rd);
535
+ }
536
+ for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
537
+ ni.exp = ni.exp * 10 + (c - '0');
538
+ if (EXP_MAX <= ni.exp) {
539
+ ni.big = 1;
540
+ }
541
+ }
542
+ if (eneg) {
543
+ ni.exp = -ni.exp;
544
+ }
545
+ }
546
+ ni.len = pi->rd.tail - pi->rd.str;
547
+ if (0 != c) {
548
+ reader_backup(&pi->rd);
549
+ }
495
550
  }
496
551
  ni.str = pi->rd.str;
497
552
  ni.len = pi->rd.tail - pi->rd.str;
498
553
  // Check for special reserved values for Infinity and NaN.
499
554
  if (ni.big) {
500
- if (0 == strcasecmp(INF_VAL, ni.str)) {
501
- ni.infinity = 1;
502
- } else if (0 == strcasecmp(NINF_VAL, ni.str)) {
503
- ni.infinity = 1;
504
- ni.neg = 1;
505
- } else if (0 == strcasecmp(NAN_VAL, ni.str)) {
506
- ni.nan = 1;
507
- }
508
- }
509
- if (BigDec == pi->options.bigdec_load) {
510
- ni.big = 1;
555
+ if (0 == strcasecmp(INF_VAL, ni.str)) {
556
+ ni.infinity = 1;
557
+ } else if (0 == strcasecmp(NINF_VAL, ni.str)) {
558
+ ni.infinity = 1;
559
+ ni.neg = 1;
560
+ } else if (0 == strcasecmp(NAN_VAL, ni.str)) {
561
+ ni.nan = 1;
562
+ }
563
+ }
564
+ if (CompatMode == pi->options.mode) {
565
+ if (pi->options.compat_bigdec) {
566
+ ni.big = 1;
567
+ }
568
+ } else if (BigDec == pi->options.bigdec_load) {
569
+ ni.big = 1;
511
570
  }
512
571
  add_num_value(pi, &ni);
513
572
  reader_release(&pi->rd);
514
573
  }
515
574
 
516
- static void
517
- read_nan(ParseInfo pi) {
518
- struct _NumInfo ni;
519
- char c;
520
-
521
- ni.str = pi->rd.str;
522
- ni.i = 0;
523
- ni.num = 0;
524
- ni.div = 1;
525
- ni.di = 0;
526
- ni.len = 0;
527
- ni.exp = 0;
528
- ni.big = 0;
575
+ static void read_nan(ParseInfo pi) {
576
+ struct _numInfo ni;
577
+ char c;
578
+
579
+ ni.str = pi->rd.str;
580
+ ni.i = 0;
581
+ ni.num = 0;
582
+ ni.div = 1;
583
+ ni.di = 0;
584
+ ni.len = 0;
585
+ ni.exp = 0;
586
+ ni.big = 0;
529
587
  ni.infinity = 0;
530
- ni.nan = 1;
531
- ni.neg = 0;
532
- ni.no_big = (FloatDec == pi->options.bigdec_load);
588
+ ni.nan = 1;
589
+ ni.neg = 0;
590
+ if (CompatMode == pi->options.mode) {
591
+ ni.no_big = !pi->options.compat_bigdec;
592
+ ni.bigdec_load = pi->options.compat_bigdec;
593
+ } else {
594
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
595
+ RubyDec == pi->options.bigdec_load);
596
+ ni.bigdec_load = pi->options.bigdec_load;
597
+ }
533
598
 
534
- if ('a' != reader_get(&pi->rd) ||
535
- ('N' != (c = reader_get(&pi->rd)) && 'n' != c)) {
536
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
537
- return;
599
+ if ('a' != reader_get(&pi->rd) || ('N' != (c = reader_get(&pi->rd)) && 'n' != c)) {
600
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
601
+ return;
538
602
  }
539
- if (BigDec == pi->options.bigdec_load) {
540
- ni.big = 1;
603
+ if (CompatMode == pi->options.mode) {
604
+ if (pi->options.compat_bigdec) {
605
+ ni.big = 1;
606
+ }
607
+ } else if (BigDec == pi->options.bigdec_load) {
608
+ ni.big = 1;
541
609
  }
542
610
  add_num_value(pi, &ni);
543
611
  }
544
612
 
545
- static void
546
- array_start(ParseInfo pi) {
547
- VALUE v = pi->start_array(pi);
613
+ static void array_start(ParseInfo pi) {
614
+ VALUE v = pi->start_array(pi);
548
615
 
549
616
  stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
550
617
  }
551
618
 
552
- static void
553
- array_end(ParseInfo pi) {
554
- Val array = stack_pop(&pi->stack);
619
+ static void array_end(ParseInfo pi) {
620
+ Val array = stack_pop(&pi->stack);
555
621
 
556
622
  if (0 == array) {
557
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
623
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
558
624
  } else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
559
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not an array close", oj_stack_next_string(array->next));
625
+ oj_set_error_at(pi,
626
+ oj_parse_error_class,
627
+ __FILE__,
628
+ __LINE__,
629
+ "expected %s, not an array close",
630
+ oj_stack_next_string(array->next));
560
631
  } else {
561
- pi->end_array(pi);
562
- add_value(pi, array->val);
632
+ pi->end_array(pi);
633
+ add_value(pi, array->val);
563
634
  }
564
635
  }
565
636
 
566
- static void
567
- hash_start(ParseInfo pi) {
568
- volatile VALUE v = pi->start_hash(pi);
637
+ static void hash_start(ParseInfo pi) {
638
+ volatile VALUE v = pi->start_hash(pi);
569
639
 
570
640
  stack_push(&pi->stack, v, NEXT_HASH_NEW);
571
641
  }
572
642
 
573
- static void
574
- hash_end(ParseInfo pi) {
575
- volatile Val hash = stack_peek(&pi->stack);
643
+ static void hash_end(ParseInfo pi) {
644
+ volatile Val hash = stack_peek(&pi->stack);
576
645
 
577
646
  // leave hash on stack until just before
578
647
  if (0 == hash) {
579
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
648
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
580
649
  } else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
581
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a hash close", oj_stack_next_string(hash->next));
650
+ oj_set_error_at(pi,
651
+ oj_parse_error_class,
652
+ __FILE__,
653
+ __LINE__,
654
+ "expected %s, not a hash close",
655
+ oj_stack_next_string(hash->next));
582
656
  } else {
583
- pi->end_hash(pi);
584
- stack_pop(&pi->stack);
585
- add_value(pi, hash->val);
657
+ pi->end_hash(pi);
658
+ stack_pop(&pi->stack);
659
+ add_value(pi, hash->val);
586
660
  }
587
661
  }
588
662
 
589
- static void
590
- comma(ParseInfo pi) {
591
- Val parent = stack_peek(&pi->stack);
663
+ static void comma(ParseInfo pi) {
664
+ Val parent = stack_peek(&pi->stack);
592
665
 
593
666
  if (0 == parent) {
594
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
667
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
595
668
  } else if (NEXT_ARRAY_COMMA == parent->next) {
596
- parent->next = NEXT_ARRAY_ELEMENT;
669
+ parent->next = NEXT_ARRAY_ELEMENT;
597
670
  } else if (NEXT_HASH_COMMA == parent->next) {
598
- parent->next = NEXT_HASH_KEY;
671
+ parent->next = NEXT_HASH_KEY;
599
672
  } else {
600
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
673
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
601
674
  }
602
675
  }
603
676
 
604
- static void
605
- colon(ParseInfo pi) {
606
- Val parent = stack_peek(&pi->stack);
677
+ static void colon(ParseInfo pi) {
678
+ Val parent = stack_peek(&pi->stack);
607
679
 
608
680
  if (0 != parent && NEXT_HASH_COLON == parent->next) {
609
- parent->next = NEXT_HASH_VALUE;
681
+ parent->next = NEXT_HASH_VALUE;
610
682
  } else {
611
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
683
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
612
684
  }
613
685
  }
614
686
 
615
- void
616
- oj_sparse2(ParseInfo pi) {
617
- int first = 1;
618
- char c;
687
+ void oj_sparse2(ParseInfo pi) {
688
+ int first = 1;
689
+ char c;
690
+ long start = 0;
619
691
 
620
692
  err_init(&pi->err);
621
693
  while (1) {
622
- c = reader_next_non_white(&pi->rd);
623
- if (!first && '\0' != c) {
624
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected characters after the JSON document");
625
- }
626
- switch (c) {
627
- case '{':
628
- hash_start(pi);
629
- break;
630
- case '}':
631
- hash_end(pi);
632
- break;
633
- case ':':
634
- colon(pi);
635
- break;
636
- case '[':
637
- array_start(pi);
638
- break;
639
- case ']':
640
- array_end(pi);
641
- break;
642
- case ',':
643
- comma(pi);
644
- break;
645
- case '"':
646
- read_str(pi);
647
- break;
648
- case '+':
649
- case '-':
650
- case '0':
651
- case '1':
652
- case '2':
653
- case '3':
654
- case '4':
655
- case '5':
656
- case '6':
657
- case '7':
658
- case '8':
659
- case '9':
660
- case 'I':
661
- reader_backup(&pi->rd);
662
- read_num(pi);
663
- break;
664
- case 'N':
665
- read_nan(pi);
666
- break;
667
- case 't':
668
- read_true(pi);
669
- break;
670
- case 'f':
671
- read_false(pi);
672
- break;
673
- case 'n':
674
- c = reader_get(&pi->rd);
675
- if ('u' == c) {
676
- if (0 == reader_expect(&pi->rd, "ll")) {
677
- add_value(pi, Qnil);
678
- } else {
679
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null");
680
- return;
681
- }
682
- } else if ('a' == c) {
683
- struct _NumInfo ni;
684
-
685
- c = reader_get(&pi->rd);
686
- if ('N' != c && 'n' != c) {
687
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected NaN");
688
- return;
689
- }
690
- ni.str = pi->rd.str;
691
- ni.i = 0;
692
- ni.num = 0;
693
- ni.div = 1;
694
- ni.di = 0;
695
- ni.len = 0;
696
- ni.exp = 0;
697
- ni.big = 0;
698
- ni.infinity = 0;
699
- ni.nan = 1;
700
- ni.neg = 0;
701
- ni.no_big = (FloatDec == pi->options.bigdec_load);
702
- add_num_value(pi, &ni);
703
- } else {
704
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid token");
705
- return;
706
- }
707
- break;
708
- case '/':
709
- skip_comment(pi);
710
- break;
711
- case '\0':
712
- return;
713
- default:
714
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
715
- return;
716
- }
717
- if (err_has(&pi->err)) {
718
- return;
719
- }
720
- if (stack_empty(&pi->stack)) {
721
- if (Qundef != pi->proc) {
722
- if (Qnil == pi->proc) {
723
- rb_yield(stack_head_val(&pi->stack));
724
- } else {
725
- #if HAS_PROC_WITH_BLOCK
726
- VALUE args[1];
727
-
728
- *args = stack_head_val(&pi->stack);
729
- rb_proc_call_with_block(pi->proc, 1, args, Qnil);
730
- #else
731
- oj_set_error_at(pi, rb_eNotImpError, __FILE__, __LINE__,
732
- "Calling a Proc with a block not supported in this version. Use func() {|x| } syntax instead.");
733
- return;
734
- #endif
735
- }
736
- } else {
737
- first = 0;
738
- }
739
- }
694
+ if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
695
+ VALUE err_clas = oj_get_json_err_class("NestingError");
696
+
697
+ oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
698
+ pi->err_class = err_clas;
699
+ return;
700
+ }
701
+ c = reader_next_non_white(&pi->rd);
702
+ if (!first && '\0' != c) {
703
+ oj_set_error_at(pi,
704
+ oj_parse_error_class,
705
+ __FILE__,
706
+ __LINE__,
707
+ "unexpected characters after the JSON document");
708
+ }
709
+ switch (c) {
710
+ case '{': hash_start(pi); break;
711
+ case '}': hash_end(pi); break;
712
+ case ':': colon(pi); break;
713
+ case '[': array_start(pi); break;
714
+ case ']': array_end(pi); break;
715
+ case ',': comma(pi); break;
716
+ case '"': read_str(pi); break;
717
+ case '+':
718
+ if (CompatMode == pi->options.mode) {
719
+ oj_set_error_at(pi,
720
+ oj_parse_error_class,
721
+ __FILE__,
722
+ __LINE__,
723
+ "unexpected character");
724
+ return;
725
+ }
726
+ pi->cur--;
727
+ read_num(pi);
728
+ break;
729
+ case '-':
730
+ case '0':
731
+ case '1':
732
+ case '2':
733
+ case '3':
734
+ case '4':
735
+ case '5':
736
+ case '6':
737
+ case '7':
738
+ case '8':
739
+ case '9':
740
+ reader_backup(&pi->rd);
741
+ read_num(pi);
742
+ break;
743
+ case 'I':
744
+ if (Yes == pi->options.allow_nan) {
745
+ reader_backup(&pi->rd);
746
+ read_num(pi);
747
+ } else {
748
+ oj_set_error_at(pi,
749
+ oj_parse_error_class,
750
+ __FILE__,
751
+ __LINE__,
752
+ "unexpected character");
753
+ return;
754
+ }
755
+ break;
756
+ case 'N':
757
+ if (Yes == pi->options.allow_nan) {
758
+ read_nan(pi);
759
+ } else {
760
+ oj_set_error_at(pi,
761
+ oj_parse_error_class,
762
+ __FILE__,
763
+ __LINE__,
764
+ "unexpected character");
765
+ return;
766
+ }
767
+ break;
768
+ case 't': read_true(pi); break;
769
+ case 'f': read_false(pi); break;
770
+ case 'n':
771
+ c = reader_get(&pi->rd);
772
+ if ('u' == c) {
773
+ if (0 == reader_expect(&pi->rd, "ll")) {
774
+ add_value(pi, Qnil);
775
+ } else {
776
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null");
777
+ return;
778
+ }
779
+ } else if ('a' == c) {
780
+ struct _numInfo ni;
781
+
782
+ c = reader_get(&pi->rd);
783
+ if ('N' != c && 'n' != c) {
784
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected NaN");
785
+ return;
786
+ }
787
+ ni.str = pi->rd.str;
788
+ ni.i = 0;
789
+ ni.num = 0;
790
+ ni.div = 1;
791
+ ni.di = 0;
792
+ ni.len = 0;
793
+ ni.exp = 0;
794
+ ni.big = 0;
795
+ ni.infinity = 0;
796
+ ni.nan = 1;
797
+ ni.neg = 0;
798
+ if (CompatMode == pi->options.mode) {
799
+ ni.no_big = !pi->options.compat_bigdec;
800
+ ni.bigdec_load = pi->options.compat_bigdec;
801
+ } else {
802
+ ni.no_big = (FloatDec == pi->options.bigdec_load ||
803
+ FastDec == pi->options.bigdec_load ||
804
+ RubyDec == pi->options.bigdec_load);
805
+ ni.bigdec_load = pi->options.bigdec_load;
806
+ }
807
+ add_num_value(pi, &ni);
808
+ } else {
809
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid token");
810
+ return;
811
+ }
812
+ break;
813
+ case '/': skip_comment(pi); break;
814
+ case '\0': return;
815
+ default:
816
+ oj_set_error_at(pi,
817
+ oj_parse_error_class,
818
+ __FILE__,
819
+ __LINE__,
820
+ "unexpected character '%c' [0x%02x]",
821
+ c,
822
+ c);
823
+ return;
824
+ }
825
+ if (err_has(&pi->err)) {
826
+ return;
827
+ }
828
+ if (stack_empty(&pi->stack)) {
829
+ if (Qundef != pi->proc) {
830
+ VALUE args[3];
831
+ long len = pi->rd.pos - start;
832
+
833
+ *args = stack_head_val(&pi->stack);
834
+ args[1] = LONG2NUM(start);
835
+ args[2] = LONG2NUM(len);
836
+
837
+ if (Qnil == pi->proc) {
838
+ rb_yield_values2(3, args);
839
+ } else {
840
+ rb_proc_call_with_block(pi->proc, 3, args, Qnil);
841
+ }
842
+ } else if (!pi->has_callbacks) {
843
+ first = 0;
844
+ }
845
+ start = pi->rd.pos;
846
+ // TBD break if option set to allow that
847
+ }
740
848
  }
741
849
  }
742
850
 
743
- static VALUE
744
- protect_parse(VALUE pip) {
851
+ static VALUE protect_parse(VALUE pip) {
745
852
  oj_sparse2((ParseInfo)pip);
746
853
 
747
854
  return Qnil;
@@ -749,87 +856,129 @@ protect_parse(VALUE pip) {
749
856
 
750
857
  VALUE
751
858
  oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
752
- volatile VALUE input;
753
- volatile VALUE wrapped_stack;
754
- VALUE result = Qnil;
755
- int line = 0;
859
+ volatile VALUE input;
860
+ volatile VALUE wrapped_stack;
861
+ VALUE result = Qnil;
862
+ int line = 0;
756
863
 
757
864
  if (argc < 1) {
758
- rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
865
+ rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
759
866
  }
760
867
  input = argv[0];
761
- if (2 == argc) {
762
- oj_parse_options(argv[1], &pi->options);
763
- }
764
- if (Qnil == input && Yes == pi->options.nilnil) {
765
- return Qnil;
868
+ if (2 <= argc) {
869
+ if (T_HASH == rb_type(argv[1])) {
870
+ oj_parse_options(argv[1], &pi->options);
871
+ } else if (3 <= argc && T_HASH == rb_type(argv[2])) {
872
+ oj_parse_options(argv[2], &pi->options);
873
+ }
874
+ }
875
+ if (Qnil == input) {
876
+ if (Yes == pi->options.nilnil) {
877
+ return Qnil;
878
+ } else {
879
+ rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
880
+ }
881
+ } else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) &&
882
+ No == pi->options.nilnil && 0 == RSTRING_LEN(input)) {
883
+ rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string.");
766
884
  }
767
885
  if (rb_block_given_p()) {
768
- pi->proc = Qnil;
886
+ pi->proc = Qnil;
769
887
  } else {
770
- pi->proc = Qundef;
888
+ pi->proc = Qundef;
771
889
  }
772
- oj_reader_init(&pi->rd, input, fd);
773
- pi->json = 0; // indicates reader is in use
890
+ oj_reader_init(&pi->rd, input, fd, CompatMode == pi->options.mode);
891
+ pi->json = 0; // indicates reader is in use
774
892
 
775
893
  if (Yes == pi->options.circular) {
776
- pi->circ_array = oj_circ_array_new();
894
+ pi->circ_array = oj_circ_array_new();
777
895
  } else {
778
- pi->circ_array = 0;
896
+ pi->circ_array = 0;
779
897
  }
780
898
  if (No == pi->options.allow_gc) {
781
- rb_gc_disable();
899
+ rb_gc_disable();
782
900
  }
783
901
  // GC can run at any time. When it runs any Object created by C will be
784
902
  // freed. We protect against this by wrapping the value stack in a ruby
785
- // data object and poviding a mark function for ruby objects on the
903
+ // data object and providing a mark function for ruby objects on the
786
904
  // value stack (while it is in scope).
787
905
  wrapped_stack = oj_stack_init(&pi->stack);
788
906
  rb_protect(protect_parse, (VALUE)pi, &line);
789
- result = stack_head_val(&pi->stack);
907
+ if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
908
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Empty input");
909
+ }
910
+ result = stack_head_val(&pi->stack);
790
911
  DATA_PTR(wrapped_stack) = 0;
791
912
  if (No == pi->options.allow_gc) {
792
- rb_gc_enable();
913
+ rb_gc_enable();
793
914
  }
794
915
  if (!err_has(&pi->err)) {
795
- // If the stack is not empty then the JSON terminated early.
796
- Val v;
797
-
798
- if (0 != (v = stack_peek(&pi->stack))) {
799
- switch (v->next) {
800
- case NEXT_ARRAY_NEW:
801
- case NEXT_ARRAY_ELEMENT:
802
- case NEXT_ARRAY_COMMA:
803
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Array not terminated");
804
- break;
805
- case NEXT_HASH_NEW:
806
- case NEXT_HASH_KEY:
807
- case NEXT_HASH_COLON:
808
- case NEXT_HASH_VALUE:
809
- case NEXT_HASH_COMMA:
810
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Hash/Object not terminated");
811
- break;
812
- default:
813
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not terminated");
814
- }
815
- }
816
- }
916
+ // If the stack is not empty then the JSON terminated early.
917
+ Val v;
918
+ VALUE err_class = oj_parse_error_class;
919
+
920
+ if (0 != line) {
921
+ VALUE ec = rb_obj_class(rb_errinfo());
922
+
923
+ if (rb_eIOError != ec) {
924
+ goto CLEANUP;
925
+ }
926
+ // Sometimes the class of the error is 0 which seems broken.
927
+ if (rb_eArgError != ec && 0 != ec) {
928
+ err_class = ec;
929
+ }
930
+ }
931
+ if (0 != (v = stack_peek(&pi->stack))) {
932
+ switch (v->next) {
933
+ case NEXT_ARRAY_NEW:
934
+ case NEXT_ARRAY_ELEMENT:
935
+ case NEXT_ARRAY_COMMA:
936
+ oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
937
+ break;
938
+ case NEXT_HASH_NEW:
939
+ case NEXT_HASH_KEY:
940
+ case NEXT_HASH_COLON:
941
+ case NEXT_HASH_VALUE:
942
+ case NEXT_HASH_COMMA:
943
+ oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated");
944
+ break;
945
+ default: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated");
946
+ }
947
+ }
948
+ }
949
+ CLEANUP:
817
950
  // proceed with cleanup
818
951
  if (0 != pi->circ_array) {
819
- oj_circ_array_free(pi->circ_array);
952
+ oj_circ_array_free(pi->circ_array);
820
953
  }
821
954
  stack_cleanup(&pi->stack);
822
955
  if (0 != fd) {
823
- close(fd);
824
- }
825
- if (0 != line) {
826
- rb_jump_tag(line);
956
+ close(fd);
827
957
  }
828
958
  if (err_has(&pi->err)) {
829
- if (Qnil != pi->err_class) {
830
- pi->err.clas = pi->err_class;
831
- }
832
- oj_err_raise(&pi->err);
959
+ rb_set_errinfo(Qnil);
960
+ if (Qnil != pi->err_class && 0 != pi->err_class) {
961
+ pi->err.clas = pi->err_class;
962
+ }
963
+ if (CompatMode == pi->options.mode && Yes != pi->options.safe) {
964
+ // The json gem requires the error message be UTF-8 encoded. In
965
+ // additional the complete JSON source should be returned but that
966
+ // is not possible without stored all the bytes read and reading
967
+ // the remaining bytes on the stream. Both seem like a very bad
968
+ // idea.
969
+ VALUE args[] = {oj_encode(rb_str_new2(pi->err.msg))};
970
+
971
+ if (pi->err.clas == oj_parse_error_class) {
972
+ // The error was an Oj::ParseError so change to a JSON::ParserError.
973
+ pi->err.clas = oj_json_parser_error_class;
974
+ }
975
+ rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
976
+ } else {
977
+ oj_err_raise(&pi->err);
978
+ }
979
+ oj_err_raise(&pi->err);
980
+ } else if (0 != line) {
981
+ rb_jump_tag(line);
833
982
  }
834
983
  return result;
835
984
  }