nano-safe-gem 0.0.1

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.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/nano-safe-gem.gemspec +12 -0
  3. data/oj-3.17.3/CHANGELOG.md +1506 -0
  4. data/oj-3.17.3/LICENSE +21 -0
  5. data/oj-3.17.3/README.md +103 -0
  6. data/oj-3.17.3/RELEASE_NOTES.md +61 -0
  7. data/oj-3.17.3/ext/oj/buf.h +85 -0
  8. data/oj-3.17.3/ext/oj/cache.c +329 -0
  9. data/oj-3.17.3/ext/oj/cache.h +22 -0
  10. data/oj-3.17.3/ext/oj/cache8.c +105 -0
  11. data/oj-3.17.3/ext/oj/cache8.h +21 -0
  12. data/oj-3.17.3/ext/oj/circarray.c +64 -0
  13. data/oj-3.17.3/ext/oj/circarray.h +22 -0
  14. data/oj-3.17.3/ext/oj/code.c +214 -0
  15. data/oj-3.17.3/ext/oj/code.h +40 -0
  16. data/oj-3.17.3/ext/oj/compat.c +239 -0
  17. data/oj-3.17.3/ext/oj/custom.c +1079 -0
  18. data/oj-3.17.3/ext/oj/debug.c +126 -0
  19. data/oj-3.17.3/ext/oj/dump.c +1765 -0
  20. data/oj-3.17.3/ext/oj/dump.h +112 -0
  21. data/oj-3.17.3/ext/oj/dump_compat.c +902 -0
  22. data/oj-3.17.3/ext/oj/dump_leaf.c +162 -0
  23. data/oj-3.17.3/ext/oj/dump_object.c +715 -0
  24. data/oj-3.17.3/ext/oj/dump_strict.c +404 -0
  25. data/oj-3.17.3/ext/oj/encode.h +16 -0
  26. data/oj-3.17.3/ext/oj/encoder.c +43 -0
  27. data/oj-3.17.3/ext/oj/err.c +57 -0
  28. data/oj-3.17.3/ext/oj/err.h +67 -0
  29. data/oj-3.17.3/ext/oj/extconf.rb +72 -0
  30. data/oj-3.17.3/ext/oj/fast.c +1730 -0
  31. data/oj-3.17.3/ext/oj/intern.c +313 -0
  32. data/oj-3.17.3/ext/oj/intern.h +22 -0
  33. data/oj-3.17.3/ext/oj/mem.c +318 -0
  34. data/oj-3.17.3/ext/oj/mem.h +53 -0
  35. data/oj-3.17.3/ext/oj/mimic_json.c +922 -0
  36. data/oj-3.17.3/ext/oj/object.c +726 -0
  37. data/oj-3.17.3/ext/oj/odd.c +245 -0
  38. data/oj-3.17.3/ext/oj/odd.h +43 -0
  39. data/oj-3.17.3/ext/oj/oj.c +2332 -0
  40. data/oj-3.17.3/ext/oj/oj.h +405 -0
  41. data/oj-3.17.3/ext/oj/parse.c +1367 -0
  42. data/oj-3.17.3/ext/oj/parse.h +113 -0
  43. data/oj-3.17.3/ext/oj/parser.c +1676 -0
  44. data/oj-3.17.3/ext/oj/parser.h +103 -0
  45. data/oj-3.17.3/ext/oj/rails.c +1480 -0
  46. data/oj-3.17.3/ext/oj/rails.h +18 -0
  47. data/oj-3.17.3/ext/oj/reader.c +220 -0
  48. data/oj-3.17.3/ext/oj/reader.h +137 -0
  49. data/oj-3.17.3/ext/oj/resolve.c +80 -0
  50. data/oj-3.17.3/ext/oj/resolve.h +12 -0
  51. data/oj-3.17.3/ext/oj/rxclass.c +144 -0
  52. data/oj-3.17.3/ext/oj/rxclass.h +26 -0
  53. data/oj-3.17.3/ext/oj/safe.c +230 -0
  54. data/oj-3.17.3/ext/oj/safe.h +79 -0
  55. data/oj-3.17.3/ext/oj/saj.c +677 -0
  56. data/oj-3.17.3/ext/oj/saj2.c +584 -0
  57. data/oj-3.17.3/ext/oj/saj2.h +23 -0
  58. data/oj-3.17.3/ext/oj/scp.c +185 -0
  59. data/oj-3.17.3/ext/oj/simd.h +219 -0
  60. data/oj-3.17.3/ext/oj/sparse.c +943 -0
  61. data/oj-3.17.3/ext/oj/stream_writer.c +329 -0
  62. data/oj-3.17.3/ext/oj/strict.c +187 -0
  63. data/oj-3.17.3/ext/oj/string_writer.c +517 -0
  64. data/oj-3.17.3/ext/oj/trace.c +72 -0
  65. data/oj-3.17.3/ext/oj/trace.h +55 -0
  66. data/oj-3.17.3/ext/oj/usual.c +1231 -0
  67. data/oj-3.17.3/ext/oj/usual.h +69 -0
  68. data/oj-3.17.3/ext/oj/util.c +136 -0
  69. data/oj-3.17.3/ext/oj/util.h +20 -0
  70. data/oj-3.17.3/ext/oj/val_stack.c +101 -0
  71. data/oj-3.17.3/ext/oj/val_stack.h +151 -0
  72. data/oj-3.17.3/ext/oj/validate.c +46 -0
  73. data/oj-3.17.3/ext/oj/wab.c +586 -0
  74. data/oj-3.17.3/lib/oj/active_support_helper.rb +39 -0
  75. data/oj-3.17.3/lib/oj/bag.rb +95 -0
  76. data/oj-3.17.3/lib/oj/easy_hash.rb +52 -0
  77. data/oj-3.17.3/lib/oj/error.rb +21 -0
  78. data/oj-3.17.3/lib/oj/json.rb +188 -0
  79. data/oj-3.17.3/lib/oj/mimic.rb +301 -0
  80. data/oj-3.17.3/lib/oj/saj.rb +80 -0
  81. data/oj-3.17.3/lib/oj/schandler.rb +143 -0
  82. data/oj-3.17.3/lib/oj/state.rb +135 -0
  83. data/oj-3.17.3/lib/oj/version.rb +4 -0
  84. data/oj-3.17.3/lib/oj.rb +15 -0
  85. data/oj-3.17.3/pages/Advanced.md +22 -0
  86. data/oj-3.17.3/pages/Compatibility.md +25 -0
  87. data/oj-3.17.3/pages/Custom.md +23 -0
  88. data/oj-3.17.3/pages/Encoding.md +65 -0
  89. data/oj-3.17.3/pages/InstallOptions.md +20 -0
  90. data/oj-3.17.3/pages/JsonGem.md +94 -0
  91. data/oj-3.17.3/pages/Modes.md +161 -0
  92. data/oj-3.17.3/pages/Options.md +337 -0
  93. data/oj-3.17.3/pages/Parser.md +309 -0
  94. data/oj-3.17.3/pages/Rails.md +167 -0
  95. data/oj-3.17.3/pages/Security.md +20 -0
  96. data/oj-3.17.3/pages/WAB.md +13 -0
  97. metadata +136 -0
