oj 3.8.1

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