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.

@@ -49,7 +49,6 @@ extern "C" {
49
49
  #if SAFE_CACHE
50
50
  #include <pthread.h>
51
51
  #endif
52
- #include "cache.h"
53
52
  #include "cache8.h"
54
53
 
55
54
  #ifdef RUBINIUS_RUBY
@@ -65,9 +64,7 @@ enum st_retval {ST_CONTINUE = 0, ST_STOP = 1, ST_DELETE = 2, ST_CHECK};
65
64
  #endif
66
65
  #endif
67
66
 
68
- #define raise_error(msg, xml, current) _oj_raise_error(msg, xml, current, __FILE__, __LINE__)
69
-
70
- #define MAX_ODD_ARGS 10
67
+ #include "err.h"
71
68
 
72
69
  typedef enum {
73
70
  Yes = 'y',
@@ -113,7 +110,7 @@ typedef struct _Options {
113
110
  char bigdec_as_num; // YesNo
114
111
  char bigdec_load; // YesNo
115
112
  const char *create_id; // 0 or string
116
- size_t max_stack; // max size to allocate on the stack
113
+ size_t create_id_len; // length of create_id
117
114
  int sec_prec; // second precision when dumping time
118
115
  DumpOpts dump_opts;
119
116
  } *Options;
@@ -131,14 +128,6 @@ typedef struct _Out {
131
128
  int allocated;
132
129
  } *Out;
133
130
 
134
- typedef struct _Odd {
135
- VALUE clas; // Ruby class
136
- VALUE create_obj;
137
- ID create_op;
138
- int attr_cnt;
139
- ID attrs[MAX_ODD_ARGS]; // 0 terminated attr IDs
140
- } *Odd;
141
-
142
131
  enum {
143
132
  STR_VAL = 0x00,
144
133
  COL_VAL = 0x01,
@@ -161,20 +150,26 @@ typedef struct _Leaf {
161
150
  uint8_t value_type;
162
151
  } *Leaf;
163
152
 
164
- extern VALUE oj_parse(char *json, Options options);
165
- extern void oj_saj_parse(VALUE handler, char *json);
153
+ extern VALUE oj_saj_parse(int argc, VALUE *argv, VALUE self);
154
+ extern VALUE oj_sc_parse(int argc, VALUE *argv, VALUE self);
155
+
156
+ extern VALUE oj_strict_parse(int argc, VALUE *argv, VALUE self);
157
+ extern VALUE oj_compat_parse(int argc, VALUE *argv, VALUE self);
158
+ extern VALUE oj_object_parse(int argc, VALUE *argv, VALUE self);
159
+
160
+ extern VALUE oj_strict_parse_cstr(int argc, VALUE *argv, char *json);
161
+ extern VALUE oj_compat_parse_cstr(int argc, VALUE *argv, char *json);
162
+ extern VALUE oj_object_parse_cstr(int argc, VALUE *argv, char *json);
163
+
164
+ extern void oj_parse_options(VALUE ropts, Options copts);
166
165
 
167
166
  extern void oj_dump_obj_to_json(VALUE obj, Options copts, Out out);
168
167
  extern void oj_write_obj_to_file(VALUE obj, const char *path, Options copts);
169
168
  extern void oj_dump_leaf_to_json(Leaf leaf, Options copts, Out out);
170
169
  extern void oj_write_leaf_to_file(Leaf leaf, const char *path, Options copts);
171
170
 
172
- extern void _oj_raise_error(const char *msg, const char *xml, const char *current, const char* file, int line);
173
-
174
171
  extern void oj_init_doc(void);
175
172
 
176
- extern Odd oj_get_odd(VALUE clas);
177
-
178
173
  extern VALUE Oj;
179
174
  extern struct _Options oj_default_options;
180
175
  #if HAS_ENCODING_SUPPORT
@@ -186,7 +181,6 @@ extern VALUE oj_bigdecimal_class;
186
181
  extern VALUE oj_date_class;
187
182
  extern VALUE oj_datetime_class;
188
183
  extern VALUE oj_doc_class;
189
- extern VALUE oj_parse_error_class;
190
184
  extern VALUE oj_stringio_class;
191
185
  extern VALUE oj_struct_class;
192
186
  extern VALUE oj_time_class;
@@ -194,15 +188,19 @@ extern VALUE oj_time_class;
194
188
  extern VALUE oj_slash_string;
195
189
 
196
190
  extern ID oj_add_value_id;
191
+ extern ID oj_array_append_id;
197
192
  extern ID oj_array_end_id;
198
193
  extern ID oj_array_start_id;
199
194
  extern ID oj_as_json_id;
200
195
  extern ID oj_error_id;
196
+ extern ID oj_fileno_id;
201
197
  extern ID oj_hash_end_id;
198
+ extern ID oj_hash_set_id;
202
199
  extern ID oj_hash_start_id;
203
200
  extern ID oj_instance_variables_id;
204
201
  extern ID oj_json_create_id;
205
202
  extern ID oj_new_id;
203
+ extern ID oj_read_id;
206
204
  extern ID oj_string_id;
207
205
  extern ID oj_to_hash_id;
208
206
  extern ID oj_to_json_id;
@@ -214,9 +212,6 @@ extern ID oj_tv_sec_id;
214
212
  extern ID oj_tv_usec_id;
215
213
  extern ID oj_utc_offset_id;
216
214
 
217
- extern Cache oj_class_cache;
218
- extern Cache oj_attr_cache;
219
-
220
215
  #if SAFE_CACHE
221
216
  extern pthread_mutex_t oj_cache_mutex;
222
217
  #endif
@@ -0,0 +1,798 @@
1
+ /* parse.c
2
+ * Copyright (c) 2013, 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 <stdio.h>
33
+ #include <string.h>
34
+ #include <unistd.h>
35
+ #include <math.h>
36
+
37
+ #include "oj.h"
38
+ #include "parse.h"
39
+ #include "buf.h"
40
+ #include "val_stack.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
+ #ifdef RUBINIUS_RUBY
46
+ #define NUM_MAX 0x07FFFFFF
47
+ #else
48
+ #define NUM_MAX (FIXNUM_MAX >> 8)
49
+ #endif
50
+ #define EXP_MAX 1023
51
+ #define I64_MAX 0x7FFFFFFFFFFFFFFFLL
52
+ #define DEC_MAX 14
53
+
54
+ static void
55
+ next_non_white(ParseInfo pi) {
56
+ for (; 1; pi->cur++) {
57
+ switch(*pi->cur) {
58
+ case ' ':
59
+ case '\t':
60
+ case '\f':
61
+ case '\n':
62
+ case '\r':
63
+ break;
64
+ default:
65
+ return;
66
+ }
67
+ }
68
+ }
69
+
70
+ static void
71
+ skip_comment(ParseInfo pi) {
72
+ if ('*' == *pi->cur) {
73
+ pi->cur++;
74
+ for (; '\0' != *pi->cur; pi->cur++) {
75
+ if ('*' == *pi->cur && '/' == *(pi->cur + 1)) {
76
+ pi->cur += 2;
77
+ return;
78
+ } else if ('\0' == *pi->cur) {
79
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
80
+ return;
81
+ }
82
+ }
83
+ } else if ('/' == *pi->cur) {
84
+ for (; 1; pi->cur++) {
85
+ switch (*pi->cur) {
86
+ case '\n':
87
+ case '\r':
88
+ case '\f':
89
+ case '\0':
90
+ return;
91
+ default:
92
+ break;
93
+ }
94
+ }
95
+ } else {
96
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
97
+ }
98
+ }
99
+
100
+ static void
101
+ add_value(ParseInfo pi, VALUE rval) {
102
+ Val parent = stack_peek(&pi->stack);
103
+
104
+ if (0 == parent) { // simple add
105
+ pi->add_value(pi, rval);
106
+ } else {
107
+ switch (parent->next) {
108
+ case NEXT_ARRAY_NEW:
109
+ case NEXT_ARRAY_ELEMENT:
110
+ pi->array_append_value(pi, rval);
111
+ parent->next = NEXT_ARRAY_COMMA;
112
+ break;
113
+ case NEXT_HASH_VALUE:
114
+ pi->hash_set_value(pi, parent->key, parent->klen, rval);
115
+ if (0 != parent->key && (parent->key < pi->json || pi->cur < parent->key)) {
116
+ xfree((char*)parent->key);
117
+ parent->key = 0;
118
+ }
119
+ parent->next = NEXT_HASH_COMMA;
120
+ break;
121
+ case NEXT_HASH_NEW:
122
+ case NEXT_HASH_KEY:
123
+ case NEXT_HASH_COMMA:
124
+ case NEXT_NONE:
125
+ case NEXT_ARRAY_COMMA:
126
+ case NEXT_HASH_COLON:
127
+ default:
128
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next));
129
+ break;
130
+ }
131
+ }
132
+ }
133
+
134
+ static void
135
+ read_null(ParseInfo pi) {
136
+ if ('u' == *pi->cur++ && 'l' == *pi->cur++ && 'l' == *pi->cur++) {
137
+ add_value(pi, Qnil);
138
+ } else {
139
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null");
140
+ }
141
+ }
142
+
143
+ static void
144
+ read_true(ParseInfo pi) {
145
+ if ('r' == *pi->cur++ && 'u' == *pi->cur++ && 'e' == *pi->cur++) {
146
+ add_value(pi, Qtrue);
147
+ } else {
148
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
149
+ }
150
+ }
151
+
152
+ static void
153
+ read_false(ParseInfo pi) {
154
+ if ('a' == *pi->cur++ && 'l' == *pi->cur++ && 's' == *pi->cur++ && 'e' == *pi->cur++) {
155
+ add_value(pi, Qfalse);
156
+ } else {
157
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
158
+ }
159
+ }
160
+
161
+ static uint32_t
162
+ read_hex(ParseInfo pi, const char *h) {
163
+ uint32_t b = 0;
164
+ int i;
165
+
166
+ for (i = 0; i < 4; i++, h++) {
167
+ b = b << 4;
168
+ if ('0' <= *h && *h <= '9') {
169
+ b += *h - '0';
170
+ } else if ('A' <= *h && *h <= 'F') {
171
+ b += *h - 'A' + 10;
172
+ } else if ('a' <= *h && *h <= 'f') {
173
+ b += *h - 'a' + 10;
174
+ } else {
175
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character");
176
+ return 0;
177
+ }
178
+ }
179
+ return b;
180
+ }
181
+
182
+ static void
183
+ unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
184
+ if (0x0000007F >= code) {
185
+ buf_append(buf, (char)code);
186
+ } else if (0x000007FF >= code) {
187
+ buf_append(buf, 0xC0 | (code >> 6));
188
+ buf_append(buf, 0x80 | (0x3F & code));
189
+ } else if (0x0000FFFF >= code) {
190
+ buf_append(buf, 0xE0 | (code >> 12));
191
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
192
+ buf_append(buf, 0x80 | (0x3F & code));
193
+ } else if (0x001FFFFF >= code) {
194
+ buf_append(buf, 0xF0 | (code >> 18));
195
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
196
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
197
+ buf_append(buf, 0x80 | (0x3F & code));
198
+ } else if (0x03FFFFFF >= code) {
199
+ buf_append(buf, 0xF8 | (code >> 24));
200
+ buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
201
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
202
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
203
+ buf_append(buf, 0x80 | (0x3F & code));
204
+ } else if (0x7FFFFFFF >= code) {
205
+ buf_append(buf, 0xFC | (code >> 30));
206
+ buf_append(buf, 0x80 | ((code >> 24) & 0x3F));
207
+ buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
208
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
209
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
210
+ buf_append(buf, 0x80 | (0x3F & code));
211
+ } else {
212
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
213
+ }
214
+ }
215
+
216
+ // entered at /
217
+ static void
218
+ read_escaped_str(ParseInfo pi, const char *start) {
219
+ struct _Buf buf;
220
+ const char *s;
221
+ int cnt = (int)(pi->cur - start);
222
+ uint32_t code;
223
+ Val parent = stack_peek(&pi->stack);
224
+
225
+ buf_init(&buf);
226
+ if (0 < cnt) {
227
+ buf_append_string(&buf, start, cnt);
228
+ }
229
+ for (s = pi->cur; '"' != *s; s++) {
230
+ if ('\0' == *s) {
231
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
232
+ buf_cleanup(&buf);
233
+ return;
234
+ } else if ('\\' == *s) {
235
+ s++;
236
+ switch (*s) {
237
+ case 'n': buf_append(&buf, '\n'); break;
238
+ case 'r': buf_append(&buf, '\r'); break;
239
+ case 't': buf_append(&buf, '\t'); break;
240
+ case 'f': buf_append(&buf, '\f'); break;
241
+ case 'b': buf_append(&buf, '\b'); break;
242
+ case '"': buf_append(&buf, '"'); break;
243
+ case '/': buf_append(&buf, '/'); break;
244
+ case '\\': buf_append(&buf, '\\'); break;
245
+ case 'u':
246
+ s++;
247
+ if (0 == (code = read_hex(pi, s)) && err_has(&pi->err)) {
248
+ buf_cleanup(&buf);
249
+ return;
250
+ }
251
+ s += 3;
252
+ if (0x0000D800 <= code && code <= 0x0000DFFF) {
253
+ uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
254
+ uint32_t c2;
255
+
256
+ s++;
257
+ if ('\\' != *s || 'u' != *(s + 1)) {
258
+ pi->cur = s;
259
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
260
+ buf_cleanup(&buf);
261
+ return;
262
+ }
263
+ s += 2;
264
+ if (0 == (c2 = read_hex(pi, s)) && err_has(&pi->err)) {
265
+ buf_cleanup(&buf);
266
+ return;
267
+ }
268
+ s += 3;
269
+ c2 = (c2 - 0x0000DC00) & 0x000003FF;
270
+ code = ((c1 << 10) | c2) + 0x00010000;
271
+ }
272
+ unicode_to_chars(pi, &buf, code);
273
+ if (err_has(&pi->err)) {
274
+ buf_cleanup(&buf);
275
+ return;
276
+ }
277
+ break;
278
+ default:
279
+ pi->cur = s;
280
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
281
+ buf_cleanup(&buf);
282
+ return;
283
+ }
284
+ } else {
285
+ buf_append(&buf, *s);
286
+ }
287
+ }
288
+ if (0 == parent) {
289
+ pi->add_cstr(pi, buf.head, buf_len(&buf), start);
290
+ } else {
291
+ switch (parent->next) {
292
+ case NEXT_ARRAY_NEW:
293
+ case NEXT_ARRAY_ELEMENT:
294
+ pi->array_append_cstr(pi, buf.head, buf_len(&buf), start);
295
+ parent->next = NEXT_ARRAY_COMMA;
296
+ break;
297
+ case NEXT_HASH_NEW:
298
+ case NEXT_HASH_KEY:
299
+ // key will not be between pi->json and pi->cur.
300
+ parent->key = strdup(buf.head);
301
+ parent->klen = buf_len(&buf);
302
+ parent->k1 = *start;
303
+ parent->next = NEXT_HASH_COLON;
304
+ break;
305
+ case NEXT_HASH_VALUE:
306
+ pi->hash_set_cstr(pi, parent->key, parent->klen, buf.head, buf_len(&buf), start);
307
+ if (0 != parent->key && (parent->key < pi->json || pi->cur < parent->key)) {
308
+ xfree((char*)parent->key);
309
+ parent->key = 0;
310
+ }
311
+ parent->next = NEXT_HASH_COMMA;
312
+ break;
313
+ case NEXT_HASH_COMMA:
314
+ case NEXT_NONE:
315
+ case NEXT_ARRAY_COMMA:
316
+ case NEXT_HASH_COLON:
317
+ default:
318
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next));
319
+ break;
320
+ }
321
+ }
322
+ pi->cur = s + 1;
323
+ buf_cleanup(&buf);
324
+ }
325
+
326
+ static void
327
+ read_str(ParseInfo pi) {
328
+ const char *str = pi->cur;
329
+ Val parent = stack_peek(&pi->stack);
330
+
331
+ for (; '"' != *pi->cur; pi->cur++) {
332
+ if ('\0' == *pi->cur) {
333
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
334
+ return;
335
+ } else if ('\\' == *pi->cur) {
336
+ read_escaped_str(pi, str);
337
+ return;
338
+ }
339
+ }
340
+ if (0 == parent) { // simple add
341
+ pi->add_cstr(pi, str, pi->cur - str, str);
342
+ } else {
343
+ switch (parent->next) {
344
+ case NEXT_ARRAY_NEW:
345
+ case NEXT_ARRAY_ELEMENT:
346
+ pi->array_append_cstr(pi, str, pi->cur - str, str);
347
+ parent->next = NEXT_ARRAY_COMMA;
348
+ break;
349
+ case NEXT_HASH_NEW:
350
+ case NEXT_HASH_KEY:
351
+ parent->key = str;
352
+ parent->klen = pi->cur - str;
353
+ parent->k1 = *str;
354
+ parent->next = NEXT_HASH_COLON;
355
+ break;
356
+ case NEXT_HASH_VALUE:
357
+ pi->hash_set_cstr(pi, parent->key, parent->klen, str, pi->cur - str, str);
358
+ if (0 != parent->key && (parent->key < pi->json || pi->cur < parent->key)) {
359
+ xfree((char*)parent->key);
360
+ parent->key = 0;
361
+ }
362
+ parent->next = NEXT_HASH_COMMA;
363
+ break;
364
+ case NEXT_HASH_COMMA:
365
+ case NEXT_NONE:
366
+ case NEXT_ARRAY_COMMA:
367
+ case NEXT_HASH_COLON:
368
+ default:
369
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a string", oj_stack_next_string(parent->next));
370
+ break;
371
+ }
372
+ }
373
+ pi->cur++; // move past "
374
+ }
375
+
376
+ static void
377
+ read_num(ParseInfo pi) {
378
+ struct _NumInfo ni;
379
+ Val parent = stack_peek(&pi->stack);
380
+ int zero_cnt = 0;
381
+
382
+ ni.str = pi->cur;
383
+ ni.i = 0;
384
+ ni.num = 0;
385
+ ni.div = 1;
386
+ ni.len = 0;
387
+ ni.exp = 0;
388
+ ni.dec_cnt = 0;
389
+ ni.big = 0;
390
+ ni.infinity = 0;
391
+ ni.neg = 0;
392
+
393
+ if ('-' == *pi->cur) {
394
+ pi->cur++;
395
+ ni.neg = 1;
396
+ } else if ('+' == *pi->cur) {
397
+ pi->cur++;
398
+ }
399
+ if ('I' == *pi->cur) {
400
+ if (0 != strncmp("Infinity", pi->cur, 8)) {
401
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
402
+ return;
403
+ }
404
+ pi->cur += 8;
405
+ ni.infinity = 1;
406
+ return;
407
+ }
408
+ for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
409
+ ni.dec_cnt++;
410
+ if (ni.big) {
411
+ ni.big++;
412
+ } else {
413
+ int d = (*pi->cur - '0');
414
+
415
+ if (0 == d) {
416
+ zero_cnt++;
417
+ } else {
418
+ zero_cnt = 0;
419
+ }
420
+ ni.i = ni.i * 10 + d;
421
+ if (I64_MAX <= ni.i || DEC_MAX < ni.dec_cnt - zero_cnt) {
422
+ ni.big = 1;
423
+ }
424
+ }
425
+ }
426
+ if ('.' == *pi->cur) {
427
+ pi->cur++;
428
+ for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
429
+ int d = (*pi->cur - '0');
430
+
431
+ if (0 == d) {
432
+ zero_cnt++;
433
+ } else {
434
+ zero_cnt = 0;
435
+ }
436
+ ni.dec_cnt++;
437
+ ni.num = ni.num * 10 + d;
438
+ ni.div *= 10;
439
+ if (I64_MAX <= ni.div || DEC_MAX < ni.dec_cnt - zero_cnt) {
440
+ ni.big = 1;
441
+ }
442
+ }
443
+ }
444
+ if ('e' == *pi->cur || 'E' == *pi->cur) {
445
+ int eneg = 0;
446
+
447
+ pi->cur++;
448
+ if ('-' == *pi->cur) {
449
+ pi->cur++;
450
+ eneg = 1;
451
+ } else if ('+' == *pi->cur) {
452
+ pi->cur++;
453
+ }
454
+ for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
455
+ ni.exp = ni.exp * 10 + (*pi->cur - '0');
456
+ if (EXP_MAX <= ni.exp) {
457
+ ni.big = 1;
458
+ }
459
+ }
460
+ if (eneg) {
461
+ ni.exp = -ni.exp;
462
+ }
463
+ }
464
+ ni.dec_cnt -= zero_cnt;
465
+ ni.len = pi->cur - ni.str;
466
+ if (Yes == pi->options.bigdec_load) {
467
+ ni.big = 1;
468
+ }
469
+ if (0 == parent) {
470
+ pi->add_num(pi, &ni);
471
+ } else {
472
+ switch (parent->next) {
473
+ case NEXT_ARRAY_NEW:
474
+ case NEXT_ARRAY_ELEMENT:
475
+ pi->array_append_num(pi, &ni);
476
+ parent->next = NEXT_ARRAY_COMMA;
477
+ break;
478
+ case NEXT_HASH_VALUE:
479
+ pi->hash_set_num(pi, parent->key, parent->klen, &ni);
480
+ if (0 != parent->key && (parent->key < pi->json || pi->cur < parent->key)) {
481
+ xfree((char*)parent->key);
482
+ parent->key = 0;
483
+ }
484
+ parent->next = NEXT_HASH_COMMA;
485
+ break;
486
+ default:
487
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s", oj_stack_next_string(parent->next));
488
+ break;
489
+ }
490
+ }
491
+ }
492
+
493
+ static void
494
+ array_start(ParseInfo pi) {
495
+ VALUE v = Qnil;
496
+
497
+ v = pi->start_array(pi);
498
+ stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
499
+ }
500
+
501
+ static void
502
+ array_end(ParseInfo pi) {
503
+ Val array = stack_pop(&pi->stack);
504
+
505
+ if (0 == array) {
506
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
507
+ } else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
508
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not an array close", oj_stack_next_string(array->next));
509
+ } else {
510
+ pi->end_array(pi);
511
+ add_value(pi, array->val);
512
+ }
513
+ }
514
+
515
+ static void
516
+ hash_start(ParseInfo pi) {
517
+ VALUE v = Qnil;
518
+
519
+ v = pi->start_hash(pi);
520
+ stack_push(&pi->stack, v, NEXT_HASH_NEW);
521
+ }
522
+
523
+ static void
524
+ hash_end(ParseInfo pi) {
525
+ Val hash = stack_peek(&pi->stack);
526
+
527
+ // leave hash on stack until just before
528
+ if (0 == hash) {
529
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
530
+ } else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
531
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected %s, not a hash close", oj_stack_next_string(hash->next));
532
+ } else {
533
+ pi->end_hash(pi);
534
+ stack_pop(&pi->stack);
535
+ add_value(pi, hash->val);
536
+ }
537
+ }
538
+
539
+ static void
540
+ comma(ParseInfo pi) {
541
+ Val parent = stack_peek(&pi->stack);
542
+
543
+ if (0 == parent) {
544
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
545
+ } else if (NEXT_ARRAY_COMMA == parent->next) {
546
+ parent->next = NEXT_ARRAY_ELEMENT;
547
+ } else if (NEXT_HASH_COMMA == parent->next) {
548
+ parent->next = NEXT_HASH_KEY;
549
+ } else {
550
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
551
+ }
552
+ }
553
+
554
+ static void
555
+ colon(ParseInfo pi) {
556
+ Val parent = stack_peek(&pi->stack);
557
+
558
+ if (0 != parent && NEXT_HASH_COLON == parent->next) {
559
+ parent->next = NEXT_HASH_VALUE;
560
+ } else {
561
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
562
+ }
563
+ }
564
+
565
+ void
566
+ oj_parse2(ParseInfo pi) {
567
+ pi->cur = pi->json;
568
+ err_init(&pi->err);
569
+ stack_init(&pi->stack);
570
+ while (1) {
571
+ next_non_white(pi);
572
+ switch (*pi->cur++) {
573
+ case '{':
574
+ hash_start(pi);
575
+ break;
576
+ case '}':
577
+ hash_end(pi);
578
+ break;
579
+ case ':':
580
+ colon(pi);
581
+ break;
582
+ case '[':
583
+ array_start(pi);
584
+ break;
585
+ case ']':
586
+ array_end(pi);
587
+ break;
588
+ case ',':
589
+ comma(pi);
590
+ break;
591
+ case '"':
592
+ read_str(pi);
593
+ break;
594
+ case '+':
595
+ case '-':
596
+ case '0':
597
+ case '1':
598
+ case '2':
599
+ case '3':
600
+ case '4':
601
+ case '5':
602
+ case '6':
603
+ case '7':
604
+ case '8':
605
+ case '9':
606
+ case 'I':
607
+ pi->cur--;
608
+ read_num(pi);
609
+ break;
610
+ case 't':
611
+ read_true(pi);
612
+ break;
613
+ case 'f':
614
+ read_false(pi);
615
+ break;
616
+ case 'n':
617
+ read_null(pi);
618
+ break;
619
+ case '/':
620
+ skip_comment(pi);
621
+ break;
622
+ case '\0':
623
+ pi->cur--;
624
+ return;
625
+ default:
626
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
627
+ return;
628
+ }
629
+ if (err_has(&pi->err)) {
630
+ return;
631
+ }
632
+ }
633
+ }
634
+
635
+ VALUE
636
+ oj_num_as_value(NumInfo ni) {
637
+ VALUE rnum = Qnil;
638
+
639
+ if (ni->infinity) {
640
+ if (ni->neg) {
641
+ rnum = rb_float_new(-OJ_INFINITY);
642
+ } else {
643
+ rnum = rb_float_new(OJ_INFINITY);
644
+ }
645
+ } else if (1 == ni->div && 0 == ni->exp) { // fixnum
646
+ if (ni->big) {
647
+ if (256 > ni->len) {
648
+ char buf[256];
649
+
650
+ memcpy(buf, ni->str, ni->len);
651
+ buf[ni->len] = '\0';
652
+ rnum = rb_cstr_to_inum(buf, 10, 0);
653
+ } else {
654
+ char *buf = ALLOC_N(char, ni->len + 1);
655
+
656
+ memcpy(buf, ni->str, ni->len);
657
+ buf[ni->len] = '\0';
658
+ rnum = rb_cstr_to_inum(buf, 10, 0);
659
+ xfree(buf);
660
+ }
661
+ } else {
662
+ if (ni->neg) {
663
+ rnum = LONG2NUM(-ni->i);
664
+ } else {
665
+ rnum = LONG2NUM(ni->i);
666
+ }
667
+ }
668
+ } else { // decimal
669
+ if (ni->big) {
670
+ rnum = rb_funcall(oj_bigdecimal_class, oj_new_id, 1, rb_str_new(ni->str, ni->len));
671
+ } else {
672
+ double d = (double)ni->i + (double)ni->num / (double)ni->div;
673
+
674
+ if (ni->neg) {
675
+ d = -d;
676
+ }
677
+ if (0 != ni->exp) {
678
+ d *= pow(10.0, ni->exp);
679
+ }
680
+ rnum = rb_float_new(d);
681
+ }
682
+ }
683
+ return rnum;
684
+ }
685
+
686
+ void
687
+ oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const char *format, ...) {
688
+ va_list ap;
689
+ char msg[128];
690
+
691
+ va_start(ap, format);
692
+ vsnprintf(msg, sizeof(msg) - 1, format, ap);
693
+ va_end(ap);
694
+ pi->err.clas = err_clas;
695
+ _oj_err_set_with_location(&pi->err, err_clas, msg, pi->json, pi->cur - 1, file, line);
696
+ }
697
+
698
+ static VALUE
699
+ protect_parse(VALUE pip) {
700
+ oj_parse2((ParseInfo)pip);
701
+
702
+ return Qnil;
703
+ }
704
+
705
+ VALUE
706
+ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json) {
707
+ char *buf = 0;
708
+ VALUE input;
709
+ VALUE result = Qnil;
710
+ int line = 0;
711
+ int free_json = 0;
712
+
713
+ if (argc < 1) {
714
+ rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
715
+ }
716
+ input = argv[0];
717
+ if (2 == argc) {
718
+ oj_parse_options(argv[1], &pi->options);
719
+ }
720
+ pi->cbc = (void*)0;
721
+ if (0 != json) {
722
+ pi->json = json;
723
+ free_json = 1;
724
+ } else if (rb_type(input) == T_STRING) {
725
+ pi->json = StringValuePtr(input);
726
+ } else {
727
+ VALUE clas = rb_obj_class(input);
728
+ VALUE s;
729
+
730
+ if (oj_stringio_class == clas) {
731
+ s = rb_funcall2(input, oj_string_id, 0, 0);
732
+ pi->json = StringValuePtr(s);
733
+ #ifndef JRUBY_RUBY
734
+ #if !IS_WINDOWS
735
+ // JRuby gets confused with what is the real fileno.
736
+ } else if (rb_respond_to(input, oj_fileno_id) && Qnil != (s = rb_funcall(input, oj_fileno_id, 0))) {
737
+ int fd = FIX2INT(s);
738
+ ssize_t cnt;
739
+ size_t len = lseek(fd, 0, SEEK_END);
740
+
741
+ lseek(fd, 0, SEEK_SET);
742
+ buf = ALLOC_N(char, len + 1);
743
+ pi->json = buf;
744
+ if (0 >= (cnt = read(fd, (char*)pi->json, len)) || cnt != (ssize_t)len) {
745
+ if (0 != buf) {
746
+ xfree(buf);
747
+ }
748
+ rb_raise(rb_eIOError, "failed to read from IO Object.");
749
+ }
750
+ ((char*)pi->json)[len] = '\0';
751
+ /* skip UTF-8 BOM if present */
752
+ if (0xEF == (uint8_t)*pi->json && 0xBB == (uint8_t)pi->json[1] && 0xBF == (uint8_t)pi->json[2]) {
753
+ pi->json += 3;
754
+ }
755
+ #endif
756
+ #endif
757
+ } else if (rb_respond_to(input, oj_read_id)) {
758
+ s = rb_funcall2(input, oj_read_id, 0, 0);
759
+ pi->json = StringValuePtr(s);
760
+ } else {
761
+ rb_raise(rb_eArgError, "strict_parse() expected a String or IO Object.");
762
+ }
763
+ }
764
+ if (Yes == pi->options.circular) {
765
+ pi->circ_array = oj_circ_array_new();
766
+ } else {
767
+ pi->circ_array = 0;
768
+ }
769
+ // GC can run at any time. When it runs any Object created by C will be
770
+ // freed. This usually only happens with large files but it does happen and
771
+ // it happens more frequently on Ruby 1.8.7.
772
+ #if HAS_GC_GUARD
773
+ rb_gc_disable();
774
+ #endif
775
+ rb_protect(protect_parse, (VALUE)pi, &line);
776
+ result = stack_head_val(&pi->stack);
777
+ #if HAS_GC_GUARD
778
+ RB_GC_GUARD(result);
779
+ rb_gc_enable();
780
+ #endif
781
+ // proceed with cleanup
782
+ if (0 != pi->circ_array) {
783
+ oj_circ_array_free(pi->circ_array);
784
+ }
785
+ if (0 != buf) {
786
+ xfree(buf);
787
+ } else if (free_json) {
788
+ xfree(json);
789
+ }
790
+ stack_cleanup(&pi->stack);
791
+ if (0 != line) {
792
+ rb_jump_tag(line);
793
+ }
794
+ if (err_has(&pi->err)) {
795
+ oj_err_raise(&pi->err);
796
+ }
797
+ return result;
798
+ }