@@ -0,0 +1,943 @@
1
+ // Copyright (c) 2013 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #include <math.h>
5
+ #include <stdio.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
8
+ #include <unistd.h>
9
+
10
+ #include "buf.h"
11
+ #include "encode.h"
12
+ #include "intern.h" // for oj_strndup()
13
+ #include "mem.h"
14
+ #include "oj.h"
15
+ #include "parse.h"
16
+ #include "val_stack.h"
17
+
18
+ // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
19
+ #define OJ_INFINITY (1.0 / 0.0)
20
+
21
+ #ifdef RUBINIUS_RUBY
22
+ #define NUM_MAX 0x07FFFFFF
23
+ #else
24
+ #define NUM_MAX (FIXNUM_MAX >> 8)
25
+ #endif
26
+ #define EXP_MAX 100000
27
+ #define DEC_MAX 15
28
+
29
+ static void skip_comment(ParseInfo pi) {
30
+ char c = reader_get(&pi->rd);
31
+
32
+ if ('*' == c) {
33
+ while ('\0' != (c = reader_get(&pi->rd))) {
34
+ if ('*' == c) {
35
+ c = reader_get(&pi->rd);
36
+ if ('/' == c) {
37
+ return;
38
+ }
39
+ }
40
+ }
41
+ } else if ('/' == c) {
42
+ while ('\0' != (c = reader_get(&pi->rd))) {
43
+ switch (c) {
44
+ case '\n':
45
+ case '\r':
46
+ case '\f':
47
+ case '\0': return;
48
+ default: break;
49
+ }
50
+ }
51
+ } else {
52
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid comment format");
53
+ }
54
+ if ('\0' == c) {
55
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "comment not terminated");
56
+ return;
57
+ }
58
+ }
59
+
60
+ static void add_value(ParseInfo pi, VALUE rval) {
61
+ Val parent = stack_peek(&pi->stack);
62
+
63
+ if (0 == parent) { // simple add
64
+ pi->add_value(pi, rval);
65
+ } else {
66
+ switch (parent->next) {
67
+ case NEXT_ARRAY_NEW:
68
+ case NEXT_ARRAY_ELEMENT:
69
+ pi->array_append_value(pi, rval);
70
+ parent->next = NEXT_ARRAY_COMMA;
71
+ break;
72
+ case NEXT_HASH_VALUE:
73
+ pi->hash_set_value(pi, parent, rval);
74
+ if (parent->kalloc) {
75
+ OJ_R_FREE((char *)parent->key);
76
+ }
77
+ parent->key = 0;
78
+ parent->kalloc = 0;
79
+ parent->next = NEXT_HASH_COMMA;
80
+ break;
81
+ case NEXT_HASH_NEW:
82
+ case NEXT_HASH_KEY:
83
+ case NEXT_HASH_COMMA:
84
+ case NEXT_NONE:
85
+ case NEXT_ARRAY_COMMA:
86
+ case NEXT_HASH_COLON:
87
+ default:
88
+ oj_set_error_at(pi,
89
+ oj_parse_error_class,
90
+ __FILE__,
91
+ __LINE__,
92
+ "expected %s",
93
+ oj_stack_next_string(parent->next));
94
+ break;
95
+ }
96
+ }
97
+ }
98
+
99
+ static void add_num_value(ParseInfo pi, NumInfo ni) {
100
+ Val parent = stack_peek(&pi->stack);
101
+
102
+ if (0 == parent) {
103
+ pi->add_num(pi, ni);
104
+ } else {
105
+ switch (parent->next) {
106
+ case NEXT_ARRAY_NEW:
107
+ case NEXT_ARRAY_ELEMENT:
108
+ pi->array_append_num(pi, ni);
109
+ parent->next = NEXT_ARRAY_COMMA;
110
+ break;
111
+ case NEXT_HASH_VALUE:
112
+ pi->hash_set_num(pi, parent, ni);
113
+ if (parent->kalloc) {
114
+ OJ_R_FREE((char *)parent->key);
115
+ }
116
+ parent->key = 0;
117
+ parent->kalloc = 0;
118
+ parent->next = NEXT_HASH_COMMA;
119
+ break;
120
+ default:
121
+ oj_set_error_at(pi,
122
+ oj_parse_error_class,
123
+ __FILE__,
124
+ __LINE__,
125
+ "expected %s",
126
+ oj_stack_next_string(parent->next));
127
+ break;
128
+ }
129
+ }
130
+ }
131
+
132
+ static void read_true(ParseInfo pi) {
133
+ if (0 == reader_expect(&pi->rd, "rue")) {
134
+ add_value(pi, Qtrue);
135
+ } else {
136
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected true");
137
+ }
138
+ }
139
+
140
+ static void read_false(ParseInfo pi) {
141
+ if (0 == reader_expect(&pi->rd, "alse")) {
142
+ add_value(pi, Qfalse);
143
+ } else {
144
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected false");
145
+ }
146
+ }
147
+
148
+ static uint32_t read_hex(ParseInfo pi) {
149
+ uint32_t b = 0;
150
+ int i;
151
+ char c;
152
+
153
+ for (i = 0; i < 4; i++) {
154
+ c = reader_get(&pi->rd);
155
+ b = b << 4;
156
+ if ('0' <= c && c <= '9') {
157
+ b += c - '0';
158
+ } else if ('A' <= c && c <= 'F') {
159
+ b += c - 'A' + 10;
160
+ } else if ('a' <= c && c <= 'f') {
161
+ b += c - 'a' + 10;
162
+ } else {
163
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hex character");
164
+ return 0;
165
+ }
166
+ }
167
+ return b;
168
+ }
169
+
170
+ static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
171
+ if (0x0000007F >= code) {
172
+ buf_append(buf, (char)code);
173
+ } else if (0x000007FF >= code) {
174
+ buf_append(buf, 0xC0 | (code >> 6));
175
+ buf_append(buf, 0x80 | (0x3F & code));
176
+ } else if (0x0000FFFF >= code) {
177
+ buf_append(buf, 0xE0 | (code >> 12));
178
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
179
+ buf_append(buf, 0x80 | (0x3F & code));
180
+ } else if (0x001FFFFF >= code) {
181
+ buf_append(buf, 0xF0 | (code >> 18));
182
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
183
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
184
+ buf_append(buf, 0x80 | (0x3F & code));
185
+ } else if (0x03FFFFFF >= code) {
186
+ buf_append(buf, 0xF8 | (code >> 24));
187
+ buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
188
+ buf_append(buf, 0x80 | ((code >> 12) & 0x3F));
189
+ buf_append(buf, 0x80 | ((code >> 6) & 0x3F));
190
+ buf_append(buf, 0x80 | (0x3F & code));
191
+ } else if (0x7FFFFFFF >= code) {
192
+ buf_append(buf, 0xFC | (code >> 30));
193
+ buf_append(buf, 0x80 | ((code >> 24) & 0x3F));
194
+ buf_append(buf, 0x80 | ((code >> 18) & 0x3F));
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 {
199
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid Unicode character");
200
+ }
201
+ }
202
+
203
+ // entered at backslash
204
+ static void read_escaped_str(ParseInfo pi) {
205
+ struct _buf buf;
206
+ char c;
207
+ uint32_t code;
208
+ Val parent = stack_peek(&pi->stack);
209
+
210
+ buf_init(&buf);
211
+ if (pi->rd.str < pi->rd.tail) {
212
+ buf_append_string(&buf, pi->rd.str, pi->rd.tail - pi->rd.str);
213
+ }
214
+ while ('\"' != (c = reader_get(&pi->rd))) {
215
+ if ('\0' == c) {
216
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
217
+ buf_cleanup(&buf);
218
+ return;
219
+ } else if ('\\' == c) {
220
+ c = reader_get(&pi->rd);
221
+ switch (c) {
222
+ case 'n': buf_append(&buf, '\n'); break;
223
+ case 'r': buf_append(&buf, '\r'); break;
224
+ case 't': buf_append(&buf, '\t'); break;
225
+ case 'f': buf_append(&buf, '\f'); break;
226
+ case 'b': buf_append(&buf, '\b'); break;
227
+ case '"': buf_append(&buf, '"'); break;
228
+ case '/': buf_append(&buf, '/'); break;
229
+ case '\\': buf_append(&buf, '\\'); break;
230
+ case 'u':
231
+ if (0 == (code = read_hex(pi)) && err_has(&pi->err)) {
232
+ buf_cleanup(&buf);
233
+ return;
234
+ }
235
+ if (0x0000D800 <= code && code <= 0x0000DFFF) {
236
+ uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
237
+ uint32_t c2;
238
+ char ch2;
239
+
240
+ c = reader_get(&pi->rd);
241
+ ch2 = reader_get(&pi->rd);
242
+ if ('\\' != c || 'u' != ch2) {
243
+ if (Yes == pi->options.allow_invalid) {
244
+ unicode_to_chars(pi, &buf, code);
245
+ reader_backup(&pi->rd);
246
+ reader_backup(&pi->rd);
247
+ break;
248
+ }
249
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
250
+ buf_cleanup(&buf);
251
+ return;
252
+ }
253
+ if (0 == (c2 = read_hex(pi)) && err_has(&pi->err)) {
254
+ buf_cleanup(&buf);
255
+ return;
256
+ }
257
+ c2 = (c2 - 0x0000DC00) & 0x000003FF;
258
+ code = ((c1 << 10) | c2) + 0x00010000;
259
+ }
260
+ unicode_to_chars(pi, &buf, code);
261
+ if (err_has(&pi->err)) {
262
+ buf_cleanup(&buf);
263
+ return;
264
+ }
265
+ break;
266
+ default:
267
+ // The json gem claims this is not an error despite the
268
+ // ECMA-404 indicating it is not valid.
269
+ if (CompatMode == pi->options.mode) {
270
+ buf_append(&buf, c);
271
+ break;
272
+ }
273
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
274
+ buf_cleanup(&buf);
275
+ return;
276
+ }
277
+ } else {
278
+ buf_append(&buf, c);
279
+ }
280
+ }
281
+ if (0 == parent) {
282
+ pi->add_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
283
+ } else {
284
+ switch (parent->next) {
285
+ case NEXT_ARRAY_NEW:
286
+ case NEXT_ARRAY_ELEMENT:
287
+ pi->array_append_cstr(pi, buf.head, buf_len(&buf), pi->rd.str);
288
+ parent->next = NEXT_ARRAY_COMMA;
289
+ break;
290
+ case NEXT_HASH_NEW:
291
+ case NEXT_HASH_KEY:
292
+ if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
293
+ parent->klen = buf_len(&buf);
294
+ parent->key = malloc(parent->klen + 1);
295
+ memcpy((char *)parent->key, buf.head, parent->klen);
296
+ *(char *)(parent->key + parent->klen) = '\0';
297
+ } else {
298
+ parent->key = "";
299
+ parent->klen = 0;
300
+ }
301
+ parent->k1 = *pi->rd.str;
302
+ parent->next = NEXT_HASH_COLON;
303
+ break;
304
+ case NEXT_HASH_VALUE:
305
+ pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), pi->rd.str);
306
+ if (parent->kalloc) {
307
+ OJ_R_FREE((char *)parent->key);
308
+ }
309
+ parent->key = 0;
310
+ parent->kalloc = 0;
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,
319
+ oj_parse_error_class,
320
+ __FILE__,
321
+ __LINE__,
322
+ "expected %s, not a string",
323
+ oj_stack_next_string(parent->next));
324
+ break;
325
+ }
326
+ }
327
+ buf_cleanup(&buf);
328
+ }
329
+
330
+ static void read_str(ParseInfo pi) {
331
+ Val parent = stack_peek(&pi->stack);
332
+ char c;
333
+
334
+ reader_protect(&pi->rd);
335
+ while ('\"' != (c = reader_get(&pi->rd))) {
336
+ if ('\0' == c) {
337
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
338
+ return;
339
+ } else if ('\\' == c) {
340
+ reader_backup(&pi->rd);
341
+ read_escaped_str(pi);
342
+ reader_release(&pi->rd);
343
+ return;
344
+ }
345
+ }
346
+ if (0 == parent) { // simple add
347
+ pi->add_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
348
+ } else {
349
+ switch (parent->next) {
350
+ case NEXT_ARRAY_NEW:
351
+ case NEXT_ARRAY_ELEMENT:
352
+ pi->array_append_cstr(pi, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
353
+ parent->next = NEXT_ARRAY_COMMA;
354
+ break;
355
+ case NEXT_HASH_NEW:
356
+ case NEXT_HASH_KEY:
357
+ parent->klen = pi->rd.tail - pi->rd.str - 1;
358
+ if (sizeof(parent->karray) <= parent->klen) {
359
+ parent->key = oj_strndup(pi->rd.str, parent->klen);
360
+ parent->kalloc = 1;
361
+ } else {
362
+ memcpy(parent->karray, pi->rd.str, parent->klen);
363
+ parent->karray[parent->klen] = '\0';
364
+ parent->key = parent->karray;
365
+ parent->kalloc = 0;
366
+ }
367
+ parent->key_val = pi->hash_key(pi, parent->key, parent->klen);
368
+ parent->k1 = *pi->rd.str;
369
+ parent->next = NEXT_HASH_COLON;
370
+ break;
371
+ case NEXT_HASH_VALUE:
372
+ pi->hash_set_cstr(pi, parent, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
373
+ if (parent->kalloc) {
374
+ OJ_R_FREE((char *)parent->key);
375
+ }
376
+ parent->key = 0;
377
+ parent->kalloc = 0;
378
+ parent->next = NEXT_HASH_COMMA;
379
+ break;
380
+ case NEXT_HASH_COMMA:
381
+ case NEXT_NONE:
382
+ case NEXT_ARRAY_COMMA:
383
+ case NEXT_HASH_COLON:
384
+ default:
385
+ oj_set_error_at(pi,
386
+ oj_parse_error_class,
387
+ __FILE__,
388
+ __LINE__,
389
+ "expected %s, not a string",
390
+ oj_stack_next_string(parent->next));
391
+ break;
392
+ }
393
+ }
394
+ reader_release(&pi->rd);
395
+ }
396
+
397
+ static void read_num(ParseInfo pi) {
398
+ struct _numInfo ni;
399
+ char c;
400
+
401
+ reader_protect(&pi->rd);
402
+ ni.pi = pi;
403
+ ni.i = 0;
404
+ ni.num = 0;
405
+ ni.div = 1;
406
+ ni.di = 0;
407
+ ni.len = 0;
408
+ ni.exp = 0;
409
+ ni.big = 0;
410
+ ni.infinity = 0;
411
+ ni.nan = 0;
412
+ ni.neg = 0;
413
+ ni.has_exp = 0;
414
+ if (CompatMode == pi->options.mode) {
415
+ ni.no_big = !pi->options.compat_bigdec;
416
+ ni.bigdec_load = pi->options.compat_bigdec;
417
+ } else {
418
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
419
+ RubyDec == pi->options.bigdec_load);
420
+ ni.bigdec_load = pi->options.bigdec_load;
421
+ }
422
+
423
+ c = reader_get(&pi->rd);
424
+ if ('-' == c) {
425
+ c = reader_get(&pi->rd);
426
+ ni.neg = 1;
427
+ } else if ('+' == c) {
428
+ c = reader_get(&pi->rd);
429
+ }
430
+ if ('I' == c) {
431
+ if (No == pi->options.allow_nan) {
432
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
433
+ return;
434
+ } else if (0 != reader_expect(&pi->rd, "nfinity")) {
435
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
436
+ return;
437
+ }
438
+ ni.infinity = 1;
439
+ } else {
440
+ int dec_cnt = 0;
441
+ bool zero1 = false;
442
+
443
+ for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
444
+ if (0 == ni.i && '0' == c) {
445
+ zero1 = true;
446
+ }
447
+ if (0 < ni.i) {
448
+ dec_cnt++;
449
+ }
450
+ if (ni.big) {
451
+ ni.big++;
452
+ } else {
453
+ int d = (c - '0');
454
+
455
+ if (0 < d) {
456
+ if (zero1 && CompatMode == pi->options.mode) {
457
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
458
+ return;
459
+ }
460
+ zero1 = false;
461
+ }
462
+ ni.i = ni.i * 10 + d;
463
+ if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
464
+ ni.big = 1;
465
+ }
466
+ }
467
+ }
468
+ if ('.' == c) {
469
+ c = reader_get(&pi->rd);
470
+ // A trailing . is not a valid decimal but if encountered allow it
471
+ // except when mimicking the JSON gem.
472
+ if (CompatMode == pi->options.mode) {
473
+ if (c < '0' || '9' < c) {
474
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
475
+ }
476
+ }
477
+ for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
478
+ int d = (c - '0');
479
+
480
+ if (0 < ni.num || 0 < ni.i) {
481
+ dec_cnt++;
482
+ }
483
+ if (INT64_MAX <= ni.div) {
484
+ if (!ni.no_big) {
485
+ ni.big = true;
486
+ }
487
+ } else {
488
+ ni.num = ni.num * 10 + d;
489
+ ni.div *= 10;
490
+ ni.di++;
491
+ if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
492
+ if (!ni.no_big) {
493
+ ni.big = true;
494
+ }
495
+ }
496
+ }
497
+ }
498
+ }
499
+ if ('e' == c || 'E' == c) {
500
+ int eneg = 0;
501
+
502
+ ni.has_exp = 1;
503
+ c = reader_get(&pi->rd);
504
+ if ('-' == c) {
505
+ c = reader_get(&pi->rd);
506
+ eneg = 1;
507
+ } else if ('+' == c) {
508
+ c = reader_get(&pi->rd);
509
+ }
510
+ for (; '0' <= c && c <= '9'; c = reader_get(&pi->rd)) {
511
+ ni.exp = ni.exp * 10 + (c - '0');
512
+ if (EXP_MAX <= ni.exp) {
513
+ ni.big = 1;
514
+ }
515
+ }
516
+ if (eneg) {
517
+ ni.exp = -ni.exp;
518
+ }
519
+ }
520
+ ni.len = pi->rd.tail - pi->rd.str;
521
+ if (0 != c) {
522
+ reader_backup(&pi->rd);
523
+ }
524
+ }
525
+ ni.str = pi->rd.str;
526
+ ni.len = pi->rd.tail - pi->rd.str;
527
+ // Check for special reserved values for Infinity and NaN.
528
+ if (ni.big) {
529
+ if (0 == strcasecmp(INF_VAL, ni.str)) {
530
+ ni.infinity = 1;
531
+ } else if (0 == strcasecmp(NINF_VAL, ni.str)) {
532
+ ni.infinity = 1;
533
+ ni.neg = 1;
534
+ } else if (0 == strcasecmp(NAN_VAL, ni.str)) {
535
+ ni.nan = 1;
536
+ }
537
+ }
538
+ if (CompatMode == pi->options.mode) {
539
+ if (pi->options.compat_bigdec) {
540
+ ni.big = 1;
541
+ }
542
+ } else if (BigDec == pi->options.bigdec_load) {
543
+ ni.big = 1;
544
+ }
545
+ add_num_value(pi, &ni);
546
+ reader_release(&pi->rd);
547
+ }
548
+
549
+ static void read_nan(ParseInfo pi) {
550
+ struct _numInfo ni;
551
+ char c;
552
+
553
+ ni.pi = pi;
554
+ ni.str = pi->rd.str;
555
+ ni.i = 0;
556
+ ni.num = 0;
557
+ ni.div = 1;
558
+ ni.di = 0;
559
+ ni.len = 0;
560
+ ni.exp = 0;
561
+ ni.big = 0;
562
+ ni.infinity = 0;
563
+ ni.nan = 1;
564
+ ni.neg = 0;
565
+ if (CompatMode == pi->options.mode) {
566
+ ni.no_big = !pi->options.compat_bigdec;
567
+ ni.bigdec_load = pi->options.compat_bigdec;
568
+ } else {
569
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
570
+ RubyDec == pi->options.bigdec_load);
571
+ ni.bigdec_load = pi->options.bigdec_load;
572
+ }
573
+
574
+ if ('a' != reader_get(&pi->rd) || ('N' != (c = reader_get(&pi->rd)) && 'n' != c)) {
575
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
576
+ return;
577
+ }
578
+ if (CompatMode == pi->options.mode) {
579
+ if (pi->options.compat_bigdec) {
580
+ ni.big = 1;
581
+ }
582
+ } else if (BigDec == pi->options.bigdec_load) {
583
+ ni.big = 1;
584
+ }
585
+ add_num_value(pi, &ni);
586
+ }
587
+
588
+ static void array_start(ParseInfo pi) {
589
+ VALUE v = pi->start_array(pi);
590
+
591
+ stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
592
+ }
593
+
594
+ static void array_end(ParseInfo pi) {
595
+ Val array = stack_pop(&pi->stack);
596
+
597
+ if (0 == array) {
598
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected array close");
599
+ } else if (NEXT_ARRAY_COMMA != array->next && NEXT_ARRAY_NEW != array->next) {
600
+ oj_set_error_at(pi,
601
+ oj_parse_error_class,
602
+ __FILE__,
603
+ __LINE__,
604
+ "expected %s, not an array close",
605
+ oj_stack_next_string(array->next));
606
+ } else {
607
+ pi->end_array(pi);
608
+ add_value(pi, array->val);
609
+ }
610
+ }
611
+
612
+ static void hash_start(ParseInfo pi) {
613
+ volatile VALUE v = pi->start_hash(pi);
614
+
615
+ stack_push(&pi->stack, v, NEXT_HASH_NEW);
616
+ }
617
+
618
+ static void hash_end(ParseInfo pi) {
619
+ volatile Val hash = stack_peek(&pi->stack);
620
+
621
+ // leave hash on stack until just before
622
+ if (0 == hash) {
623
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected hash close");
624
+ } else if (NEXT_HASH_COMMA != hash->next && NEXT_HASH_NEW != hash->next) {
625
+ oj_set_error_at(pi,
626
+ oj_parse_error_class,
627
+ __FILE__,
628
+ __LINE__,
629
+ "expected %s, not a hash close",
630
+ oj_stack_next_string(hash->next));
631
+ } else {
632
+ pi->end_hash(pi);
633
+ stack_pop(&pi->stack);
634
+ add_value(pi, hash->val);
635
+ }
636
+ }
637
+
638
+ static void comma(ParseInfo pi) {
639
+ Val parent = stack_peek(&pi->stack);
640
+
641
+ if (0 == parent) {
642
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
643
+ } else if (NEXT_ARRAY_COMMA == parent->next) {
644
+ parent->next = NEXT_ARRAY_ELEMENT;
645
+ } else if (NEXT_HASH_COMMA == parent->next) {
646
+ parent->next = NEXT_HASH_KEY;
647
+ } else {
648
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected comma");
649
+ }
650
+ }
651
+
652
+ static void colon(ParseInfo pi) {
653
+ Val parent = stack_peek(&pi->stack);
654
+
655
+ if (0 != parent && NEXT_HASH_COLON == parent->next) {
656
+ parent->next = NEXT_HASH_VALUE;
657
+ } else {
658
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected colon");
659
+ }
660
+ }
661
+
662
+ void oj_sparse2(ParseInfo pi) {
663
+ int first = 1;
664
+ char c;
665
+ long start = 0;
666
+
667
+ err_init(&pi->err);
668
+ while (1) {
669
+ if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
670
+ VALUE err_clas = oj_get_json_err_class("NestingError");
671
+
672
+ oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
673
+ pi->err_class = err_clas;
674
+ return;
675
+ }
676
+ c = reader_next_non_white(&pi->rd);
677
+ if (!first && '\0' != c) {
678
+ oj_set_error_at(pi,
679
+ oj_parse_error_class,
680
+ __FILE__,
681
+ __LINE__,
682
+ "unexpected characters after the JSON document");
683
+ }
684
+ switch (c) {
685
+ case '{': hash_start(pi); break;
686
+ case '}': hash_end(pi); break;
687
+ case ':': colon(pi); break;
688
+ case '[': array_start(pi); break;
689
+ case ']': array_end(pi); break;
690
+ case ',': comma(pi); break;
691
+ case '"': read_str(pi); break;
692
+ case '+':
693
+ if (CompatMode == pi->options.mode) {
694
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
695
+ return;
696
+ }
697
+ pi->cur--;
698
+ read_num(pi);
699
+ break;
700
+ case '-':
701
+ case '0':
702
+ case '1':
703
+ case '2':
704
+ case '3':
705
+ case '4':
706
+ case '5':
707
+ case '6':
708
+ case '7':
709
+ case '8':
710
+ case '9':
711
+ reader_backup(&pi->rd);
712
+ read_num(pi);
713
+ break;
714
+ case 'I':
715
+ if (Yes == pi->options.allow_nan) {
716
+ reader_backup(&pi->rd);
717
+ read_num(pi);
718
+ } else {
719
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
720
+ return;
721
+ }
722
+ break;
723
+ case 'N':
724
+ if (Yes == pi->options.allow_nan) {
725
+ read_nan(pi);
726
+ } else {
727
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
728
+ return;
729
+ }
730
+ break;
731
+ case 't': read_true(pi); break;
732
+ case 'f': read_false(pi); break;
733
+ case 'n':
734
+ c = reader_get(&pi->rd);
735
+ if ('u' == c) {
736
+ if (0 == reader_expect(&pi->rd, "ll")) {
737
+ add_value(pi, Qnil);
738
+ } else {
739
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected null");
740
+ return;
741
+ }
742
+ } else if ('a' == c) {
743
+ struct _numInfo ni;
744
+
745
+ c = reader_get(&pi->rd);
746
+ if ('N' != c && 'n' != c) {
747
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected NaN");
748
+ return;
749
+ }
750
+ ni.pi = pi;
751
+ ni.str = pi->rd.str;
752
+ ni.i = 0;
753
+ ni.num = 0;
754
+ ni.div = 1;
755
+ ni.di = 0;
756
+ ni.len = 0;
757
+ ni.exp = 0;
758
+ ni.big = 0;
759
+ ni.infinity = 0;
760
+ ni.nan = 1;
761
+ ni.neg = 0;
762
+ if (CompatMode == pi->options.mode) {
763
+ ni.no_big = !pi->options.compat_bigdec;
764
+ ni.bigdec_load = pi->options.compat_bigdec;
765
+ } else {
766
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
767
+ RubyDec == pi->options.bigdec_load);
768
+ ni.bigdec_load = pi->options.bigdec_load;
769
+ }
770
+ add_num_value(pi, &ni);
771
+ } else {
772
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid token");
773
+ return;
774
+ }
775
+ break;
776
+ case '/': skip_comment(pi); break;
777
+ case '\0': return;
778
+ default:
779
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character '%c' [0x%02x]", c, c);
780
+ return;
781
+ }
782
+ if (err_has(&pi->err)) {
783
+ return;
784
+ }
785
+ if (stack_empty(&pi->stack)) {
786
+ if (Qundef != pi->proc) {
787
+ VALUE args[3];
788
+ long len = pi->rd.pos - start;
789
+
790
+ *args = stack_head_val(&pi->stack);
791
+ args[1] = LONG2NUM(start);
792
+ args[2] = LONG2NUM(len);
793
+
794
+ if (Qnil == pi->proc) {
795
+ rb_yield_values2(3, args);
796
+ } else {
797
+ rb_proc_call_with_block(pi->proc, 3, args, Qnil);
798
+ }
799
+ } else if (!pi->has_callbacks) {
800
+ first = 0;
801
+ }
802
+ start = pi->rd.pos;
803
+ // TBD break if option set to allow that
804
+ }
805
+ }
806
+ }
807
+
808
+ static VALUE protect_parse(VALUE pip) {
809
+ oj_sparse2((ParseInfo)pip);
810
+
811
+ return Qnil;
812
+ }
813
+
814
+ VALUE
815
+ oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
816
+ volatile VALUE input;
817
+ volatile VALUE wrapped_stack;
818
+ VALUE result = Qnil;
819
+ int line = 0;
820
+
821
+ if (argc < 1) {
822
+ rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
823
+ }
824
+ input = argv[0];
825
+ if (2 <= argc) {
826
+ if (T_HASH == rb_type(argv[1])) {
827
+ oj_parse_options(argv[1], &pi->options);
828
+ } else if (3 <= argc && T_HASH == rb_type(argv[2])) {
829
+ oj_parse_options(argv[2], &pi->options);
830
+ }
831
+ }
832
+ if (Qnil == input) {
833
+ if (Yes == pi->options.nilnil) {
834
+ return Qnil;
835
+ } else {
836
+ rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
837
+ }
838
+ } else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) && No == pi->options.nilnil &&
839
+ 0 == RSTRING_LEN(input)) {
840
+ rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string.");
841
+ }
842
+ if (rb_block_given_p()) {
843
+ pi->proc = Qnil;
844
+ } else {
845
+ pi->proc = Qundef;
846
+ }
847
+ oj_reader_init(&pi->rd, input, fd, CompatMode == pi->options.mode);
848
+ pi->json = 0; // indicates reader is in use
849
+
850
+ if (Yes == pi->options.circular) {
851
+ pi->circ_array = oj_circ_array_new();
852
+ } else {
853
+ pi->circ_array = 0;
854
+ }
855
+ if (No == pi->options.allow_gc) {
856
+ rb_gc_disable();
857
+ }
858
+ // GC can run at any time. When it runs any Object created by C will be
859
+ // freed. We protect against this by wrapping the value stack in a ruby
860
+ // data object and providing a mark function for ruby objects on the
861
+ // value stack (while it is in scope).
862
+ wrapped_stack = oj_stack_init(&pi->stack);
863
+ rb_protect(protect_parse, (VALUE)pi, &line);
864
+ if (Qundef == pi->stack.head->val && !empty_ok(&pi->options)) {
865
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Empty input");
866
+ }
867
+ result = stack_head_val(&pi->stack);
868
+ DATA_PTR(wrapped_stack) = 0;
869
+ if (No == pi->options.allow_gc) {
870
+ rb_gc_enable();
871
+ }
872
+ if (!err_has(&pi->err)) {
873
+ // If the stack is not empty then the JSON terminated early.
874
+ Val v;
875
+ VALUE err_class = oj_parse_error_class;
876
+
877
+ if (0 != line) {
878
+ VALUE ec = rb_obj_class(rb_errinfo());
879
+
880
+ if (rb_eIOError != ec) {
881
+ goto CLEANUP;
882
+ }
883
+ // Sometimes the class of the error is 0 which seems broken.
884
+ if (rb_eArgError != ec && 0 != ec) {
885
+ err_class = ec;
886
+ }
887
+ }
888
+ if (0 != (v = stack_peek(&pi->stack))) {
889
+ switch (v->next) {
890
+ case NEXT_ARRAY_NEW:
891
+ case NEXT_ARRAY_ELEMENT:
892
+ case NEXT_ARRAY_COMMA: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); break;
893
+ case NEXT_HASH_NEW:
894
+ case NEXT_HASH_KEY:
895
+ case NEXT_HASH_COLON:
896
+ case NEXT_HASH_VALUE:
897
+ case NEXT_HASH_COMMA:
898
+ oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Hash/Object not terminated");
899
+ break;
900
+ default: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "not terminated");
901
+ }
902
+ }
903
+ }
904
+ CLEANUP:
905
+ // proceed with cleanup
906
+ if (0 != pi->circ_array) {
907
+ oj_circ_array_free(pi->circ_array);
908
+ }
909
+ stack_cleanup(&pi->stack);
910
+ if (0 != fd) {
911
+ #ifdef _WIN32
912
+ rb_w32_close(fd);
913
+ #else
914
+ close(fd);
915
+ #endif
916
+ }
917
+ if (err_has(&pi->err)) {
918
+ rb_set_errinfo(Qnil);
919
+ if (Qnil != pi->err_class && 0 != pi->err_class) {
920
+ pi->err.clas = pi->err_class;
921
+ }
922
+ if (CompatMode == pi->options.mode && Yes != pi->options.safe) {
923
+ // The json gem requires the error message be UTF-8 encoded. In
924
+ // additional the complete JSON source should be returned but that
925
+ // is not possible without stored all the bytes read and reading
926
+ // the remaining bytes on the stream. Both seem like a very bad
927
+ // idea.
928
+ VALUE args[] = {oj_encode(rb_str_new2(pi->err.msg))};
929
+
930
+ if (pi->err.clas == oj_parse_error_class) {
931
+ // The error was an Oj::ParseError so change to a JSON::ParserError.
932
+ pi->err.clas = oj_json_parser_error_class;
933
+ }
934
+ rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
935
+ } else {
936
+ oj_err_raise(&pi->err);
937
+ }
938
+ oj_err_raise(&pi->err);
939
+ } else if (0 != line) {
940
+ rb_jump_tag(line);
941
+ }
942
+ return result;
943
+ }