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/saj.c
CHANGED
|
@@ -1,73 +1,46 @@
|
|
|
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) 2012 Peter Ohler. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
|
30
3
|
|
|
31
4
|
#if !IS_WINDOWS
|
|
32
|
-
#include <sys/resource.h>
|
|
5
|
+
#include <sys/resource.h> /* for getrlimit() on linux */
|
|
33
6
|
#endif
|
|
34
|
-
#include <
|
|
7
|
+
#include <math.h>
|
|
35
8
|
#include <stdio.h>
|
|
9
|
+
#include <stdlib.h>
|
|
36
10
|
#include <string.h>
|
|
37
|
-
#include <math.h>
|
|
38
11
|
#include <sys/types.h>
|
|
39
12
|
#include <unistd.h>
|
|
40
13
|
|
|
41
14
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
|
42
|
-
#define OJ_INFINITY (1.0/0.0)
|
|
15
|
+
#define OJ_INFINITY (1.0 / 0.0)
|
|
43
16
|
|
|
44
|
-
#include "oj.h"
|
|
45
17
|
#include "encode.h"
|
|
18
|
+
#include "oj.h"
|
|
46
19
|
|
|
47
|
-
typedef struct
|
|
48
|
-
char
|
|
49
|
-
char
|
|
50
|
-
void
|
|
51
|
-
VALUE
|
|
52
|
-
int
|
|
53
|
-
int
|
|
54
|
-
int
|
|
55
|
-
int
|
|
56
|
-
int
|
|
57
|
-
int
|
|
58
|
-
} *ParseInfo;
|
|
59
|
-
|
|
60
|
-
static void
|
|
61
|
-
static void
|
|
62
|
-
static void
|
|
63
|
-
static void
|
|
64
|
-
static void
|
|
65
|
-
static void
|
|
66
|
-
static void
|
|
67
|
-
static void
|
|
68
|
-
static void
|
|
69
|
-
static char*
|
|
70
|
-
static void
|
|
20
|
+
typedef struct _parseInfo {
|
|
21
|
+
char *str; /* buffer being read from */
|
|
22
|
+
char *s; /* current position in buffer */
|
|
23
|
+
void *stack_min;
|
|
24
|
+
VALUE handler;
|
|
25
|
+
int has_hash_start;
|
|
26
|
+
int has_hash_end;
|
|
27
|
+
int has_array_start;
|
|
28
|
+
int has_array_end;
|
|
29
|
+
int has_add_value;
|
|
30
|
+
int has_error;
|
|
31
|
+
} * ParseInfo;
|
|
32
|
+
|
|
33
|
+
static void read_next(ParseInfo pi, const char *key);
|
|
34
|
+
static void read_hash(ParseInfo pi, const char *key);
|
|
35
|
+
static void read_array(ParseInfo pi, const char *key);
|
|
36
|
+
static void read_str(ParseInfo pi, const char *key);
|
|
37
|
+
static void read_num(ParseInfo pi, const char *key);
|
|
38
|
+
static void read_true(ParseInfo pi, const char *key);
|
|
39
|
+
static void read_false(ParseInfo pi, const char *key);
|
|
40
|
+
static void read_nil(ParseInfo pi, const char *key);
|
|
41
|
+
static void next_non_white(ParseInfo pi);
|
|
42
|
+
static char *read_quoted_value(ParseInfo pi);
|
|
43
|
+
static void skip_comment(ParseInfo pi);
|
|
71
44
|
|
|
72
45
|
/* This JSON parser is a single pass, destructive, callback parser. It is a
|
|
73
46
|
* single pass parse since it only make one pass over the characters in the
|
|
@@ -77,131 +50,113 @@ static void skip_comment(ParseInfo pi);
|
|
|
77
50
|
* a SAX parser because it uses callback when document elements are
|
|
78
51
|
* encountered.
|
|
79
52
|
*
|
|
80
|
-
* Parsing is very tolerant. Lack of headers and even
|
|
53
|
+
* Parsing is very tolerant. Lack of headers and even misspelled element
|
|
81
54
|
* endings are passed over without raising an error. A best attempt is made in
|
|
82
55
|
* all cases to parse the string.
|
|
83
56
|
*/
|
|
84
57
|
|
|
85
|
-
inline static void
|
|
86
|
-
|
|
87
|
-
char
|
|
88
|
-
|
|
89
|
-
int
|
|
90
|
-
int col = 1;
|
|
58
|
+
inline static void call_error(const char *msg, ParseInfo pi, const char *file, int line) {
|
|
59
|
+
char buf[128];
|
|
60
|
+
const char *s = pi->s;
|
|
61
|
+
int jline = 1;
|
|
62
|
+
int col = 1;
|
|
91
63
|
|
|
92
64
|
for (; pi->str < s && '\n' != *s; s--) {
|
|
93
|
-
|
|
65
|
+
col++;
|
|
94
66
|
}
|
|
95
67
|
for (; pi->str < s; s--) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
68
|
+
if ('\n' == *s) {
|
|
69
|
+
jline++;
|
|
70
|
+
}
|
|
99
71
|
}
|
|
100
72
|
sprintf(buf, "%s at line %d, column %d [%s:%d]", msg, jline, col, file, line);
|
|
101
73
|
rb_funcall(pi->handler, oj_error_id, 3, rb_str_new2(buf), LONG2NUM(jline), LONG2NUM(col));
|
|
102
74
|
}
|
|
103
75
|
|
|
104
|
-
inline static void
|
|
105
|
-
next_non_white(ParseInfo pi) {
|
|
76
|
+
inline static void next_non_white(ParseInfo pi) {
|
|
106
77
|
for (; 1; pi->s++) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
break;
|
|
117
|
-
default:
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
78
|
+
switch (*pi->s) {
|
|
79
|
+
case ' ':
|
|
80
|
+
case '\t':
|
|
81
|
+
case '\f':
|
|
82
|
+
case '\n':
|
|
83
|
+
case '\r': break;
|
|
84
|
+
case '/': skip_comment(pi); break;
|
|
85
|
+
default: return;
|
|
86
|
+
}
|
|
120
87
|
}
|
|
121
88
|
}
|
|
122
89
|
|
|
123
|
-
inline static void
|
|
124
|
-
|
|
125
|
-
volatile VALUE k;
|
|
90
|
+
inline static void call_add_value(VALUE handler, VALUE value, const char *key) {
|
|
91
|
+
volatile VALUE k;
|
|
126
92
|
|
|
127
93
|
if (0 == key) {
|
|
128
|
-
|
|
94
|
+
k = Qnil;
|
|
129
95
|
} else {
|
|
130
|
-
|
|
131
|
-
|
|
96
|
+
k = rb_str_new2(key);
|
|
97
|
+
k = oj_encode(k);
|
|
132
98
|
}
|
|
133
99
|
rb_funcall(handler, oj_add_value_id, 2, value, k);
|
|
134
100
|
}
|
|
135
101
|
|
|
136
|
-
inline static void
|
|
137
|
-
|
|
138
|
-
volatile VALUE k;
|
|
102
|
+
inline static void call_no_value(VALUE handler, ID method, const char *key) {
|
|
103
|
+
volatile VALUE k;
|
|
139
104
|
|
|
140
105
|
if (0 == key) {
|
|
141
|
-
|
|
106
|
+
k = Qnil;
|
|
142
107
|
} else {
|
|
143
|
-
|
|
144
|
-
|
|
108
|
+
k = rb_str_new2(key);
|
|
109
|
+
k = oj_encode(k);
|
|
145
110
|
}
|
|
146
111
|
rb_funcall(handler, method, 1, k);
|
|
147
112
|
}
|
|
148
113
|
|
|
149
|
-
static void
|
|
150
|
-
skip_comment(ParseInfo pi) {
|
|
114
|
+
static void skip_comment(ParseInfo pi) {
|
|
151
115
|
pi->s++; /* skip first / */
|
|
152
116
|
if ('*' == *pi->s) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
117
|
+
pi->s++;
|
|
118
|
+
for (; '\0' != *pi->s; pi->s++) {
|
|
119
|
+
if ('*' == *pi->s && '/' == *(pi->s + 1)) {
|
|
120
|
+
pi->s++;
|
|
121
|
+
return;
|
|
122
|
+
} else if ('\0' == *pi->s) {
|
|
123
|
+
if (pi->has_error) {
|
|
124
|
+
call_error("comment not terminated", pi, __FILE__, __LINE__);
|
|
125
|
+
} else {
|
|
126
|
+
raise_error("comment not terminated", pi->str, pi->s);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
166
130
|
} else if ('/' == *pi->s) {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
}
|
|
131
|
+
for (; 1; pi->s++) {
|
|
132
|
+
switch (*pi->s) {
|
|
133
|
+
case '\n':
|
|
134
|
+
case '\r':
|
|
135
|
+
case '\f':
|
|
136
|
+
case '\0': return;
|
|
137
|
+
default: break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
178
140
|
} else {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
141
|
+
if (pi->has_error) {
|
|
142
|
+
call_error("invalid comment", pi, __FILE__, __LINE__);
|
|
143
|
+
} else {
|
|
144
|
+
raise_error("invalid comment", pi->str, pi->s);
|
|
145
|
+
}
|
|
184
146
|
}
|
|
185
147
|
}
|
|
186
148
|
|
|
187
|
-
static void
|
|
188
|
-
|
|
189
|
-
VALUE obj;
|
|
149
|
+
static void read_next(ParseInfo pi, const char *key) {
|
|
150
|
+
VALUE obj;
|
|
190
151
|
|
|
191
|
-
if ((void*)&obj < pi->stack_min) {
|
|
192
|
-
|
|
152
|
+
if ((void *)&obj < pi->stack_min) {
|
|
153
|
+
rb_raise(rb_eSysStackError, "JSON is too deeply nested");
|
|
193
154
|
}
|
|
194
|
-
next_non_white(pi);
|
|
155
|
+
next_non_white(pi); /* skip white space */
|
|
195
156
|
switch (*pi->s) {
|
|
196
|
-
case '{':
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
case '[':
|
|
200
|
-
read_array(pi, key);
|
|
201
|
-
break;
|
|
202
|
-
case '"':
|
|
203
|
-
read_str(pi, key);
|
|
204
|
-
break;
|
|
157
|
+
case '{': read_hash(pi, key); break;
|
|
158
|
+
case '[': read_array(pi, key); break;
|
|
159
|
+
case '"': read_str(pi, key); break;
|
|
205
160
|
case '+':
|
|
206
161
|
case '-':
|
|
207
162
|
case '0':
|
|
@@ -213,113 +168,98 @@ read_next(ParseInfo pi, const char *key) {
|
|
|
213
168
|
case '6':
|
|
214
169
|
case '7':
|
|
215
170
|
case '8':
|
|
216
|
-
case '9':
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
case '
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
read_true(pi, key);
|
|
224
|
-
break;
|
|
225
|
-
case 'f':
|
|
226
|
-
read_false(pi, key);
|
|
227
|
-
break;
|
|
228
|
-
case 'n':
|
|
229
|
-
read_nil(pi, key);
|
|
230
|
-
break;
|
|
231
|
-
case '\0':
|
|
232
|
-
return;
|
|
233
|
-
default:
|
|
234
|
-
return;
|
|
171
|
+
case '9': read_num(pi, key); break;
|
|
172
|
+
case 'I': read_num(pi, key); break;
|
|
173
|
+
case 't': read_true(pi, key); break;
|
|
174
|
+
case 'f': read_false(pi, key); break;
|
|
175
|
+
case 'n': read_nil(pi, key); break;
|
|
176
|
+
case '\0': return;
|
|
177
|
+
default: return;
|
|
235
178
|
}
|
|
236
179
|
}
|
|
237
180
|
|
|
238
|
-
static void
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
181
|
+
static void read_hash(ParseInfo pi, const char *key) {
|
|
182
|
+
const char *ks;
|
|
183
|
+
|
|
242
184
|
if (pi->has_hash_start) {
|
|
243
|
-
|
|
185
|
+
call_no_value(pi->handler, oj_hash_start_id, key);
|
|
244
186
|
}
|
|
245
187
|
pi->s++;
|
|
246
188
|
next_non_white(pi);
|
|
247
189
|
if ('}' == *pi->s) {
|
|
248
|
-
|
|
190
|
+
pi->s++;
|
|
249
191
|
} else {
|
|
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
|
-
|
|
192
|
+
while (1) {
|
|
193
|
+
next_non_white(pi);
|
|
194
|
+
ks = read_quoted_value(pi);
|
|
195
|
+
next_non_white(pi);
|
|
196
|
+
if (':' == *pi->s) {
|
|
197
|
+
pi->s++;
|
|
198
|
+
} else {
|
|
199
|
+
if (pi->has_error) {
|
|
200
|
+
call_error("invalid format, expected :", pi, __FILE__, __LINE__);
|
|
201
|
+
}
|
|
202
|
+
raise_error("invalid format, expected :", pi->str, pi->s);
|
|
203
|
+
}
|
|
204
|
+
read_next(pi, ks);
|
|
205
|
+
next_non_white(pi);
|
|
206
|
+
if ('}' == *pi->s) {
|
|
207
|
+
pi->s++;
|
|
208
|
+
break;
|
|
209
|
+
} else if (',' == *pi->s) {
|
|
210
|
+
pi->s++;
|
|
211
|
+
} else {
|
|
212
|
+
if (pi->has_error) {
|
|
213
|
+
call_error("invalid format, expected , or } while in an object", pi, __FILE__, __LINE__);
|
|
214
|
+
}
|
|
215
|
+
raise_error("invalid format, expected , or } while in an object", pi->str, pi->s);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
276
218
|
}
|
|
277
219
|
if (pi->has_hash_end) {
|
|
278
|
-
|
|
220
|
+
call_no_value(pi->handler, oj_hash_end_id, key);
|
|
279
221
|
}
|
|
280
222
|
}
|
|
281
223
|
|
|
282
|
-
static void
|
|
283
|
-
read_array(ParseInfo pi, const char *key) {
|
|
224
|
+
static void read_array(ParseInfo pi, const char *key) {
|
|
284
225
|
if (pi->has_array_start) {
|
|
285
|
-
|
|
226
|
+
call_no_value(pi->handler, oj_array_start_id, key);
|
|
286
227
|
}
|
|
287
228
|
pi->s++;
|
|
288
229
|
next_non_white(pi);
|
|
289
230
|
if (']' == *pi->s) {
|
|
290
|
-
|
|
231
|
+
pi->s++;
|
|
291
232
|
} else {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
233
|
+
while (1) {
|
|
234
|
+
read_next(pi, 0);
|
|
235
|
+
next_non_white(pi);
|
|
236
|
+
if (',' == *pi->s) {
|
|
237
|
+
pi->s++;
|
|
238
|
+
} else if (']' == *pi->s) {
|
|
239
|
+
pi->s++;
|
|
240
|
+
break;
|
|
241
|
+
} else {
|
|
242
|
+
if (pi->has_error) {
|
|
243
|
+
call_error("invalid format, expected , or ] while in an array", pi, __FILE__, __LINE__);
|
|
244
|
+
}
|
|
245
|
+
raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
307
248
|
}
|
|
308
249
|
if (pi->has_array_end) {
|
|
309
|
-
|
|
250
|
+
call_no_value(pi->handler, oj_array_end_id, key);
|
|
310
251
|
}
|
|
311
252
|
}
|
|
312
253
|
|
|
313
|
-
static void
|
|
314
|
-
|
|
315
|
-
char *text;
|
|
254
|
+
static void read_str(ParseInfo pi, const char *key) {
|
|
255
|
+
char *text;
|
|
316
256
|
|
|
317
257
|
text = read_quoted_value(pi);
|
|
318
258
|
if (pi->has_add_value) {
|
|
319
|
-
|
|
259
|
+
VALUE s = rb_str_new2(text);
|
|
320
260
|
|
|
321
|
-
|
|
322
|
-
|
|
261
|
+
s = oj_encode(s);
|
|
262
|
+
call_add_value(pi->handler, s, key);
|
|
323
263
|
}
|
|
324
264
|
}
|
|
325
265
|
|
|
@@ -329,230 +269,224 @@ read_str(ParseInfo pi, const char *key) {
|
|
|
329
269
|
#define NUM_MAX (FIXNUM_MAX >> 8)
|
|
330
270
|
#endif
|
|
331
271
|
|
|
332
|
-
static void
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
long
|
|
337
|
-
long
|
|
338
|
-
|
|
339
|
-
int
|
|
340
|
-
int
|
|
341
|
-
int big = 0;
|
|
272
|
+
static void read_num(ParseInfo pi, const char *key) {
|
|
273
|
+
char *start = pi->s;
|
|
274
|
+
int64_t n = 0;
|
|
275
|
+
long a = 0;
|
|
276
|
+
long div = 1;
|
|
277
|
+
long e = 0;
|
|
278
|
+
int neg = 0;
|
|
279
|
+
int eneg = 0;
|
|
280
|
+
int big = 0;
|
|
342
281
|
|
|
343
282
|
if ('-' == *pi->s) {
|
|
344
|
-
|
|
345
|
-
|
|
283
|
+
pi->s++;
|
|
284
|
+
neg = 1;
|
|
346
285
|
} else if ('+' == *pi->s) {
|
|
347
|
-
|
|
286
|
+
pi->s++;
|
|
348
287
|
}
|
|
349
288
|
if ('I' == *pi->s) {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
289
|
+
if (0 != strncmp("Infinity", pi->s, 8)) {
|
|
290
|
+
if (pi->has_error) {
|
|
291
|
+
call_error("number or other value", pi, __FILE__, __LINE__);
|
|
292
|
+
}
|
|
293
|
+
raise_error("number or other value", pi->str, pi->s);
|
|
294
|
+
}
|
|
295
|
+
pi->s += 8;
|
|
296
|
+
if (neg) {
|
|
297
|
+
if (pi->has_add_value) {
|
|
298
|
+
call_add_value(pi->handler, rb_float_new(-OJ_INFINITY), key);
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
if (pi->has_add_value) {
|
|
302
|
+
call_add_value(pi->handler, rb_float_new(OJ_INFINITY), key);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return;
|
|
367
306
|
}
|
|
368
307
|
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
308
|
+
if (big) {
|
|
309
|
+
big++;
|
|
310
|
+
} else {
|
|
311
|
+
n = n * 10 + (*pi->s - '0');
|
|
312
|
+
if (NUM_MAX <= n) {
|
|
313
|
+
big = 1;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
377
316
|
}
|
|
378
317
|
if ('.' == *pi->s) {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
318
|
+
pi->s++;
|
|
319
|
+
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
|
320
|
+
a = a * 10 + (*pi->s - '0');
|
|
321
|
+
div *= 10;
|
|
322
|
+
if (NUM_MAX <= div) {
|
|
323
|
+
big = 1;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
387
326
|
}
|
|
388
327
|
if ('e' == *pi->s || 'E' == *pi->s) {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
328
|
+
pi->s++;
|
|
329
|
+
if ('-' == *pi->s) {
|
|
330
|
+
pi->s++;
|
|
331
|
+
eneg = 1;
|
|
332
|
+
} else if ('+' == *pi->s) {
|
|
333
|
+
pi->s++;
|
|
334
|
+
}
|
|
335
|
+
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
|
336
|
+
e = e * 10 + (*pi->s - '0');
|
|
337
|
+
if (NUM_MAX <= e) {
|
|
338
|
+
big = 1;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
402
341
|
}
|
|
403
342
|
if (0 == e && 0 == a && 1 == div) {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
343
|
+
if (big) {
|
|
344
|
+
char c = *pi->s;
|
|
345
|
+
|
|
346
|
+
*pi->s = '\0';
|
|
347
|
+
if (pi->has_add_value) {
|
|
348
|
+
call_add_value(pi->handler, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)), key);
|
|
349
|
+
}
|
|
350
|
+
*pi->s = c;
|
|
351
|
+
} else {
|
|
352
|
+
if (neg) {
|
|
353
|
+
n = -n;
|
|
354
|
+
}
|
|
355
|
+
if (pi->has_add_value) {
|
|
356
|
+
call_add_value(pi->handler, LONG2NUM(n), key);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return;
|
|
421
360
|
} else { /* decimal */
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
361
|
+
if (big) {
|
|
362
|
+
char c = *pi->s;
|
|
363
|
+
|
|
364
|
+
*pi->s = '\0';
|
|
365
|
+
if (pi->has_add_value) {
|
|
366
|
+
call_add_value(pi->handler, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)), key);
|
|
367
|
+
}
|
|
368
|
+
*pi->s = c;
|
|
369
|
+
} else {
|
|
370
|
+
double d = (double)n + (double)a / (double)div;
|
|
371
|
+
|
|
372
|
+
if (neg) {
|
|
373
|
+
d = -d;
|
|
374
|
+
}
|
|
375
|
+
if (1 < big) {
|
|
376
|
+
e += big - 1;
|
|
377
|
+
}
|
|
378
|
+
if (0 != e) {
|
|
379
|
+
if (eneg) {
|
|
380
|
+
e = -e;
|
|
381
|
+
}
|
|
382
|
+
d *= pow(10.0, e);
|
|
383
|
+
}
|
|
384
|
+
if (pi->has_add_value) {
|
|
385
|
+
call_add_value(pi->handler, rb_float_new(d), key);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
449
388
|
}
|
|
450
389
|
}
|
|
451
390
|
|
|
452
|
-
static void
|
|
453
|
-
read_true(ParseInfo pi, const char *key) {
|
|
391
|
+
static void read_true(ParseInfo pi, const char *key) {
|
|
454
392
|
pi->s++;
|
|
455
393
|
if ('r' != *pi->s || 'u' != *(pi->s + 1) || 'e' != *(pi->s + 2)) {
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
394
|
+
if (pi->has_error) {
|
|
395
|
+
call_error("invalid format, expected 'true'", pi, __FILE__, __LINE__);
|
|
396
|
+
}
|
|
397
|
+
raise_error("invalid format, expected 'true'", pi->str, pi->s);
|
|
460
398
|
}
|
|
461
399
|
pi->s += 3;
|
|
462
400
|
if (pi->has_add_value) {
|
|
463
|
-
|
|
401
|
+
call_add_value(pi->handler, Qtrue, key);
|
|
464
402
|
}
|
|
465
403
|
}
|
|
466
404
|
|
|
467
|
-
static void
|
|
468
|
-
read_false(ParseInfo pi, const char *key) {
|
|
405
|
+
static void read_false(ParseInfo pi, const char *key) {
|
|
469
406
|
pi->s++;
|
|
470
407
|
if ('a' != *pi->s || 'l' != *(pi->s + 1) || 's' != *(pi->s + 2) || 'e' != *(pi->s + 3)) {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
408
|
+
if (pi->has_error) {
|
|
409
|
+
call_error("invalid format, expected 'false'", pi, __FILE__, __LINE__);
|
|
410
|
+
}
|
|
411
|
+
raise_error("invalid format, expected 'false'", pi->str, pi->s);
|
|
475
412
|
}
|
|
476
413
|
pi->s += 4;
|
|
477
414
|
if (pi->has_add_value) {
|
|
478
|
-
|
|
415
|
+
call_add_value(pi->handler, Qfalse, key);
|
|
479
416
|
}
|
|
480
417
|
}
|
|
481
418
|
|
|
482
|
-
static void
|
|
483
|
-
read_nil(ParseInfo pi, const char *key) {
|
|
419
|
+
static void read_nil(ParseInfo pi, const char *key) {
|
|
484
420
|
pi->s++;
|
|
485
421
|
if ('u' != *pi->s || 'l' != *(pi->s + 1) || 'l' != *(pi->s + 2)) {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
422
|
+
if (pi->has_error) {
|
|
423
|
+
call_error("invalid format, expected 'null'", pi, __FILE__, __LINE__);
|
|
424
|
+
}
|
|
425
|
+
raise_error("invalid format, expected 'null'", pi->str, pi->s);
|
|
490
426
|
}
|
|
491
427
|
pi->s += 3;
|
|
492
428
|
if (pi->has_add_value) {
|
|
493
|
-
|
|
429
|
+
call_add_value(pi->handler, Qnil, key);
|
|
494
430
|
}
|
|
495
431
|
}
|
|
496
432
|
|
|
497
|
-
static uint32_t
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
int i;
|
|
433
|
+
static uint32_t read_hex(ParseInfo pi, char *h) {
|
|
434
|
+
uint32_t b = 0;
|
|
435
|
+
int i;
|
|
501
436
|
|
|
502
437
|
/* TBD this can be made faster with a table */
|
|
503
438
|
for (i = 0; i < 4; i++, h++) {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
439
|
+
b = b << 4;
|
|
440
|
+
if ('0' <= *h && *h <= '9') {
|
|
441
|
+
b += *h - '0';
|
|
442
|
+
} else if ('A' <= *h && *h <= 'F') {
|
|
443
|
+
b += *h - 'A' + 10;
|
|
444
|
+
} else if ('a' <= *h && *h <= 'f') {
|
|
445
|
+
b += *h - 'a' + 10;
|
|
446
|
+
} else {
|
|
447
|
+
pi->s = h;
|
|
448
|
+
if (pi->has_error) {
|
|
449
|
+
call_error("invalid hex character", pi, __FILE__, __LINE__);
|
|
450
|
+
}
|
|
451
|
+
raise_error("invalid hex character", pi->str, pi->s);
|
|
452
|
+
}
|
|
518
453
|
}
|
|
519
454
|
return b;
|
|
520
455
|
}
|
|
521
456
|
|
|
522
|
-
static char*
|
|
523
|
-
unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
|
|
457
|
+
static char *unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
|
|
524
458
|
if (0x0000007F >= code) {
|
|
525
|
-
|
|
459
|
+
*t = (char)code;
|
|
526
460
|
} else if (0x000007FF >= code) {
|
|
527
|
-
|
|
528
|
-
|
|
461
|
+
*t++ = 0xC0 | (code >> 6);
|
|
462
|
+
*t = 0x80 | (0x3F & code);
|
|
529
463
|
} else if (0x0000FFFF >= code) {
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
464
|
+
*t++ = 0xE0 | (code >> 12);
|
|
465
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
|
466
|
+
*t = 0x80 | (0x3F & code);
|
|
533
467
|
} else if (0x001FFFFF >= code) {
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
468
|
+
*t++ = 0xF0 | (code >> 18);
|
|
469
|
+
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
|
470
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
|
471
|
+
*t = 0x80 | (0x3F & code);
|
|
538
472
|
} else if (0x03FFFFFF >= code) {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
473
|
+
*t++ = 0xF8 | (code >> 24);
|
|
474
|
+
*t++ = 0x80 | ((code >> 18) & 0x3F);
|
|
475
|
+
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
|
476
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
|
477
|
+
*t = 0x80 | (0x3F & code);
|
|
544
478
|
} else if (0x7FFFFFFF >= code) {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
479
|
+
*t++ = 0xFC | (code >> 30);
|
|
480
|
+
*t++ = 0x80 | ((code >> 24) & 0x3F);
|
|
481
|
+
*t++ = 0x80 | ((code >> 18) & 0x3F);
|
|
482
|
+
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
|
483
|
+
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
|
484
|
+
*t = 0x80 | (0x3F & code);
|
|
551
485
|
} else {
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
486
|
+
if (pi->has_error) {
|
|
487
|
+
call_error("invalid Unicode", pi, __FILE__, __LINE__);
|
|
488
|
+
}
|
|
489
|
+
raise_error("invalid Unicode", pi->str, pi->s);
|
|
556
490
|
}
|
|
557
491
|
return t;
|
|
558
492
|
}
|
|
@@ -560,119 +494,117 @@ unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
|
|
|
560
494
|
/* Assume the value starts immediately and goes until the quote character is
|
|
561
495
|
* reached again. Do not read the character after the terminating quote.
|
|
562
496
|
*/
|
|
563
|
-
static char*
|
|
564
|
-
|
|
565
|
-
char
|
|
566
|
-
char
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
h++; /* skip quote character */
|
|
497
|
+
static char *read_quoted_value(ParseInfo pi) {
|
|
498
|
+
char *value = 0;
|
|
499
|
+
char *h = pi->s; /* head */
|
|
500
|
+
char *t = h; /* tail */
|
|
501
|
+
uint32_t code;
|
|
502
|
+
|
|
503
|
+
h++; /* skip quote character */
|
|
571
504
|
t++;
|
|
572
505
|
value = h;
|
|
573
506
|
for (; '"' != *h; h++, t++) {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
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
|
-
*t
|
|
507
|
+
if ('\0' == *h) {
|
|
508
|
+
pi->s = h;
|
|
509
|
+
raise_error("quoted string not terminated", pi->str, pi->s);
|
|
510
|
+
} else if ('\\' == *h) {
|
|
511
|
+
h++;
|
|
512
|
+
switch (*h) {
|
|
513
|
+
case 'n': *t = '\n'; break;
|
|
514
|
+
case 'r': *t = '\r'; break;
|
|
515
|
+
case 't': *t = '\t'; break;
|
|
516
|
+
case 'f': *t = '\f'; break;
|
|
517
|
+
case 'b': *t = '\b'; break;
|
|
518
|
+
case '"': *t = '"'; break;
|
|
519
|
+
case '/': *t = '/'; break;
|
|
520
|
+
case '\\': *t = '\\'; break;
|
|
521
|
+
case 'u':
|
|
522
|
+
h++;
|
|
523
|
+
code = read_hex(pi, h);
|
|
524
|
+
h += 3;
|
|
525
|
+
if (0x0000D800 <= code && code <= 0x0000DFFF) {
|
|
526
|
+
uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
|
|
527
|
+
uint32_t c2;
|
|
528
|
+
|
|
529
|
+
h++;
|
|
530
|
+
if ('\\' != *h || 'u' != *(h + 1)) {
|
|
531
|
+
pi->s = h;
|
|
532
|
+
if (pi->has_error) {
|
|
533
|
+
call_error("invalid escaped character", pi, __FILE__, __LINE__);
|
|
534
|
+
}
|
|
535
|
+
raise_error("invalid escaped character", pi->str, pi->s);
|
|
536
|
+
}
|
|
537
|
+
h += 2;
|
|
538
|
+
c2 = read_hex(pi, h);
|
|
539
|
+
h += 3;
|
|
540
|
+
c2 = (c2 - 0x0000DC00) & 0x000003FF;
|
|
541
|
+
code = ((c1 << 10) | c2) + 0x00010000;
|
|
542
|
+
}
|
|
543
|
+
t = unicode_to_chars(pi, t, code);
|
|
544
|
+
break;
|
|
545
|
+
default:
|
|
546
|
+
pi->s = h;
|
|
547
|
+
if (pi->has_error) {
|
|
548
|
+
call_error("invalid escaped character", pi, __FILE__, __LINE__);
|
|
549
|
+
}
|
|
550
|
+
raise_error("invalid escaped character", pi->str, pi->s);
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
} else if (t != h) {
|
|
554
|
+
*t = *h;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
*t = '\0'; /* terminate value */
|
|
625
558
|
pi->s = h + 1;
|
|
626
559
|
|
|
627
560
|
return value;
|
|
628
561
|
}
|
|
629
562
|
|
|
630
|
-
static void
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
struct _ParseInfo pi;
|
|
563
|
+
static void saj_parse(VALUE handler, char *json) {
|
|
564
|
+
volatile VALUE obj = Qnil;
|
|
565
|
+
struct _parseInfo pi;
|
|
634
566
|
|
|
635
567
|
if (0 == json) {
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
568
|
+
if (pi.has_error) {
|
|
569
|
+
call_error("Invalid arg, xml string can not be null", &pi, __FILE__, __LINE__);
|
|
570
|
+
}
|
|
571
|
+
raise_error("Invalid arg, xml string can not be null", json, 0);
|
|
640
572
|
}
|
|
641
573
|
/* skip UTF-8 BOM if present */
|
|
642
574
|
if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
|
|
643
|
-
|
|
575
|
+
json += 3;
|
|
644
576
|
}
|
|
645
577
|
/* initialize parse info */
|
|
646
578
|
pi.str = json;
|
|
647
|
-
pi.s
|
|
579
|
+
pi.s = json;
|
|
648
580
|
#if IS_WINDOWS
|
|
649
|
-
pi.stack_min = (void*)((char*)&obj - (
|
|
581
|
+
pi.stack_min = (void *)((char *)&obj - (512L * 1024L)); /* assume a 1M stack and give half to ruby */
|
|
650
582
|
#else
|
|
651
583
|
{
|
|
652
|
-
|
|
584
|
+
struct rlimit lim;
|
|
653
585
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
586
|
+
if (0 == getrlimit(RLIMIT_STACK, &lim) && RLIM_INFINITY != lim.rlim_cur) {
|
|
587
|
+
pi.stack_min = (void *)((char *)&obj - (lim.rlim_cur / 4 * 3)); /* let 3/4ths of the stack be used only */
|
|
588
|
+
} else {
|
|
589
|
+
pi.stack_min = 0; /* indicates not to check stack limit */
|
|
590
|
+
}
|
|
659
591
|
}
|
|
660
592
|
#endif
|
|
661
|
-
pi.handler
|
|
662
|
-
pi.has_hash_start
|
|
663
|
-
pi.has_hash_end
|
|
593
|
+
pi.handler = handler;
|
|
594
|
+
pi.has_hash_start = rb_respond_to(handler, oj_hash_start_id);
|
|
595
|
+
pi.has_hash_end = rb_respond_to(handler, oj_hash_end_id);
|
|
664
596
|
pi.has_array_start = rb_respond_to(handler, oj_array_start_id);
|
|
665
|
-
pi.has_array_end
|
|
666
|
-
pi.has_add_value
|
|
667
|
-
pi.has_error
|
|
597
|
+
pi.has_array_end = rb_respond_to(handler, oj_array_end_id);
|
|
598
|
+
pi.has_add_value = rb_respond_to(handler, oj_add_value_id);
|
|
599
|
+
pi.has_error = rb_respond_to(handler, oj_error_id);
|
|
668
600
|
read_next(&pi, 0);
|
|
669
601
|
next_non_white(&pi);
|
|
670
602
|
if ('\0' != *pi.s) {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
603
|
+
if (pi.has_error) {
|
|
604
|
+
call_error("invalid format, extra characters", &pi, __FILE__, __LINE__);
|
|
605
|
+
} else {
|
|
606
|
+
raise_error("invalid format, extra characters", pi.str, pi.s);
|
|
607
|
+
}
|
|
676
608
|
}
|
|
677
609
|
}
|
|
678
610
|
|
|
@@ -682,51 +614,55 @@ saj_parse(VALUE handler, char *json) {
|
|
|
682
614
|
* if the JSON is malformed.
|
|
683
615
|
* @param [Oj::Saj] handler Saj (responds to Oj::Saj methods) like handler
|
|
684
616
|
* @param [IO|String] io IO Object to read from
|
|
617
|
+
* @deprecated The sc_parse() method along with the ScHandler is the preferred
|
|
618
|
+
* callback parser. It is slightly faster and handles streams while the
|
|
619
|
+
* saj_parse() method requires a complete read before parsing.
|
|
620
|
+
* @see sc_parse
|
|
685
621
|
*/
|
|
686
622
|
VALUE
|
|
687
623
|
oj_saj_parse(int argc, VALUE *argv, VALUE self) {
|
|
688
|
-
char
|
|
689
|
-
size_t
|
|
690
|
-
VALUE
|
|
624
|
+
char *json = 0;
|
|
625
|
+
size_t len = 0;
|
|
626
|
+
VALUE input = argv[1];
|
|
691
627
|
|
|
692
628
|
if (argc < 2) {
|
|
693
|
-
|
|
629
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n");
|
|
694
630
|
}
|
|
695
631
|
if (rb_type(input) == T_STRING) {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
632
|
+
// the json string gets modified so make a copy of it
|
|
633
|
+
len = RSTRING_LEN(input) + 1;
|
|
634
|
+
json = ALLOC_N(char, len);
|
|
635
|
+
strcpy(json, StringValuePtr(input));
|
|
700
636
|
} else {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
637
|
+
VALUE clas = rb_obj_class(input);
|
|
638
|
+
volatile VALUE s;
|
|
639
|
+
|
|
640
|
+
if (oj_stringio_class == clas) {
|
|
641
|
+
s = rb_funcall2(input, oj_string_id, 0, 0);
|
|
642
|
+
len = RSTRING_LEN(s) + 1;
|
|
643
|
+
json = ALLOC_N(char, len);
|
|
644
|
+
strcpy(json, rb_string_value_cstr((VALUE *)&s));
|
|
709
645
|
#if !IS_WINDOWS
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
646
|
+
} else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
|
|
647
|
+
int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
|
|
648
|
+
ssize_t cnt;
|
|
649
|
+
|
|
650
|
+
len = lseek(fd, 0, SEEK_END);
|
|
651
|
+
lseek(fd, 0, SEEK_SET);
|
|
652
|
+
json = ALLOC_N(char, len + 1);
|
|
653
|
+
if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) {
|
|
654
|
+
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
|
655
|
+
}
|
|
656
|
+
json[len] = '\0';
|
|
721
657
|
#endif
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
658
|
+
} else if (rb_respond_to(input, oj_read_id)) {
|
|
659
|
+
s = rb_funcall2(input, oj_read_id, 0, 0);
|
|
660
|
+
len = RSTRING_LEN(s) + 1;
|
|
661
|
+
json = ALLOC_N(char, len);
|
|
662
|
+
strcpy(json, rb_string_value_cstr((VALUE *)&s));
|
|
663
|
+
} else {
|
|
664
|
+
rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
|
|
665
|
+
}
|
|
730
666
|
}
|
|
731
667
|
saj_parse(*argv, json);
|
|
732
668
|
xfree(json);
|