oj 2.0.14 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of oj might be problematic. Click here for more details.

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