oj 2.18.3 → 3.13.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1324 -0
  3. data/README.md +51 -204
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +49 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -68
  11. data/ext/oj/circarray.h +16 -42
  12. data/ext/oj/code.c +221 -0
  13. data/ext/oj/code.h +40 -0
  14. data/ext/oj/compat.c +231 -107
  15. data/ext/oj/custom.c +1125 -0
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +935 -2513
  18. data/ext/oj/dump.h +108 -0
  19. data/ext/oj/dump_compat.c +936 -0
  20. data/ext/oj/dump_leaf.c +164 -0
  21. data/ext/oj/dump_object.c +761 -0
  22. data/ext/oj/dump_strict.c +410 -0
  23. data/ext/oj/encode.h +7 -42
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -54
  26. data/ext/oj/err.h +52 -46
  27. data/ext/oj/extconf.rb +21 -30
  28. data/ext/oj/fast.c +1097 -1080
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +893 -0
  32. data/ext/oj/object.c +549 -620
  33. data/ext/oj/odd.c +155 -167
  34. data/ext/oj/odd.h +37 -63
  35. data/ext/oj/oj.c +1661 -2063
  36. data/ext/oj/oj.h +341 -270
  37. data/ext/oj/parse.c +974 -737
  38. data/ext/oj/parse.h +105 -97
  39. data/ext/oj/parser.c +1526 -0
  40. data/ext/oj/parser.h +90 -0
  41. data/ext/oj/rails.c +1504 -0
  42. data/ext/oj/rails.h +18 -0
  43. data/ext/oj/reader.c +141 -163
  44. data/ext/oj/reader.h +75 -113
  45. data/ext/oj/resolve.c +45 -93
  46. data/ext/oj/resolve.h +7 -34
  47. data/ext/oj/rxclass.c +143 -0
  48. data/ext/oj/rxclass.h +26 -0
  49. data/ext/oj/saj.c +447 -511
  50. data/ext/oj/saj2.c +348 -0
  51. data/ext/oj/scp.c +91 -138
  52. data/ext/oj/sparse.c +793 -644
  53. data/ext/oj/stream_writer.c +331 -0
  54. data/ext/oj/strict.c +145 -109
  55. data/ext/oj/string_writer.c +493 -0
  56. data/ext/oj/trace.c +72 -0
  57. data/ext/oj/trace.h +28 -0
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +62 -70
  62. data/ext/oj/val_stack.h +95 -129
  63. data/ext/oj/validate.c +51 -0
  64. data/ext/oj/wab.c +622 -0
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +17 -8
  67. data/lib/oj/error.rb +10 -11
  68. data/lib/oj/json.rb +176 -0
  69. data/lib/oj/mimic.rb +158 -19
  70. data/lib/oj/state.rb +132 -0
  71. data/lib/oj/version.rb +2 -2
  72. data/lib/oj.rb +1 -31
  73. data/pages/Advanced.md +22 -0
  74. data/pages/Compatibility.md +25 -0
  75. data/pages/Custom.md +23 -0
  76. data/pages/Encoding.md +65 -0
  77. data/pages/JsonGem.md +94 -0
  78. data/pages/Modes.md +161 -0
  79. data/pages/Options.md +327 -0
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +167 -0
  82. data/pages/Security.md +20 -0
  83. data/pages/WAB.md +13 -0
  84. data/test/activerecord/result_test.rb +32 -0
  85. data/test/activesupport4/decoding_test.rb +108 -0
  86. data/test/activesupport4/encoding_test.rb +531 -0
  87. data/test/activesupport4/test_helper.rb +41 -0
  88. data/test/activesupport5/abstract_unit.rb +45 -0
  89. data/test/activesupport5/decoding_test.rb +133 -0
  90. data/test/activesupport5/encoding_test.rb +500 -0
  91. data/test/activesupport5/encoding_test_cases.rb +98 -0
  92. data/test/activesupport5/test_helper.rb +72 -0
  93. data/test/activesupport5/time_zone_test_helpers.rb +39 -0
  94. data/test/activesupport6/abstract_unit.rb +44 -0
  95. data/test/activesupport6/decoding_test.rb +133 -0
  96. data/test/activesupport6/encoding_test.rb +507 -0
  97. data/test/activesupport6/encoding_test_cases.rb +98 -0
  98. data/test/activesupport6/test_common.rb +17 -0
  99. data/test/activesupport6/test_helper.rb +163 -0
  100. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  101. data/test/activesupport7/abstract_unit.rb +49 -0
  102. data/test/activesupport7/decoding_test.rb +125 -0
  103. data/test/activesupport7/encoding_test.rb +486 -0
  104. data/test/activesupport7/encoding_test_cases.rb +104 -0
  105. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  106. data/test/bar.rb +9 -0
  107. data/test/baz.rb +16 -0
  108. data/test/bug.rb +11 -46
  109. data/test/foo.rb +69 -16
  110. data/test/helper.rb +10 -1
  111. data/test/isolated/shared.rb +12 -8
  112. data/test/isolated/test_mimic_rails_after.rb +3 -3
  113. data/test/isolated/test_mimic_rails_before.rb +3 -3
  114. data/test/json_gem/json_addition_test.rb +216 -0
  115. data/test/json_gem/json_common_interface_test.rb +153 -0
  116. data/test/json_gem/json_encoding_test.rb +107 -0
  117. data/test/json_gem/json_ext_parser_test.rb +20 -0
  118. data/test/json_gem/json_fixtures_test.rb +35 -0
  119. data/test/json_gem/json_generator_test.rb +397 -0
  120. data/test/json_gem/json_generic_object_test.rb +90 -0
  121. data/test/json_gem/json_parser_test.rb +470 -0
  122. data/test/json_gem/json_string_matching_test.rb +42 -0
  123. data/test/json_gem/test_helper.rb +26 -0
  124. data/test/mem.rb +33 -0
  125. data/test/perf.rb +1 -1
  126. data/test/perf_compat.rb +30 -28
  127. data/test/perf_dump.rb +50 -0
  128. data/test/perf_object.rb +1 -1
  129. data/test/perf_once.rb +58 -0
  130. data/test/perf_parser.rb +189 -0
  131. data/test/perf_scp.rb +11 -10
  132. data/test/perf_strict.rb +30 -19
  133. data/test/perf_wab.rb +131 -0
  134. data/test/prec.rb +23 -0
  135. data/test/sample.rb +0 -1
  136. data/test/sample_json.rb +1 -1
  137. data/test/test_compat.rb +219 -102
  138. data/test/test_custom.rb +533 -0
  139. data/test/test_fast.rb +107 -35
  140. data/test/test_file.rb +19 -25
  141. data/test/test_generate.rb +21 -0
  142. data/test/test_hash.rb +11 -1
  143. data/test/test_integer_range.rb +72 -0
  144. data/test/test_null.rb +376 -0
  145. data/test/test_object.rb +357 -70
  146. data/test/test_parser.rb +27 -0
  147. data/test/test_parser_saj.rb +245 -0
  148. data/test/test_parser_usual.rb +217 -0
  149. data/test/test_rails.rb +35 -0
  150. data/test/test_saj.rb +1 -1
  151. data/test/test_scp.rb +39 -2
  152. data/test/test_strict.rb +186 -7
  153. data/test/test_various.rb +160 -774
  154. data/test/test_wab.rb +307 -0
  155. data/test/test_writer.rb +90 -2
  156. data/test/tests.rb +24 -0
  157. data/test/tests_mimic.rb +14 -0
  158. data/test/tests_mimic_addition.rb +7 -0
  159. data/test/zoo.rb +13 -0
  160. metadata +194 -56
  161. data/ext/oj/hash.c +0 -163
  162. data/ext/oj/hash.h +0 -46
  163. data/ext/oj/hash_test.c +0 -512
  164. data/test/activesupport_datetime_test.rb +0 -23
  165. data/test/bug2.rb +0 -10
  166. data/test/bug3.rb +0 -46
  167. data/test/bug_fast.rb +0 -32
  168. data/test/bug_load.rb +0 -24
  169. data/test/crash.rb +0 -111
  170. data/test/curl/curl_oj.rb +0 -46
  171. data/test/curl/get_oj.rb +0 -24
  172. data/test/curl/just_curl.rb +0 -31
  173. data/test/curl/just_oj.rb +0 -51
  174. data/test/example.rb +0 -11
  175. data/test/io.rb +0 -48
  176. data/test/isolated/test_mimic_rails_datetime.rb +0 -27
  177. data/test/mod.rb +0 -16
  178. data/test/rails.rb +0 -50
  179. data/test/russian.rb +0 -18
  180. data/test/struct.rb +0 -29
  181. data/test/test_serializer.rb +0 -59
  182. data/test/write_timebars.rb +0 -31
data/ext/oj/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
  }