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