oj_windows 3.16.15

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