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