oj 2.18.5 → 3.16.11

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