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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +1324 -0
- data/README.md +51 -204
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +49 -72
- data/ext/oj/cache.c +326 -0
- data/ext/oj/cache.h +21 -0
- data/ext/oj/cache8.c +61 -64
- data/ext/oj/cache8.h +12 -39
- data/ext/oj/circarray.c +37 -68
- data/ext/oj/circarray.h +16 -42
- data/ext/oj/code.c +221 -0
- data/ext/oj/code.h +40 -0
- data/ext/oj/compat.c +231 -107
- data/ext/oj/custom.c +1125 -0
- data/ext/oj/debug.c +132 -0
- data/ext/oj/dump.c +935 -2513
- data/ext/oj/dump.h +108 -0
- data/ext/oj/dump_compat.c +936 -0
- data/ext/oj/dump_leaf.c +164 -0
- data/ext/oj/dump_object.c +761 -0
- data/ext/oj/dump_strict.c +410 -0
- data/ext/oj/encode.h +7 -42
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +40 -54
- data/ext/oj/err.h +52 -46
- data/ext/oj/extconf.rb +21 -30
- data/ext/oj/fast.c +1097 -1080
- data/ext/oj/intern.c +301 -0
- data/ext/oj/intern.h +26 -0
- data/ext/oj/mimic_json.c +893 -0
- data/ext/oj/object.c +549 -620
- data/ext/oj/odd.c +155 -167
- data/ext/oj/odd.h +37 -63
- data/ext/oj/oj.c +1661 -2063
- data/ext/oj/oj.h +341 -270
- data/ext/oj/parse.c +974 -737
- data/ext/oj/parse.h +105 -97
- data/ext/oj/parser.c +1526 -0
- data/ext/oj/parser.h +90 -0
- data/ext/oj/rails.c +1504 -0
- data/ext/oj/rails.h +18 -0
- data/ext/oj/reader.c +141 -163
- data/ext/oj/reader.h +75 -113
- data/ext/oj/resolve.c +45 -93
- data/ext/oj/resolve.h +7 -34
- data/ext/oj/rxclass.c +143 -0
- data/ext/oj/rxclass.h +26 -0
- data/ext/oj/saj.c +447 -511
- data/ext/oj/saj2.c +348 -0
- data/ext/oj/scp.c +91 -138
- data/ext/oj/sparse.c +793 -644
- data/ext/oj/stream_writer.c +331 -0
- data/ext/oj/strict.c +145 -109
- data/ext/oj/string_writer.c +493 -0
- data/ext/oj/trace.c +72 -0
- data/ext/oj/trace.h +28 -0
- data/ext/oj/usual.c +1254 -0
- data/ext/oj/util.c +136 -0
- data/ext/oj/util.h +20 -0
- data/ext/oj/val_stack.c +62 -70
- data/ext/oj/val_stack.h +95 -129
- data/ext/oj/validate.c +51 -0
- data/ext/oj/wab.c +622 -0
- data/lib/oj/bag.rb +1 -0
- data/lib/oj/easy_hash.rb +17 -8
- data/lib/oj/error.rb +10 -11
- data/lib/oj/json.rb +176 -0
- data/lib/oj/mimic.rb +158 -19
- data/lib/oj/state.rb +132 -0
- data/lib/oj/version.rb +2 -2
- data/lib/oj.rb +1 -31
- data/pages/Advanced.md +22 -0
- data/pages/Compatibility.md +25 -0
- data/pages/Custom.md +23 -0
- data/pages/Encoding.md +65 -0
- data/pages/JsonGem.md +94 -0
- data/pages/Modes.md +161 -0
- data/pages/Options.md +327 -0
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +167 -0
- data/pages/Security.md +20 -0
- data/pages/WAB.md +13 -0
- data/test/activerecord/result_test.rb +32 -0
- data/test/activesupport4/decoding_test.rb +108 -0
- data/test/activesupport4/encoding_test.rb +531 -0
- data/test/activesupport4/test_helper.rb +41 -0
- data/test/activesupport5/abstract_unit.rb +45 -0
- data/test/activesupport5/decoding_test.rb +133 -0
- data/test/activesupport5/encoding_test.rb +500 -0
- data/test/activesupport5/encoding_test_cases.rb +98 -0
- data/test/activesupport5/test_helper.rb +72 -0
- data/test/activesupport5/time_zone_test_helpers.rb +39 -0
- data/test/activesupport6/abstract_unit.rb +44 -0
- data/test/activesupport6/decoding_test.rb +133 -0
- data/test/activesupport6/encoding_test.rb +507 -0
- data/test/activesupport6/encoding_test_cases.rb +98 -0
- data/test/activesupport6/test_common.rb +17 -0
- data/test/activesupport6/test_helper.rb +163 -0
- data/test/activesupport6/time_zone_test_helpers.rb +39 -0
- data/test/activesupport7/abstract_unit.rb +49 -0
- data/test/activesupport7/decoding_test.rb +125 -0
- data/test/activesupport7/encoding_test.rb +486 -0
- data/test/activesupport7/encoding_test_cases.rb +104 -0
- data/test/activesupport7/time_zone_test_helpers.rb +47 -0
- data/test/bar.rb +9 -0
- data/test/baz.rb +16 -0
- data/test/bug.rb +11 -46
- data/test/foo.rb +69 -16
- data/test/helper.rb +10 -1
- data/test/isolated/shared.rb +12 -8
- data/test/isolated/test_mimic_rails_after.rb +3 -3
- data/test/isolated/test_mimic_rails_before.rb +3 -3
- data/test/json_gem/json_addition_test.rb +216 -0
- data/test/json_gem/json_common_interface_test.rb +153 -0
- data/test/json_gem/json_encoding_test.rb +107 -0
- data/test/json_gem/json_ext_parser_test.rb +20 -0
- data/test/json_gem/json_fixtures_test.rb +35 -0
- data/test/json_gem/json_generator_test.rb +397 -0
- data/test/json_gem/json_generic_object_test.rb +90 -0
- data/test/json_gem/json_parser_test.rb +470 -0
- data/test/json_gem/json_string_matching_test.rb +42 -0
- data/test/json_gem/test_helper.rb +26 -0
- data/test/mem.rb +33 -0
- data/test/perf.rb +1 -1
- data/test/perf_compat.rb +30 -28
- data/test/perf_dump.rb +50 -0
- data/test/perf_object.rb +1 -1
- data/test/perf_once.rb +58 -0
- data/test/perf_parser.rb +189 -0
- data/test/perf_scp.rb +11 -10
- data/test/perf_strict.rb +30 -19
- data/test/perf_wab.rb +131 -0
- data/test/prec.rb +23 -0
- data/test/sample.rb +0 -1
- data/test/sample_json.rb +1 -1
- data/test/test_compat.rb +219 -102
- data/test/test_custom.rb +533 -0
- data/test/test_fast.rb +107 -35
- data/test/test_file.rb +19 -25
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +11 -1
- data/test/test_integer_range.rb +72 -0
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +357 -70
- data/test/test_parser.rb +27 -0
- data/test/test_parser_saj.rb +245 -0
- data/test/test_parser_usual.rb +217 -0
- data/test/test_rails.rb +35 -0
- data/test/test_saj.rb +1 -1
- data/test/test_scp.rb +39 -2
- data/test/test_strict.rb +186 -7
- data/test/test_various.rb +160 -774
- data/test/test_wab.rb +307 -0
- data/test/test_writer.rb +90 -2
- data/test/tests.rb +24 -0
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- data/test/zoo.rb +13 -0
- metadata +194 -56
- data/ext/oj/hash.c +0 -163
- data/ext/oj/hash.h +0 -46
- data/ext/oj/hash_test.c +0 -512
- data/test/activesupport_datetime_test.rb +0 -23
- data/test/bug2.rb +0 -10
- data/test/bug3.rb +0 -46
- data/test/bug_fast.rb +0 -32
- data/test/bug_load.rb +0 -24
- data/test/crash.rb +0 -111
- data/test/curl/curl_oj.rb +0 -46
- data/test/curl/get_oj.rb +0 -24
- data/test/curl/just_curl.rb +0 -31
- data/test/curl/just_oj.rb +0 -51
- data/test/example.rb +0 -11
- data/test/io.rb +0 -48
- data/test/isolated/test_mimic_rails_datetime.rb +0 -27
- data/test/mod.rb +0 -16
- data/test/rails.rb +0 -50
- data/test/russian.rb +0 -18
- data/test/struct.rb +0 -29
- data/test/test_serializer.rb +0 -59
- data/test/write_timebars.rb +0 -31
data/ext/oj/sparse.c
CHANGED
|
@@ -1,747 +1,854 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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 <
|
|
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
|
|
18
|
+
#define OJ_INFINITY (1.0 / 0.0)
|
|
45
19
|
|
|
46
20
|
#ifdef RUBINIUS_RUBY
|
|
47
|
-
#define NUM_MAX
|
|
21
|
+
#define NUM_MAX 0x07FFFFFF
|
|
48
22
|
#else
|
|
49
|
-
#define NUM_MAX
|
|
23
|
+
#define NUM_MAX (FIXNUM_MAX >> 8)
|
|
50
24
|
#endif
|
|
51
|
-
#define EXP_MAX
|
|
52
|
-
#define DEC_MAX
|
|
25
|
+
#define EXP_MAX 100000
|
|
26
|
+
#define DEC_MAX 15
|
|
53
27
|
|
|
54
|
-
static void
|
|
55
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
51
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
|
|
81
52
|
}
|
|
82
53
|
if ('\0' == c) {
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
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) {
|
|
93
|
-
|
|
62
|
+
if (0 == parent) { // simple add
|
|
63
|
+
pi->add_value(pi, rval);
|
|
94
64
|
} else {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
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
|
-
|
|
102
|
+
pi->add_num(pi, ni);
|
|
129
103
|
} else {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
|
|
133
|
+
add_value(pi, Qtrue);
|
|
156
134
|
} else {
|
|
157
|
-
|
|
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
|
-
|
|
141
|
+
add_value(pi, Qfalse);
|
|
165
142
|
} else {
|
|
166
|
-
|
|
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
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
171
|
+
buf_append(buf, (char)code);
|
|
197
172
|
} else if (0x000007FF >= code) {
|
|
198
|
-
|
|
199
|
-
|
|
173
|
+
buf_append(buf, 0xC0 | (code >> 6));
|
|
174
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
|
200
175
|
} else if (0x0000FFFF >= code) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
-
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
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
|
-
|
|
293
|
+
pi->add_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
|
|
302
294
|
} else {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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
|
-
|
|
344
|
-
|
|
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
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|
-
|
|
407
|
-
|
|
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
|
|
412
|
-
ni.num
|
|
413
|
-
ni.div
|
|
414
|
-
ni.di
|
|
415
|
-
ni.len
|
|
416
|
-
ni.exp
|
|
417
|
-
ni.big
|
|
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
|
|
420
|
-
ni.neg
|
|
421
|
-
ni.
|
|
422
|
-
|
|
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
|
-
|
|
426
|
-
|
|
439
|
+
c = reader_get(&pi->rd);
|
|
440
|
+
ni.neg = 1;
|
|
427
441
|
} else if ('+' == c) {
|
|
428
|
-
|
|
442
|
+
c = reader_get(&pi->rd);
|
|
429
443
|
}
|
|
430
444
|
if ('I' == c) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
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
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
}
|
|
509
|
-
if (
|
|
510
|
-
|
|
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
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
ni.
|
|
522
|
-
ni.
|
|
523
|
-
ni.
|
|
524
|
-
ni.
|
|
525
|
-
ni.
|
|
526
|
-
ni.
|
|
527
|
-
ni.
|
|
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
|
|
531
|
-
ni.neg
|
|
532
|
-
|
|
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
|
-
|
|
536
|
-
|
|
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 (
|
|
540
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
562
|
-
|
|
632
|
+
pi->end_array(pi);
|
|
633
|
+
add_value(pi, array->val);
|
|
563
634
|
}
|
|
564
635
|
}
|
|
565
636
|
|
|
566
|
-
static void
|
|
567
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
584
|
-
|
|
585
|
-
|
|
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
|
-
|
|
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
|
-
|
|
667
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
|
595
668
|
} else if (NEXT_ARRAY_COMMA == parent->next) {
|
|
596
|
-
|
|
669
|
+
parent->next = NEXT_ARRAY_ELEMENT;
|
|
597
670
|
} else if (NEXT_HASH_COMMA == parent->next) {
|
|
598
|
-
|
|
671
|
+
parent->next = NEXT_HASH_KEY;
|
|
599
672
|
} else {
|
|
600
|
-
|
|
673
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
|
601
674
|
}
|
|
602
675
|
}
|
|
603
676
|
|
|
604
|
-
static void
|
|
605
|
-
|
|
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
|
-
|
|
681
|
+
parent->next = NEXT_HASH_VALUE;
|
|
610
682
|
} else {
|
|
611
|
-
|
|
683
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
|
|
612
684
|
}
|
|
613
685
|
}
|
|
614
686
|
|
|
615
|
-
void
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
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
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
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
|
|
753
|
-
volatile VALUE
|
|
754
|
-
VALUE
|
|
755
|
-
int
|
|
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
|
-
|
|
865
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
|
759
866
|
}
|
|
760
867
|
input = argv[0];
|
|
761
|
-
if (2
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
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
|
-
|
|
886
|
+
pi->proc = Qnil;
|
|
769
887
|
} else {
|
|
770
|
-
|
|
888
|
+
pi->proc = Qundef;
|
|
771
889
|
}
|
|
772
|
-
oj_reader_init(&pi->rd, input, fd);
|
|
773
|
-
pi->json = 0;
|
|
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
|
-
|
|
894
|
+
pi->circ_array = oj_circ_array_new();
|
|
777
895
|
} else {
|
|
778
|
-
|
|
896
|
+
pi->circ_array = 0;
|
|
779
897
|
}
|
|
780
898
|
if (No == pi->options.allow_gc) {
|
|
781
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
913
|
+
rb_gc_enable();
|
|
793
914
|
}
|
|
794
915
|
if (!err_has(&pi->err)) {
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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
|
-
|
|
952
|
+
oj_circ_array_free(pi->circ_array);
|
|
820
953
|
}
|
|
821
954
|
stack_cleanup(&pi->stack);
|
|
822
955
|
if (0 != fd) {
|
|
823
|
-
|
|
824
|
-
}
|
|
825
|
-
if (0 != line) {
|
|
826
|
-
rb_jump_tag(line);
|
|
956
|
+
close(fd);
|
|
827
957
|
}
|
|
828
958
|
if (err_has(&pi->err)) {
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
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
|
}
|