oj 2.0.0 → 3.0.0

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 (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
- }