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