oj 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +17 -23
  3. data/README.md +74 -425
  4. data/ext/oj/buf.h +103 -0
  5. data/ext/oj/cache8.c +4 -0
  6. data/ext/oj/circarray.c +68 -0
  7. data/ext/oj/circarray.h +23 -0
  8. data/ext/oj/code.c +227 -0
  9. data/ext/oj/code.h +40 -0
  10. data/ext/oj/compat.c +243 -0
  11. data/ext/oj/custom.c +1097 -0
  12. data/ext/oj/dump.c +766 -1534
  13. data/ext/oj/dump.h +92 -0
  14. data/ext/oj/dump_compat.c +937 -0
  15. data/ext/oj/dump_leaf.c +254 -0
  16. data/ext/oj/dump_object.c +810 -0
  17. data/ext/oj/dump_rails.c +329 -0
  18. data/ext/oj/dump_strict.c +416 -0
  19. data/ext/oj/encode.h +51 -0
  20. data/ext/oj/err.c +57 -0
  21. data/ext/oj/err.h +70 -0
  22. data/ext/oj/extconf.rb +17 -7
  23. data/ext/oj/fast.c +213 -180
  24. data/ext/oj/hash.c +163 -0
  25. data/ext/oj/hash.h +46 -0
  26. data/ext/oj/hash_test.c +512 -0
  27. data/ext/oj/mimic_json.c +817 -0
  28. data/ext/oj/mimic_rails.c +806 -0
  29. data/ext/oj/mimic_rails.h +17 -0
  30. data/ext/oj/object.c +752 -0
  31. data/ext/oj/odd.c +230 -0
  32. data/ext/oj/odd.h +44 -0
  33. data/ext/oj/oj.c +1288 -929
  34. data/ext/oj/oj.h +240 -69
  35. data/ext/oj/parse.c +1014 -0
  36. data/ext/oj/parse.h +92 -0
  37. data/ext/oj/reader.c +223 -0
  38. data/ext/oj/reader.h +151 -0
  39. data/ext/oj/resolve.c +127 -0
  40. data/ext/oj/{cache.h → resolve.h} +6 -13
  41. data/ext/oj/rxclass.c +133 -0
  42. data/ext/oj/rxclass.h +27 -0
  43. data/ext/oj/saj.c +77 -175
  44. data/ext/oj/scp.c +224 -0
  45. data/ext/oj/sparse.c +911 -0
  46. data/ext/oj/stream_writer.c +301 -0
  47. data/ext/oj/strict.c +162 -0
  48. data/ext/oj/string_writer.c +480 -0
  49. data/ext/oj/val_stack.c +98 -0
  50. data/ext/oj/val_stack.h +188 -0
  51. data/lib/oj/active_support_helper.rb +41 -0
  52. data/lib/oj/bag.rb +6 -10
  53. data/lib/oj/easy_hash.rb +52 -0
  54. data/lib/oj/json.rb +172 -0
  55. data/lib/oj/mimic.rb +260 -5
  56. data/lib/oj/saj.rb +13 -10
  57. data/lib/oj/schandler.rb +142 -0
  58. data/lib/oj/state.rb +131 -0
  59. data/lib/oj/version.rb +1 -1
  60. data/lib/oj.rb +11 -23
  61. data/pages/Advanced.md +22 -0
  62. data/pages/Compatibility.md +25 -0
  63. data/pages/Custom.md +23 -0
  64. data/pages/Encoding.md +65 -0
  65. data/pages/JsonGem.md +79 -0
  66. data/pages/Modes.md +140 -0
  67. data/pages/Options.md +250 -0
  68. data/pages/Rails.md +60 -0
  69. data/pages/Security.md +20 -0
  70. data/test/_test_active.rb +76 -0
  71. data/test/_test_active_mimic.rb +96 -0
  72. data/test/_test_mimic_rails.rb +126 -0
  73. data/test/activesupport4/decoding_test.rb +105 -0
  74. data/test/activesupport4/encoding_test.rb +531 -0
  75. data/test/activesupport4/test_helper.rb +41 -0
  76. data/test/activesupport5/decoding_test.rb +125 -0
  77. data/test/activesupport5/encoding_test.rb +483 -0
  78. data/test/activesupport5/encoding_test_cases.rb +90 -0
  79. data/test/activesupport5/test_helper.rb +50 -0
  80. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  81. data/test/helper.rb +27 -0
  82. data/test/isolated/shared.rb +310 -0
  83. data/test/isolated/test_mimic_after.rb +13 -0
  84. data/test/isolated/test_mimic_alone.rb +12 -0
  85. data/test/isolated/test_mimic_as_json.rb +45 -0
  86. data/test/isolated/test_mimic_before.rb +13 -0
  87. data/test/isolated/test_mimic_define.rb +28 -0
  88. data/test/isolated/test_mimic_rails_after.rb +22 -0
  89. data/test/isolated/test_mimic_rails_before.rb +21 -0
  90. data/test/isolated/test_mimic_redefine.rb +15 -0
  91. data/test/json_gem/json_addition_test.rb +216 -0
  92. data/test/json_gem/json_common_interface_test.rb +143 -0
  93. data/test/json_gem/json_encoding_test.rb +109 -0
  94. data/test/json_gem/json_ext_parser_test.rb +20 -0
  95. data/test/json_gem/json_fixtures_test.rb +35 -0
  96. data/test/json_gem/json_generator_test.rb +383 -0
  97. data/test/json_gem/json_generic_object_test.rb +90 -0
  98. data/test/json_gem/json_parser_test.rb +470 -0
  99. data/test/json_gem/json_string_matching_test.rb +42 -0
  100. data/test/json_gem/test_helper.rb +18 -0
  101. data/test/perf_compat.rb +130 -0
  102. data/test/perf_fast.rb +9 -9
  103. data/test/perf_file.rb +64 -0
  104. data/test/{perf_obj.rb → perf_object.rb} +24 -10
  105. data/test/perf_scp.rb +151 -0
  106. data/test/perf_strict.rb +32 -113
  107. data/test/sample.rb +2 -3
  108. data/test/test_compat.rb +474 -0
  109. data/test/test_custom.rb +355 -0
  110. data/test/test_debian.rb +53 -0
  111. data/test/test_fast.rb +66 -16
  112. data/test/test_file.rb +237 -0
  113. data/test/test_gc.rb +49 -0
  114. data/test/test_hash.rb +29 -0
  115. data/test/test_null.rb +376 -0
  116. data/test/test_object.rb +1010 -0
  117. data/test/test_saj.rb +16 -16
  118. data/test/test_scp.rb +417 -0
  119. data/test/test_strict.rb +410 -0
  120. data/test/test_various.rb +815 -0
  121. data/test/test_writer.rb +308 -0
  122. data/test/tests.rb +9 -902
  123. data/test/tests_mimic.rb +14 -0
  124. data/test/tests_mimic_addition.rb +7 -0
  125. metadata +253 -38
  126. data/ext/oj/cache.c +0 -148
  127. data/ext/oj/foo.rb +0 -6
  128. data/ext/oj/load.c +0 -1049
  129. data/test/a.rb +0 -38
  130. data/test/perf1.rb +0 -64
  131. data/test/perf2.rb +0 -76
  132. data/test/perf_obj_old.rb +0 -213
  133. data/test/test_mimic.rb +0 -208
