oj 3.10.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +104 -0
  4. data/ext/oj/buf.h +103 -0
  5. data/ext/oj/cache8.c +107 -0
  6. data/ext/oj/cache8.h +48 -0
  7. data/ext/oj/circarray.c +68 -0
  8. data/ext/oj/circarray.h +23 -0
  9. data/ext/oj/code.c +235 -0
  10. data/ext/oj/code.h +42 -0
  11. data/ext/oj/compat.c +299 -0
  12. data/ext/oj/custom.c +1218 -0
  13. data/ext/oj/dump.c +1249 -0
  14. data/ext/oj/dump.h +96 -0
  15. data/ext/oj/dump_compat.c +975 -0
  16. data/ext/oj/dump_leaf.c +252 -0
  17. data/ext/oj/dump_object.c +844 -0
  18. data/ext/oj/dump_strict.c +434 -0
  19. data/ext/oj/encode.h +45 -0
  20. data/ext/oj/err.c +57 -0
  21. data/ext/oj/err.h +70 -0
  22. data/ext/oj/extconf.rb +53 -0
  23. data/ext/oj/fast.c +1771 -0
  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 +890 -0
  28. data/ext/oj/object.c +775 -0
  29. data/ext/oj/odd.c +231 -0
  30. data/ext/oj/odd.h +44 -0
  31. data/ext/oj/oj.c +1723 -0
  32. data/ext/oj/oj.h +387 -0
  33. data/ext/oj/parse.c +1134 -0
  34. data/ext/oj/parse.h +112 -0
  35. data/ext/oj/rails.c +1528 -0
  36. data/ext/oj/rails.h +21 -0
  37. data/ext/oj/reader.c +231 -0
  38. data/ext/oj/reader.h +151 -0
  39. data/ext/oj/resolve.c +102 -0
  40. data/ext/oj/resolve.h +14 -0
  41. data/ext/oj/rxclass.c +147 -0
  42. data/ext/oj/rxclass.h +27 -0
  43. data/ext/oj/saj.c +714 -0
  44. data/ext/oj/scp.c +224 -0
  45. data/ext/oj/sparse.c +924 -0
  46. data/ext/oj/stream_writer.c +363 -0
  47. data/ext/oj/strict.c +212 -0
  48. data/ext/oj/string_writer.c +534 -0
  49. data/ext/oj/trace.c +79 -0
  50. data/ext/oj/trace.h +28 -0
  51. data/ext/oj/util.c +136 -0
  52. data/ext/oj/util.h +19 -0
  53. data/ext/oj/val_stack.c +118 -0
  54. data/ext/oj/val_stack.h +185 -0
  55. data/ext/oj/wab.c +631 -0
  56. data/lib/oj.rb +21 -0
  57. data/lib/oj/active_support_helper.rb +41 -0
  58. data/lib/oj/bag.rb +88 -0
  59. data/lib/oj/easy_hash.rb +52 -0
  60. data/lib/oj/error.rb +22 -0
  61. data/lib/oj/json.rb +176 -0
  62. data/lib/oj/mimic.rb +267 -0
  63. data/lib/oj/saj.rb +66 -0
  64. data/lib/oj/schandler.rb +142 -0
  65. data/lib/oj/state.rb +131 -0
  66. data/lib/oj/version.rb +5 -0
  67. data/pages/Advanced.md +22 -0
  68. data/pages/Compatibility.md +25 -0
  69. data/pages/Custom.md +23 -0
  70. data/pages/Encoding.md +65 -0
  71. data/pages/JsonGem.md +79 -0
  72. data/pages/Modes.md +155 -0
  73. data/pages/Options.md +287 -0
  74. data/pages/Rails.md +155 -0
  75. data/pages/Security.md +20 -0
  76. data/pages/WAB.md +13 -0
  77. data/test/_test_active.rb +76 -0
  78. data/test/_test_active_mimic.rb +96 -0
  79. data/test/_test_mimic_rails.rb +126 -0
  80. data/test/activerecord/result_test.rb +27 -0
  81. data/test/activesupport4/decoding_test.rb +108 -0
  82. data/test/activesupport4/encoding_test.rb +531 -0
  83. data/test/activesupport4/test_helper.rb +41 -0
  84. data/test/activesupport5/abstract_unit.rb +45 -0
  85. data/test/activesupport5/decoding_test.rb +133 -0
  86. data/test/activesupport5/encoding_test.rb +500 -0
  87. data/test/activesupport5/encoding_test_cases.rb +98 -0
  88. data/test/activesupport5/test_helper.rb +72 -0
  89. data/test/activesupport5/time_zone_test_helpers.rb +39 -0
  90. data/test/activesupport6/abstract_unit.rb +44 -0
  91. data/test/activesupport6/decoding_test.rb +133 -0
  92. data/test/activesupport6/encoding_test.rb +507 -0
  93. data/test/activesupport6/encoding_test_cases.rb +98 -0
  94. data/test/activesupport6/test_common.rb +17 -0
  95. data/test/activesupport6/test_helper.rb +163 -0
  96. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  97. data/test/bar.rb +35 -0
  98. data/test/baz.rb +16 -0
  99. data/test/files.rb +29 -0
  100. data/test/foo.rb +52 -0
  101. data/test/helper.rb +26 -0
  102. data/test/isolated/shared.rb +308 -0
  103. data/test/isolated/test_mimic_after.rb +13 -0
  104. data/test/isolated/test_mimic_alone.rb +12 -0
  105. data/test/isolated/test_mimic_as_json.rb +45 -0
  106. data/test/isolated/test_mimic_before.rb +13 -0
  107. data/test/isolated/test_mimic_define.rb +28 -0
  108. data/test/isolated/test_mimic_rails_after.rb +22 -0
  109. data/test/isolated/test_mimic_rails_before.rb +21 -0
  110. data/test/isolated/test_mimic_redefine.rb +15 -0
  111. data/test/json_gem/json_addition_test.rb +216 -0
  112. data/test/json_gem/json_common_interface_test.rb +148 -0
  113. data/test/json_gem/json_encoding_test.rb +107 -0
  114. data/test/json_gem/json_ext_parser_test.rb +20 -0
  115. data/test/json_gem/json_fixtures_test.rb +35 -0
  116. data/test/json_gem/json_generator_test.rb +383 -0
  117. data/test/json_gem/json_generic_object_test.rb +90 -0
  118. data/test/json_gem/json_parser_test.rb +470 -0
  119. data/test/json_gem/json_string_matching_test.rb +42 -0
  120. data/test/json_gem/test_helper.rb +18 -0
  121. data/test/perf.rb +107 -0
  122. data/test/perf_compat.rb +130 -0
  123. data/test/perf_fast.rb +164 -0
  124. data/test/perf_file.rb +64 -0
  125. data/test/perf_object.rb +138 -0
  126. data/test/perf_saj.rb +109 -0
  127. data/test/perf_scp.rb +151 -0
  128. data/test/perf_simple.rb +287 -0
  129. data/test/perf_strict.rb +145 -0
  130. data/test/perf_wab.rb +131 -0
  131. data/test/prec.rb +23 -0
  132. data/test/sample.rb +54 -0
  133. data/test/sample/change.rb +14 -0
  134. data/test/sample/dir.rb +19 -0
  135. data/test/sample/doc.rb +36 -0
  136. data/test/sample/file.rb +48 -0
  137. data/test/sample/group.rb +16 -0
  138. data/test/sample/hasprops.rb +16 -0
  139. data/test/sample/layer.rb +12 -0
  140. data/test/sample/line.rb +20 -0
  141. data/test/sample/oval.rb +10 -0
  142. data/test/sample/rect.rb +10 -0
  143. data/test/sample/shape.rb +35 -0
  144. data/test/sample/text.rb +20 -0
  145. data/test/sample_json.rb +37 -0
  146. data/test/test_compat.rb +502 -0
  147. data/test/test_custom.rb +527 -0
  148. data/test/test_debian.rb +53 -0
  149. data/test/test_fast.rb +470 -0
  150. data/test/test_file.rb +239 -0
  151. data/test/test_gc.rb +49 -0
  152. data/test/test_hash.rb +29 -0
  153. data/test/test_integer_range.rb +72 -0
  154. data/test/test_null.rb +376 -0
  155. data/test/test_object.rb +1027 -0
  156. data/test/test_rails.rb +26 -0
  157. data/test/test_saj.rb +186 -0
  158. data/test/test_scp.rb +433 -0
  159. data/test/test_strict.rb +433 -0
  160. data/test/test_various.rb +719 -0
  161. data/test/test_wab.rb +307 -0
  162. data/test/test_writer.rb +380 -0
  163. data/test/tests.rb +25 -0
  164. data/test/tests_mimic.rb +14 -0
  165. data/test/tests_mimic_addition.rb +7 -0
  166. data/test/zoo.rb +13 -0
  167. metadata +381 -0
