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/parse.c
CHANGED
|
@@ -1,783 +1,969 @@
|
|
|
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 "parse.h"
|
|
5
|
+
|
|
6
|
+
#include <math.h>
|
|
7
|
+
#include <ruby/util.h>
|
|
32
8
|
#include <stdio.h>
|
|
9
|
+
#include <stdlib.h>
|
|
33
10
|
#include <string.h>
|
|
34
11
|
#include <unistd.h>
|
|
35
|
-
#include <math.h>
|
|
36
12
|
|
|
37
|
-
#include "oj.h"
|
|
38
|
-
#include "parse.h"
|
|
39
13
|
#include "buf.h"
|
|
14
|
+
#include "encode.h"
|
|
15
|
+
#include "oj.h"
|
|
16
|
+
#include "rxclass.h"
|
|
40
17
|
#include "val_stack.h"
|
|
41
18
|
|
|
42
19
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
|
43
|
-
#define OJ_INFINITY
|
|
20
|
+
#define OJ_INFINITY (1.0 / 0.0)
|
|
44
21
|
|
|
45
22
|
//#define EXP_MAX 1023
|
|
46
|
-
#define EXP_MAX
|
|
47
|
-
#define DEC_MAX
|
|
23
|
+
#define EXP_MAX 100000
|
|
24
|
+
#define DEC_MAX 15
|
|
48
25
|
|
|
49
|
-
static void
|
|
50
|
-
next_non_white(ParseInfo pi) {
|
|
26
|
+
static void next_non_white(ParseInfo pi) {
|
|
51
27
|
for (; 1; pi->cur++) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
28
|
+
switch (*pi->cur) {
|
|
29
|
+
case ' ':
|
|
30
|
+
case '\t':
|
|
31
|
+
case '\f':
|
|
32
|
+
case '\n':
|
|
33
|
+
case '\r': break;
|
|
34
|
+
default: return;
|
|
35
|
+
}
|
|
62
36
|
}
|
|
63
37
|
}
|
|
64
38
|
|
|
65
|
-
static void
|
|
66
|
-
skip_comment(ParseInfo pi) {
|
|
39
|
+
static void skip_comment(ParseInfo pi) {
|
|
67
40
|
if ('*' == *pi->cur) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
41
|
+
pi->cur++;
|
|
42
|
+
for (; pi->cur < pi->end; pi->cur++) {
|
|
43
|
+
if ('*' == *pi->cur && '/' == *(pi->cur + 1)) {
|
|
44
|
+
pi->cur += 2;
|
|
45
|
+
return;
|
|
46
|
+
} else if (pi->end <= pi->cur) {
|
|
47
|
+
oj_set_error_at(pi,
|
|
48
|
+
oj_parse_error_class,
|
|
49
|
+
__FILE__,
|
|
50
|
+
__LINE__,
|
|
51
|
+
"comment not terminated");
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
78
55
|
} else if ('/' == *pi->cur) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
}
|
|
56
|
+
for (; 1; pi->cur++) {
|
|
57
|
+
switch (*pi->cur) {
|
|
58
|
+
case '\n':
|
|
59
|
+
case '\r':
|
|
60
|
+
case '\f':
|
|
61
|
+
case '\0': return;
|
|
62
|
+
default: break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
90
65
|
} else {
|
|
91
|
-
|
|
66
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
|
|
92
67
|
}
|
|
93
68
|
}
|
|
94
69
|
|
|
95
|
-
static void
|
|
96
|
-
|
|
97
|
-
Val parent = stack_peek(&pi->stack);
|
|
70
|
+
static void add_value(ParseInfo pi, VALUE rval) {
|
|
71
|
+
Val parent = stack_peek(&pi->stack);
|
|
98
72
|
|
|
99
|
-
if (0 == parent) {
|
|
100
|
-
|
|
73
|
+
if (0 == parent) { // simple add
|
|
74
|
+
pi->add_value(pi, rval);
|
|
101
75
|
} else {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
76
|
+
switch (parent->next) {
|
|
77
|
+
case NEXT_ARRAY_NEW:
|
|
78
|
+
case NEXT_ARRAY_ELEMENT:
|
|
79
|
+
pi->array_append_value(pi, rval);
|
|
80
|
+
parent->next = NEXT_ARRAY_COMMA;
|
|
81
|
+
break;
|
|
82
|
+
case NEXT_HASH_VALUE:
|
|
83
|
+
pi->hash_set_value(pi, parent, rval);
|
|
84
|
+
if (0 != parent->key && 0 < parent->klen &&
|
|
85
|
+
(parent->key < pi->json || pi->cur < parent->key)) {
|
|
86
|
+
xfree((char *)parent->key);
|
|
87
|
+
parent->key = 0;
|
|
88
|
+
}
|
|
89
|
+
parent->next = NEXT_HASH_COMMA;
|
|
90
|
+
break;
|
|
91
|
+
case NEXT_HASH_NEW:
|
|
92
|
+
case NEXT_HASH_KEY:
|
|
93
|
+
case NEXT_HASH_COMMA:
|
|
94
|
+
case NEXT_NONE:
|
|
95
|
+
case NEXT_ARRAY_COMMA:
|
|
96
|
+
case NEXT_HASH_COLON:
|
|
97
|
+
default:
|
|
98
|
+
oj_set_error_at(pi,
|
|
99
|
+
oj_parse_error_class,
|
|
100
|
+
__FILE__,
|
|
101
|
+
__LINE__,
|
|
102
|
+
"expected %s",
|
|
103
|
+
oj_stack_next_string(parent->next));
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
126
106
|
}
|
|
127
107
|
}
|
|
128
108
|
|
|
129
|
-
static void
|
|
130
|
-
read_null(ParseInfo pi) {
|
|
109
|
+
static void read_null(ParseInfo pi) {
|
|
131
110
|
if ('u' == *pi->cur++ && 'l' == *pi->cur++ && 'l' == *pi->cur++) {
|
|
132
|
-
|
|
111
|
+
add_value(pi, Qnil);
|
|
133
112
|
} else {
|
|
134
|
-
|
|
113
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null");
|
|
135
114
|
}
|
|
136
115
|
}
|
|
137
116
|
|
|
138
|
-
static void
|
|
139
|
-
read_true(ParseInfo pi) {
|
|
117
|
+
static void read_true(ParseInfo pi) {
|
|
140
118
|
if ('r' == *pi->cur++ && 'u' == *pi->cur++ && 'e' == *pi->cur++) {
|
|
141
|
-
|
|
119
|
+
add_value(pi, Qtrue);
|
|
142
120
|
} else {
|
|
143
|
-
|
|
121
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
|
|
144
122
|
}
|
|
145
123
|
}
|
|
146
124
|
|
|
147
|
-
static void
|
|
148
|
-
read_false(ParseInfo pi) {
|
|
125
|
+
static void read_false(ParseInfo pi) {
|
|
149
126
|
if ('a' == *pi->cur++ && 'l' == *pi->cur++ && 's' == *pi->cur++ && 'e' == *pi->cur++) {
|
|
150
|
-
|
|
127
|
+
add_value(pi, Qfalse);
|
|
151
128
|
} else {
|
|
152
|
-
|
|
129
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
|
|
153
130
|
}
|
|
154
131
|
}
|
|
155
132
|
|
|
156
|
-
static uint32_t
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
int i;
|
|
133
|
+
static uint32_t read_hex(ParseInfo pi, const char *h) {
|
|
134
|
+
uint32_t b = 0;
|
|
135
|
+
int i;
|
|
160
136
|
|
|
161
137
|
for (i = 0; i < 4; i++, h++) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
138
|
+
b = b << 4;
|
|
139
|
+
if ('0' <= *h && *h <= '9') {
|
|
140
|
+
b += *h - '0';
|
|
141
|
+
} else if ('A' <= *h && *h <= 'F') {
|
|
142
|
+
b += *h - 'A' + 10;
|
|
143
|
+
} else if ('a' <= *h && *h <= 'f') {
|
|
144
|
+
b += *h - 'a' + 10;
|
|
145
|
+
} else {
|
|
146
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character");
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
173
149
|
}
|
|
174
150
|
return b;
|
|
175
151
|
}
|
|
176
152
|
|
|
177
|
-
static void
|
|
178
|
-
unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
|
153
|
+
static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
|
179
154
|
if (0x0000007F >= code) {
|
|
180
|
-
|
|
155
|
+
buf_append(buf, (char)code);
|
|
181
156
|
} else if (0x000007FF >= code) {
|
|
182
|
-
|
|
183
|
-
|
|
157
|
+
buf_append(buf, 0xC0 | (code >> 6));
|
|
158
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
|
184
159
|
} else if (0x0000FFFF >= code) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
160
|
+
buf_append(buf, 0xE0 | (code >> 12));
|
|
161
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
|
162
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
|
188
163
|
} else if (0x001FFFFF >= code) {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
164
|
+
buf_append(buf, 0xF0 | (code >> 18));
|
|
165
|
+
buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
|
|
166
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
|
167
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
|
193
168
|
} else if (0x03FFFFFF >= code) {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
169
|
+
buf_append(buf, 0xF8 | (code >> 24));
|
|
170
|
+
buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
|
|
171
|
+
buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
|
|
172
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
|
173
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
|
199
174
|
} else if (0x7FFFFFFF >= code) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
175
|
+
buf_append(buf, 0xFC | (code >> 30));
|
|
176
|
+
buf_append(buf, 0x80 | ((code >> 24) & 0x3F));
|
|
177
|
+
buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
|
|
178
|
+
buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
|
|
179
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
|
180
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
|
206
181
|
} else {
|
|
207
|
-
|
|
182
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
|
|
208
183
|
}
|
|
209
184
|
}
|
|
210
185
|
|
|
211
186
|
// entered at /
|
|
212
|
-
static void
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
Val parent = stack_peek(&pi->stack);
|
|
187
|
+
static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
188
|
+
struct _buf buf;
|
|
189
|
+
const char *s;
|
|
190
|
+
int cnt = (int)(pi->cur - start);
|
|
191
|
+
uint32_t code;
|
|
192
|
+
Val parent = stack_peek(&pi->stack);
|
|
219
193
|
|
|
220
194
|
buf_init(&buf);
|
|
221
195
|
if (0 < cnt) {
|
|
222
|
-
|
|
196
|
+
buf_append_string(&buf, start, cnt);
|
|
223
197
|
}
|
|
224
198
|
for (s = pi->cur; '"' != *s; s++) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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
|
-
|
|
199
|
+
if (s >= pi->end) {
|
|
200
|
+
oj_set_error_at(pi,
|
|
201
|
+
oj_parse_error_class,
|
|
202
|
+
__FILE__,
|
|
203
|
+
__LINE__,
|
|
204
|
+
"quoted string not terminated");
|
|
205
|
+
buf_cleanup(&buf);
|
|
206
|
+
return;
|
|
207
|
+
} else if ('\\' == *s) {
|
|
208
|
+
s++;
|
|
209
|
+
switch (*s) {
|
|
210
|
+
case 'n': buf_append(&buf, '\n'); break;
|
|
211
|
+
case 'r': buf_append(&buf, '\r'); break;
|
|
212
|
+
case 't': buf_append(&buf, '\t'); break;
|
|
213
|
+
case 'f': buf_append(&buf, '\f'); break;
|
|
214
|
+
case 'b': buf_append(&buf, '\b'); break;
|
|
215
|
+
case '"': buf_append(&buf, '"'); break;
|
|
216
|
+
case '/': buf_append(&buf, '/'); break;
|
|
217
|
+
case '\\': buf_append(&buf, '\\'); break;
|
|
218
|
+
case 'u':
|
|
219
|
+
s++;
|
|
220
|
+
if (0 == (code = read_hex(pi, s)) && err_has(&pi->err)) {
|
|
221
|
+
buf_cleanup(&buf);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
s += 3;
|
|
225
|
+
if (0x0000D800 <= code && code <= 0x0000DFFF) {
|
|
226
|
+
uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
|
|
227
|
+
uint32_t c2;
|
|
228
|
+
|
|
229
|
+
s++;
|
|
230
|
+
if ('\\' != *s || 'u' != *(s + 1)) {
|
|
231
|
+
if (Yes == pi->options.allow_invalid) {
|
|
232
|
+
s--;
|
|
233
|
+
unicode_to_chars(pi, &buf, code);
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
pi->cur = s;
|
|
237
|
+
oj_set_error_at(pi,
|
|
238
|
+
oj_parse_error_class,
|
|
239
|
+
__FILE__,
|
|
240
|
+
__LINE__,
|
|
241
|
+
"invalid escaped character");
|
|
242
|
+
buf_cleanup(&buf);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
s += 2;
|
|
246
|
+
if (0 == (c2 = read_hex(pi, s)) && err_has(&pi->err)) {
|
|
247
|
+
buf_cleanup(&buf);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
s += 3;
|
|
251
|
+
c2 = (c2 - 0x0000DC00) & 0x000003FF;
|
|
252
|
+
code = ((c1 << 10) | c2) + 0x00010000;
|
|
253
|
+
}
|
|
254
|
+
unicode_to_chars(pi, &buf, code);
|
|
255
|
+
if (err_has(&pi->err)) {
|
|
256
|
+
buf_cleanup(&buf);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
break;
|
|
260
|
+
default:
|
|
261
|
+
// The json gem claims this is not an error despite the
|
|
262
|
+
// ECMA-404 indicating it is not valid.
|
|
263
|
+
if (CompatMode == pi->options.mode) {
|
|
264
|
+
buf_append(&buf, *s);
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
pi->cur = s;
|
|
268
|
+
oj_set_error_at(pi,
|
|
269
|
+
oj_parse_error_class,
|
|
270
|
+
__FILE__,
|
|
271
|
+
__LINE__,
|
|
272
|
+
"invalid escaped character");
|
|
273
|
+
buf_cleanup(&buf);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
buf_append(&buf, *s);
|
|
278
|
+
}
|
|
287
279
|
}
|
|
288
280
|
if (0 == parent) {
|
|
289
|
-
|
|
281
|
+
pi->add_cstr(pi, buf.head, buf_len(&buf), start);
|
|
290
282
|
} else {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
283
|
+
switch (parent->next) {
|
|
284
|
+
case NEXT_ARRAY_NEW:
|
|
285
|
+
case NEXT_ARRAY_ELEMENT:
|
|
286
|
+
pi->array_append_cstr(pi, buf.head, buf_len(&buf), start);
|
|
287
|
+
parent->next = NEXT_ARRAY_COMMA;
|
|
288
|
+
break;
|
|
289
|
+
case NEXT_HASH_NEW:
|
|
290
|
+
case NEXT_HASH_KEY:
|
|
291
|
+
if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
|
|
292
|
+
parent->klen = buf_len(&buf);
|
|
293
|
+
parent->key = malloc(parent->klen + 1);
|
|
294
|
+
memcpy((char *)parent->key, buf.head, parent->klen);
|
|
295
|
+
*(char *)(parent->key + parent->klen) = '\0';
|
|
296
|
+
} else {
|
|
297
|
+
parent->key = "";
|
|
298
|
+
parent->klen = 0;
|
|
299
|
+
}
|
|
300
|
+
parent->k1 = *start;
|
|
301
|
+
parent->next = NEXT_HASH_COLON;
|
|
302
|
+
break;
|
|
303
|
+
case NEXT_HASH_VALUE:
|
|
304
|
+
pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start);
|
|
305
|
+
if (0 != parent->key && 0 < parent->klen &&
|
|
306
|
+
(parent->key < pi->json || pi->cur < parent->key)) {
|
|
307
|
+
xfree((char *)parent->key);
|
|
308
|
+
parent->key = 0;
|
|
309
|
+
}
|
|
310
|
+
parent->next = NEXT_HASH_COMMA;
|
|
311
|
+
break;
|
|
312
|
+
case NEXT_HASH_COMMA:
|
|
313
|
+
case NEXT_NONE:
|
|
314
|
+
case NEXT_ARRAY_COMMA:
|
|
315
|
+
case NEXT_HASH_COLON:
|
|
316
|
+
default:
|
|
317
|
+
oj_set_error_at(pi,
|
|
318
|
+
oj_parse_error_class,
|
|
319
|
+
__FILE__,
|
|
320
|
+
__LINE__,
|
|
321
|
+
"expected %s, not a string",
|
|
322
|
+
oj_stack_next_string(parent->next));
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
325
|
}
|
|
326
326
|
pi->cur = s + 1;
|
|
327
327
|
buf_cleanup(&buf);
|
|
328
328
|
}
|
|
329
329
|
|
|
330
|
-
static void
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
Val parent = stack_peek(&pi->stack);
|
|
330
|
+
static void read_str(ParseInfo pi) {
|
|
331
|
+
const char *str = pi->cur;
|
|
332
|
+
Val parent = stack_peek(&pi->stack);
|
|
334
333
|
|
|
335
334
|
for (; '"' != *pi->cur; pi->cur++) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
335
|
+
if (pi->end <= pi->cur) {
|
|
336
|
+
oj_set_error_at(pi,
|
|
337
|
+
oj_parse_error_class,
|
|
338
|
+
__FILE__,
|
|
339
|
+
__LINE__,
|
|
340
|
+
"quoted string not terminated");
|
|
341
|
+
return;
|
|
342
|
+
} else if ('\0' == *pi->cur) {
|
|
343
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string");
|
|
344
|
+
return;
|
|
345
|
+
} else if ('\\' == *pi->cur) {
|
|
346
|
+
read_escaped_str(pi, str);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
346
349
|
}
|
|
347
|
-
if (0 == parent) {
|
|
348
|
-
|
|
350
|
+
if (0 == parent) { // simple add
|
|
351
|
+
pi->add_cstr(pi, str, pi->cur - str, str);
|
|
349
352
|
} else {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
353
|
+
switch (parent->next) {
|
|
354
|
+
case NEXT_ARRAY_NEW:
|
|
355
|
+
case NEXT_ARRAY_ELEMENT:
|
|
356
|
+
pi->array_append_cstr(pi, str, pi->cur - str, str);
|
|
357
|
+
parent->next = NEXT_ARRAY_COMMA;
|
|
358
|
+
break;
|
|
359
|
+
case NEXT_HASH_NEW:
|
|
360
|
+
case NEXT_HASH_KEY:
|
|
361
|
+
if (Qundef == (parent->key_val = pi->hash_key(pi, str, pi->cur - str))) {
|
|
362
|
+
parent->key = str;
|
|
363
|
+
parent->klen = pi->cur - str;
|
|
364
|
+
} else {
|
|
365
|
+
parent->key = "";
|
|
366
|
+
parent->klen = 0;
|
|
367
|
+
}
|
|
368
|
+
parent->k1 = *str;
|
|
369
|
+
parent->next = NEXT_HASH_COLON;
|
|
370
|
+
break;
|
|
371
|
+
case NEXT_HASH_VALUE:
|
|
372
|
+
pi->hash_set_cstr(pi, parent, str, pi->cur - str, str);
|
|
373
|
+
if (0 != parent->key && 0 < parent->klen &&
|
|
374
|
+
(parent->key < pi->json || pi->cur < parent->key)) {
|
|
375
|
+
xfree((char *)parent->key);
|
|
376
|
+
parent->key = 0;
|
|
377
|
+
}
|
|
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
|
+
}
|
|
384
393
|
}
|
|
385
|
-
pi->cur++;
|
|
394
|
+
pi->cur++; // move past "
|
|
386
395
|
}
|
|
387
396
|
|
|
388
|
-
static void
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
ni.
|
|
394
|
-
ni.
|
|
395
|
-
ni.
|
|
396
|
-
ni.
|
|
397
|
-
ni.
|
|
398
|
-
ni.
|
|
399
|
-
ni.
|
|
400
|
-
ni.big = 0;
|
|
397
|
+
static void read_num(ParseInfo pi) {
|
|
398
|
+
struct _numInfo ni;
|
|
399
|
+
Val parent = stack_peek(&pi->stack);
|
|
400
|
+
|
|
401
|
+
ni.str = pi->cur;
|
|
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;
|
|
401
409
|
ni.infinity = 0;
|
|
402
|
-
ni.nan
|
|
403
|
-
ni.neg
|
|
404
|
-
ni.
|
|
405
|
-
|
|
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
|
+
}
|
|
406
421
|
|
|
407
422
|
if ('-' == *pi->cur) {
|
|
408
|
-
|
|
409
|
-
|
|
423
|
+
pi->cur++;
|
|
424
|
+
ni.neg = 1;
|
|
410
425
|
} else if ('+' == *pi->cur) {
|
|
411
|
-
|
|
426
|
+
if (StrictMode == pi->options.mode) {
|
|
427
|
+
oj_set_error_at(pi,
|
|
428
|
+
oj_parse_error_class,
|
|
429
|
+
__FILE__,
|
|
430
|
+
__LINE__,
|
|
431
|
+
"not a number or other value");
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
pi->cur++;
|
|
412
435
|
}
|
|
413
436
|
if ('I' == *pi->cur) {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
437
|
+
if (No == pi->options.allow_nan || 0 != strncmp("Infinity", pi->cur, 8)) {
|
|
438
|
+
oj_set_error_at(pi,
|
|
439
|
+
oj_parse_error_class,
|
|
440
|
+
__FILE__,
|
|
441
|
+
__LINE__,
|
|
442
|
+
"not a number or other value");
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
pi->cur += 8;
|
|
446
|
+
ni.infinity = 1;
|
|
420
447
|
} else if ('N' == *pi->cur || 'n' == *pi->cur) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
448
|
+
if ('a' != pi->cur[1] || ('N' != pi->cur[2] && 'n' != pi->cur[2])) {
|
|
449
|
+
oj_set_error_at(pi,
|
|
450
|
+
oj_parse_error_class,
|
|
451
|
+
__FILE__,
|
|
452
|
+
__LINE__,
|
|
453
|
+
"not a number or other value");
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
pi->cur += 3;
|
|
457
|
+
ni.nan = 1;
|
|
427
458
|
} else {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
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
|
-
|
|
459
|
+
int dec_cnt = 0;
|
|
460
|
+
bool zero1 = false;
|
|
461
|
+
|
|
462
|
+
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
|
463
|
+
if (0 == ni.i && '0' == *pi->cur) {
|
|
464
|
+
zero1 = true;
|
|
465
|
+
}
|
|
466
|
+
if (0 < ni.i) {
|
|
467
|
+
dec_cnt++;
|
|
468
|
+
}
|
|
469
|
+
if (!ni.big) {
|
|
470
|
+
int d = (*pi->cur - '0');
|
|
471
|
+
|
|
472
|
+
if (0 < d) {
|
|
473
|
+
if (zero1 && CompatMode == pi->options.mode) {
|
|
474
|
+
oj_set_error_at(pi,
|
|
475
|
+
oj_parse_error_class,
|
|
476
|
+
__FILE__,
|
|
477
|
+
__LINE__,
|
|
478
|
+
"not a number");
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
zero1 = false;
|
|
482
|
+
}
|
|
483
|
+
ni.i = ni.i * 10 + d;
|
|
484
|
+
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
|
485
|
+
ni.big = 1;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if ('.' == *pi->cur) {
|
|
490
|
+
pi->cur++;
|
|
491
|
+
// A trailing . is not a valid decimal but if encountered allow it
|
|
492
|
+
// except when mimicking the JSON gem or in strict mode.
|
|
493
|
+
if (StrictMode == pi->options.mode || CompatMode == pi->options.mode) {
|
|
494
|
+
int pos = (int)(pi->cur - ni.str);
|
|
495
|
+
|
|
496
|
+
if (1 == pos || (2 == pos && ni.neg)) {
|
|
497
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
if (*pi->cur < '0' || '9' < *pi->cur) {
|
|
501
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
|
506
|
+
int d = (*pi->cur - '0');
|
|
507
|
+
|
|
508
|
+
if (0 < ni.num || 0 < ni.i) {
|
|
509
|
+
dec_cnt++;
|
|
510
|
+
}
|
|
511
|
+
if (INT64_MAX <= ni.div) {
|
|
512
|
+
if (!ni.no_big) {
|
|
513
|
+
ni.big = true;
|
|
514
|
+
}
|
|
515
|
+
} else {
|
|
516
|
+
ni.num = ni.num * 10 + d;
|
|
517
|
+
ni.div *= 10;
|
|
518
|
+
ni.di++;
|
|
519
|
+
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
|
520
|
+
if (!ni.no_big) {
|
|
521
|
+
ni.big = true;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if ('e' == *pi->cur || 'E' == *pi->cur) {
|
|
528
|
+
int eneg = 0;
|
|
529
|
+
|
|
530
|
+
ni.has_exp = 1;
|
|
531
|
+
pi->cur++;
|
|
532
|
+
if ('-' == *pi->cur) {
|
|
533
|
+
pi->cur++;
|
|
534
|
+
eneg = 1;
|
|
535
|
+
} else if ('+' == *pi->cur) {
|
|
536
|
+
pi->cur++;
|
|
537
|
+
}
|
|
538
|
+
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
|
539
|
+
ni.exp = ni.exp * 10 + (*pi->cur - '0');
|
|
540
|
+
if (EXP_MAX <= ni.exp) {
|
|
541
|
+
ni.big = true;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
if (eneg) {
|
|
545
|
+
ni.exp = -ni.exp;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
ni.len = pi->cur - ni.str;
|
|
481
549
|
}
|
|
482
550
|
// Check for special reserved values for Infinity and NaN.
|
|
483
551
|
if (ni.big) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
552
|
+
if (0 == strcasecmp(INF_VAL, ni.str)) {
|
|
553
|
+
ni.infinity = 1;
|
|
554
|
+
} else if (0 == strcasecmp(NINF_VAL, ni.str)) {
|
|
555
|
+
ni.infinity = 1;
|
|
556
|
+
ni.neg = 1;
|
|
557
|
+
} else if (0 == strcasecmp(NAN_VAL, ni.str)) {
|
|
558
|
+
ni.nan = 1;
|
|
559
|
+
}
|
|
492
560
|
}
|
|
493
|
-
if (
|
|
494
|
-
|
|
561
|
+
if (CompatMode == pi->options.mode) {
|
|
562
|
+
if (pi->options.compat_bigdec) {
|
|
563
|
+
ni.big = 1;
|
|
564
|
+
}
|
|
565
|
+
} else if (BigDec == pi->options.bigdec_load) {
|
|
566
|
+
ni.big = 1;
|
|
495
567
|
}
|
|
496
568
|
if (0 == parent) {
|
|
497
|
-
|
|
569
|
+
pi->add_num(pi, &ni);
|
|
498
570
|
} else {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
571
|
+
switch (parent->next) {
|
|
572
|
+
case NEXT_ARRAY_NEW:
|
|
573
|
+
case NEXT_ARRAY_ELEMENT:
|
|
574
|
+
pi->array_append_num(pi, &ni);
|
|
575
|
+
parent->next = NEXT_ARRAY_COMMA;
|
|
576
|
+
break;
|
|
577
|
+
case NEXT_HASH_VALUE:
|
|
578
|
+
pi->hash_set_num(pi, parent, &ni);
|
|
579
|
+
if (0 != parent->key && 0 < parent->klen &&
|
|
580
|
+
(parent->key < pi->json || pi->cur < parent->key)) {
|
|
581
|
+
xfree((char *)parent->key);
|
|
582
|
+
parent->key = 0;
|
|
583
|
+
}
|
|
584
|
+
parent->next = NEXT_HASH_COMMA;
|
|
585
|
+
break;
|
|
586
|
+
default:
|
|
587
|
+
oj_set_error_at(pi,
|
|
588
|
+
oj_parse_error_class,
|
|
589
|
+
__FILE__,
|
|
590
|
+
__LINE__,
|
|
591
|
+
"expected %s",
|
|
592
|
+
oj_stack_next_string(parent->next));
|
|
593
|
+
break;
|
|
594
|
+
}
|
|
517
595
|
}
|
|
518
596
|
}
|
|
519
597
|
|
|
520
|
-
static void
|
|
521
|
-
|
|
522
|
-
volatile VALUE v = pi->start_array(pi);
|
|
598
|
+
static void array_start(ParseInfo pi) {
|
|
599
|
+
volatile VALUE v = pi->start_array(pi);
|
|
523
600
|
|
|
524
601
|
stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
|
|
525
602
|
}
|
|
526
603
|
|
|
527
|
-
static void
|
|
528
|
-
|
|
529
|
-
Val array = stack_pop(&pi->stack);
|
|
604
|
+
static void array_end(ParseInfo pi) {
|
|
605
|
+
Val array = stack_pop(&pi->stack);
|
|
530
606
|
|
|
531
607
|
if (0 == array) {
|
|
532
|
-
|
|
608
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
|
|
533
609
|
} else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
|
|
534
|
-
|
|
610
|
+
oj_set_error_at(pi,
|
|
611
|
+
oj_parse_error_class,
|
|
612
|
+
__FILE__,
|
|
613
|
+
__LINE__,
|
|
614
|
+
"expected %s, not an array close",
|
|
615
|
+
oj_stack_next_string(array->next));
|
|
535
616
|
} else {
|
|
536
|
-
|
|
537
|
-
|
|
617
|
+
pi->end_array(pi);
|
|
618
|
+
add_value(pi, array->val);
|
|
538
619
|
}
|
|
539
620
|
}
|
|
540
621
|
|
|
541
|
-
static void
|
|
542
|
-
|
|
543
|
-
volatile VALUE v = pi->start_hash(pi);
|
|
622
|
+
static void hash_start(ParseInfo pi) {
|
|
623
|
+
volatile VALUE v = pi->start_hash(pi);
|
|
544
624
|
|
|
545
625
|
stack_push(&pi->stack, v, NEXT_HASH_NEW);
|
|
546
626
|
}
|
|
547
627
|
|
|
548
|
-
static void
|
|
549
|
-
|
|
550
|
-
volatile Val hash = stack_peek(&pi->stack);
|
|
628
|
+
static void hash_end(ParseInfo pi) {
|
|
629
|
+
volatile Val hash = stack_peek(&pi->stack);
|
|
551
630
|
|
|
552
631
|
// leave hash on stack until just before
|
|
553
632
|
if (0 == hash) {
|
|
554
|
-
|
|
633
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
|
|
555
634
|
} else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
|
|
556
|
-
|
|
635
|
+
oj_set_error_at(pi,
|
|
636
|
+
oj_parse_error_class,
|
|
637
|
+
__FILE__,
|
|
638
|
+
__LINE__,
|
|
639
|
+
"expected %s, not a hash close",
|
|
640
|
+
oj_stack_next_string(hash->next));
|
|
557
641
|
} else {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
642
|
+
pi->end_hash(pi);
|
|
643
|
+
stack_pop(&pi->stack);
|
|
644
|
+
add_value(pi, hash->val);
|
|
561
645
|
}
|
|
562
646
|
}
|
|
563
647
|
|
|
564
|
-
static void
|
|
565
|
-
|
|
566
|
-
Val parent = stack_peek(&pi->stack);
|
|
648
|
+
static void comma(ParseInfo pi) {
|
|
649
|
+
Val parent = stack_peek(&pi->stack);
|
|
567
650
|
|
|
568
651
|
if (0 == parent) {
|
|
569
|
-
|
|
652
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
|
570
653
|
} else if (NEXT_ARRAY_COMMA == parent->next) {
|
|
571
|
-
|
|
654
|
+
parent->next = NEXT_ARRAY_ELEMENT;
|
|
572
655
|
} else if (NEXT_HASH_COMMA == parent->next) {
|
|
573
|
-
|
|
656
|
+
parent->next = NEXT_HASH_KEY;
|
|
574
657
|
} else {
|
|
575
|
-
|
|
658
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
|
576
659
|
}
|
|
577
660
|
}
|
|
578
661
|
|
|
579
|
-
static void
|
|
580
|
-
|
|
581
|
-
Val parent = stack_peek(&pi->stack);
|
|
662
|
+
static void colon(ParseInfo pi) {
|
|
663
|
+
Val parent = stack_peek(&pi->stack);
|
|
582
664
|
|
|
583
665
|
if (0 != parent && NEXT_HASH_COLON == parent->next) {
|
|
584
|
-
|
|
666
|
+
parent->next = NEXT_HASH_VALUE;
|
|
585
667
|
} else {
|
|
586
|
-
|
|
668
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
|
|
587
669
|
}
|
|
588
670
|
}
|
|
589
671
|
|
|
590
|
-
void
|
|
591
|
-
|
|
592
|
-
|
|
672
|
+
void oj_parse2(ParseInfo pi) {
|
|
673
|
+
int first = 1;
|
|
674
|
+
long start = 0;
|
|
593
675
|
|
|
594
676
|
pi->cur = pi->json;
|
|
595
677
|
err_init(&pi->err);
|
|
596
678
|
while (1) {
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
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
|
-
|
|
679
|
+
if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
|
|
680
|
+
VALUE err_clas = oj_get_json_err_class("NestingError");
|
|
681
|
+
|
|
682
|
+
oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
|
|
683
|
+
pi->err_class = err_clas;
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
next_non_white(pi);
|
|
687
|
+
if (!first && '\0' != *pi->cur) {
|
|
688
|
+
oj_set_error_at(pi,
|
|
689
|
+
oj_parse_error_class,
|
|
690
|
+
__FILE__,
|
|
691
|
+
__LINE__,
|
|
692
|
+
"unexpected characters after the JSON document");
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// If no tokens are consumed (i.e. empty string), throw a parse error
|
|
696
|
+
// this is the behavior of JSON.parse in both Ruby and JS.
|
|
697
|
+
if (No == pi->options.empty_string && 1 == first && '\0' == *pi->cur) {
|
|
698
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
switch (*pi->cur++) {
|
|
702
|
+
case '{': hash_start(pi); break;
|
|
703
|
+
case '}': hash_end(pi); break;
|
|
704
|
+
case ':': colon(pi); break;
|
|
705
|
+
case '[': array_start(pi); break;
|
|
706
|
+
case ']': array_end(pi); break;
|
|
707
|
+
case ',': comma(pi); break;
|
|
708
|
+
case '"':
|
|
709
|
+
read_str(pi);
|
|
710
|
+
break;
|
|
711
|
+
// case '+':
|
|
712
|
+
case '+':
|
|
713
|
+
if (CompatMode == pi->options.mode) {
|
|
714
|
+
oj_set_error_at(pi,
|
|
715
|
+
oj_parse_error_class,
|
|
716
|
+
__FILE__,
|
|
717
|
+
__LINE__,
|
|
718
|
+
"unexpected character");
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
pi->cur--;
|
|
722
|
+
read_num(pi);
|
|
723
|
+
break;
|
|
724
|
+
case '-':
|
|
725
|
+
case '0':
|
|
726
|
+
case '1':
|
|
727
|
+
case '2':
|
|
728
|
+
case '3':
|
|
729
|
+
case '4':
|
|
730
|
+
case '5':
|
|
731
|
+
case '6':
|
|
732
|
+
case '7':
|
|
733
|
+
case '8':
|
|
734
|
+
case '9':
|
|
735
|
+
pi->cur--;
|
|
736
|
+
read_num(pi);
|
|
737
|
+
break;
|
|
738
|
+
case 'I':
|
|
739
|
+
case 'N':
|
|
740
|
+
if (Yes == pi->options.allow_nan) {
|
|
741
|
+
pi->cur--;
|
|
742
|
+
read_num(pi);
|
|
743
|
+
} else {
|
|
744
|
+
oj_set_error_at(pi,
|
|
745
|
+
oj_parse_error_class,
|
|
746
|
+
__FILE__,
|
|
747
|
+
__LINE__,
|
|
748
|
+
"unexpected character");
|
|
749
|
+
}
|
|
750
|
+
break;
|
|
751
|
+
case 't': read_true(pi); break;
|
|
752
|
+
case 'f': read_false(pi); break;
|
|
753
|
+
case 'n':
|
|
754
|
+
if ('u' == *pi->cur) {
|
|
755
|
+
read_null(pi);
|
|
756
|
+
} else {
|
|
757
|
+
pi->cur--;
|
|
758
|
+
read_num(pi);
|
|
759
|
+
}
|
|
760
|
+
break;
|
|
761
|
+
case '/':
|
|
762
|
+
skip_comment(pi);
|
|
763
|
+
if (first) {
|
|
764
|
+
continue;
|
|
765
|
+
}
|
|
766
|
+
break;
|
|
767
|
+
case '\0': pi->cur--; return;
|
|
768
|
+
default:
|
|
769
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
if (err_has(&pi->err)) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
if (stack_empty(&pi->stack)) {
|
|
776
|
+
if (Qundef != pi->proc) {
|
|
777
|
+
VALUE args[3];
|
|
778
|
+
long len = (pi->cur - pi->json) - start;
|
|
779
|
+
|
|
780
|
+
*args = stack_head_val(&pi->stack);
|
|
781
|
+
args[1] = LONG2NUM(start);
|
|
782
|
+
args[2] = LONG2NUM(len);
|
|
783
|
+
|
|
784
|
+
if (Qnil == pi->proc) {
|
|
785
|
+
rb_yield_values2(3, args);
|
|
786
|
+
} else {
|
|
787
|
+
rb_proc_call_with_block(pi->proc, 3, args, Qnil);
|
|
788
|
+
}
|
|
789
|
+
} else if (!pi->has_callbacks) {
|
|
790
|
+
first = 0;
|
|
791
|
+
}
|
|
792
|
+
start = pi->cur - pi->json;
|
|
793
|
+
}
|
|
689
794
|
}
|
|
690
795
|
}
|
|
691
796
|
|
|
797
|
+
static VALUE rescue_big_decimal(VALUE str, VALUE ignore) {
|
|
798
|
+
rb_raise(oj_parse_error_class, "Invalid value for BigDecimal()");
|
|
799
|
+
return Qnil;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
static VALUE parse_big_decimal(VALUE str) {
|
|
803
|
+
return rb_funcall(rb_cObject, oj_bigdecimal_id, 1, str);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
static long double exp_plus[] = {
|
|
807
|
+
1.0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
|
|
808
|
+
1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19,
|
|
809
|
+
1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29,
|
|
810
|
+
1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39,
|
|
811
|
+
1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49,
|
|
812
|
+
};
|
|
813
|
+
|
|
692
814
|
VALUE
|
|
693
815
|
oj_num_as_value(NumInfo ni) {
|
|
694
|
-
volatile VALUE
|
|
816
|
+
volatile VALUE rnum = Qnil;
|
|
695
817
|
|
|
696
818
|
if (ni->infinity) {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
819
|
+
if (ni->neg) {
|
|
820
|
+
rnum = rb_float_new(-OJ_INFINITY);
|
|
821
|
+
} else {
|
|
822
|
+
rnum = rb_float_new(OJ_INFINITY);
|
|
823
|
+
}
|
|
702
824
|
} else if (ni->nan) {
|
|
703
|
-
|
|
704
|
-
} else if (1 == ni->div && 0 == ni->exp) {
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
} else {
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
825
|
+
rnum = rb_float_new(0.0 / 0.0);
|
|
826
|
+
} else if (1 == ni->div && 0 == ni->exp && !ni->has_exp) { // fixnum
|
|
827
|
+
if (ni->big) {
|
|
828
|
+
if (256 > ni->len) {
|
|
829
|
+
char buf[256];
|
|
830
|
+
|
|
831
|
+
memcpy(buf, ni->str, ni->len);
|
|
832
|
+
buf[ni->len] = '\0';
|
|
833
|
+
rnum = rb_cstr_to_inum(buf, 10, 0);
|
|
834
|
+
} else {
|
|
835
|
+
char *buf = ALLOC_N(char, ni->len + 1);
|
|
836
|
+
|
|
837
|
+
memcpy(buf, ni->str, ni->len);
|
|
838
|
+
buf[ni->len] = '\0';
|
|
839
|
+
rnum = rb_cstr_to_inum(buf, 10, 0);
|
|
840
|
+
xfree(buf);
|
|
841
|
+
}
|
|
842
|
+
} else {
|
|
843
|
+
if (ni->neg) {
|
|
844
|
+
rnum = rb_ll2inum(-ni->i);
|
|
845
|
+
} else {
|
|
846
|
+
rnum = rb_ll2inum(ni->i);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
} else { // decimal
|
|
850
|
+
if (ni->big) {
|
|
851
|
+
volatile VALUE bd = rb_str_new(ni->str, ni->len);
|
|
852
|
+
|
|
853
|
+
rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
|
|
854
|
+
if (ni->no_big) {
|
|
855
|
+
rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
|
|
856
|
+
}
|
|
857
|
+
} else if (FastDec == ni->bigdec_load) {
|
|
858
|
+
long double ld = (long double)ni->i * (long double)ni->div + (long double)ni->num;
|
|
859
|
+
int x = (int)((int64_t)ni->exp - ni->di);
|
|
860
|
+
|
|
861
|
+
if (0 < x) {
|
|
862
|
+
if (x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
|
|
863
|
+
ld *= exp_plus[x];
|
|
864
|
+
} else {
|
|
865
|
+
ld *= powl(10.0, x);
|
|
866
|
+
}
|
|
867
|
+
} else if (x < 0) {
|
|
868
|
+
if (-x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
|
|
869
|
+
ld /= exp_plus[-x];
|
|
870
|
+
} else {
|
|
871
|
+
ld /= powl(10.0, -x);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
if (ni->neg) {
|
|
875
|
+
ld = -ld;
|
|
876
|
+
}
|
|
877
|
+
rnum = rb_float_new((double)ld);
|
|
878
|
+
} else if (RubyDec == ni->bigdec_load) {
|
|
879
|
+
volatile VALUE sv = rb_str_new(ni->str, ni->len);
|
|
880
|
+
|
|
881
|
+
rnum = rb_funcall(sv, rb_intern("to_f"), 0);
|
|
882
|
+
} else {
|
|
883
|
+
char * end;
|
|
884
|
+
double d = strtod(ni->str, &end);
|
|
885
|
+
|
|
886
|
+
if ((long)ni->len != (long)(end - ni->str)) {
|
|
887
|
+
rb_raise(oj_parse_error_class, "Invalid float");
|
|
888
|
+
}
|
|
889
|
+
rnum = rb_float_new(d);
|
|
890
|
+
}
|
|
759
891
|
}
|
|
760
892
|
return rnum;
|
|
761
893
|
}
|
|
762
894
|
|
|
763
|
-
void
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
895
|
+
void oj_set_error_at(ParseInfo pi,
|
|
896
|
+
VALUE err_clas,
|
|
897
|
+
const char *file,
|
|
898
|
+
int line,
|
|
899
|
+
const char *format,
|
|
900
|
+
...) {
|
|
901
|
+
va_list ap;
|
|
902
|
+
char msg[256];
|
|
903
|
+
char * p = msg;
|
|
904
|
+
char * end = p + sizeof(msg) - 2;
|
|
905
|
+
char * start;
|
|
906
|
+
Val vp;
|
|
907
|
+
int mlen;
|
|
767
908
|
|
|
768
909
|
va_start(ap, format);
|
|
769
|
-
vsnprintf(msg, sizeof(msg) - 1, format, ap);
|
|
910
|
+
mlen = vsnprintf(msg, sizeof(msg) - 1, format, ap);
|
|
911
|
+
if (0 < mlen) {
|
|
912
|
+
if (sizeof(msg) - 2 < (size_t)mlen) {
|
|
913
|
+
p = end - 2;
|
|
914
|
+
} else {
|
|
915
|
+
p += mlen;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
770
918
|
va_end(ap);
|
|
771
919
|
pi->err.clas = err_clas;
|
|
920
|
+
if (p + 3 < end) {
|
|
921
|
+
*p++ = ' ';
|
|
922
|
+
*p++ = '(';
|
|
923
|
+
*p++ = 'a';
|
|
924
|
+
*p++ = 'f';
|
|
925
|
+
*p++ = 't';
|
|
926
|
+
*p++ = 'e';
|
|
927
|
+
*p++ = 'r';
|
|
928
|
+
*p++ = ' ';
|
|
929
|
+
start = p;
|
|
930
|
+
for (vp = pi->stack.head; vp < pi->stack.tail; vp++) {
|
|
931
|
+
if (end <= p + 1 + vp->klen) {
|
|
932
|
+
break;
|
|
933
|
+
}
|
|
934
|
+
if (NULL != vp->key) {
|
|
935
|
+
if (start < p) {
|
|
936
|
+
*p++ = '.';
|
|
937
|
+
}
|
|
938
|
+
memcpy(p, vp->key, vp->klen);
|
|
939
|
+
p += vp->klen;
|
|
940
|
+
} else {
|
|
941
|
+
if (RUBY_T_ARRAY == rb_type(vp->val)) {
|
|
942
|
+
if (end <= p + 12) {
|
|
943
|
+
break;
|
|
944
|
+
}
|
|
945
|
+
p += snprintf(p, end - p, "[%ld]", RARRAY_LEN(vp->val));
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
*p++ = ')';
|
|
950
|
+
}
|
|
951
|
+
*p = '\0';
|
|
772
952
|
if (0 == pi->json) {
|
|
773
|
-
|
|
953
|
+
oj_err_set(&pi->err,
|
|
954
|
+
err_clas,
|
|
955
|
+
"%s at line %d, column %d [%s:%d]",
|
|
956
|
+
msg,
|
|
957
|
+
pi->rd.line,
|
|
958
|
+
pi->rd.col,
|
|
959
|
+
file,
|
|
960
|
+
line);
|
|
774
961
|
} else {
|
|
775
|
-
|
|
962
|
+
_oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
|
|
776
963
|
}
|
|
777
964
|
}
|
|
778
965
|
|
|
779
|
-
static VALUE
|
|
780
|
-
protect_parse(VALUE pip) {
|
|
966
|
+
static VALUE protect_parse(VALUE pip) {
|
|
781
967
|
oj_parse2((ParseInfo)pip);
|
|
782
968
|
|
|
783
969
|
return Qnil;
|
|
@@ -785,91 +971,103 @@ protect_parse(VALUE pip) {
|
|
|
785
971
|
|
|
786
972
|
extern int oj_utf8_index;
|
|
787
973
|
|
|
788
|
-
static void
|
|
789
|
-
|
|
790
|
-
#if HAS_ENCODING_SUPPORT
|
|
791
|
-
rb_encoding *enc = rb_to_encoding(rb_obj_encoding(*inputp));
|
|
974
|
+
static void oj_pi_set_input_str(ParseInfo pi, volatile VALUE *inputp) {
|
|
975
|
+
int idx = RB_ENCODING_GET(*inputp);
|
|
792
976
|
|
|
793
|
-
if (
|
|
794
|
-
|
|
977
|
+
if (oj_utf8_encoding_index != idx) {
|
|
978
|
+
rb_encoding *enc = rb_enc_from_index(idx);
|
|
979
|
+
*inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
|
|
795
980
|
}
|
|
796
|
-
|
|
797
|
-
pi->json
|
|
798
|
-
pi->end = pi->json + RSTRING_LEN(*inputp);
|
|
981
|
+
pi->json = RSTRING_PTR(*inputp);
|
|
982
|
+
pi->end = pi->json + RSTRING_LEN(*inputp);
|
|
799
983
|
}
|
|
800
984
|
|
|
801
985
|
VALUE
|
|
802
986
|
oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
|
|
803
|
-
char
|
|
804
|
-
volatile VALUE
|
|
805
|
-
volatile VALUE
|
|
806
|
-
volatile VALUE
|
|
807
|
-
int
|
|
808
|
-
int
|
|
987
|
+
char * buf = 0;
|
|
988
|
+
volatile VALUE input;
|
|
989
|
+
volatile VALUE wrapped_stack;
|
|
990
|
+
volatile VALUE result = Qnil;
|
|
991
|
+
int line = 0;
|
|
992
|
+
int free_json = 0;
|
|
809
993
|
|
|
810
994
|
if (argc < 1) {
|
|
811
|
-
|
|
995
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
|
812
996
|
}
|
|
813
997
|
input = argv[0];
|
|
814
|
-
if (2
|
|
815
|
-
|
|
998
|
+
if (2 <= argc) {
|
|
999
|
+
if (T_HASH == rb_type(argv[1])) {
|
|
1000
|
+
oj_parse_options(argv[1], &pi->options);
|
|
1001
|
+
} else if (3 <= argc && T_HASH == rb_type(argv[2])) {
|
|
1002
|
+
oj_parse_options(argv[2], &pi->options);
|
|
1003
|
+
}
|
|
816
1004
|
}
|
|
817
1005
|
if (yieldOk && rb_block_given_p()) {
|
|
818
|
-
|
|
1006
|
+
pi->proc = Qnil;
|
|
819
1007
|
} else {
|
|
820
|
-
|
|
1008
|
+
pi->proc = Qundef;
|
|
821
1009
|
}
|
|
822
1010
|
if (0 != json) {
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
1011
|
+
pi->json = json;
|
|
1012
|
+
pi->end = json + len;
|
|
1013
|
+
free_json = 1;
|
|
826
1014
|
} else if (T_STRING == rb_type(input)) {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
1015
|
+
if (CompatMode == pi->options.mode) {
|
|
1016
|
+
if (No == pi->options.nilnil && 0 == RSTRING_LEN(input)) {
|
|
1017
|
+
rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string.");
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
oj_pi_set_input_str(pi, &input);
|
|
1021
|
+
} else if (Qnil == input) {
|
|
1022
|
+
if (Yes == pi->options.nilnil) {
|
|
1023
|
+
return Qnil;
|
|
1024
|
+
} else {
|
|
1025
|
+
rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
|
|
1026
|
+
}
|
|
830
1027
|
} else {
|
|
831
|
-
|
|
832
|
-
|
|
1028
|
+
VALUE clas = rb_obj_class(input);
|
|
1029
|
+
volatile VALUE s;
|
|
833
1030
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
1031
|
+
if (oj_stringio_class == clas) {
|
|
1032
|
+
s = rb_funcall2(input, oj_string_id, 0, 0);
|
|
1033
|
+
oj_pi_set_input_str(pi, &s);
|
|
837
1034
|
#if !IS_WINDOWS
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
1035
|
+
} else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
|
|
1036
|
+
int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
|
|
1037
|
+
ssize_t cnt;
|
|
1038
|
+
size_t len = lseek(fd, 0, SEEK_END);
|
|
1039
|
+
|
|
1040
|
+
lseek(fd, 0, SEEK_SET);
|
|
1041
|
+
buf = ALLOC_N(char, len + 1);
|
|
1042
|
+
pi->json = buf;
|
|
1043
|
+
pi->end = buf + len;
|
|
1044
|
+
if (0 >= (cnt = read(fd, (char *)pi->json, len)) || cnt != (ssize_t)len) {
|
|
1045
|
+
if (0 != buf) {
|
|
1046
|
+
xfree(buf);
|
|
1047
|
+
}
|
|
1048
|
+
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
|
1049
|
+
}
|
|
1050
|
+
((char *)pi->json)[len] = '\0';
|
|
1051
|
+
/* skip UTF-8 BOM if present */
|
|
1052
|
+
if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] &&
|
|
1053
|
+
0xBF == (uint8_t)pi->json[2]) {
|
|
1054
|
+
pi->cur += 3;
|
|
1055
|
+
}
|
|
858
1056
|
#endif
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
}
|
|
1057
|
+
} else if (rb_respond_to(input, oj_read_id)) {
|
|
1058
|
+
// use stream parser instead
|
|
1059
|
+
return oj_pi_sparse(argc, argv, pi, 0);
|
|
1060
|
+
} else {
|
|
1061
|
+
rb_raise(rb_eArgError, "parse() expected a String or IO Object.");
|
|
1062
|
+
}
|
|
865
1063
|
}
|
|
866
1064
|
if (Yes == pi->options.circular) {
|
|
867
|
-
|
|
1065
|
+
pi->circ_array = oj_circ_array_new();
|
|
868
1066
|
} else {
|
|
869
|
-
|
|
1067
|
+
pi->circ_array = 0;
|
|
870
1068
|
}
|
|
871
1069
|
if (No == pi->options.allow_gc) {
|
|
872
|
-
|
|
1070
|
+
rb_gc_disable();
|
|
873
1071
|
}
|
|
874
1072
|
// GC can run at any time. When it runs any Object created by C will be
|
|
875
1073
|
// freed. We protect against this by wrapping the value stack in a ruby
|
|
@@ -877,78 +1075,117 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
|
877
1075
|
// value stack (while it is in scope).
|
|
878
1076
|
wrapped_stack = oj_stack_init(&pi->stack);
|
|
879
1077
|
rb_protect(protect_parse, (VALUE)pi, &line);
|
|
880
|
-
|
|
1078
|
+
if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
|
|
1079
|
+
if (No == pi->options.nilnil ||
|
|
1080
|
+
(CompatMode == pi->options.mode && 0 < pi->cur - pi->json)) {
|
|
1081
|
+
oj_set_error_at(pi, oj_json_parser_error_class, __FILE__, __LINE__, "Empty input");
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
result = stack_head_val(&pi->stack);
|
|
881
1085
|
DATA_PTR(wrapped_stack) = 0;
|
|
882
1086
|
if (No == pi->options.allow_gc) {
|
|
883
|
-
|
|
1087
|
+
rb_gc_enable();
|
|
884
1088
|
}
|
|
885
1089
|
if (!err_has(&pi->err)) {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
1090
|
+
// If the stack is not empty then the JSON terminated early.
|
|
1091
|
+
Val v;
|
|
1092
|
+
VALUE err_class = oj_parse_error_class;
|
|
1093
|
+
|
|
1094
|
+
if (0 != line) {
|
|
1095
|
+
VALUE ec = rb_obj_class(rb_errinfo());
|
|
1096
|
+
|
|
1097
|
+
if (rb_eArgError != ec && 0 != ec) {
|
|
1098
|
+
err_class = ec;
|
|
1099
|
+
}
|
|
1100
|
+
if (rb_eIOError != ec) {
|
|
1101
|
+
goto CLEANUP;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
if (NULL != (v = stack_peek(&pi->stack))) {
|
|
1105
|
+
switch (v->next) {
|
|
1106
|
+
case NEXT_ARRAY_NEW:
|
|
1107
|
+
case NEXT_ARRAY_ELEMENT:
|
|
1108
|
+
case NEXT_ARRAY_COMMA:
|
|
1109
|
+
oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
|
|
1110
|
+
break;
|
|
1111
|
+
case NEXT_HASH_NEW:
|
|
1112
|
+
case NEXT_HASH_KEY:
|
|
1113
|
+
case NEXT_HASH_COLON:
|
|
1114
|
+
case NEXT_HASH_VALUE:
|
|
1115
|
+
case NEXT_HASH_COMMA:
|
|
1116
|
+
oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated");
|
|
1117
|
+
break;
|
|
1118
|
+
default: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated");
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
907
1121
|
}
|
|
1122
|
+
CLEANUP:
|
|
908
1123
|
// proceed with cleanup
|
|
909
1124
|
if (0 != pi->circ_array) {
|
|
910
|
-
|
|
1125
|
+
oj_circ_array_free(pi->circ_array);
|
|
911
1126
|
}
|
|
912
1127
|
if (0 != buf) {
|
|
913
|
-
|
|
1128
|
+
xfree(buf);
|
|
914
1129
|
} else if (free_json) {
|
|
915
|
-
|
|
1130
|
+
xfree(json);
|
|
916
1131
|
}
|
|
917
1132
|
stack_cleanup(&pi->stack);
|
|
918
|
-
if (
|
|
919
|
-
|
|
1133
|
+
if (pi->str_rx.head != oj_default_options.str_rx.head) {
|
|
1134
|
+
oj_rxclass_cleanup(&pi->str_rx);
|
|
920
1135
|
}
|
|
921
1136
|
if (err_has(&pi->err)) {
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1137
|
+
rb_set_errinfo(Qnil);
|
|
1138
|
+
if (Qnil != pi->err_class) {
|
|
1139
|
+
pi->err.clas = pi->err_class;
|
|
1140
|
+
}
|
|
1141
|
+
if ((CompatMode == pi->options.mode || RailsMode == pi->options.mode) && Yes != pi->options.safe) {
|
|
1142
|
+
// The json gem requires the error message be UTF-8 encoded. In
|
|
1143
|
+
// additional the complete JSON source must be returned. There
|
|
1144
|
+
// does not seem to be a size limit.
|
|
1145
|
+
VALUE msg = oj_encode(rb_str_new2(pi->err.msg));
|
|
1146
|
+
VALUE args[1];
|
|
1147
|
+
|
|
1148
|
+
if (NULL != pi->json) {
|
|
1149
|
+
msg = rb_str_append(msg, oj_encode(rb_str_new2(" in '")));
|
|
1150
|
+
msg = rb_str_append(msg, oj_encode(rb_str_new2(pi->json)));
|
|
1151
|
+
}
|
|
1152
|
+
args[0] = msg;
|
|
1153
|
+
if (pi->err.clas == oj_parse_error_class) {
|
|
1154
|
+
// The error was an Oj::ParseError so change to a JSON::ParserError.
|
|
1155
|
+
pi->err.clas = oj_json_parser_error_class;
|
|
1156
|
+
}
|
|
1157
|
+
rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
|
|
1158
|
+
} else {
|
|
1159
|
+
oj_err_raise(&pi->err);
|
|
1160
|
+
}
|
|
1161
|
+
} else if (0 != line) {
|
|
1162
|
+
rb_jump_tag(line);
|
|
926
1163
|
}
|
|
927
1164
|
if (pi->options.quirks_mode == No) {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1165
|
+
switch (rb_type(result)) {
|
|
1166
|
+
case T_NIL:
|
|
1167
|
+
case T_TRUE:
|
|
1168
|
+
case T_FALSE:
|
|
1169
|
+
case T_FIXNUM:
|
|
1170
|
+
case T_FLOAT:
|
|
1171
|
+
case T_CLASS:
|
|
1172
|
+
case T_STRING:
|
|
1173
|
+
case T_SYMBOL: {
|
|
1174
|
+
struct _err err;
|
|
1175
|
+
|
|
1176
|
+
if (Qnil == pi->err_class) {
|
|
1177
|
+
err.clas = oj_parse_error_class;
|
|
1178
|
+
} else {
|
|
1179
|
+
err.clas = pi->err_class;
|
|
1180
|
+
}
|
|
1181
|
+
snprintf(err.msg, sizeof(err.msg), "unexpected non-document value");
|
|
1182
|
+
oj_err_raise(&err);
|
|
1183
|
+
break;
|
|
1184
|
+
}
|
|
1185
|
+
default:
|
|
1186
|
+
// okay
|
|
1187
|
+
break;
|
|
1188
|
+
}
|
|
952
1189
|
}
|
|
953
1190
|
return result;
|
|
954
1191
|
}
|