data/ext/oj/load.c DELETED
@@ -1,1049 +0,0 @@
1
- /* load.c
2
- * Copyright (c) 2012, Peter Ohler
3
- * All rights reserved.
4
- *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
7
- *
8
- * - Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- *
11
- * - Redistributions in binary form must reproduce the above copyright notice,
12
- * this list of conditions and the following disclaimer in the documentation
13
- * and/or other materials provided with the distribution.
14
- *
15
- * - Neither the name of Peter Ohler nor the names of its contributors may be
16
- * used to endorse or promote products derived from this software without
17
- * specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
- */
30
-
31
- #if SAFE_CACHE
32
- #include <pthread.h>
33
- #endif
34
- #if !IS_WINDOWS
35
- #include <sys/resource.h> // for getrlimit() on linux
36
- #endif
37
- #include <stdlib.h>
38
- #include <stdio.h>
39
- #include <string.h>
40
- #include <math.h>
41
-
42
- //Workaround:
43
- #ifndef INFINITY
44
- #define INFINITY (1.0/0.0)
45
- #endif
46
-
47
- #include "oj.h"
48
-
49
- enum {
50
- TIME_HINT = 0x0100,
51
- };
52
-
53
- typedef struct _CircArray {
54
- VALUE obj_array[1024];
55
- VALUE *objs;
56
- unsigned long size; // allocated size or initial array size
57
- unsigned long cnt;
58
- } *CircArray;
59
-
60
- typedef struct _ParseInfo {
61
- char *str; /* buffer being read from */
62
- char *s; /* current position in buffer */
63
- CircArray circ_array;
64
- Options options;
65
- void *stack_min;
66
- } *ParseInfo;
67
-
68
- static CircArray circ_array_new(void);
69
- static void circ_array_free(CircArray ca);
70
- static void circ_array_set(CircArray ca, VALUE obj, unsigned long id);
71
- static VALUE circ_array_get(CircArray ca, unsigned long id);
72
-
73
- static VALUE classname2class(const char *name, ParseInfo pi);
74
- static VALUE read_next(ParseInfo pi, int hint);
75
- static VALUE read_obj(ParseInfo pi);
76
- static VALUE read_array(ParseInfo pi, int hint);
77
- static VALUE read_str(ParseInfo pi, int hint);
78
- static VALUE read_num(ParseInfo pi);
79
- static VALUE read_time(ParseInfo pi);
80
- static VALUE read_true(ParseInfo pi);
81
- static VALUE read_false(ParseInfo pi);
82
- static VALUE read_nil(ParseInfo pi);
83
- static void next_non_white(ParseInfo pi);
84
- static char* read_quoted_value(ParseInfo pi);
85
- static void skip_comment(ParseInfo pi);
86
-
87
-
88
- /* This XML parser is a single pass, destructive, callback parser. It is a
89
- * single pass parse since it only make one pass over the characters in the
90
- * XML document string. It is destructive because it re-uses the content of
91
- * the string for values in the callback and places \0 characters at various
92
- * places to mark the end of tokens and strings. It is a callback parser like
93
- * a SAX parser because it uses callback when document elements are
94
- * encountered.
95
- *
96
- * Parsing is very tolerant. Lack of headers and even mispelled element
97
- * endings are passed over without raising an error. A best attempt is made in
98
- * all cases to parse the string.
99
- */
100
-
101
- inline static void
102
- next_non_white(ParseInfo pi) {
103
- for (; 1; pi->s++) {
104
- switch(*pi->s) {
105
- case ' ':
106
- case '\t':
107
- case '\f':
108
- case '\n':
109
- case '\r':
110
- break;
111
- case '/':
112
- skip_comment(pi);
113
- break;
114
- default:
115
- return;
116
- }
117
- }
118
- }
119
-
120
- inline static void
121
- next_white(ParseInfo pi) {
122
- for (; 1; pi->s++) {
123
- switch(*pi->s) {
124
- case ' ':
125
- case '\t':
126
- case '\f':
127
- case '\n':
128
- case '\r':
129
- case '\0':
130
- return;
131
- default:
132
- break;
133
- }
134
- }
135
- }
136
-
137
- inline static VALUE
138
- resolve_classname(VALUE mod, const char *class_name, int auto_define) {
139
- VALUE clas;
140
- ID ci = rb_intern(class_name);
141
-
142
- if (rb_const_defined_at(mod, ci) || !auto_define) {
143
- clas = rb_const_get_at(mod, ci);
144
- } else {
145
- clas = rb_define_class_under(mod, class_name, oj_bag_class);
146
- }
147
- return clas;
148
- }
149
-
150
- inline static VALUE
151
- classname2obj(const char *name, ParseInfo pi) {
152
- VALUE clas = classname2class(name, pi);
153
-
154
- if (Qundef == clas) {
155
- return Qnil;
156
- } else {
157
- return rb_obj_alloc(clas);
158
- }
159
- }
160
-
161
- static VALUE
162
- classname2class(const char *name, ParseInfo pi) {
163
- VALUE clas;
164
- VALUE *slot;
165
- int auto_define = (Yes == pi->options->auto_define);
166
-
167
- #if SAFE_CACHE
168
- pthread_mutex_lock(&oj_cache_mutex);
169
- #endif
170
- if (Qundef == (clas = oj_cache_get(oj_class_cache, name, &slot))) {
171
- char class_name[1024];
172
- char *s;
173
- const char *n = name;
174
-
175
- clas = rb_cObject;
176
- for (s = class_name; '\0' != *n; n++) {
177
- if (':' == *n) {
178
- *s = '\0';
179
- n++;
180
- if (':' != *n) {
181
- raise_error("Invalid classname, expected another ':'", pi->str, pi->s);
182
- }
183
- if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
184
- return Qundef;
185
- }
186
- s = class_name;
187
- } else {
188
- *s++ = *n;
189
- }
190
- }
191
- *s = '\0';
192
- if (Qundef != (clas = resolve_classname(clas, class_name, auto_define))) {
193
- *slot = clas;
194
- }
195
- }
196
- #if SAFE_CACHE
197
- pthread_mutex_unlock(&oj_cache_mutex);
198
- #endif
199
- return clas;
200
- }
201
-
202
- #if HAS_RSTRUCT
203
- inline static VALUE
204
- structname2obj(const char *name) {
205
- VALUE ost;
206
-
207
- ost = rb_const_get(oj_struct_class, rb_intern(name));
208
- // use encoding as the indicator for Ruby 1.8.7 or 1.9.x
209
- #if HAS_ENCODING_SUPPORT
210
- return rb_struct_alloc_noinit(ost);
211
- #else
212
- return rb_struct_new(ost);
213
- #endif
214
- }
215
- #endif
216
-
217
- inline static unsigned long
218
- read_ulong(const char *s, ParseInfo pi) {
219
- unsigned long n = 0;
220
-
221
- for (; '\0' != *s; s++) {
222
- if ('0' <= *s && *s <= '9') {
223
- n = n * 10 + (*s - '0');
224
- } else {
225
- raise_error("Not a valid ID number", pi->str, pi->s);
226
- }
227
- }
228
- return n;
229
- }
230
-
231
- static CircArray
232
- circ_array_new() {
233
- CircArray ca;
234
-
235
- if (0 == (ca = ALLOC(struct _CircArray))) {
236
- rb_raise(rb_eNoMemError, "not enough memory\n");
237
- }
238
- ca->objs = ca->obj_array;
239
- ca->size = sizeof(ca->obj_array) / sizeof(VALUE);
240
- ca->cnt = 0;
241
-
242
- return ca;
243
- }
244
-
245
- static void
246
- circ_array_free(CircArray ca) {
247
- if (ca->objs != ca->obj_array) {
248
- xfree(ca->objs);
249
- }
250
- xfree(ca);
251
- }
252
-
253
- static void
254
- circ_array_set(CircArray ca, VALUE obj, unsigned long id) {
255
- if (0 < id && 0 != ca) {
256
- unsigned long i;
257
-
258
- if (ca->size < id) {
259
- unsigned long cnt = id + 512;
260
-
261
- if (ca->objs == ca->obj_array) {
262
- if (0 == (ca->objs = ALLOC_N(VALUE, cnt))) {
263
- rb_raise(rb_eNoMemError, "not enough memory\n");
264
- }
265
- memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt);
266
- } else {
267
- REALLOC_N(ca->objs, VALUE, cnt);
268
- }
269
- ca->size = cnt;
270
- }
271
- id--;
272
- for (i = ca->cnt; i < id; i++) {
273
- ca->objs[i] = Qnil;
274
- }
275
- ca->objs[id] = obj;
276
- if (ca->cnt <= id) {
277
- ca->cnt = id + 1;
278
- }
279
- }
280
- }
281
-
282
- static VALUE
283
- circ_array_get(CircArray ca, unsigned long id) {
284
- VALUE obj = Qnil;
285
-
286
- if (id <= ca->cnt && 0 != ca) {
287
- obj = ca->objs[id - 1];
288
- }
289
- return obj;
290
- }
291
-
292
- static void
293
- skip_comment(ParseInfo pi) {
294
- pi->s++; // skip first /
295
- if ('*' == *pi->s) {
296
- pi->s++;
297
- for (; '\0' != *pi->s; pi->s++) {
298
- if ('*' == *pi->s && '/' == *(pi->s + 1)) {
299
- pi->s++;
300
- return;
301
- } else if ('\0' == *pi->s) {
302
- raise_error("comment not terminated", pi->str, pi->s);
303
- }
304
- }
305
- } else if ('/' == *pi->s) {
306
- for (; 1; pi->s++) {
307
- switch (*pi->s) {
308
- case '\n':
309
- case '\r':
310
- case '\f':
311
- case '\0':
312
- return;
313
- default:
314
- break;
315
- }
316
- }
317
- } else {
318
- raise_error("invalid comment", pi->str, pi->s);
319
- }
320
- }
321
-
322
- static VALUE
323
- read_next(ParseInfo pi, int hint) {
324
- VALUE obj;
325
-
326
- if ((void*)&obj < pi->stack_min) {
327
- rb_raise(rb_eSysStackError, "JSON is too deeply nested");
328
- }
329
- next_non_white(pi); // skip white space
330
- switch (*pi->s) {
331
- case '{':
332
- obj = read_obj(pi);
333
- break;
334
- case '[':
335
- obj = read_array(pi, hint);
336
- break;
337
- case '"':
338
- obj = read_str(pi, hint);
339
- break;
340
- case '+':
341
- case '-':
342
- case '0':
343
- case '1':
344
- case '2':
345
- case '3':
346
- case '4':
347
- case '5':
348
- case '6':
349
- case '7':
350
- case '8':
351
- case '9':
352
- if (TIME_HINT == hint) {
353
- obj = read_time(pi);
354
- } else {
355
- obj = read_num(pi);
356
- }
357
- break;
358
- case 'I':
359
- obj = read_num(pi);
360
- break;
361
- case 't':
362
- obj = read_true(pi);
363
- break;
364
- case 'f':
365
- obj = read_false(pi);
366
- break;
367
- case 'n':
368
- obj = read_nil(pi);
369
- break;
370
- case '\0':
371
- obj = Qundef;
372
- break;
373
- default:
374
- obj = Qundef;
375
- break;
376
- }
377
- return obj;
378
- }
379
-
380
- static VALUE
381
- read_obj(ParseInfo pi) {
382
- VALUE obj = Qundef;
383
- VALUE key = Qundef;
384
- VALUE val = Qundef;
385
- const char *ks;
386
- int obj_type = T_NONE;
387
- const char *json_class_name = 0;
388
- Mode mode = pi->options->mode;
389
- Odd odd = 0;
390
- VALUE odd_args[MAX_ODD_ARGS];
391
- VALUE *vp;
392
-
393
- pi->s++;
394
- next_non_white(pi);
395
- if ('}' == *pi->s) {
396
- pi->s++;
397
- return rb_hash_new();
398
- }
399
- while (1) {
400
- next_non_white(pi);
401
- ks = 0;
402
- key = Qundef;
403
- val = Qundef;
404
- if ('"' != *pi->s || Qundef == (key = read_str(pi, 0))) {
405
- raise_error("unexpected character", pi->str, pi->s);
406
- }
407
- next_non_white(pi);
408
- if (':' == *pi->s) {
409
- pi->s++;
410
- } else {
411
- raise_error("invalid format, expected :", pi->str, pi->s);
412
- }
413
- if (T_STRING == rb_type(key)) {
414
- ks = StringValuePtr(key);
415
- } else {
416
- ks = 0;
417
- }
418
- if (0 != ks && Qundef == obj && ObjectMode == mode) {
419
- if ('^' == *ks && '\0' == ks[2]) { // special directions
420
- switch (ks[1]) {
421
- case 't': // Time
422
- obj = read_next(pi, TIME_HINT); // raises if can not convert to Time
423
- key = Qundef;
424
- break;
425
- case 'c': // Class
426
- obj = read_next(pi, T_CLASS);
427
- key = Qundef;
428
- break;
429
- case 's': // String
430
- obj = read_next(pi, T_STRING);
431
- key = Qundef;
432
- break;
433
- case 'm': // Symbol
434
- obj = read_next(pi, T_SYMBOL);
435
- key = Qundef;
436
- break;
437
- case 'o': // Object
438
- obj = read_next(pi, T_OBJECT);
439
- obj_type = T_OBJECT;
440
- key = Qundef;
441
- break;
442
- case 'O': // Odd class
443
- if (0 == (odd = oj_get_odd(read_next(pi, T_CLASS)))) {
444
- raise_error("Not a valid build in class.", pi->str, pi->s);
445
- }
446
- obj = Qundef;
447
- key = Qundef;
448
- for (vp = odd_args + MAX_ODD_ARGS - 1; odd_args <=vp; vp--) {
449
- *vp = Qnil;
450
- }
451
- break;
452
- case 'u': // Struct
453
- obj = read_next(pi, T_STRUCT);
454
- obj_type = T_STRUCT;
455
- key = Qundef;
456
- break;
457
- default:
458
- // handle later
459
- break;
460
- }
461
- }
462
- }
463
- if (Qundef != key) {
464
- if (Qundef == val && Qundef == (val = read_next(pi, 0))) {
465
- raise_error("unexpected character", pi->str, pi->s);
466
- }
467
- if (Qundef == obj && 0 == odd) {
468
- obj = rb_hash_new();
469
- obj_type = T_HASH;
470
- }
471
- if (ObjectMode == mode && 0 != ks && '^' == *ks) {
472
- int val_type = rb_type(val);
473
-
474
- if ('i' == ks[1] && '\0' == ks[2] && T_FIXNUM == val_type) {
475
- circ_array_set(pi->circ_array, obj, NUM2ULONG(val));
476
- key = Qundef;
477
- } else if ('#' == ks[1] &&
478
- (T_NONE == obj_type || T_HASH == obj_type) &&
479
- T_ARRAY == val_type && 2 == RARRAY_LEN(val)) { // Hash entry
480
- VALUE *np = RARRAY_PTR(val);
481
-
482
- key = *np;
483
- val = *(np + 1);
484
- }
485
- }
486
- if (Qundef != key) {
487
- if (0 != odd) {
488
- ID *idp;
489
-
490
- for (idp = odd->attrs, vp = odd_args; 0 != *idp; idp++, vp++) {
491
- if (0 == strcmp(rb_id2name(*idp), ks)) {
492
- *vp = val;
493
- break;
494
- }
495
- }
496
- if (odd_args + MAX_ODD_ARGS <= vp) {
497
- raise_error("invalid attribute", pi->str, pi->s);
498
- }
499
- } else if (T_OBJECT == obj_type) {
500
- VALUE *slot;
501
- ID var_id;
502
-
503
- #if SAFE_CACHE
504
- pthread_mutex_lock(&oj_cache_mutex);
505
- #endif
506
- if (Qundef == (var_id = oj_cache_get(oj_attr_cache, ks, &slot))) {
507
- char attr[1024];
508
-
509
- if ('~' == *ks) {
510
- strncpy(attr, ks + 1, sizeof(attr) - 1);
511
- } else {
512
- *attr = '@';
513
- strncpy(attr + 1, ks, sizeof(attr) - 2);
514
- }
515
- attr[sizeof(attr) - 1] = '\0';
516
- var_id = rb_intern(attr);
517
- *slot = var_id;
518
- }
519
- #if SAFE_CACHE
520
- pthread_mutex_unlock(&oj_cache_mutex);
521
- #endif
522
- #if HAS_EXCEPTION_MAGIC
523
- if ('~' == *ks && Qtrue == rb_obj_is_kind_of(obj, rb_eException)) {
524
- if (0 == strcmp("~mesg", ks)) {
525
- VALUE args[1];
526
-
527
- args[0] = val;
528
- obj = rb_class_new_instance(1, args, rb_class_of(obj));
529
- } else if (0 == strcmp("~bt", ks)) {
530
- rb_funcall(obj, rb_intern("set_backtrace"), 1, val);
531
- }
532
- } else {
533
- rb_ivar_set(obj, var_id, val);
534
- }
535
- #else
536
- rb_ivar_set(obj, var_id, val);
537
- #endif
538
- } else if (T_HASH == obj_type) {
539
- if (Yes == pi->options->sym_key) {
540
- rb_hash_aset(obj, rb_str_intern(key), val);
541
- } else {
542
- rb_hash_aset(obj, key, val);
543
- }
544
- if ((CompatMode == mode || ObjectMode == mode) &&
545
- 0 == json_class_name && 0 != ks &&
546
- 0 != pi->options->create_id && *pi->options->create_id == *ks && 0 == strcmp(pi->options->create_id, ks) &&
547
- T_STRING == rb_type(val)) {
548
- json_class_name = StringValuePtr(val);
549
- }
550
- } else {
551
- raise_error("invalid Object format, too many Hash entries.", pi->str, pi->s);
552
- }
553
- }
554
- }
555
- next_non_white(pi);
556
- if ('}' == *pi->s) {
557
- pi->s++;
558
- break;
559
- } else if (',' == *pi->s) {
560
- pi->s++;
561
- } else {
562
- //printf("*** '%s'\n", pi->s);
563
- raise_error("invalid format, expected , or } while in an object", pi->str, pi->s);
564
- }
565
- }
566
- if (0 != odd) {
567
- obj = rb_funcall2(odd->create_obj, odd->create_op, odd->attr_cnt, odd_args);
568
- } else if (0 != json_class_name) {
569
- VALUE clas = classname2class(json_class_name, pi);
570
- VALUE args[1];
571
-
572
- *args = obj;
573
- obj = rb_funcall2(clas, oj_json_create_id, 1, args);
574
- }
575
- return obj;
576
- }
577
-
578
- static VALUE
579
- read_array(ParseInfo pi, int hint) {
580
- VALUE a = Qundef;
581
- VALUE e;
582
- int type = T_NONE;
583
- int cnt = 0;
584
- int a_str;
585
- #if HAS_RSTRUCT
586
- long slen = 0;
587
- #endif
588
-
589
- pi->s++;
590
- next_non_white(pi);
591
- if (']' == *pi->s) {
592
- pi->s++;
593
- return rb_ary_new();
594
- }
595
- while (1) {
596
- next_non_white(pi);
597
- a_str = ('"' == *pi->s);
598
- if (Qundef == (e = read_next(pi, 0))) {
599
- raise_error("unexpected character", pi->str, pi->s);
600
- }
601
- #if HAS_RSTRUCT
602
- if (Qundef == a && T_STRUCT == hint && T_STRING == rb_type(e)) {
603
- a = structname2obj(StringValuePtr(e));
604
- type = T_STRUCT;
605
- slen = RSTRUCT_LEN(a);
606
- e = Qundef;
607
- }
608
- #endif
609
- if (Qundef == a) {
610
- a = rb_ary_new();
611
- type = T_ARRAY;
612
- }
613
- if (a_str && T_FIXNUM == rb_type(e)) {
614
- circ_array_set(pi->circ_array, a, NUM2ULONG(e));
615
- e = Qundef;
616
- }
617
- if (Qundef != e) {
618
- if (T_STRUCT == type) {
619
- #if HAS_RSTRUCT
620
- if (slen <= cnt) {
621
- raise_error("Too many elements for Struct", pi->str, pi->s);
622
- }
623
- RSTRUCT_PTR(a)[cnt] = e;
624
- #else
625
- raise_error("Ruby structs not supported with this version of Ruby", pi->str, pi->s);
626
- #endif
627
- } else {
628
- rb_ary_push(a, e);
629
- }
630
- cnt++;
631
- }
632
- next_non_white(pi);
633
- if (',' == *pi->s) {
634
- pi->s++;
635
- } else if (']' == *pi->s) {
636
- pi->s++;
637
- break;
638
- } else {
639
- raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s);
640
- }
641
- }
642
- return a;
643
- }
644
-
645
- static VALUE
646
- read_str(ParseInfo pi, int hint) {
647
- char *text;
648
- VALUE obj;
649
- int escaped;
650
-
651
- escaped = ('\\' == pi->s[1]);
652
- text = read_quoted_value(pi);
653
- if (ObjectMode != pi->options->mode) {
654
- hint = T_STRING;
655
- }
656
- switch (hint) {
657
- case T_CLASS:
658
- obj = classname2class(text, pi);
659
- break;
660
- case T_OBJECT:
661
- obj = classname2obj(text, pi);
662
- break;
663
- case T_STRING:
664
- obj = rb_str_new2(text);
665
- #if HAS_ENCODING_SUPPORT
666
- rb_enc_associate(obj, oj_utf8_encoding);
667
- #endif
668
- break;
669
- case T_SYMBOL:
670
- #if HAS_ENCODING_SUPPORT
671
- obj = rb_str_new2(text);
672
- rb_enc_associate(obj, oj_utf8_encoding);
673
- obj = rb_funcall(obj, oj_to_sym_id, 0);
674
- #else
675
- obj = ID2SYM(rb_intern(text));
676
- #endif
677
- break;
678
- case 0:
679
- default:
680
- obj = Qundef;
681
- if (':' == *text && !escaped) { // Symbol
682
- #if HAS_ENCODING_SUPPORT
683
- obj = rb_str_new2(text + 1);
684
- rb_enc_associate(obj, oj_utf8_encoding);
685
- obj = rb_funcall(obj, oj_to_sym_id, 0);
686
- #else
687
- obj = ID2SYM(rb_intern(text + 1));
688
- #endif
689
- } else if (ObjectMode == pi->options->mode && '^' == *text && '\0' != text[2]) {
690
- char c1 = text[1];
691
-
692
- if ('r' == c1 && 0 != pi->circ_array) {
693
- obj = circ_array_get(pi->circ_array, read_ulong(text + 2, pi));
694
- } else if ('i' == c1) {
695
- obj = ULONG2NUM(read_ulong(text + 2, pi));
696
- }
697
- }
698
- if (Qundef == obj) {
699
- obj = rb_str_new2(text);
700
- #if HAS_ENCODING_SUPPORT
701
- rb_enc_associate(obj, oj_utf8_encoding);
702
- #endif
703
- }
704
- break;
705
- }
706
- return obj;
707
- }
708
-
709
- #ifdef RUBINIUS_RUBY
710
- #define NUM_MAX 0x07FFFFFF
711
- #else
712
- #define NUM_MAX (FIXNUM_MAX >> 8)
713
- #endif
714
-
715
- static VALUE
716
- read_num(ParseInfo pi) {
717
- char *start = pi->s;
718
- int64_t n = 0;
719
- long a = 0;
720
- long div = 1;
721
- long e = 0;
722
- int neg = 0;
723
- int eneg = 0;
724
- int big = 0;
725
-
726
- if ('-' == *pi->s) {
727
- pi->s++;
728
- neg = 1;
729
- } else if ('+' == *pi->s) {
730
- pi->s++;
731
- }
732
- if ('I' == *pi->s) {
733
- if (0 != strncmp("Infinity", pi->s, 8)) {
734
- raise_error("number or other value", pi->str, pi->s);
735
- }
736
- pi->s += 8;
737
- if (neg) {
738
- return rb_float_new(-INFINITY);
739
- } else {
740
- return rb_float_new(INFINITY);
741
- }
742
- }
743
- for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
744
- if (big) {
745
- big++;
746
- } else {
747
- n = n * 10 + (*pi->s - '0');
748
- if (NUM_MAX <= n) {
749
- big = 1;
750
- }
751
- }
752
- }
753
- if ('.' == *pi->s) {
754
- pi->s++;
755
- for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
756
- a = a * 10 + (*pi->s - '0');
757
- div *= 10;
758
- if (NUM_MAX <= div) {
759
- big = 1;
760
- }
761
- }
762
- }
763
- if ('e' == *pi->s || 'E' == *pi->s) {
764
- pi->s++;
765
- if ('-' == *pi->s) {
766
- pi->s++;
767
- eneg = 1;
768
- } else if ('+' == *pi->s) {
769
- pi->s++;
770
- }
771
- for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
772
- e = e * 10 + (*pi->s - '0');
773
- if (NUM_MAX <= e) {
774
- big = 1;
775
- }
776
- }
777
- }
778
- if (0 == e && 0 == a && 1 == div) {
779
- if (big) {
780
- char c = *pi->s;
781
- VALUE num;
782
-
783
- *pi->s = '\0';
784
- num = rb_cstr_to_inum(start, 10, 0);
785
- *pi->s = c;
786
-
787
- return num;
788
- } else {
789
- if (neg) {
790
- n = -n;
791
- }
792
- return LONG2NUM(n);
793
- }
794
- } else { // decimal
795
- if (big) {
796
- char c = *pi->s;
797
- VALUE num;
798
-
799
- *pi->s = '\0';
800
- num = rb_funcall(oj_bigdecimal_class, oj_new_id, 1, rb_str_new2(start));
801
- *pi->s = c;
802
-
803
- return num;
804
- } else {
805
- double d = (double)n + (double)a / (double)div;
806
-
807
- if (neg) {
808
- d = -d;
809
- }
810
- if (1 < big) {
811
- e += big - 1;
812
- }
813
- if (0 != e) {
814
- if (eneg) {
815
- e = -e;
816
- }
817
- d *= pow(10.0, e);
818
- }
819
- return rb_float_new(d);
820
- }
821
- }
822
- }
823
-
824
- static VALUE
825
- read_time(ParseInfo pi) {
826
- time_t v = 0;
827
- long v2 = 0;
828
-
829
- for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
830
- v = v * 10 + (*pi->s - '0');
831
- }
832
- if ('.' == *pi->s) {
833
- int cnt;
834
-
835
- pi->s++;
836
- for (cnt = 9; 0 < cnt && '0' <= *pi->s && *pi->s <= '9'; pi->s++, cnt--) {
837
- v2 = v2 * 10 + (*pi->s - '0');
838
- }
839
- for (; 0 < cnt; cnt--) {
840
- v2 *= 10;
841
- }
842
- }
843
- #if HAS_NANO_TIME
844
- return rb_time_nano_new(v, v2);
845
- #else
846
- return rb_time_new(v, v2 / 1000);
847
- #endif
848
- }
849
-
850
- static VALUE
851
- read_true(ParseInfo pi) {
852
- pi->s++;
853
- if ('r' != *pi->s || 'u' != *(pi->s + 1) || 'e' != *(pi->s + 2)) {
854
- raise_error("invalid format, expected 'true'", pi->str, pi->s);
855
- }
856
- pi->s += 3;
857
-
858
- return Qtrue;
859
- }
860
-
861
- static VALUE
862
- read_false(ParseInfo pi) {
863
- pi->s++;
864
- if ('a' != *pi->s || 'l' != *(pi->s + 1) || 's' != *(pi->s + 2) || 'e' != *(pi->s + 3)) {
865
- raise_error("invalid format, expected 'false'", pi->str, pi->s);
866
- }
867
- pi->s += 4;
868
-
869
- return Qfalse;
870
- }
871
-
872
- static VALUE
873
- read_nil(ParseInfo pi) {
874
- pi->s++;
875
- if ('u' != *pi->s || 'l' != *(pi->s + 1) || 'l' != *(pi->s + 2)) {
876
- raise_error("invalid format, expected 'nil'", pi->str, pi->s);
877
- }
878
- pi->s += 3;
879
-
880
- return Qnil;
881
- }
882
-
883
- static uint32_t
884
- read_hex(ParseInfo pi, char *h) {
885
- uint32_t b = 0;
886
- int i;
887
-
888
- // TBD this can be made faster with a table
889
- for (i = 0; i < 4; i++, h++) {
890
- b = b << 4;
891
- if ('0' <= *h && *h <= '9') {
892
- b += *h - '0';
893
- } else if ('A' <= *h && *h <= 'F') {
894
- b += *h - 'A' + 10;
895
- } else if ('a' <= *h && *h <= 'f') {
896
- b += *h - 'a' + 10;
897
- } else {
898
- pi->s = h;
899
- raise_error("invalid hex character", pi->str, pi->s);
900
- }
901
- }
902
- return b;
903
- }
904
-
905
- static char*
906
- unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
907
- if (0x0000007F >= code) {
908
- *t = (char)code;
909
- } else if (0x000007FF >= code) {
910
- *t++ = 0xC0 | (code >> 6);
911
- *t = 0x80 | (0x3F & code);
912
- } else if (0x0000FFFF >= code) {
913
- *t++ = 0xE0 | (code >> 12);
914
- *t++ = 0x80 | ((code >> 6) & 0x3F);
915
- *t = 0x80 | (0x3F & code);
916
- } else if (0x001FFFFF >= code) {
917
- *t++ = 0xF0 | (code >> 18);
918
- *t++ = 0x80 | ((code >> 12) & 0x3F);
919
- *t++ = 0x80 | ((code >> 6) & 0x3F);
920
- *t = 0x80 | (0x3F & code);
921
- } else if (0x03FFFFFF >= code) {
922
- *t++ = 0xF8 | (code >> 24);
923
- *t++ = 0x80 | ((code >> 18) & 0x3F);
924
- *t++ = 0x80 | ((code >> 12) & 0x3F);
925
- *t++ = 0x80 | ((code >> 6) & 0x3F);
926
- *t = 0x80 | (0x3F & code);
927
- } else if (0x7FFFFFFF >= code) {
928
- *t++ = 0xFC | (code >> 30);
929
- *t++ = 0x80 | ((code >> 24) & 0x3F);
930
- *t++ = 0x80 | ((code >> 18) & 0x3F);
931
- *t++ = 0x80 | ((code >> 12) & 0x3F);
932
- *t++ = 0x80 | ((code >> 6) & 0x3F);
933
- *t = 0x80 | (0x3F & code);
934
- } else {
935
- raise_error("invalid Unicode", pi->str, pi->s);
936
- }
937
- return t;
938
- }
939
-
940
- /* Assume the value starts immediately and goes until the quote character is
941
- * reached again. Do not read the character after the terminating quote.
942
- */
943
- static char*
944
- read_quoted_value(ParseInfo pi) {
945
- char *value = 0;
946
- char *h = pi->s; // head
947
- char *t = h; // tail
948
- uint32_t code;
949
-
950
- h++; // skip quote character
951
- t++;
952
- value = h;
953
- for (; '"' != *h; h++, t++) {
954
- if ('\0' == *h) {
955
- pi->s = h;
956
- raise_error("quoted string not terminated", pi->str, pi->s);
957
- } else if ('\\' == *h) {
958
- h++;
959
- switch (*h) {
960
- case 'n': *t = '\n'; break;
961
- case 'r': *t = '\r'; break;
962
- case 't': *t = '\t'; break;
963
- case 'f': *t = '\f'; break;
964
- case 'b': *t = '\b'; break;
965
- case '"': *t = '"'; break;
966
- case '/': *t = '/'; break;
967
- case '\\': *t = '\\'; break;
968
- case 'u':
969
- h++;
970
- code = read_hex(pi, h);
971
- h += 3;
972
- if (0x0000D800 <= code && code <= 0x0000DFFF) {
973
- uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
974
- uint32_t c2;
975
-
976
- h++;
977
- if ('\\' != *h || 'u' != *(h + 1)) {
978
- pi->s = h;
979
- raise_error("invalid escaped character", pi->str, pi->s);
980
- }
981
- h += 2;
982
- c2 = read_hex(pi, h);
983
- h += 3;
984
- c2 = (c2 - 0x0000DC00) & 0x000003FF;
985
- code = ((c1 << 10) | c2) + 0x00010000;
986
- }
987
- t = unicode_to_chars(pi, t, code);
988
- break;
989
- default:
990
- pi->s = h;
991
- raise_error("invalid escaped character", pi->str, pi->s);
992
- break;
993
- }
994
- } else if (t != h) {
995
- *t = *h;
996
- }
997
- }
998
- *t = '\0'; // terminate value
999
- pi->s = h + 1;
1000
-
1001
- return value;
1002
- }
1003
-
1004
- VALUE
1005
- oj_parse(char *json, Options options) {
1006
- VALUE obj;
1007
- struct _ParseInfo pi;
1008
-
1009
- if (0 == json) {
1010
- raise_error("Invalid arg, xml string can not be null", json, 0);
1011
- }
1012
- /* skip UTF-8 BOM if present */
1013
- if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
1014
- json += 3;
1015
- }
1016
- /* initialize parse info */
1017
- pi.str = json;
1018
- pi.s = json;
1019
- pi.circ_array = 0;
1020
- if (Yes == options->circular) {
1021
- pi.circ_array = circ_array_new();
1022
- }
1023
- pi.options = options;
1024
- #if IS_WINDOWS
1025
- pi.stack_min = (void*)((char*)&obj - (512 * 1024)); // assume a 1M stack and give half to ruby
1026
- #else
1027
- {
1028
- struct rlimit lim;
1029
-
1030
- if (0 == getrlimit(RLIMIT_STACK, &lim)) {
1031
- pi.stack_min = (void*)((char*)&obj - (lim.rlim_cur / 4 * 3)); // let 3/4ths of the stack be used only
1032
- } else {
1033
- pi.stack_min = 0; // indicates not to check stack limit
1034
- }
1035
- }
1036
- #endif
1037
- obj = read_next(&pi, 0);
1038
- if (Yes == options->circular) {
1039
- circ_array_free(pi.circ_array);
1040
- }
1041
- if (Qundef == obj) {
1042
- raise_error("no object read", pi.str, pi.s);
1043
- }
1044
- next_non_white(&pi);
1045
- if ('\0' != *pi.s) {
1046
- raise_error("invalid format, extra characters", pi.str, pi.s);
1047
- }
1048
- return obj;
1049
- }