@@ -0,0 +1,631 @@
1
+ /* wab.c
2
+ * Copyright (c) 2012, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include <stdlib.h>
7
+ #include <stdio.h>
8
+ #include <string.h>
9
+ #include <time.h>
10
+ #include <unistd.h>
11
+
12
+ #include "oj.h"
13
+ #include "err.h"
14
+ #include "parse.h"
15
+ #include "encode.h"
16
+ #include "dump.h"
17
+ #include "trace.h"
18
+ #include "util.h"
19
+
20
+ // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
21
+ #define OJ_INFINITY (1.0/0.0)
22
+
23
+ static char hex_chars[256] = "\
24
+ ................................\
25
+ ................xxxxxxxxxx......\
26
+ .xxxxxx.........................\
27
+ .xxxxxx.........................\
28
+ ................................\
29
+ ................................\
30
+ ................................\
31
+ ................................";
32
+
33
+ static VALUE wab_uuid_clas = Qundef;
34
+ static VALUE uri_clas = Qundef;
35
+ static VALUE uri_http_clas = Qundef;
36
+
37
+ ///// dump functions /////
38
+
39
+ static VALUE
40
+ resolve_wab_uuid_class() {
41
+ if (Qundef == wab_uuid_clas) {
42
+ volatile VALUE wab_module;
43
+
44
+ wab_uuid_clas = Qnil;
45
+ if (rb_const_defined_at(rb_cObject, rb_intern("WAB"))) {
46
+ wab_module = rb_const_get_at(rb_cObject, rb_intern("WAB"));
47
+ if (rb_const_defined_at(wab_module, rb_intern("UUID"))) {
48
+ wab_uuid_clas = rb_const_get(wab_module, rb_intern("UUID"));
49
+ }
50
+ }
51
+ }
52
+ return wab_uuid_clas;
53
+ }
54
+
55
+ static VALUE
56
+ resolve_uri_class() {
57
+ if (Qundef == uri_clas) {
58
+
59
+ uri_clas = Qnil;
60
+ if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) {
61
+ uri_clas = rb_const_get_at(rb_cObject, rb_intern("URI"));
62
+ }
63
+ }
64
+ return uri_clas;
65
+ }
66
+
67
+ static VALUE
68
+ resolve_uri_http_class() {
69
+ if (Qundef == uri_http_clas) {
70
+ volatile VALUE uri_module;
71
+
72
+ uri_http_clas = Qnil;
73
+ if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) {
74
+ uri_module = rb_const_get_at(rb_cObject, rb_intern("URI"));
75
+ if (rb_const_defined_at(uri_module, rb_intern("HTTP"))) {
76
+ uri_http_clas = rb_const_get(uri_module, rb_intern("HTTP"));
77
+ }
78
+ }
79
+ }
80
+ return uri_http_clas;
81
+ }
82
+
83
+ static void
84
+ raise_wab(VALUE obj) {
85
+ rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in wab mode.\n", rb_class2name(rb_obj_class(obj)));
86
+ }
87
+
88
+ // Removed dependencies on math due to problems with CentOS 5.4.
89
+ static void
90
+ dump_float(VALUE obj, int depth, Out out, bool as_ok) {
91
+ char buf[64];
92
+ char *b;
93
+ double d = rb_num2dbl(obj);
94
+ int cnt = 0;
95
+
96
+ if (0.0 == d) {
97
+ b = buf;
98
+ *b++ = '0';
99
+ *b++ = '.';
100
+ *b++ = '0';
101
+ *b++ = '\0';
102
+ cnt = 3;
103
+ } else {
104
+ if (OJ_INFINITY == d || -OJ_INFINITY == d || isnan(d)) {
105
+ raise_wab(obj);
106
+ } else if (d == (double)(long long int)d) {
107
+ cnt = snprintf(buf, sizeof(buf), "%.1f", d);
108
+ } else {
109
+ cnt = snprintf(buf, sizeof(buf), "%0.16g", d);
110
+ }
111
+ }
112
+ assure_size(out, cnt);
113
+ for (b = buf; '\0' != *b; b++) {
114
+ *out->cur++ = *b;
115
+ }
116
+ *out->cur = '\0';
117
+ }
118
+
119
+ static void
120
+ dump_array(VALUE a, int depth, Out out, bool as_ok) {
121
+ size_t size;
122
+ int i, cnt;
123
+ int d2 = depth + 1;
124
+
125
+ cnt = (int)RARRAY_LEN(a);
126
+ *out->cur++ = '[';
127
+ size = 2;
128
+ assure_size(out, size);
129
+ if (0 == cnt) {
130
+ *out->cur++ = ']';
131
+ } else {
132
+ size = d2 * out->indent + 2;
133
+ cnt--;
134
+ for (i = 0; i <= cnt; i++) {
135
+ assure_size(out, size);
136
+ fill_indent(out, d2);
137
+ oj_dump_wab_val(rb_ary_entry(a, i), d2, out);
138
+ if (i < cnt) {
139
+ *out->cur++ = ',';
140
+ }
141
+ }
142
+ size = depth * out->indent + 1;
143
+ assure_size(out, size);
144
+ fill_indent(out, depth);
145
+ *out->cur++ = ']';
146
+ }
147
+ *out->cur = '\0';
148
+ }
149
+
150
+ static int
151
+ hash_cb(VALUE key, VALUE value, VALUE ov) {
152
+ Out out = (Out)ov;
153
+ int depth = out->depth;
154
+ long size;
155
+ int rtype = rb_type(key);
156
+
157
+ if (rtype != T_SYMBOL) {
158
+ rb_raise(rb_eTypeError, "In :wab mode all Hash keys must be Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));
159
+ }
160
+ size = depth * out->indent + 1;
161
+ assure_size(out, size);
162
+ fill_indent(out, depth);
163
+ oj_dump_sym(key, 0, out, false);
164
+ *out->cur++ = ':';
165
+ oj_dump_wab_val(value, depth, out);
166
+ out->depth = depth;
167
+ *out->cur++ = ',';
168
+
169
+ return ST_CONTINUE;
170
+ }
171
+
172
+ static void
173
+ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
174
+ int cnt;
175
+ size_t size;
176
+
177
+ cnt = (int)RHASH_SIZE(obj);
178
+ size = depth * out->indent + 2;
179
+ assure_size(out, 2);
180
+ *out->cur++ = '{';
181
+ if (0 == cnt) {
182
+ *out->cur++ = '}';
183
+ } else {
184
+ out->depth = depth + 1;
185
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
186
+ if (',' == *(out->cur - 1)) {
187
+ out->cur--; // backup to overwrite last comma
188
+ }
189
+ assure_size(out, size);
190
+ fill_indent(out, depth);
191
+ *out->cur++ = '}';
192
+ }
193
+ *out->cur = '\0';
194
+ }
195
+
196
+ static void
197
+ dump_time(VALUE obj, Out out) {
198
+ char buf[64];
199
+ struct _timeInfo ti;
200
+ int len;
201
+ time_t sec;
202
+ long long nsec;
203
+
204
+ #ifdef HAVE_RB_TIME_TIMESPEC
205
+ if (16 <= sizeof(struct timespec)) {
206
+ struct timespec ts = rb_time_timespec(obj);
207
+
208
+ sec = ts.tv_sec;
209
+ nsec = ts.tv_nsec;
210
+ } else {
211
+ sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
212
+ nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
213
+ }
214
+ #else
215
+ sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
216
+ nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
217
+ #endif
218
+
219
+ assure_size(out, 36);
220
+ // 2012-01-05T23:58:07.123456000Z
221
+ sec_as_time(sec, &ti);
222
+
223
+ len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, (long)nsec);
224
+ oj_dump_cstr(buf, len, 0, 0, out);
225
+ }
226
+
227
+ static void
228
+ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
229
+ volatile VALUE clas = rb_obj_class(obj);
230
+
231
+ if (rb_cTime == clas) {
232
+ dump_time(obj, out);
233
+ } else if (oj_bigdecimal_class == clas) {
234
+ volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
235
+
236
+ oj_dump_raw(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), out);
237
+ } else if (resolve_wab_uuid_class() == clas) {
238
+ oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false);
239
+ } else if (resolve_uri_http_class() == clas) {
240
+ oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false);
241
+ } else {
242
+ raise_wab(obj);
243
+ }
244
+ }
245
+
246
+ static DumpFunc wab_funcs[] = {
247
+ NULL, // RUBY_T_NONE = 0x00,
248
+ dump_obj, // RUBY_T_OBJECT = 0x01,
249
+ NULL, // RUBY_T_CLASS = 0x02,
250
+ NULL, // RUBY_T_MODULE = 0x03,
251
+ dump_float, // RUBY_T_FLOAT = 0x04,
252
+ oj_dump_str, // RUBY_T_STRING = 0x05,
253
+ NULL, // RUBY_T_REGEXP = 0x06,
254
+ dump_array, // RUBY_T_ARRAY = 0x07,
255
+ dump_hash, // RUBY_T_HASH = 0x08,
256
+ NULL, // RUBY_T_STRUCT = 0x09,
257
+ oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
258
+ NULL, // RUBY_T_FILE = 0x0b,
259
+ dump_obj, // RUBY_T_DATA = 0x0c,
260
+ NULL, // RUBY_T_MATCH = 0x0d,
261
+ NULL, // RUBY_T_COMPLEX = 0x0e,
262
+ NULL, // RUBY_T_RATIONAL = 0x0f,
263
+ NULL, // 0x10
264
+ oj_dump_nil, // RUBY_T_NIL = 0x11,
265
+ oj_dump_true, // RUBY_T_TRUE = 0x12,
266
+ oj_dump_false, // RUBY_T_FALSE = 0x13,
267
+ oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
268
+ oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
269
+ };
270
+
271
+ void
272
+ oj_dump_wab_val(VALUE obj, int depth, Out out) {
273
+ int type = rb_type(obj);
274
+
275
+ if (Yes == out->opts->trace) {
276
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
277
+ }
278
+ if (MAX_DEPTH < depth) {
279
+ rb_raise(rb_eNoMemError, "Too deeply nested.\n");
280
+ }
281
+ if (0 < type && type <= RUBY_T_FIXNUM) {
282
+ DumpFunc f = wab_funcs[type];
283
+
284
+ if (NULL != f) {
285
+ f(obj, depth, out, false);
286
+ if (Yes == out->opts->trace) {
287
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
288
+ }
289
+ return;
290
+ }
291
+ }
292
+ raise_wab(obj);
293
+ }
294
+
295
+ ///// load functions /////
296
+
297
+ static void
298
+ hash_end(ParseInfo pi) {
299
+ if (Yes == pi->options.trace) {
300
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
301
+ }
302
+ }
303
+
304
+ static void
305
+ array_end(ParseInfo pi) {
306
+ if (Yes == pi->options.trace) {
307
+ oj_trace_parse_array_end(pi, __FILE__, __LINE__);
308
+ }
309
+ }
310
+
311
+ static VALUE
312
+ noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
313
+ return Qundef;
314
+ }
315
+
316
+ static void
317
+ add_value(ParseInfo pi, VALUE val) {
318
+ if (Yes == pi->options.trace) {
319
+ oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
320
+ }
321
+ pi->stack.head->val = val;
322
+ }
323
+
324
+ // 123e4567-e89b-12d3-a456-426655440000
325
+ static bool
326
+ uuid_check(const char *str, int len) {
327
+ int i;
328
+
329
+ for (i = 0; i < 8; i++, str++) {
330
+ if ('x' != hex_chars[*(uint8_t*)str]) {
331
+ return false;
332
+ }
333
+ }
334
+ str++;
335
+ for (i = 0; i < 4; i++, str++) {
336
+ if ('x' != hex_chars[*(uint8_t*)str]) {
337
+ return false;
338
+ }
339
+ }
340
+ str++;
341
+ for (i = 0; i < 4; i++, str++) {
342
+ if ('x' != hex_chars[*(uint8_t*)str]) {
343
+ return false;
344
+ }
345
+ }
346
+ str++;
347
+ for (i = 0; i < 4; i++, str++) {
348
+ if ('x' != hex_chars[*(uint8_t*)str]) {
349
+ return false;
350
+ }
351
+ }
352
+ str++;
353
+ for (i = 0; i < 12; i++, str++) {
354
+ if ('x' != hex_chars[*(uint8_t*)str]) {
355
+ return false;
356
+ }
357
+ }
358
+ return true;
359
+ }
360
+
361
+ static const char*
362
+ read_num(const char *s, int len, int *vp) {
363
+ uint32_t v = 0;
364
+
365
+ for (; 0 < len; len--, s++) {
366
+ if ('0' <= *s && *s <= '9') {
367
+ v = v * 10 + *s - '0';
368
+ } else {
369
+ return NULL;
370
+ }
371
+ }
372
+ *vp = (int)v;
373
+
374
+ return s;
375
+ }
376
+
377
+ static VALUE
378
+ time_parse(const char *s, int len) {
379
+ struct tm tm;
380
+ bool neg = false;
381
+ long nsecs = 0;
382
+ int i;
383
+ time_t secs;
384
+
385
+ memset(&tm, 0, sizeof(tm));
386
+ if ('-' == *s) {
387
+ s++;
388
+ neg = true;
389
+ }
390
+ if (NULL == (s = read_num(s, 4, &tm.tm_year))) {
391
+ return Qnil;
392
+ }
393
+ if (neg) {
394
+ tm.tm_year = -tm.tm_year;
395
+ neg = false;
396
+ }
397
+ tm.tm_year -= 1900;
398
+ s++;
399
+ if (NULL == (s = read_num(s, 2, &tm.tm_mon))) {
400
+ return Qnil;
401
+ }
402
+ tm.tm_mon--;
403
+ s++;
404
+ if (NULL == (s = read_num(s, 2, &tm.tm_mday))) {
405
+ return Qnil;
406
+ }
407
+ s++;
408
+ if (NULL == (s = read_num(s, 2, &tm.tm_hour))) {
409
+ return Qnil;
410
+ }
411
+ s++;
412
+ if (NULL == (s = read_num(s, 2, &tm.tm_min))) {
413
+ return Qnil;
414
+ }
415
+ s++;
416
+ if (NULL == (s = read_num(s, 2, &tm.tm_sec))) {
417
+ return Qnil;
418
+ }
419
+ s++;
420
+
421
+ for (i = 9; 0 < i; i--, s++) {
422
+ if ('0' <= *s && *s <= '9') {
423
+ nsecs = nsecs * 10 + *s - '0';
424
+ } else {
425
+ return Qnil;
426
+ }
427
+ }
428
+ #if IS_WINDOWS
429
+ secs = (time_t)mktime(&tm);
430
+ memset(&tm, 0, sizeof(tm));
431
+ tm.tm_year = 70;
432
+ tm.tm_mday = 1;
433
+ secs -= (time_t)mktime(&tm);
434
+ #else
435
+ secs = (time_t)timegm(&tm);
436
+ #endif
437
+ return rb_funcall(rb_time_nano_new(secs, nsecs), oj_utc_id, 0);
438
+ }
439
+
440
+ static VALUE
441
+ protect_uri(VALUE rstr) {
442
+ return rb_funcall(resolve_uri_class(), oj_parse_id, 1, rstr);
443
+ }
444
+
445
+ static VALUE
446
+ cstr_to_rstr(const char *str, size_t len) {
447
+ volatile VALUE v = Qnil;
448
+
449
+ if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] && ':' == str[16] && '.' == str[19] && 'Z' == str[29]) {
450
+ if (Qnil != (v = time_parse(str, (int)len))) {
451
+ return v;
452
+ }
453
+ }
454
+ if (36 == len && '-' == str[8] && '-' == str[13] && '-' == str[18] && '-' == str[23] && uuid_check(str, (int)len) && Qnil != resolve_wab_uuid_class()) {
455
+ return rb_funcall(wab_uuid_clas, oj_new_id, 1, rb_str_new(str, len));
456
+ }
457
+ v = rb_str_new(str, len);
458
+ if (7 < len && 0 == strncasecmp("http://", str, 7)) {
459
+ int err = 0;
460
+ volatile VALUE uri = rb_protect(protect_uri, v, &err);
461
+
462
+ if (0 == err) {
463
+ return uri;
464
+ }
465
+ }
466
+ return oj_encode(v);
467
+ }
468
+
469
+ static void
470
+ add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
471
+ pi->stack.head->val = cstr_to_rstr(str, len);
472
+ if (Yes == pi->options.trace) {
473
+ oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
474
+ }
475
+ }
476
+
477
+ static void
478
+ add_num(ParseInfo pi, NumInfo ni) {
479
+ if (ni->infinity || ni->nan) {
480
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
481
+ }
482
+ pi->stack.head->val = oj_num_as_value(ni);
483
+ if (Yes == pi->options.trace) {
484
+ oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
485
+ }
486
+ }
487
+
488
+ static VALUE
489
+ start_hash(ParseInfo pi) {
490
+ if (Yes == pi->options.trace) {
491
+ oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
492
+ }
493
+ if (Qnil != pi->options.hash_class) {
494
+ return rb_class_new_instance(0, NULL, pi->options.hash_class);
495
+ }
496
+ return rb_hash_new();
497
+ }
498
+
499
+ static VALUE
500
+ calc_hash_key(ParseInfo pi, Val parent) {
501
+ volatile VALUE rkey = parent->key_val;
502
+
503
+ if (Qundef == rkey) {
504
+ rkey = rb_str_new(parent->key, parent->klen);
505
+ }
506
+ rkey = oj_encode(rkey);
507
+ rkey = rb_str_intern(rkey);
508
+
509
+ return rkey;
510
+ }
511
+
512
+ static void
513
+ hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
514
+ volatile VALUE rval = cstr_to_rstr(str, len);
515
+
516
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
517
+ if (Yes == pi->options.trace) {
518
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
519
+ }
520
+ }
521
+
522
+ static void
523
+ hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
524
+ volatile VALUE rval = Qnil;
525
+
526
+ if (ni->infinity || ni->nan) {
527
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
528
+ }
529
+ rval = oj_num_as_value(ni);
530
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
531
+ if (Yes == pi->options.trace) {
532
+ oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
533
+ }
534
+ }
535
+
536
+ static void
537
+ hash_set_value(ParseInfo pi, Val parent, VALUE value) {
538
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
539
+ if (Yes == pi->options.trace) {
540
+ oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
541
+ }
542
+ }
543
+
544
+ static VALUE
545
+ start_array(ParseInfo pi) {
546
+ if (Yes == pi->options.trace) {
547
+ oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
548
+ }
549
+ return rb_ary_new();
550
+ }
551
+
552
+ static void
553
+ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
554
+ volatile VALUE rval = cstr_to_rstr(str, len);
555
+
556
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
557
+ if (Yes == pi->options.trace) {
558
+ oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, rval);
559
+ }
560
+ }
561
+
562
+ static void
563
+ array_append_num(ParseInfo pi, NumInfo ni) {
564
+ volatile VALUE rval = Qnil;
565
+
566
+ if (ni->infinity || ni->nan) {
567
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
568
+ }
569
+ rval = oj_num_as_value(ni);
570
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
571
+ if (Yes == pi->options.trace) {
572
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
573
+ }
574
+ }
575
+
576
+ static void
577
+ array_append_value(ParseInfo pi, VALUE value) {
578
+ rb_ary_push(stack_peek(&pi->stack)->val, value);
579
+ if (Yes == pi->options.trace) {
580
+ oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
581
+ }
582
+ }
583
+
584
+ void
585
+ oj_set_wab_callbacks(ParseInfo pi) {
586
+ pi->start_hash = start_hash;
587
+ pi->end_hash = hash_end;
588
+ pi->hash_key = noop_hash_key;
589
+ pi->hash_set_cstr = hash_set_cstr;
590
+ pi->hash_set_num = hash_set_num;
591
+ pi->hash_set_value = hash_set_value;
592
+ pi->start_array = start_array;
593
+ pi->end_array = array_end;
594
+ pi->array_append_cstr = array_append_cstr;
595
+ pi->array_append_num = array_append_num;
596
+ pi->array_append_value = array_append_value;
597
+ pi->add_cstr = add_cstr;
598
+ pi->add_num = add_num;
599
+ pi->add_value = add_value;
600
+ pi->expect_value = 1;
601
+ }
602
+
603
+ VALUE
604
+ oj_wab_parse(int argc, VALUE *argv, VALUE self) {
605
+ struct _parseInfo pi;
606
+
607
+ parse_info_init(&pi);
608
+ pi.options = oj_default_options;
609
+ pi.handler = Qnil;
610
+ pi.err_class = Qnil;
611
+ oj_set_wab_callbacks(&pi);
612
+
613
+ if (T_STRING == rb_type(*argv)) {
614
+ return oj_pi_parse(argc, argv, &pi, 0, 0, true);
615
+ } else {
616
+ return oj_pi_sparse(argc, argv, &pi, 0);
617
+ }
618
+ }
619
+
620
+ VALUE
621
+ oj_wab_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
622
+ struct _parseInfo pi;
623
+
624
+ parse_info_init(&pi);
625
+ pi.options = oj_default_options;
626
+ pi.handler = Qnil;
627
+ pi.err_class = Qnil;
628
+ oj_set_wab_callbacks(&pi);
629
+
630
+ return oj_pi_parse(argc, argv, &pi, json, len, true);
631
+ }