oj 3.7.4 → 3.13.21
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 +4 -4
- data/CHANGELOG.md +1352 -0
- data/README.md +29 -8
- data/RELEASE_NOTES.md +61 -0
- data/ext/oj/buf.h +53 -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 -43
- data/ext/oj/circarray.h +16 -17
- data/ext/oj/code.c +165 -179
- data/ext/oj/code.h +27 -29
- data/ext/oj/compat.c +174 -194
- data/ext/oj/custom.c +809 -866
- data/ext/oj/debug.c +132 -0
- data/ext/oj/dump.c +848 -863
- data/ext/oj/dump.h +81 -67
- data/ext/oj/dump_compat.c +85 -123
- data/ext/oj/dump_leaf.c +100 -188
- data/ext/oj/dump_object.c +527 -656
- data/ext/oj/dump_strict.c +315 -338
- data/ext/oj/encode.h +7 -34
- data/ext/oj/encoder.c +43 -0
- data/ext/oj/err.c +40 -29
- data/ext/oj/err.h +48 -48
- data/ext/oj/extconf.rb +17 -4
- data/ext/oj/fast.c +1070 -1087
- data/ext/oj/intern.c +301 -0
- data/ext/oj/intern.h +26 -0
- data/ext/oj/mimic_json.c +469 -436
- data/ext/oj/object.c +525 -593
- data/ext/oj/odd.c +154 -138
- data/ext/oj/odd.h +37 -38
- data/ext/oj/oj.c +1325 -986
- data/ext/oj/oj.h +333 -316
- data/ext/oj/parse.c +1002 -846
- data/ext/oj/parse.h +92 -87
- data/ext/oj/parser.c +1557 -0
- data/ext/oj/parser.h +91 -0
- data/ext/oj/rails.c +888 -878
- data/ext/oj/rails.h +11 -14
- data/ext/oj/reader.c +141 -147
- data/ext/oj/reader.h +73 -89
- data/ext/oj/resolve.c +41 -62
- data/ext/oj/resolve.h +7 -9
- data/ext/oj/rxclass.c +71 -75
- data/ext/oj/rxclass.h +18 -19
- data/ext/oj/saj.c +443 -486
- data/ext/oj/saj2.c +602 -0
- data/ext/oj/scp.c +88 -113
- data/ext/oj/sparse.c +787 -709
- data/ext/oj/stream_writer.c +133 -159
- data/ext/oj/strict.c +127 -118
- data/ext/oj/string_writer.c +230 -249
- data/ext/oj/trace.c +34 -41
- data/ext/oj/trace.h +19 -19
- 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 +59 -67
- data/ext/oj/val_stack.h +91 -129
- data/ext/oj/validate.c +46 -0
- data/ext/oj/wab.c +342 -353
- data/lib/oj/bag.rb +1 -0
- data/lib/oj/easy_hash.rb +5 -4
- data/lib/oj/error.rb +1 -1
- data/lib/oj/json.rb +1 -1
- data/lib/oj/mimic.rb +48 -14
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/state.rb +8 -7
- data/lib/oj/version.rb +2 -2
- data/lib/oj.rb +0 -8
- data/pages/Compatibility.md +1 -1
- data/pages/JsonGem.md +15 -0
- data/pages/Modes.md +53 -46
- data/pages/Options.md +72 -11
- data/pages/Parser.md +309 -0
- data/pages/Rails.md +73 -22
- data/pages/Security.md +1 -1
- data/test/activerecord/result_test.rb +7 -2
- data/test/activesupport5/abstract_unit.rb +45 -0
- data/test/activesupport5/decoding_test.rb +68 -60
- data/test/activesupport5/encoding_test.rb +111 -96
- data/test/activesupport5/encoding_test_cases.rb +33 -25
- data/test/activesupport5/test_helper.rb +43 -21
- data/test/activesupport5/time_zone_test_helpers.rb +18 -3
- 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 +6 -12
- data/test/baz.rb +16 -0
- data/test/bug.rb +16 -0
- data/test/foo.rb +69 -75
- data/test/helper.rb +16 -0
- data/test/json_gem/json_common_interface_test.rb +8 -3
- data/test/json_gem/json_generator_test.rb +18 -4
- data/test/json_gem/json_parser_test.rb +9 -0
- data/test/json_gem/test_helper.rb +12 -0
- data/test/mem.rb +33 -0
- data/test/perf.rb +1 -1
- data/test/perf_dump.rb +50 -0
- 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 +17 -23
- data/test/prec.rb +23 -0
- data/test/sample_json.rb +1 -1
- data/test/test_compat.rb +46 -10
- data/test/test_custom.rb +147 -8
- data/test/test_fast.rb +62 -2
- data/test/test_file.rb +25 -2
- data/test/test_gc.rb +13 -0
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +11 -1
- data/test/test_integer_range.rb +7 -2
- data/test/test_object.rb +85 -9
- data/test/test_parser.rb +27 -0
- data/test/test_parser_saj.rb +335 -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 +5 -5
- data/test/test_strict.rb +26 -1
- data/test/test_various.rb +87 -65
- data/test/test_wab.rb +2 -0
- data/test/test_writer.rb +19 -2
- data/test/tests.rb +1 -1
- data/test/zoo.rb +13 -0
- metadata +60 -110
- data/ext/oj/hash.c +0 -163
- data/ext/oj/hash.h +0 -46
- data/ext/oj/hash_test.c +0 -512
data/ext/oj/sparse.c
CHANGED
|
@@ -1,784 +1,854 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* All rights reserved.
|
|
4
|
-
*/
|
|
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.
|
|
5
3
|
|
|
6
|
-
#include <
|
|
4
|
+
#include <math.h>
|
|
7
5
|
#include <stdio.h>
|
|
6
|
+
#include <stdlib.h>
|
|
8
7
|
#include <string.h>
|
|
9
8
|
#include <unistd.h>
|
|
10
|
-
#include <math.h>
|
|
11
9
|
|
|
12
|
-
#include "
|
|
10
|
+
#include "buf.h"
|
|
13
11
|
#include "encode.h"
|
|
12
|
+
#include "intern.h" // for oj_strndup()
|
|
13
|
+
#include "oj.h"
|
|
14
14
|
#include "parse.h"
|
|
15
|
-
#include "buf.h"
|
|
16
|
-
#include "hash.h" // for oj_strndup()
|
|
17
15
|
#include "val_stack.h"
|
|
18
16
|
|
|
19
17
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
|
20
|
-
#define OJ_INFINITY
|
|
18
|
+
#define OJ_INFINITY (1.0 / 0.0)
|
|
21
19
|
|
|
22
20
|
#ifdef RUBINIUS_RUBY
|
|
23
|
-
#define NUM_MAX
|
|
21
|
+
#define NUM_MAX 0x07FFFFFF
|
|
24
22
|
#else
|
|
25
|
-
#define NUM_MAX
|
|
23
|
+
#define NUM_MAX (FIXNUM_MAX >> 8)
|
|
26
24
|
#endif
|
|
27
|
-
#define EXP_MAX
|
|
28
|
-
#define DEC_MAX
|
|
25
|
+
#define EXP_MAX 100000
|
|
26
|
+
#define DEC_MAX 15
|
|
29
27
|
|
|
30
|
-
static void
|
|
31
|
-
|
|
32
|
-
char c = reader_get(&pi->rd);
|
|
28
|
+
static void skip_comment(ParseInfo pi) {
|
|
29
|
+
char c = reader_get(&pi->rd);
|
|
33
30
|
|
|
34
31
|
if ('*' == c) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
+
}
|
|
43
40
|
} else if ('/' == c) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
}
|
|
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
|
+
}
|
|
55
50
|
} else {
|
|
56
|
-
|
|
51
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
|
|
57
52
|
}
|
|
58
53
|
if ('\0' == c) {
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
|
|
55
|
+
return;
|
|
61
56
|
}
|
|
62
57
|
}
|
|
63
58
|
|
|
64
|
-
static void
|
|
65
|
-
|
|
66
|
-
Val parent = stack_peek(&pi->stack);
|
|
59
|
+
static void add_value(ParseInfo pi, VALUE rval) {
|
|
60
|
+
Val parent = stack_peek(&pi->stack);
|
|
67
61
|
|
|
68
|
-
if (0 == parent) {
|
|
69
|
-
|
|
62
|
+
if (0 == parent) { // simple add
|
|
63
|
+
pi->add_value(pi, rval);
|
|
70
64
|
} else {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
+
}
|
|
96
95
|
}
|
|
97
96
|
}
|
|
98
97
|
|
|
99
|
-
static void
|
|
100
|
-
|
|
101
|
-
Val parent = stack_peek(&pi->stack);
|
|
98
|
+
static void add_num_value(ParseInfo pi, NumInfo ni) {
|
|
99
|
+
Val parent = stack_peek(&pi->stack);
|
|
102
100
|
|
|
103
101
|
if (0 == parent) {
|
|
104
|
-
|
|
102
|
+
pi->add_num(pi, ni);
|
|
105
103
|
} else {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
+
}
|
|
125
128
|
}
|
|
126
129
|
}
|
|
127
130
|
|
|
128
|
-
static void
|
|
129
|
-
read_true(ParseInfo pi) {
|
|
131
|
+
static void read_true(ParseInfo pi) {
|
|
130
132
|
if (0 == reader_expect(&pi->rd, "rue")) {
|
|
131
|
-
|
|
133
|
+
add_value(pi, Qtrue);
|
|
132
134
|
} else {
|
|
133
|
-
|
|
135
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
|
|
134
136
|
}
|
|
135
137
|
}
|
|
136
138
|
|
|
137
|
-
static void
|
|
138
|
-
read_false(ParseInfo pi) {
|
|
139
|
+
static void read_false(ParseInfo pi) {
|
|
139
140
|
if (0 == reader_expect(&pi->rd, "alse")) {
|
|
140
|
-
|
|
141
|
+
add_value(pi, Qfalse);
|
|
141
142
|
} else {
|
|
142
|
-
|
|
143
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
|
|
143
144
|
}
|
|
144
145
|
}
|
|
145
146
|
|
|
146
|
-
static uint32_t
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
char c;
|
|
147
|
+
static uint32_t read_hex(ParseInfo pi) {
|
|
148
|
+
uint32_t b = 0;
|
|
149
|
+
int i;
|
|
150
|
+
char c;
|
|
151
151
|
|
|
152
152
|
for (i = 0; i < 4; i++) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
+
}
|
|
165
165
|
}
|
|
166
166
|
return b;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
static void
|
|
170
|
-
unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
|
169
|
+
static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
|
171
170
|
if (0x0000007F >= code) {
|
|
172
|
-
|
|
171
|
+
buf_append(buf, (char)code);
|
|
173
172
|
} else if (0x000007FF >= code) {
|
|
174
|
-
|
|
175
|
-
|
|
173
|
+
buf_append(buf, 0xC0 | (code >> 6));
|
|
174
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
|
176
175
|
} else if (0x0000FFFF >= code) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
176
|
+
buf_append(buf, 0xE0 | (code >> 12));
|
|
177
|
+
buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
|
|
178
|
+
buf_append(buf, 0x80 | (0x3F & code));
|
|
180
179
|
} else if (0x001FFFFF >= code) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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));
|
|
185
184
|
} else if (0x03FFFFFF >= code) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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));
|
|
191
190
|
} else if (0x7FFFFFFF >= code) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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));
|
|
198
197
|
} else {
|
|
199
|
-
|
|
198
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
|
|
200
199
|
}
|
|
201
200
|
}
|
|
202
201
|
|
|
203
202
|
// entered at backslash
|
|
204
|
-
static void
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
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);
|
|
210
208
|
|
|
211
209
|
buf_init(&buf);
|
|
212
210
|
if (pi->rd.str < pi->rd.tail) {
|
|
213
|
-
|
|
211
|
+
buf_append_string(&buf, pi->rd.str, pi->rd.tail - pi->rd.str);
|
|
214
212
|
}
|
|
215
213
|
while ('\"' != (c = reader_get(&pi->rd))) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
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
|
+
}
|
|
286
291
|
}
|
|
287
292
|
if (0 == parent) {
|
|
288
|
-
|
|
293
|
+
pi->add_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
|
|
289
294
|
} else {
|
|
290
|
-
|
|
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
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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
|
+
}
|
|
327
337
|
}
|
|
328
338
|
buf_cleanup(&buf);
|
|
329
339
|
}
|
|
330
340
|
|
|
331
|
-
static void
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
char c;
|
|
341
|
+
static void read_str(ParseInfo pi) {
|
|
342
|
+
Val parent = stack_peek(&pi->stack);
|
|
343
|
+
char c;
|
|
335
344
|
|
|
336
345
|
reader_protect(&pi->rd);
|
|
337
346
|
while ('\"' != (c = reader_get(&pi->rd))) {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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);
|
|
350
363
|
} else {
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
+
}
|
|
390
408
|
}
|
|
391
409
|
reader_release(&pi->rd);
|
|
392
410
|
}
|
|
393
411
|
|
|
394
|
-
static void
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
char c;
|
|
412
|
+
static void read_num(ParseInfo pi) {
|
|
413
|
+
struct _numInfo ni;
|
|
414
|
+
char c;
|
|
398
415
|
|
|
399
416
|
reader_protect(&pi->rd);
|
|
400
|
-
ni.i
|
|
401
|
-
ni.num
|
|
402
|
-
ni.div
|
|
403
|
-
ni.di
|
|
404
|
-
ni.len
|
|
405
|
-
ni.exp
|
|
406
|
-
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;
|
|
407
424
|
ni.infinity = 0;
|
|
408
|
-
ni.nan
|
|
409
|
-
ni.neg
|
|
410
|
-
ni.
|
|
411
|
-
|
|
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
|
+
|
|
412
437
|
c = reader_get(&pi->rd);
|
|
413
438
|
if ('-' == c) {
|
|
414
|
-
|
|
415
|
-
|
|
439
|
+
c = reader_get(&pi->rd);
|
|
440
|
+
ni.neg = 1;
|
|
416
441
|
} else if ('+' == c) {
|
|
417
|
-
|
|
442
|
+
c = reader_get(&pi->rd);
|
|
418
443
|
}
|
|
419
444
|
if ('I' == c) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
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;
|
|
428
461
|
} else {
|
|
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
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
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
|
+
}
|
|
505
550
|
}
|
|
506
551
|
ni.str = pi->rd.str;
|
|
507
552
|
ni.len = pi->rd.tail - pi->rd.str;
|
|
508
553
|
// Check for special reserved values for Infinity and NaN.
|
|
509
554
|
if (ni.big) {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
if (
|
|
520
|
-
|
|
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;
|
|
521
570
|
}
|
|
522
571
|
add_num_value(pi, &ni);
|
|
523
572
|
reader_release(&pi->rd);
|
|
524
573
|
}
|
|
525
574
|
|
|
526
|
-
static void
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
ni.
|
|
532
|
-
ni.
|
|
533
|
-
ni.
|
|
534
|
-
ni.
|
|
535
|
-
ni.
|
|
536
|
-
ni.
|
|
537
|
-
ni.
|
|
538
|
-
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;
|
|
539
587
|
ni.infinity = 0;
|
|
540
|
-
ni.nan
|
|
541
|
-
ni.neg
|
|
542
|
-
|
|
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
|
+
}
|
|
543
598
|
|
|
544
|
-
if ('a' != reader_get(&pi->rd) ||
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
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;
|
|
548
602
|
}
|
|
549
|
-
if (
|
|
550
|
-
|
|
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;
|
|
551
609
|
}
|
|
552
610
|
add_num_value(pi, &ni);
|
|
553
611
|
}
|
|
554
612
|
|
|
555
|
-
static void
|
|
556
|
-
|
|
557
|
-
VALUE v = pi->start_array(pi);
|
|
613
|
+
static void array_start(ParseInfo pi) {
|
|
614
|
+
VALUE v = pi->start_array(pi);
|
|
558
615
|
|
|
559
616
|
stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
|
|
560
617
|
}
|
|
561
618
|
|
|
562
|
-
static void
|
|
563
|
-
|
|
564
|
-
Val array = stack_pop(&pi->stack);
|
|
619
|
+
static void array_end(ParseInfo pi) {
|
|
620
|
+
Val array = stack_pop(&pi->stack);
|
|
565
621
|
|
|
566
622
|
if (0 == array) {
|
|
567
|
-
|
|
623
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
|
|
568
624
|
} else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
|
|
569
|
-
|
|
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));
|
|
570
631
|
} else {
|
|
571
|
-
|
|
572
|
-
|
|
632
|
+
pi->end_array(pi);
|
|
633
|
+
add_value(pi, array->val);
|
|
573
634
|
}
|
|
574
635
|
}
|
|
575
636
|
|
|
576
|
-
static void
|
|
577
|
-
|
|
578
|
-
volatile VALUE v = pi->start_hash(pi);
|
|
637
|
+
static void hash_start(ParseInfo pi) {
|
|
638
|
+
volatile VALUE v = pi->start_hash(pi);
|
|
579
639
|
|
|
580
640
|
stack_push(&pi->stack, v, NEXT_HASH_NEW);
|
|
581
641
|
}
|
|
582
642
|
|
|
583
|
-
static void
|
|
584
|
-
|
|
585
|
-
volatile Val hash = stack_peek(&pi->stack);
|
|
643
|
+
static void hash_end(ParseInfo pi) {
|
|
644
|
+
volatile Val hash = stack_peek(&pi->stack);
|
|
586
645
|
|
|
587
646
|
// leave hash on stack until just before
|
|
588
647
|
if (0 == hash) {
|
|
589
|
-
|
|
648
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
|
|
590
649
|
} else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
|
|
591
|
-
|
|
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));
|
|
592
656
|
} else {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
657
|
+
pi->end_hash(pi);
|
|
658
|
+
stack_pop(&pi->stack);
|
|
659
|
+
add_value(pi, hash->val);
|
|
596
660
|
}
|
|
597
661
|
}
|
|
598
662
|
|
|
599
|
-
static void
|
|
600
|
-
|
|
601
|
-
Val parent = stack_peek(&pi->stack);
|
|
663
|
+
static void comma(ParseInfo pi) {
|
|
664
|
+
Val parent = stack_peek(&pi->stack);
|
|
602
665
|
|
|
603
666
|
if (0 == parent) {
|
|
604
|
-
|
|
667
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
|
605
668
|
} else if (NEXT_ARRAY_COMMA == parent->next) {
|
|
606
|
-
|
|
669
|
+
parent->next = NEXT_ARRAY_ELEMENT;
|
|
607
670
|
} else if (NEXT_HASH_COMMA == parent->next) {
|
|
608
|
-
|
|
671
|
+
parent->next = NEXT_HASH_KEY;
|
|
609
672
|
} else {
|
|
610
|
-
|
|
673
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
|
|
611
674
|
}
|
|
612
675
|
}
|
|
613
676
|
|
|
614
|
-
static void
|
|
615
|
-
|
|
616
|
-
Val parent = stack_peek(&pi->stack);
|
|
677
|
+
static void colon(ParseInfo pi) {
|
|
678
|
+
Val parent = stack_peek(&pi->stack);
|
|
617
679
|
|
|
618
680
|
if (0 != parent && NEXT_HASH_COLON == parent->next) {
|
|
619
|
-
|
|
681
|
+
parent->next = NEXT_HASH_VALUE;
|
|
620
682
|
} else {
|
|
621
|
-
|
|
683
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
|
|
622
684
|
}
|
|
623
685
|
}
|
|
624
686
|
|
|
625
|
-
void
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
long start = 0;
|
|
687
|
+
void oj_sparse2(ParseInfo pi) {
|
|
688
|
+
int first = 1;
|
|
689
|
+
char c;
|
|
690
|
+
long start = 0;
|
|
630
691
|
|
|
631
692
|
err_init(&pi->err);
|
|
632
693
|
while (1) {
|
|
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
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
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
|
+
}
|
|
777
848
|
}
|
|
778
849
|
}
|
|
779
850
|
|
|
780
|
-
static VALUE
|
|
781
|
-
protect_parse(VALUE pip) {
|
|
851
|
+
static VALUE protect_parse(VALUE pip) {
|
|
782
852
|
oj_sparse2((ParseInfo)pip);
|
|
783
853
|
|
|
784
854
|
return Qnil;
|
|
@@ -786,46 +856,47 @@ protect_parse(VALUE pip) {
|
|
|
786
856
|
|
|
787
857
|
VALUE
|
|
788
858
|
oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
|
|
789
|
-
volatile VALUE
|
|
790
|
-
volatile VALUE
|
|
791
|
-
VALUE
|
|
792
|
-
int
|
|
859
|
+
volatile VALUE input;
|
|
860
|
+
volatile VALUE wrapped_stack;
|
|
861
|
+
VALUE result = Qnil;
|
|
862
|
+
int line = 0;
|
|
793
863
|
|
|
794
864
|
if (argc < 1) {
|
|
795
|
-
|
|
865
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
|
796
866
|
}
|
|
797
867
|
input = argv[0];
|
|
798
868
|
if (2 <= argc) {
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
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
|
+
}
|
|
804
874
|
}
|
|
805
875
|
if (Qnil == input) {
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
} else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) &&
|
|
812
|
-
|
|
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.");
|
|
813
884
|
}
|
|
814
885
|
if (rb_block_given_p()) {
|
|
815
|
-
|
|
886
|
+
pi->proc = Qnil;
|
|
816
887
|
} else {
|
|
817
|
-
|
|
888
|
+
pi->proc = Qundef;
|
|
818
889
|
}
|
|
819
890
|
oj_reader_init(&pi->rd, input, fd, CompatMode == pi->options.mode);
|
|
820
|
-
pi->json = 0;
|
|
891
|
+
pi->json = 0; // indicates reader is in use
|
|
821
892
|
|
|
822
893
|
if (Yes == pi->options.circular) {
|
|
823
|
-
|
|
894
|
+
pi->circ_array = oj_circ_array_new();
|
|
824
895
|
} else {
|
|
825
|
-
|
|
896
|
+
pi->circ_array = 0;
|
|
826
897
|
}
|
|
827
898
|
if (No == pi->options.allow_gc) {
|
|
828
|
-
|
|
899
|
+
rb_gc_disable();
|
|
829
900
|
}
|
|
830
901
|
// GC can run at any time. When it runs any Object created by C will be
|
|
831
902
|
// freed. We protect against this by wrapping the value stack in a ruby
|
|
@@ -834,77 +905,84 @@ oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
|
|
|
834
905
|
wrapped_stack = oj_stack_init(&pi->stack);
|
|
835
906
|
rb_protect(protect_parse, (VALUE)pi, &line);
|
|
836
907
|
if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
|
|
837
|
-
|
|
908
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Empty input");
|
|
838
909
|
}
|
|
839
|
-
result
|
|
910
|
+
result = stack_head_val(&pi->stack);
|
|
840
911
|
DATA_PTR(wrapped_stack) = 0;
|
|
841
912
|
if (No == pi->options.allow_gc) {
|
|
842
|
-
|
|
913
|
+
rb_gc_enable();
|
|
843
914
|
}
|
|
844
915
|
if (!err_has(&pi->err)) {
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
}
|
|
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
|
+
}
|
|
878
948
|
}
|
|
879
949
|
CLEANUP:
|
|
880
950
|
// proceed with cleanup
|
|
881
951
|
if (0 != pi->circ_array) {
|
|
882
|
-
|
|
952
|
+
oj_circ_array_free(pi->circ_array);
|
|
883
953
|
}
|
|
884
954
|
stack_cleanup(&pi->stack);
|
|
885
955
|
if (0 != fd) {
|
|
886
|
-
|
|
956
|
+
#ifdef _WIN32
|
|
957
|
+
rb_w32_close(fd);
|
|
958
|
+
#else
|
|
959
|
+
close(fd);
|
|
960
|
+
#endif
|
|
887
961
|
}
|
|
888
962
|
if (err_has(&pi->err)) {
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
963
|
+
rb_set_errinfo(Qnil);
|
|
964
|
+
if (Qnil != pi->err_class && 0 != pi->err_class) {
|
|
965
|
+
pi->err.clas = pi->err_class;
|
|
966
|
+
}
|
|
967
|
+
if (CompatMode == pi->options.mode && Yes != pi->options.safe) {
|
|
968
|
+
// The json gem requires the error message be UTF-8 encoded. In
|
|
969
|
+
// additional the complete JSON source should be returned but that
|
|
970
|
+
// is not possible without stored all the bytes read and reading
|
|
971
|
+
// the remaining bytes on the stream. Both seem like a very bad
|
|
972
|
+
// idea.
|
|
973
|
+
VALUE args[] = {oj_encode(rb_str_new2(pi->err.msg))};
|
|
974
|
+
|
|
975
|
+
if (pi->err.clas == oj_parse_error_class) {
|
|
976
|
+
// The error was an Oj::ParseError so change to a JSON::ParserError.
|
|
977
|
+
pi->err.clas = oj_json_parser_error_class;
|
|
978
|
+
}
|
|
979
|
+
rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
|
|
980
|
+
} else {
|
|
981
|
+
oj_err_raise(&pi->err);
|
|
982
|
+
}
|
|
983
|
+
oj_err_raise(&pi->err);
|
|
906
984
|
} else if (0 != line) {
|
|
907
|
-
|
|
985
|
+
rb_jump_tag(line);
|
|
908
986
|
}
|
|
909
987
|
return result;
|
|
910
988
|
}
|