oj 2.0.0 → 3.0.0
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 +7 -0
- data/LICENSE +17 -23
- data/README.md +74 -425
- data/ext/oj/buf.h +103 -0
- data/ext/oj/cache8.c +4 -0
- data/ext/oj/circarray.c +68 -0
- data/ext/oj/circarray.h +23 -0
- data/ext/oj/code.c +227 -0
- data/ext/oj/code.h +40 -0
- data/ext/oj/compat.c +243 -0
- data/ext/oj/custom.c +1097 -0
- data/ext/oj/dump.c +766 -1534
- data/ext/oj/dump.h +92 -0
- data/ext/oj/dump_compat.c +937 -0
- data/ext/oj/dump_leaf.c +254 -0
- data/ext/oj/dump_object.c +810 -0
- data/ext/oj/dump_rails.c +329 -0
- data/ext/oj/dump_strict.c +416 -0
- data/ext/oj/encode.h +51 -0
- data/ext/oj/err.c +57 -0
- data/ext/oj/err.h +70 -0
- data/ext/oj/extconf.rb +17 -7
- data/ext/oj/fast.c +213 -180
- data/ext/oj/hash.c +163 -0
- data/ext/oj/hash.h +46 -0
- data/ext/oj/hash_test.c +512 -0
- data/ext/oj/mimic_json.c +817 -0
- data/ext/oj/mimic_rails.c +806 -0
- data/ext/oj/mimic_rails.h +17 -0
- data/ext/oj/object.c +752 -0
- data/ext/oj/odd.c +230 -0
- data/ext/oj/odd.h +44 -0
- data/ext/oj/oj.c +1288 -929
- data/ext/oj/oj.h +240 -69
- data/ext/oj/parse.c +1014 -0
- data/ext/oj/parse.h +92 -0
- data/ext/oj/reader.c +223 -0
- data/ext/oj/reader.h +151 -0
- data/ext/oj/resolve.c +127 -0
- data/ext/oj/{cache.h → resolve.h} +6 -13
- data/ext/oj/rxclass.c +133 -0
- data/ext/oj/rxclass.h +27 -0
- data/ext/oj/saj.c +77 -175
- data/ext/oj/scp.c +224 -0
- data/ext/oj/sparse.c +911 -0
- data/ext/oj/stream_writer.c +301 -0
- data/ext/oj/strict.c +162 -0
- data/ext/oj/string_writer.c +480 -0
- data/ext/oj/val_stack.c +98 -0
- data/ext/oj/val_stack.h +188 -0
- data/lib/oj/active_support_helper.rb +41 -0
- data/lib/oj/bag.rb +6 -10
- data/lib/oj/easy_hash.rb +52 -0
- data/lib/oj/json.rb +172 -0
- data/lib/oj/mimic.rb +260 -5
- data/lib/oj/saj.rb +13 -10
- data/lib/oj/schandler.rb +142 -0
- data/lib/oj/state.rb +131 -0
- data/lib/oj/version.rb +1 -1
- data/lib/oj.rb +11 -23
- 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 +79 -0
- data/pages/Modes.md +140 -0
- data/pages/Options.md +250 -0
- data/pages/Rails.md +60 -0
- data/pages/Security.md +20 -0
- data/test/_test_active.rb +76 -0
- data/test/_test_active_mimic.rb +96 -0
- data/test/_test_mimic_rails.rb +126 -0
- data/test/activesupport4/decoding_test.rb +105 -0
- data/test/activesupport4/encoding_test.rb +531 -0
- data/test/activesupport4/test_helper.rb +41 -0
- data/test/activesupport5/decoding_test.rb +125 -0
- data/test/activesupport5/encoding_test.rb +483 -0
- data/test/activesupport5/encoding_test_cases.rb +90 -0
- data/test/activesupport5/test_helper.rb +50 -0
- data/test/activesupport5/time_zone_test_helpers.rb +24 -0
- data/test/helper.rb +27 -0
- data/test/isolated/shared.rb +310 -0
- data/test/isolated/test_mimic_after.rb +13 -0
- data/test/isolated/test_mimic_alone.rb +12 -0
- data/test/isolated/test_mimic_as_json.rb +45 -0
- data/test/isolated/test_mimic_before.rb +13 -0
- data/test/isolated/test_mimic_define.rb +28 -0
- data/test/isolated/test_mimic_rails_after.rb +22 -0
- data/test/isolated/test_mimic_rails_before.rb +21 -0
- data/test/isolated/test_mimic_redefine.rb +15 -0
- data/test/json_gem/json_addition_test.rb +216 -0
- data/test/json_gem/json_common_interface_test.rb +143 -0
- data/test/json_gem/json_encoding_test.rb +109 -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 +383 -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 +18 -0
- data/test/perf_compat.rb +130 -0
- data/test/perf_fast.rb +9 -9
- data/test/perf_file.rb +64 -0
- data/test/{perf_obj.rb → perf_object.rb} +24 -10
- data/test/perf_scp.rb +151 -0
- data/test/perf_strict.rb +32 -113
- data/test/sample.rb +2 -3
- data/test/test_compat.rb +474 -0
- data/test/test_custom.rb +355 -0
- data/test/test_debian.rb +53 -0
- data/test/test_fast.rb +66 -16
- data/test/test_file.rb +237 -0
- data/test/test_gc.rb +49 -0
- data/test/test_hash.rb +29 -0
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +1010 -0
- data/test/test_saj.rb +16 -16
- data/test/test_scp.rb +417 -0
- data/test/test_strict.rb +410 -0
- data/test/test_various.rb +815 -0
- data/test/test_writer.rb +308 -0
- data/test/tests.rb +9 -902
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- metadata +253 -38
- data/ext/oj/cache.c +0 -148
- data/ext/oj/foo.rb +0 -6
- data/ext/oj/load.c +0 -1049
- data/test/a.rb +0 -38
- data/test/perf1.rb +0 -64
- data/test/perf2.rb +0 -76
- data/test/perf_obj_old.rb +0 -213
- data/test/test_mimic.rb +0 -208
data/ext/oj/load.c
DELETED
|
@@ -1,1049 +0,0 @@
|
|
|
1
|
-
/* load.c
|
|
2
|
-
* Copyright (c) 2012, Peter Ohler
|
|
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
|
-
*/
|
|
30
|
-
|
|
31
|
-
#if SAFE_CACHE
|
|
32
|
-
#include <pthread.h>
|
|
33
|
-
#endif
|
|
34
|
-
#if !IS_WINDOWS
|
|
35
|
-
#include <sys/resource.h> // for getrlimit() on linux
|
|
36
|
-
#endif
|
|
37
|
-
#include <stdlib.h>
|
|
38
|
-
#include <stdio.h>
|
|
39
|
-
#include <string.h>
|
|
40
|
-
#include <math.h>
|
|
41
|
-
|
|
42
|
-
//Workaround:
|
|
43
|
-
#ifndef INFINITY
|
|
44
|
-
#define INFINITY (1.0/0.0)
|
|
45
|
-
#endif
|
|
46
|
-
|
|
47
|
-
#include "oj.h"
|
|
48
|
-
|
|
49
|
-
enum {
|
|
50
|
-
TIME_HINT = 0x0100,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
typedef struct _CircArray {
|
|
54
|
-
VALUE obj_array[1024];
|
|
55
|
-
VALUE *objs;
|
|
56
|
-
unsigned long size; // allocated size or initial array size
|
|
57
|
-
unsigned long cnt;
|
|
58
|
-
} *CircArray;
|
|
59
|
-
|
|
60
|
-
typedef struct _ParseInfo {
|
|
61
|
-
char *str; /* buffer being read from */
|
|
62
|
-
char *s; /* current position in buffer */
|
|
63
|
-
CircArray circ_array;
|
|
64
|
-
Options options;
|
|
65
|
-
void *stack_min;
|
|
66
|
-
} *ParseInfo;
|
|
67
|
-
|
|
68
|
-
static CircArray circ_array_new(void);
|
|
69
|
-
static void circ_array_free(CircArray ca);
|
|
70
|
-
static void circ_array_set(CircArray ca, VALUE obj, unsigned long id);
|
|
71
|
-
static VALUE circ_array_get(CircArray ca, unsigned long id);
|
|
72
|
-
|
|
73
|
-
static VALUE classname2class(const char *name, ParseInfo pi);
|
|
74
|
-
static VALUE read_next(ParseInfo pi, int hint);
|
|
75
|
-
static VALUE read_obj(ParseInfo pi);
|
|
76
|
-
static VALUE read_array(ParseInfo pi, int hint);
|
|
77
|
-
static VALUE read_str(ParseInfo pi, int hint);
|
|
78
|
-
static VALUE read_num(ParseInfo pi);
|
|
79
|
-
static VALUE read_time(ParseInfo pi);
|
|
80
|
-
static VALUE read_true(ParseInfo pi);
|
|
81
|
-
static VALUE read_false(ParseInfo pi);
|
|
82
|
-
static VALUE read_nil(ParseInfo pi);
|
|
83
|
-
static void next_non_white(ParseInfo pi);
|
|
84
|
-
static char* read_quoted_value(ParseInfo pi);
|
|
85
|
-
static void skip_comment(ParseInfo pi);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
/* This XML parser is a single pass, destructive, callback parser. It is a
|
|
89
|
-
* single pass parse since it only make one pass over the characters in the
|
|
90
|
-
* XML document string. It is destructive because it re-uses the content of
|
|
91
|
-
* the string for values in the callback and places \0 characters at various
|
|
92
|
-
* places to mark the end of tokens and strings. It is a callback parser like
|
|
93
|
-
* a SAX parser because it uses callback when document elements are
|
|
94
|
-
* encountered.
|
|
95
|
-
*
|
|
96
|
-
* Parsing is very tolerant. Lack of headers and even mispelled element
|
|
97
|
-
* endings are passed over without raising an error. A best attempt is made in
|
|
98
|
-
* all cases to parse the string.
|
|
99
|
-
*/
|
|
100
|
-
|
|
101
|
-
inline static void
|
|
102
|
-
next_non_white(ParseInfo pi) {
|
|
103
|
-
for (; 1; pi->s++) {
|
|
104
|
-
switch(*pi->s) {
|
|
105
|
-
case ' ':
|
|
106
|
-
case '\t':
|
|
107
|
-
case '\f':
|
|
108
|
-
case '\n':
|
|
109
|
-
case '\r':
|
|
110
|
-
break;
|
|
111
|
-
case '/':
|
|
112
|
-
skip_comment(pi);
|
|
113
|
-
break;
|
|
114
|
-
default:
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
inline static void
|
|
121
|
-
next_white(ParseInfo pi) {
|
|
122
|
-
for (; 1; pi->s++) {
|
|
123
|
-
switch(*pi->s) {
|
|
124
|
-
case ' ':
|
|
125
|
-
case '\t':
|
|
126
|
-
case '\f':
|
|
127
|
-
case '\n':
|
|
128
|
-
case '\r':
|
|
129
|
-
case '\0':
|
|
130
|
-
return;
|
|
131
|
-
default:
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
inline static VALUE
|
|
138
|
-
resolve_classname(VALUE mod, const char *class_name, int auto_define) {
|
|
139
|
-
VALUE clas;
|
|
140
|
-
ID ci = rb_intern(class_name);
|
|
141
|
-
|
|
142
|
-
if (rb_const_defined_at(mod, ci) || !auto_define) {
|
|
143
|
-
clas = rb_const_get_at(mod, ci);
|
|
144
|
-
} else {
|
|
145
|
-
clas = rb_define_class_under(mod, class_name, oj_bag_class);
|
|
146
|
-
}
|
|
147
|
-
return clas;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
inline static VALUE
|
|
151
|
-
classname2obj(const char *name, ParseInfo pi) {
|
|
152
|
-
VALUE clas = classname2class(name, pi);
|
|
153
|
-
|
|
154
|
-
if (Qundef == clas) {
|
|
155
|
-
return Qnil;
|
|
156
|
-
} else {
|
|
157
|
-
return rb_obj_alloc(clas);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
static VALUE
|
|
162
|
-
classname2class(const char *name, ParseInfo pi) {
|
|
163
|
-
VALUE clas;
|
|
164
|
-
VALUE *slot;
|
|
165
|
-
int auto_define = (Yes == pi->options->auto_define);
|
|
166
|
-
|
|
167
|
-
#if SAFE_CACHE
|
|
168
|
-
pthread_mutex_lock(&oj_cache_mutex);
|
|
169
|
-
#endif
|
|
170
|
-
if (Qundef == (clas = oj_cache_get(oj_class_cache, name, &slot))) {
|
|
171
|
-
char class_name[1024];
|
|
172
|
-
char *s;
|
|
173
|
-
const char *n = name;
|
|
174
|
-
|
|
175
|
-
clas = rb_cObject;
|
|
176
|
-
for (s = class_name; '\0' != *n; n++) {
|
|
177
|
-
if (':' == *n) {
|
|
178
|
-
*s = '\0';
|
|
179
|
-
n++;
|
|
180
|
-
if (':' != *n) {
|
|
181
|
-
raise_error("Invalid classname, expected another ':'", pi->str, pi->s);
|
|
182
|
-
}
|
|
183
|
-
if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
|
|
184
|
-
return Qundef;
|
|
185
|
-
}
|
|
186
|
-
s = class_name;
|
|
187
|
-
} else {
|
|
188
|
-
*s++ = *n;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
*s = '\0';
|
|
192
|
-
if (Qundef != (clas = resolve_classname(clas, class_name, auto_define))) {
|
|
193
|
-
*slot = clas;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
#if SAFE_CACHE
|
|
197
|
-
pthread_mutex_unlock(&oj_cache_mutex);
|
|
198
|
-
#endif
|
|
199
|
-
return clas;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
#if HAS_RSTRUCT
|
|
203
|
-
inline static VALUE
|
|
204
|
-
structname2obj(const char *name) {
|
|
205
|
-
VALUE ost;
|
|
206
|
-
|
|
207
|
-
ost = rb_const_get(oj_struct_class, rb_intern(name));
|
|
208
|
-
// use encoding as the indicator for Ruby 1.8.7 or 1.9.x
|
|
209
|
-
#if HAS_ENCODING_SUPPORT
|
|
210
|
-
return rb_struct_alloc_noinit(ost);
|
|
211
|
-
#else
|
|
212
|
-
return rb_struct_new(ost);
|
|
213
|
-
#endif
|
|
214
|
-
}
|
|
215
|
-
#endif
|
|
216
|
-
|
|
217
|
-
inline static unsigned long
|
|
218
|
-
read_ulong(const char *s, ParseInfo pi) {
|
|
219
|
-
unsigned long n = 0;
|
|
220
|
-
|
|
221
|
-
for (; '\0' != *s; s++) {
|
|
222
|
-
if ('0' <= *s && *s <= '9') {
|
|
223
|
-
n = n * 10 + (*s - '0');
|
|
224
|
-
} else {
|
|
225
|
-
raise_error("Not a valid ID number", pi->str, pi->s);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
return n;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
static CircArray
|
|
232
|
-
circ_array_new() {
|
|
233
|
-
CircArray ca;
|
|
234
|
-
|
|
235
|
-
if (0 == (ca = ALLOC(struct _CircArray))) {
|
|
236
|
-
rb_raise(rb_eNoMemError, "not enough memory\n");
|
|
237
|
-
}
|
|
238
|
-
ca->objs = ca->obj_array;
|
|
239
|
-
ca->size = sizeof(ca->obj_array) / sizeof(VALUE);
|
|
240
|
-
ca->cnt = 0;
|
|
241
|
-
|
|
242
|
-
return ca;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
static void
|
|
246
|
-
circ_array_free(CircArray ca) {
|
|
247
|
-
if (ca->objs != ca->obj_array) {
|
|
248
|
-
xfree(ca->objs);
|
|
249
|
-
}
|
|
250
|
-
xfree(ca);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
static void
|
|
254
|
-
circ_array_set(CircArray ca, VALUE obj, unsigned long id) {
|
|
255
|
-
if (0 < id && 0 != ca) {
|
|
256
|
-
unsigned long i;
|
|
257
|
-
|
|
258
|
-
if (ca->size < id) {
|
|
259
|
-
unsigned long cnt = id + 512;
|
|
260
|
-
|
|
261
|
-
if (ca->objs == ca->obj_array) {
|
|
262
|
-
if (0 == (ca->objs = ALLOC_N(VALUE, cnt))) {
|
|
263
|
-
rb_raise(rb_eNoMemError, "not enough memory\n");
|
|
264
|
-
}
|
|
265
|
-
memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt);
|
|
266
|
-
} else {
|
|
267
|
-
REALLOC_N(ca->objs, VALUE, cnt);
|
|
268
|
-
}
|
|
269
|
-
ca->size = cnt;
|
|
270
|
-
}
|
|
271
|
-
id--;
|
|
272
|
-
for (i = ca->cnt; i < id; i++) {
|
|
273
|
-
ca->objs[i] = Qnil;
|
|
274
|
-
}
|
|
275
|
-
ca->objs[id] = obj;
|
|
276
|
-
if (ca->cnt <= id) {
|
|
277
|
-
ca->cnt = id + 1;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
static VALUE
|
|
283
|
-
circ_array_get(CircArray ca, unsigned long id) {
|
|
284
|
-
VALUE obj = Qnil;
|
|
285
|
-
|
|
286
|
-
if (id <= ca->cnt && 0 != ca) {
|
|
287
|
-
obj = ca->objs[id - 1];
|
|
288
|
-
}
|
|
289
|
-
return obj;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
static void
|
|
293
|
-
skip_comment(ParseInfo pi) {
|
|
294
|
-
pi->s++; // skip first /
|
|
295
|
-
if ('*' == *pi->s) {
|
|
296
|
-
pi->s++;
|
|
297
|
-
for (; '\0' != *pi->s; pi->s++) {
|
|
298
|
-
if ('*' == *pi->s && '/' == *(pi->s + 1)) {
|
|
299
|
-
pi->s++;
|
|
300
|
-
return;
|
|
301
|
-
} else if ('\0' == *pi->s) {
|
|
302
|
-
raise_error("comment not terminated", pi->str, pi->s);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
} else if ('/' == *pi->s) {
|
|
306
|
-
for (; 1; pi->s++) {
|
|
307
|
-
switch (*pi->s) {
|
|
308
|
-
case '\n':
|
|
309
|
-
case '\r':
|
|
310
|
-
case '\f':
|
|
311
|
-
case '\0':
|
|
312
|
-
return;
|
|
313
|
-
default:
|
|
314
|
-
break;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
} else {
|
|
318
|
-
raise_error("invalid comment", pi->str, pi->s);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
static VALUE
|
|
323
|
-
read_next(ParseInfo pi, int hint) {
|
|
324
|
-
VALUE obj;
|
|
325
|
-
|
|
326
|
-
if ((void*)&obj < pi->stack_min) {
|
|
327
|
-
rb_raise(rb_eSysStackError, "JSON is too deeply nested");
|
|
328
|
-
}
|
|
329
|
-
next_non_white(pi); // skip white space
|
|
330
|
-
switch (*pi->s) {
|
|
331
|
-
case '{':
|
|
332
|
-
obj = read_obj(pi);
|
|
333
|
-
break;
|
|
334
|
-
case '[':
|
|
335
|
-
obj = read_array(pi, hint);
|
|
336
|
-
break;
|
|
337
|
-
case '"':
|
|
338
|
-
obj = read_str(pi, hint);
|
|
339
|
-
break;
|
|
340
|
-
case '+':
|
|
341
|
-
case '-':
|
|
342
|
-
case '0':
|
|
343
|
-
case '1':
|
|
344
|
-
case '2':
|
|
345
|
-
case '3':
|
|
346
|
-
case '4':
|
|
347
|
-
case '5':
|
|
348
|
-
case '6':
|
|
349
|
-
case '7':
|
|
350
|
-
case '8':
|
|
351
|
-
case '9':
|
|
352
|
-
if (TIME_HINT == hint) {
|
|
353
|
-
obj = read_time(pi);
|
|
354
|
-
} else {
|
|
355
|
-
obj = read_num(pi);
|
|
356
|
-
}
|
|
357
|
-
break;
|
|
358
|
-
case 'I':
|
|
359
|
-
obj = read_num(pi);
|
|
360
|
-
break;
|
|
361
|
-
case 't':
|
|
362
|
-
obj = read_true(pi);
|
|
363
|
-
break;
|
|
364
|
-
case 'f':
|
|
365
|
-
obj = read_false(pi);
|
|
366
|
-
break;
|
|
367
|
-
case 'n':
|
|
368
|
-
obj = read_nil(pi);
|
|
369
|
-
break;
|
|
370
|
-
case '\0':
|
|
371
|
-
obj = Qundef;
|
|
372
|
-
break;
|
|
373
|
-
default:
|
|
374
|
-
obj = Qundef;
|
|
375
|
-
break;
|
|
376
|
-
}
|
|
377
|
-
return obj;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
static VALUE
|
|
381
|
-
read_obj(ParseInfo pi) {
|
|
382
|
-
VALUE obj = Qundef;
|
|
383
|
-
VALUE key = Qundef;
|
|
384
|
-
VALUE val = Qundef;
|
|
385
|
-
const char *ks;
|
|
386
|
-
int obj_type = T_NONE;
|
|
387
|
-
const char *json_class_name = 0;
|
|
388
|
-
Mode mode = pi->options->mode;
|
|
389
|
-
Odd odd = 0;
|
|
390
|
-
VALUE odd_args[MAX_ODD_ARGS];
|
|
391
|
-
VALUE *vp;
|
|
392
|
-
|
|
393
|
-
pi->s++;
|
|
394
|
-
next_non_white(pi);
|
|
395
|
-
if ('}' == *pi->s) {
|
|
396
|
-
pi->s++;
|
|
397
|
-
return rb_hash_new();
|
|
398
|
-
}
|
|
399
|
-
while (1) {
|
|
400
|
-
next_non_white(pi);
|
|
401
|
-
ks = 0;
|
|
402
|
-
key = Qundef;
|
|
403
|
-
val = Qundef;
|
|
404
|
-
if ('"' != *pi->s || Qundef == (key = read_str(pi, 0))) {
|
|
405
|
-
raise_error("unexpected character", pi->str, pi->s);
|
|
406
|
-
}
|
|
407
|
-
next_non_white(pi);
|
|
408
|
-
if (':' == *pi->s) {
|
|
409
|
-
pi->s++;
|
|
410
|
-
} else {
|
|
411
|
-
raise_error("invalid format, expected :", pi->str, pi->s);
|
|
412
|
-
}
|
|
413
|
-
if (T_STRING == rb_type(key)) {
|
|
414
|
-
ks = StringValuePtr(key);
|
|
415
|
-
} else {
|
|
416
|
-
ks = 0;
|
|
417
|
-
}
|
|
418
|
-
if (0 != ks && Qundef == obj && ObjectMode == mode) {
|
|
419
|
-
if ('^' == *ks && '\0' == ks[2]) { // special directions
|
|
420
|
-
switch (ks[1]) {
|
|
421
|
-
case 't': // Time
|
|
422
|
-
obj = read_next(pi, TIME_HINT); // raises if can not convert to Time
|
|
423
|
-
key = Qundef;
|
|
424
|
-
break;
|
|
425
|
-
case 'c': // Class
|
|
426
|
-
obj = read_next(pi, T_CLASS);
|
|
427
|
-
key = Qundef;
|
|
428
|
-
break;
|
|
429
|
-
case 's': // String
|
|
430
|
-
obj = read_next(pi, T_STRING);
|
|
431
|
-
key = Qundef;
|
|
432
|
-
break;
|
|
433
|
-
case 'm': // Symbol
|
|
434
|
-
obj = read_next(pi, T_SYMBOL);
|
|
435
|
-
key = Qundef;
|
|
436
|
-
break;
|
|
437
|
-
case 'o': // Object
|
|
438
|
-
obj = read_next(pi, T_OBJECT);
|
|
439
|
-
obj_type = T_OBJECT;
|
|
440
|
-
key = Qundef;
|
|
441
|
-
break;
|
|
442
|
-
case 'O': // Odd class
|
|
443
|
-
if (0 == (odd = oj_get_odd(read_next(pi, T_CLASS)))) {
|
|
444
|
-
raise_error("Not a valid build in class.", pi->str, pi->s);
|
|
445
|
-
}
|
|
446
|
-
obj = Qundef;
|
|
447
|
-
key = Qundef;
|
|
448
|
-
for (vp = odd_args + MAX_ODD_ARGS - 1; odd_args <=vp; vp--) {
|
|
449
|
-
*vp = Qnil;
|
|
450
|
-
}
|
|
451
|
-
break;
|
|
452
|
-
case 'u': // Struct
|
|
453
|
-
obj = read_next(pi, T_STRUCT);
|
|
454
|
-
obj_type = T_STRUCT;
|
|
455
|
-
key = Qundef;
|
|
456
|
-
break;
|
|
457
|
-
default:
|
|
458
|
-
// handle later
|
|
459
|
-
break;
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
if (Qundef != key) {
|
|
464
|
-
if (Qundef == val && Qundef == (val = read_next(pi, 0))) {
|
|
465
|
-
raise_error("unexpected character", pi->str, pi->s);
|
|
466
|
-
}
|
|
467
|
-
if (Qundef == obj && 0 == odd) {
|
|
468
|
-
obj = rb_hash_new();
|
|
469
|
-
obj_type = T_HASH;
|
|
470
|
-
}
|
|
471
|
-
if (ObjectMode == mode && 0 != ks && '^' == *ks) {
|
|
472
|
-
int val_type = rb_type(val);
|
|
473
|
-
|
|
474
|
-
if ('i' == ks[1] && '\0' == ks[2] && T_FIXNUM == val_type) {
|
|
475
|
-
circ_array_set(pi->circ_array, obj, NUM2ULONG(val));
|
|
476
|
-
key = Qundef;
|
|
477
|
-
} else if ('#' == ks[1] &&
|
|
478
|
-
(T_NONE == obj_type || T_HASH == obj_type) &&
|
|
479
|
-
T_ARRAY == val_type && 2 == RARRAY_LEN(val)) { // Hash entry
|
|
480
|
-
VALUE *np = RARRAY_PTR(val);
|
|
481
|
-
|
|
482
|
-
key = *np;
|
|
483
|
-
val = *(np + 1);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
if (Qundef != key) {
|
|
487
|
-
if (0 != odd) {
|
|
488
|
-
ID *idp;
|
|
489
|
-
|
|
490
|
-
for (idp = odd->attrs, vp = odd_args; 0 != *idp; idp++, vp++) {
|
|
491
|
-
if (0 == strcmp(rb_id2name(*idp), ks)) {
|
|
492
|
-
*vp = val;
|
|
493
|
-
break;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
if (odd_args + MAX_ODD_ARGS <= vp) {
|
|
497
|
-
raise_error("invalid attribute", pi->str, pi->s);
|
|
498
|
-
}
|
|
499
|
-
} else if (T_OBJECT == obj_type) {
|
|
500
|
-
VALUE *slot;
|
|
501
|
-
ID var_id;
|
|
502
|
-
|
|
503
|
-
#if SAFE_CACHE
|
|
504
|
-
pthread_mutex_lock(&oj_cache_mutex);
|
|
505
|
-
#endif
|
|
506
|
-
if (Qundef == (var_id = oj_cache_get(oj_attr_cache, ks, &slot))) {
|
|
507
|
-
char attr[1024];
|
|
508
|
-
|
|
509
|
-
if ('~' == *ks) {
|
|
510
|
-
strncpy(attr, ks + 1, sizeof(attr) - 1);
|
|
511
|
-
} else {
|
|
512
|
-
*attr = '@';
|
|
513
|
-
strncpy(attr + 1, ks, sizeof(attr) - 2);
|
|
514
|
-
}
|
|
515
|
-
attr[sizeof(attr) - 1] = '\0';
|
|
516
|
-
var_id = rb_intern(attr);
|
|
517
|
-
*slot = var_id;
|
|
518
|
-
}
|
|
519
|
-
#if SAFE_CACHE
|
|
520
|
-
pthread_mutex_unlock(&oj_cache_mutex);
|
|
521
|
-
#endif
|
|
522
|
-
#if HAS_EXCEPTION_MAGIC
|
|
523
|
-
if ('~' == *ks && Qtrue == rb_obj_is_kind_of(obj, rb_eException)) {
|
|
524
|
-
if (0 == strcmp("~mesg", ks)) {
|
|
525
|
-
VALUE args[1];
|
|
526
|
-
|
|
527
|
-
args[0] = val;
|
|
528
|
-
obj = rb_class_new_instance(1, args, rb_class_of(obj));
|
|
529
|
-
} else if (0 == strcmp("~bt", ks)) {
|
|
530
|
-
rb_funcall(obj, rb_intern("set_backtrace"), 1, val);
|
|
531
|
-
}
|
|
532
|
-
} else {
|
|
533
|
-
rb_ivar_set(obj, var_id, val);
|
|
534
|
-
}
|
|
535
|
-
#else
|
|
536
|
-
rb_ivar_set(obj, var_id, val);
|
|
537
|
-
#endif
|
|
538
|
-
} else if (T_HASH == obj_type) {
|
|
539
|
-
if (Yes == pi->options->sym_key) {
|
|
540
|
-
rb_hash_aset(obj, rb_str_intern(key), val);
|
|
541
|
-
} else {
|
|
542
|
-
rb_hash_aset(obj, key, val);
|
|
543
|
-
}
|
|
544
|
-
if ((CompatMode == mode || ObjectMode == mode) &&
|
|
545
|
-
0 == json_class_name && 0 != ks &&
|
|
546
|
-
0 != pi->options->create_id && *pi->options->create_id == *ks && 0 == strcmp(pi->options->create_id, ks) &&
|
|
547
|
-
T_STRING == rb_type(val)) {
|
|
548
|
-
json_class_name = StringValuePtr(val);
|
|
549
|
-
}
|
|
550
|
-
} else {
|
|
551
|
-
raise_error("invalid Object format, too many Hash entries.", pi->str, pi->s);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
next_non_white(pi);
|
|
556
|
-
if ('}' == *pi->s) {
|
|
557
|
-
pi->s++;
|
|
558
|
-
break;
|
|
559
|
-
} else if (',' == *pi->s) {
|
|
560
|
-
pi->s++;
|
|
561
|
-
} else {
|
|
562
|
-
//printf("*** '%s'\n", pi->s);
|
|
563
|
-
raise_error("invalid format, expected , or } while in an object", pi->str, pi->s);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
if (0 != odd) {
|
|
567
|
-
obj = rb_funcall2(odd->create_obj, odd->create_op, odd->attr_cnt, odd_args);
|
|
568
|
-
} else if (0 != json_class_name) {
|
|
569
|
-
VALUE clas = classname2class(json_class_name, pi);
|
|
570
|
-
VALUE args[1];
|
|
571
|
-
|
|
572
|
-
*args = obj;
|
|
573
|
-
obj = rb_funcall2(clas, oj_json_create_id, 1, args);
|
|
574
|
-
}
|
|
575
|
-
return obj;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
static VALUE
|
|
579
|
-
read_array(ParseInfo pi, int hint) {
|
|
580
|
-
VALUE a = Qundef;
|
|
581
|
-
VALUE e;
|
|
582
|
-
int type = T_NONE;
|
|
583
|
-
int cnt = 0;
|
|
584
|
-
int a_str;
|
|
585
|
-
#if HAS_RSTRUCT
|
|
586
|
-
long slen = 0;
|
|
587
|
-
#endif
|
|
588
|
-
|
|
589
|
-
pi->s++;
|
|
590
|
-
next_non_white(pi);
|
|
591
|
-
if (']' == *pi->s) {
|
|
592
|
-
pi->s++;
|
|
593
|
-
return rb_ary_new();
|
|
594
|
-
}
|
|
595
|
-
while (1) {
|
|
596
|
-
next_non_white(pi);
|
|
597
|
-
a_str = ('"' == *pi->s);
|
|
598
|
-
if (Qundef == (e = read_next(pi, 0))) {
|
|
599
|
-
raise_error("unexpected character", pi->str, pi->s);
|
|
600
|
-
}
|
|
601
|
-
#if HAS_RSTRUCT
|
|
602
|
-
if (Qundef == a && T_STRUCT == hint && T_STRING == rb_type(e)) {
|
|
603
|
-
a = structname2obj(StringValuePtr(e));
|
|
604
|
-
type = T_STRUCT;
|
|
605
|
-
slen = RSTRUCT_LEN(a);
|
|
606
|
-
e = Qundef;
|
|
607
|
-
}
|
|
608
|
-
#endif
|
|
609
|
-
if (Qundef == a) {
|
|
610
|
-
a = rb_ary_new();
|
|
611
|
-
type = T_ARRAY;
|
|
612
|
-
}
|
|
613
|
-
if (a_str && T_FIXNUM == rb_type(e)) {
|
|
614
|
-
circ_array_set(pi->circ_array, a, NUM2ULONG(e));
|
|
615
|
-
e = Qundef;
|
|
616
|
-
}
|
|
617
|
-
if (Qundef != e) {
|
|
618
|
-
if (T_STRUCT == type) {
|
|
619
|
-
#if HAS_RSTRUCT
|
|
620
|
-
if (slen <= cnt) {
|
|
621
|
-
raise_error("Too many elements for Struct", pi->str, pi->s);
|
|
622
|
-
}
|
|
623
|
-
RSTRUCT_PTR(a)[cnt] = e;
|
|
624
|
-
#else
|
|
625
|
-
raise_error("Ruby structs not supported with this version of Ruby", pi->str, pi->s);
|
|
626
|
-
#endif
|
|
627
|
-
} else {
|
|
628
|
-
rb_ary_push(a, e);
|
|
629
|
-
}
|
|
630
|
-
cnt++;
|
|
631
|
-
}
|
|
632
|
-
next_non_white(pi);
|
|
633
|
-
if (',' == *pi->s) {
|
|
634
|
-
pi->s++;
|
|
635
|
-
} else if (']' == *pi->s) {
|
|
636
|
-
pi->s++;
|
|
637
|
-
break;
|
|
638
|
-
} else {
|
|
639
|
-
raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s);
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
return a;
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
static VALUE
|
|
646
|
-
read_str(ParseInfo pi, int hint) {
|
|
647
|
-
char *text;
|
|
648
|
-
VALUE obj;
|
|
649
|
-
int escaped;
|
|
650
|
-
|
|
651
|
-
escaped = ('\\' == pi->s[1]);
|
|
652
|
-
text = read_quoted_value(pi);
|
|
653
|
-
if (ObjectMode != pi->options->mode) {
|
|
654
|
-
hint = T_STRING;
|
|
655
|
-
}
|
|
656
|
-
switch (hint) {
|
|
657
|
-
case T_CLASS:
|
|
658
|
-
obj = classname2class(text, pi);
|
|
659
|
-
break;
|
|
660
|
-
case T_OBJECT:
|
|
661
|
-
obj = classname2obj(text, pi);
|
|
662
|
-
break;
|
|
663
|
-
case T_STRING:
|
|
664
|
-
obj = rb_str_new2(text);
|
|
665
|
-
#if HAS_ENCODING_SUPPORT
|
|
666
|
-
rb_enc_associate(obj, oj_utf8_encoding);
|
|
667
|
-
#endif
|
|
668
|
-
break;
|
|
669
|
-
case T_SYMBOL:
|
|
670
|
-
#if HAS_ENCODING_SUPPORT
|
|
671
|
-
obj = rb_str_new2(text);
|
|
672
|
-
rb_enc_associate(obj, oj_utf8_encoding);
|
|
673
|
-
obj = rb_funcall(obj, oj_to_sym_id, 0);
|
|
674
|
-
#else
|
|
675
|
-
obj = ID2SYM(rb_intern(text));
|
|
676
|
-
#endif
|
|
677
|
-
break;
|
|
678
|
-
case 0:
|
|
679
|
-
default:
|
|
680
|
-
obj = Qundef;
|
|
681
|
-
if (':' == *text && !escaped) { // Symbol
|
|
682
|
-
#if HAS_ENCODING_SUPPORT
|
|
683
|
-
obj = rb_str_new2(text + 1);
|
|
684
|
-
rb_enc_associate(obj, oj_utf8_encoding);
|
|
685
|
-
obj = rb_funcall(obj, oj_to_sym_id, 0);
|
|
686
|
-
#else
|
|
687
|
-
obj = ID2SYM(rb_intern(text + 1));
|
|
688
|
-
#endif
|
|
689
|
-
} else if (ObjectMode == pi->options->mode && '^' == *text && '\0' != text[2]) {
|
|
690
|
-
char c1 = text[1];
|
|
691
|
-
|
|
692
|
-
if ('r' == c1 && 0 != pi->circ_array) {
|
|
693
|
-
obj = circ_array_get(pi->circ_array, read_ulong(text + 2, pi));
|
|
694
|
-
} else if ('i' == c1) {
|
|
695
|
-
obj = ULONG2NUM(read_ulong(text + 2, pi));
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
if (Qundef == obj) {
|
|
699
|
-
obj = rb_str_new2(text);
|
|
700
|
-
#if HAS_ENCODING_SUPPORT
|
|
701
|
-
rb_enc_associate(obj, oj_utf8_encoding);
|
|
702
|
-
#endif
|
|
703
|
-
}
|
|
704
|
-
break;
|
|
705
|
-
}
|
|
706
|
-
return obj;
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
#ifdef RUBINIUS_RUBY
|
|
710
|
-
#define NUM_MAX 0x07FFFFFF
|
|
711
|
-
#else
|
|
712
|
-
#define NUM_MAX (FIXNUM_MAX >> 8)
|
|
713
|
-
#endif
|
|
714
|
-
|
|
715
|
-
static VALUE
|
|
716
|
-
read_num(ParseInfo pi) {
|
|
717
|
-
char *start = pi->s;
|
|
718
|
-
int64_t n = 0;
|
|
719
|
-
long a = 0;
|
|
720
|
-
long div = 1;
|
|
721
|
-
long e = 0;
|
|
722
|
-
int neg = 0;
|
|
723
|
-
int eneg = 0;
|
|
724
|
-
int big = 0;
|
|
725
|
-
|
|
726
|
-
if ('-' == *pi->s) {
|
|
727
|
-
pi->s++;
|
|
728
|
-
neg = 1;
|
|
729
|
-
} else if ('+' == *pi->s) {
|
|
730
|
-
pi->s++;
|
|
731
|
-
}
|
|
732
|
-
if ('I' == *pi->s) {
|
|
733
|
-
if (0 != strncmp("Infinity", pi->s, 8)) {
|
|
734
|
-
raise_error("number or other value", pi->str, pi->s);
|
|
735
|
-
}
|
|
736
|
-
pi->s += 8;
|
|
737
|
-
if (neg) {
|
|
738
|
-
return rb_float_new(-INFINITY);
|
|
739
|
-
} else {
|
|
740
|
-
return rb_float_new(INFINITY);
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
|
744
|
-
if (big) {
|
|
745
|
-
big++;
|
|
746
|
-
} else {
|
|
747
|
-
n = n * 10 + (*pi->s - '0');
|
|
748
|
-
if (NUM_MAX <= n) {
|
|
749
|
-
big = 1;
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
if ('.' == *pi->s) {
|
|
754
|
-
pi->s++;
|
|
755
|
-
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
|
756
|
-
a = a * 10 + (*pi->s - '0');
|
|
757
|
-
div *= 10;
|
|
758
|
-
if (NUM_MAX <= div) {
|
|
759
|
-
big = 1;
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
if ('e' == *pi->s || 'E' == *pi->s) {
|
|
764
|
-
pi->s++;
|
|
765
|
-
if ('-' == *pi->s) {
|
|
766
|
-
pi->s++;
|
|
767
|
-
eneg = 1;
|
|
768
|
-
} else if ('+' == *pi->s) {
|
|
769
|
-
pi->s++;
|
|
770
|
-
}
|
|
771
|
-
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
|
772
|
-
e = e * 10 + (*pi->s - '0');
|
|
773
|
-
if (NUM_MAX <= e) {
|
|
774
|
-
big = 1;
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
if (0 == e && 0 == a && 1 == div) {
|
|
779
|
-
if (big) {
|
|
780
|
-
char c = *pi->s;
|
|
781
|
-
VALUE num;
|
|
782
|
-
|
|
783
|
-
*pi->s = '\0';
|
|
784
|
-
num = rb_cstr_to_inum(start, 10, 0);
|
|
785
|
-
*pi->s = c;
|
|
786
|
-
|
|
787
|
-
return num;
|
|
788
|
-
} else {
|
|
789
|
-
if (neg) {
|
|
790
|
-
n = -n;
|
|
791
|
-
}
|
|
792
|
-
return LONG2NUM(n);
|
|
793
|
-
}
|
|
794
|
-
} else { // decimal
|
|
795
|
-
if (big) {
|
|
796
|
-
char c = *pi->s;
|
|
797
|
-
VALUE num;
|
|
798
|
-
|
|
799
|
-
*pi->s = '\0';
|
|
800
|
-
num = rb_funcall(oj_bigdecimal_class, oj_new_id, 1, rb_str_new2(start));
|
|
801
|
-
*pi->s = c;
|
|
802
|
-
|
|
803
|
-
return num;
|
|
804
|
-
} else {
|
|
805
|
-
double d = (double)n + (double)a / (double)div;
|
|
806
|
-
|
|
807
|
-
if (neg) {
|
|
808
|
-
d = -d;
|
|
809
|
-
}
|
|
810
|
-
if (1 < big) {
|
|
811
|
-
e += big - 1;
|
|
812
|
-
}
|
|
813
|
-
if (0 != e) {
|
|
814
|
-
if (eneg) {
|
|
815
|
-
e = -e;
|
|
816
|
-
}
|
|
817
|
-
d *= pow(10.0, e);
|
|
818
|
-
}
|
|
819
|
-
return rb_float_new(d);
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
static VALUE
|
|
825
|
-
read_time(ParseInfo pi) {
|
|
826
|
-
time_t v = 0;
|
|
827
|
-
long v2 = 0;
|
|
828
|
-
|
|
829
|
-
for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
|
|
830
|
-
v = v * 10 + (*pi->s - '0');
|
|
831
|
-
}
|
|
832
|
-
if ('.' == *pi->s) {
|
|
833
|
-
int cnt;
|
|
834
|
-
|
|
835
|
-
pi->s++;
|
|
836
|
-
for (cnt = 9; 0 < cnt && '0' <= *pi->s && *pi->s <= '9'; pi->s++, cnt--) {
|
|
837
|
-
v2 = v2 * 10 + (*pi->s - '0');
|
|
838
|
-
}
|
|
839
|
-
for (; 0 < cnt; cnt--) {
|
|
840
|
-
v2 *= 10;
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
#if HAS_NANO_TIME
|
|
844
|
-
return rb_time_nano_new(v, v2);
|
|
845
|
-
#else
|
|
846
|
-
return rb_time_new(v, v2 / 1000);
|
|
847
|
-
#endif
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
static VALUE
|
|
851
|
-
read_true(ParseInfo pi) {
|
|
852
|
-
pi->s++;
|
|
853
|
-
if ('r' != *pi->s || 'u' != *(pi->s + 1) || 'e' != *(pi->s + 2)) {
|
|
854
|
-
raise_error("invalid format, expected 'true'", pi->str, pi->s);
|
|
855
|
-
}
|
|
856
|
-
pi->s += 3;
|
|
857
|
-
|
|
858
|
-
return Qtrue;
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
static VALUE
|
|
862
|
-
read_false(ParseInfo pi) {
|
|
863
|
-
pi->s++;
|
|
864
|
-
if ('a' != *pi->s || 'l' != *(pi->s + 1) || 's' != *(pi->s + 2) || 'e' != *(pi->s + 3)) {
|
|
865
|
-
raise_error("invalid format, expected 'false'", pi->str, pi->s);
|
|
866
|
-
}
|
|
867
|
-
pi->s += 4;
|
|
868
|
-
|
|
869
|
-
return Qfalse;
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
static VALUE
|
|
873
|
-
read_nil(ParseInfo pi) {
|
|
874
|
-
pi->s++;
|
|
875
|
-
if ('u' != *pi->s || 'l' != *(pi->s + 1) || 'l' != *(pi->s + 2)) {
|
|
876
|
-
raise_error("invalid format, expected 'nil'", pi->str, pi->s);
|
|
877
|
-
}
|
|
878
|
-
pi->s += 3;
|
|
879
|
-
|
|
880
|
-
return Qnil;
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
static uint32_t
|
|
884
|
-
read_hex(ParseInfo pi, char *h) {
|
|
885
|
-
uint32_t b = 0;
|
|
886
|
-
int i;
|
|
887
|
-
|
|
888
|
-
// TBD this can be made faster with a table
|
|
889
|
-
for (i = 0; i < 4; i++, h++) {
|
|
890
|
-
b = b << 4;
|
|
891
|
-
if ('0' <= *h && *h <= '9') {
|
|
892
|
-
b += *h - '0';
|
|
893
|
-
} else if ('A' <= *h && *h <= 'F') {
|
|
894
|
-
b += *h - 'A' + 10;
|
|
895
|
-
} else if ('a' <= *h && *h <= 'f') {
|
|
896
|
-
b += *h - 'a' + 10;
|
|
897
|
-
} else {
|
|
898
|
-
pi->s = h;
|
|
899
|
-
raise_error("invalid hex character", pi->str, pi->s);
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
return b;
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
static char*
|
|
906
|
-
unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
|
|
907
|
-
if (0x0000007F >= code) {
|
|
908
|
-
*t = (char)code;
|
|
909
|
-
} else if (0x000007FF >= code) {
|
|
910
|
-
*t++ = 0xC0 | (code >> 6);
|
|
911
|
-
*t = 0x80 | (0x3F & code);
|
|
912
|
-
} else if (0x0000FFFF >= code) {
|
|
913
|
-
*t++ = 0xE0 | (code >> 12);
|
|
914
|
-
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
|
915
|
-
*t = 0x80 | (0x3F & code);
|
|
916
|
-
} else if (0x001FFFFF >= code) {
|
|
917
|
-
*t++ = 0xF0 | (code >> 18);
|
|
918
|
-
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
|
919
|
-
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
|
920
|
-
*t = 0x80 | (0x3F & code);
|
|
921
|
-
} else if (0x03FFFFFF >= code) {
|
|
922
|
-
*t++ = 0xF8 | (code >> 24);
|
|
923
|
-
*t++ = 0x80 | ((code >> 18) & 0x3F);
|
|
924
|
-
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
|
925
|
-
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
|
926
|
-
*t = 0x80 | (0x3F & code);
|
|
927
|
-
} else if (0x7FFFFFFF >= code) {
|
|
928
|
-
*t++ = 0xFC | (code >> 30);
|
|
929
|
-
*t++ = 0x80 | ((code >> 24) & 0x3F);
|
|
930
|
-
*t++ = 0x80 | ((code >> 18) & 0x3F);
|
|
931
|
-
*t++ = 0x80 | ((code >> 12) & 0x3F);
|
|
932
|
-
*t++ = 0x80 | ((code >> 6) & 0x3F);
|
|
933
|
-
*t = 0x80 | (0x3F & code);
|
|
934
|
-
} else {
|
|
935
|
-
raise_error("invalid Unicode", pi->str, pi->s);
|
|
936
|
-
}
|
|
937
|
-
return t;
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
/* Assume the value starts immediately and goes until the quote character is
|
|
941
|
-
* reached again. Do not read the character after the terminating quote.
|
|
942
|
-
*/
|
|
943
|
-
static char*
|
|
944
|
-
read_quoted_value(ParseInfo pi) {
|
|
945
|
-
char *value = 0;
|
|
946
|
-
char *h = pi->s; // head
|
|
947
|
-
char *t = h; // tail
|
|
948
|
-
uint32_t code;
|
|
949
|
-
|
|
950
|
-
h++; // skip quote character
|
|
951
|
-
t++;
|
|
952
|
-
value = h;
|
|
953
|
-
for (; '"' != *h; h++, t++) {
|
|
954
|
-
if ('\0' == *h) {
|
|
955
|
-
pi->s = h;
|
|
956
|
-
raise_error("quoted string not terminated", pi->str, pi->s);
|
|
957
|
-
} else if ('\\' == *h) {
|
|
958
|
-
h++;
|
|
959
|
-
switch (*h) {
|
|
960
|
-
case 'n': *t = '\n'; break;
|
|
961
|
-
case 'r': *t = '\r'; break;
|
|
962
|
-
case 't': *t = '\t'; break;
|
|
963
|
-
case 'f': *t = '\f'; break;
|
|
964
|
-
case 'b': *t = '\b'; break;
|
|
965
|
-
case '"': *t = '"'; break;
|
|
966
|
-
case '/': *t = '/'; break;
|
|
967
|
-
case '\\': *t = '\\'; break;
|
|
968
|
-
case 'u':
|
|
969
|
-
h++;
|
|
970
|
-
code = read_hex(pi, h);
|
|
971
|
-
h += 3;
|
|
972
|
-
if (0x0000D800 <= code && code <= 0x0000DFFF) {
|
|
973
|
-
uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
|
|
974
|
-
uint32_t c2;
|
|
975
|
-
|
|
976
|
-
h++;
|
|
977
|
-
if ('\\' != *h || 'u' != *(h + 1)) {
|
|
978
|
-
pi->s = h;
|
|
979
|
-
raise_error("invalid escaped character", pi->str, pi->s);
|
|
980
|
-
}
|
|
981
|
-
h += 2;
|
|
982
|
-
c2 = read_hex(pi, h);
|
|
983
|
-
h += 3;
|
|
984
|
-
c2 = (c2 - 0x0000DC00) & 0x000003FF;
|
|
985
|
-
code = ((c1 << 10) | c2) + 0x00010000;
|
|
986
|
-
}
|
|
987
|
-
t = unicode_to_chars(pi, t, code);
|
|
988
|
-
break;
|
|
989
|
-
default:
|
|
990
|
-
pi->s = h;
|
|
991
|
-
raise_error("invalid escaped character", pi->str, pi->s);
|
|
992
|
-
break;
|
|
993
|
-
}
|
|
994
|
-
} else if (t != h) {
|
|
995
|
-
*t = *h;
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
*t = '\0'; // terminate value
|
|
999
|
-
pi->s = h + 1;
|
|
1000
|
-
|
|
1001
|
-
return value;
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
VALUE
|
|
1005
|
-
oj_parse(char *json, Options options) {
|
|
1006
|
-
VALUE obj;
|
|
1007
|
-
struct _ParseInfo pi;
|
|
1008
|
-
|
|
1009
|
-
if (0 == json) {
|
|
1010
|
-
raise_error("Invalid arg, xml string can not be null", json, 0);
|
|
1011
|
-
}
|
|
1012
|
-
/* skip UTF-8 BOM if present */
|
|
1013
|
-
if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
|
|
1014
|
-
json += 3;
|
|
1015
|
-
}
|
|
1016
|
-
/* initialize parse info */
|
|
1017
|
-
pi.str = json;
|
|
1018
|
-
pi.s = json;
|
|
1019
|
-
pi.circ_array = 0;
|
|
1020
|
-
if (Yes == options->circular) {
|
|
1021
|
-
pi.circ_array = circ_array_new();
|
|
1022
|
-
}
|
|
1023
|
-
pi.options = options;
|
|
1024
|
-
#if IS_WINDOWS
|
|
1025
|
-
pi.stack_min = (void*)((char*)&obj - (512 * 1024)); // assume a 1M stack and give half to ruby
|
|
1026
|
-
#else
|
|
1027
|
-
{
|
|
1028
|
-
struct rlimit lim;
|
|
1029
|
-
|
|
1030
|
-
if (0 == getrlimit(RLIMIT_STACK, &lim)) {
|
|
1031
|
-
pi.stack_min = (void*)((char*)&obj - (lim.rlim_cur / 4 * 3)); // let 3/4ths of the stack be used only
|
|
1032
|
-
} else {
|
|
1033
|
-
pi.stack_min = 0; // indicates not to check stack limit
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
#endif
|
|
1037
|
-
obj = read_next(&pi, 0);
|
|
1038
|
-
if (Yes == options->circular) {
|
|
1039
|
-
circ_array_free(pi.circ_array);
|
|
1040
|
-
}
|
|
1041
|
-
if (Qundef == obj) {
|
|
1042
|
-
raise_error("no object read", pi.str, pi.s);
|
|
1043
|
-
}
|
|
1044
|
-
next_non_white(&pi);
|
|
1045
|
-
if ('\0' != *pi.s) {
|
|
1046
|
-
raise_error("invalid format, extra characters", pi.str, pi.s);
|
|
1047
|
-
}
|
|
1048
|
-
return obj;
|
|
1049
|
-
}
|