oj_windows 3.16.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +44 -0
  3. data/LICENSE +21 -0
  4. data/README.md +164 -0
  5. data/ext/oj_windows/buf.h +85 -0
  6. data/ext/oj_windows/cache.c +339 -0
  7. data/ext/oj_windows/cache.h +22 -0
  8. data/ext/oj_windows/cache8.c +105 -0
  9. data/ext/oj_windows/cache8.h +21 -0
  10. data/ext/oj_windows/circarray.c +64 -0
  11. data/ext/oj_windows/circarray.h +22 -0
  12. data/ext/oj_windows/code.c +214 -0
  13. data/ext/oj_windows/code.h +40 -0
  14. data/ext/oj_windows/compat.c +239 -0
  15. data/ext/oj_windows/custom.c +1074 -0
  16. data/ext/oj_windows/debug.c +126 -0
  17. data/ext/oj_windows/dump.c +1556 -0
  18. data/ext/oj_windows/dump.h +110 -0
  19. data/ext/oj_windows/dump_compat.c +901 -0
  20. data/ext/oj_windows/dump_leaf.c +162 -0
  21. data/ext/oj_windows/dump_object.c +710 -0
  22. data/ext/oj_windows/dump_strict.c +405 -0
  23. data/ext/oj_windows/encode.h +16 -0
  24. data/ext/oj_windows/err.c +57 -0
  25. data/ext/oj_windows/err.h +67 -0
  26. data/ext/oj_windows/extconf.rb +77 -0
  27. data/ext/oj_windows/fast.c +1710 -0
  28. data/ext/oj_windows/intern.c +325 -0
  29. data/ext/oj_windows/intern.h +22 -0
  30. data/ext/oj_windows/mem.c +320 -0
  31. data/ext/oj_windows/mem.h +53 -0
  32. data/ext/oj_windows/mimic_json.c +919 -0
  33. data/ext/oj_windows/object.c +726 -0
  34. data/ext/oj_windows/odd.c +245 -0
  35. data/ext/oj_windows/odd.h +43 -0
  36. data/ext/oj_windows/oj.c +2097 -0
  37. data/ext/oj_windows/oj.h +420 -0
  38. data/ext/oj_windows/parse.c +1317 -0
  39. data/ext/oj_windows/parse.h +113 -0
  40. data/ext/oj_windows/parser.c +1600 -0
  41. data/ext/oj_windows/parser.h +103 -0
  42. data/ext/oj_windows/rails.c +1484 -0
  43. data/ext/oj_windows/rails.h +18 -0
  44. data/ext/oj_windows/reader.c +222 -0
  45. data/ext/oj_windows/reader.h +137 -0
  46. data/ext/oj_windows/resolve.c +80 -0
  47. data/ext/oj_windows/resolve.h +12 -0
  48. data/ext/oj_windows/rxclass.c +144 -0
  49. data/ext/oj_windows/rxclass.h +26 -0
  50. data/ext/oj_windows/saj.c +675 -0
  51. data/ext/oj_windows/saj2.c +584 -0
  52. data/ext/oj_windows/saj2.h +23 -0
  53. data/ext/oj_windows/scp.c +187 -0
  54. data/ext/oj_windows/simd.h +47 -0
  55. data/ext/oj_windows/sparse.c +946 -0
  56. data/ext/oj_windows/stream_writer.c +329 -0
  57. data/ext/oj_windows/strict.c +189 -0
  58. data/ext/oj_windows/string_writer.c +517 -0
  59. data/ext/oj_windows/trace.c +72 -0
  60. data/ext/oj_windows/trace.h +55 -0
  61. data/ext/oj_windows/usual.c +1218 -0
  62. data/ext/oj_windows/usual.h +69 -0
  63. data/ext/oj_windows/util.c +136 -0
  64. data/ext/oj_windows/util.h +20 -0
  65. data/ext/oj_windows/val_stack.c +101 -0
  66. data/ext/oj_windows/val_stack.h +151 -0
  67. data/ext/oj_windows/validate.c +46 -0
  68. data/ext/oj_windows/wab.c +584 -0
  69. data/lib/oj/active_support_helper.rb +39 -0
  70. data/lib/oj/bag.rb +95 -0
  71. data/lib/oj/easy_hash.rb +52 -0
  72. data/lib/oj/error.rb +21 -0
  73. data/lib/oj/json.rb +188 -0
  74. data/lib/oj/mimic.rb +301 -0
  75. data/lib/oj/saj.rb +80 -0
  76. data/lib/oj/schandler.rb +143 -0
  77. data/lib/oj/state.rb +135 -0
  78. data/lib/oj/version.rb +4 -0
  79. data/lib/oj_windows/active_support_helper.rb +39 -0
  80. data/lib/oj_windows/bag.rb +95 -0
  81. data/lib/oj_windows/easy_hash.rb +52 -0
  82. data/lib/oj_windows/error.rb +21 -0
  83. data/lib/oj_windows/json.rb +188 -0
  84. data/lib/oj_windows/mimic.rb +301 -0
  85. data/lib/oj_windows/saj.rb +80 -0
  86. data/lib/oj_windows/schandler.rb +143 -0
  87. data/lib/oj_windows/state.rb +135 -0
  88. data/lib/oj_windows/version.rb +4 -0
  89. data/lib/oj_windows.rb +15 -0
  90. data/pages/Advanced.md +38 -0
  91. data/pages/Compatibility.md +49 -0
  92. data/pages/Custom.md +37 -0
  93. data/pages/Encoding.md +61 -0
  94. data/pages/InstallOptions.md +20 -0
  95. data/pages/JsonGem.md +60 -0
  96. data/pages/Modes.md +94 -0
  97. data/pages/Options.md +339 -0
  98. data/pages/Parser.md +134 -0
  99. data/pages/Rails.md +85 -0
  100. data/pages/Security.md +43 -0
  101. data/pages/WAB.md +12 -0
  102. metadata +242 -0
@@ -0,0 +1,584 @@
1
+ // Copyright (c) 2012 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include <time.h>
8
+ #if !IS_WINDOWS
9
+ #include <unistd.h>
10
+ #endif
11
+
12
+ #include "dump.h"
13
+ #include "encode.h"
14
+ #include "err.h"
15
+ #include "intern.h"
16
+ #include "oj.h"
17
+ #include "parse.h"
18
+ #include "trace.h"
19
+ #include "util.h"
20
+
21
+ // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
22
+ #ifdef _MSC_VER
23
+ #define OJ_INFINITY HUGE_VAL
24
+ #else
25
+ #define OJ_INFINITY (1.0 / 0.0)
26
+ #endif
27
+
28
+ static char hex_chars[256] = "\
29
+ ................................\
30
+ ................xxxxxxxxxx......\
31
+ .xxxxxx.........................\
32
+ .xxxxxx.........................\
33
+ ................................\
34
+ ................................\
35
+ ................................\
36
+ ................................";
37
+
38
+ static VALUE wab_uuid_clas = Qundef;
39
+ static VALUE uri_clas = Qundef;
40
+ static VALUE uri_http_clas = Qundef;
41
+
42
+ ///// dump functions /////
43
+
44
+ static VALUE resolve_wab_uuid_class(void) {
45
+ if (Qundef == wab_uuid_clas) {
46
+ volatile VALUE wab_module;
47
+
48
+ wab_uuid_clas = Qnil;
49
+ if (rb_const_defined_at(rb_cObject, rb_intern("WAB"))) {
50
+ wab_module = rb_const_get_at(rb_cObject, rb_intern("WAB"));
51
+ if (rb_const_defined_at(wab_module, rb_intern("UUID"))) {
52
+ wab_uuid_clas = rb_const_get(wab_module, rb_intern("UUID"));
53
+ }
54
+ }
55
+ }
56
+ return wab_uuid_clas;
57
+ }
58
+
59
+ static VALUE resolve_uri_class(void) {
60
+ if (Qundef == uri_clas) {
61
+ uri_clas = Qnil;
62
+ if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) {
63
+ uri_clas = rb_const_get_at(rb_cObject, rb_intern("URI"));
64
+ }
65
+ }
66
+ return uri_clas;
67
+ }
68
+
69
+ static VALUE resolve_uri_http_class(void) {
70
+ if (Qundef == uri_http_clas) {
71
+ volatile VALUE uri_module;
72
+
73
+ uri_http_clas = Qnil;
74
+ if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) {
75
+ uri_module = rb_const_get_at(rb_cObject, rb_intern("URI"));
76
+ if (rb_const_defined_at(uri_module, rb_intern("HTTP"))) {
77
+ uri_http_clas = rb_const_get(uri_module, rb_intern("HTTP"));
78
+ }
79
+ }
80
+ }
81
+ return uri_http_clas;
82
+ }
83
+
84
+ static void 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 dump_float(VALUE obj, int depth, Out out, bool as_ok) {
90
+ char buf[64];
91
+ char *b;
92
+ double d = rb_num2dbl(obj);
93
+ int cnt = 0;
94
+
95
+ if (0.0 == d) {
96
+ b = buf;
97
+ *b++ = '0';
98
+ *b++ = '.';
99
+ *b++ = '0';
100
+ *b++ = '\0';
101
+ cnt = 3;
102
+ } else {
103
+ if (OJ_INFINITY == d || -OJ_INFINITY == d || isnan(d)) {
104
+ raise_wab(obj);
105
+ } else if (d == (double)(long long int)d) {
106
+ cnt = snprintf(buf, sizeof(buf), "%.1f", d);
107
+ } else {
108
+ cnt = snprintf(buf, sizeof(buf), "%0.16g", d);
109
+ }
110
+ }
111
+ assure_size(out, cnt);
112
+ for (b = buf; '\0' != *b; b++) {
113
+ *out->cur++ = *b;
114
+ }
115
+ *out->cur = '\0';
116
+ }
117
+
118
+ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
119
+ size_t size;
120
+ size_t i;
121
+ size_t cnt;
122
+ int d2 = depth + 1;
123
+
124
+ cnt = RARRAY_LEN(a);
125
+ *out->cur++ = '[';
126
+ size = 2;
127
+ assure_size(out, size);
128
+ if (0 == cnt) {
129
+ *out->cur++ = ']';
130
+ } else {
131
+ size = d2 * out->indent + 2;
132
+ assure_size(out, size * cnt);
133
+ cnt--;
134
+ for (i = 0; i <= cnt; i++) {
135
+ fill_indent(out, d2);
136
+ oj_dump_wab_val(RARRAY_AREF(a, i), d2, out);
137
+ if (i < cnt) {
138
+ *out->cur++ = ',';
139
+ }
140
+ }
141
+ size = depth * out->indent + 1;
142
+ assure_size(out, size);
143
+ fill_indent(out, depth);
144
+ *out->cur++ = ']';
145
+ }
146
+ *out->cur = '\0';
147
+ }
148
+
149
+ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
150
+ Out out = (Out)ov;
151
+ int depth = out->depth;
152
+ long size;
153
+ int rtype = rb_type(key);
154
+
155
+ if (rtype != T_SYMBOL) {
156
+ rb_raise(rb_eTypeError,
157
+ "In :wab mode all Hash keys must be Symbols, not %s.\n",
158
+ 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 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 dump_time(VALUE obj, Out out) {
196
+ char buf[64];
197
+ struct _timeInfo ti;
198
+ int len;
199
+ time_t sec;
200
+ long long nsec;
201
+
202
+ if (16 <= sizeof(struct timespec)) {
203
+ struct timespec ts = rb_time_timespec(obj);
204
+
205
+ sec = ts.tv_sec;
206
+ nsec = ts.tv_nsec;
207
+ } else {
208
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
209
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
210
+ }
211
+
212
+ assure_size(out, 36);
213
+ // 2012-01-05T23:58:07.123456000Z
214
+ sec_as_time(sec, &ti);
215
+
216
+ len = sprintf(buf,
217
+ "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ",
218
+ ti.year,
219
+ ti.mon,
220
+ ti.day,
221
+ ti.hour,
222
+ ti.min,
223
+ ti.sec,
224
+ (long)nsec);
225
+ oj_dump_cstr(buf, len, 0, 0, out);
226
+ }
227
+
228
+ static void 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 = oj_safe_string_convert(obj);
235
+
236
+ oj_dump_raw(RSTRING_PTR(rstr), RSTRING_LEN(rstr), out);
237
+ } else if (resolve_wab_uuid_class() == clas) {
238
+ oj_dump_str(oj_safe_string_convert(obj), depth, out, false);
239
+ } else if (resolve_uri_http_class() == clas) {
240
+ oj_dump_str(oj_safe_string_convert(obj), 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 oj_dump_wab_val(VALUE obj, int depth, Out out) {
272
+ int type = rb_type(obj);
273
+
274
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
275
+ if (MAX_DEPTH < depth) {
276
+ rb_raise(rb_eNoMemError, "Too deeply nested.\n");
277
+ }
278
+ if (0 < type && type <= RUBY_T_FIXNUM) {
279
+ DumpFunc f = wab_funcs[type];
280
+
281
+ if (NULL != f) {
282
+ f(obj, depth, out, false);
283
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
284
+ return;
285
+ }
286
+ }
287
+ raise_wab(obj);
288
+ }
289
+
290
+ ///// load functions /////
291
+
292
+ static VALUE calc_hash_key(ParseInfo pi, Val parent) {
293
+ volatile VALUE rkey = parent->key_val;
294
+
295
+ if (Qundef != rkey) {
296
+ rkey = oj_encode(rkey);
297
+ rkey = rb_str_intern(rkey);
298
+
299
+ return rkey;
300
+ }
301
+ if (Yes == pi->options.cache_keys) {
302
+ rkey = oj_sym_intern(parent->key, parent->klen);
303
+ } else {
304
+ #if HAVE_RB_ENC_INTERNED_STR
305
+ rkey = rb_enc_interned_str(parent->key, parent->klen, oj_utf8_encoding);
306
+ #else
307
+ rkey = rb_utf8_str_new(parent->key, parent->klen);
308
+ rkey = rb_str_intern(rkey);
309
+ OBJ_FREEZE(rkey);
310
+ #endif
311
+ }
312
+ return rkey;
313
+ }
314
+
315
+ static void hash_end(ParseInfo pi) {
316
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
317
+ }
318
+
319
+ static void array_end(ParseInfo pi) {
320
+ TRACE_PARSE_ARRAY_END(pi->options.trace, pi);
321
+ }
322
+
323
+ static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
324
+ return Qundef;
325
+ }
326
+
327
+ static void add_value(ParseInfo pi, VALUE val) {
328
+ TRACE_PARSE_CALL(pi->options.trace, "add_value", pi, val);
329
+ pi->stack.head->val = val;
330
+ }
331
+
332
+ // 123e4567-e89b-12d3-a456-426655440000
333
+ static bool uuid_check(const char *str, int len) {
334
+ int i;
335
+
336
+ for (i = 0; i < 8; i++, str++) {
337
+ if ('x' != hex_chars[*(uint8_t *)str]) {
338
+ return false;
339
+ }
340
+ }
341
+ str++;
342
+ for (i = 0; i < 4; i++, str++) {
343
+ if ('x' != hex_chars[*(uint8_t *)str]) {
344
+ return false;
345
+ }
346
+ }
347
+ str++;
348
+ for (i = 0; i < 4; i++, str++) {
349
+ if ('x' != hex_chars[*(uint8_t *)str]) {
350
+ return false;
351
+ }
352
+ }
353
+ str++;
354
+ for (i = 0; i < 4; i++, str++) {
355
+ if ('x' != hex_chars[*(uint8_t *)str]) {
356
+ return false;
357
+ }
358
+ }
359
+ str++;
360
+ for (i = 0; i < 12; i++, str++) {
361
+ if ('x' != hex_chars[*(uint8_t *)str]) {
362
+ return false;
363
+ }
364
+ }
365
+ return true;
366
+ }
367
+
368
+ static const char *read_num(const char *s, int len, int *vp) {
369
+ uint32_t v = 0;
370
+
371
+ for (; 0 < len; len--, s++) {
372
+ if ('0' <= *s && *s <= '9') {
373
+ v = v * 10 + *s - '0';
374
+ } else {
375
+ return NULL;
376
+ }
377
+ }
378
+ *vp = (int)v;
379
+
380
+ return s;
381
+ }
382
+
383
+ static VALUE time_parse(const char *s, int len) {
384
+ struct tm tm;
385
+ bool neg = false;
386
+ long nsecs = 0;
387
+ int i;
388
+ time_t secs;
389
+
390
+ memset(&tm, 0, sizeof(tm));
391
+ if ('-' == *s) {
392
+ s++;
393
+ neg = true;
394
+ }
395
+ if (NULL == (s = read_num(s, 4, &tm.tm_year))) {
396
+ return Qnil;
397
+ }
398
+ if (neg) {
399
+ tm.tm_year = -tm.tm_year;
400
+ neg = false;
401
+ }
402
+ tm.tm_year -= 1900;
403
+ s++;
404
+ if (NULL == (s = read_num(s, 2, &tm.tm_mon))) {
405
+ return Qnil;
406
+ }
407
+ tm.tm_mon--;
408
+ s++;
409
+ if (NULL == (s = read_num(s, 2, &tm.tm_mday))) {
410
+ return Qnil;
411
+ }
412
+ s++;
413
+ if (NULL == (s = read_num(s, 2, &tm.tm_hour))) {
414
+ return Qnil;
415
+ }
416
+ s++;
417
+ if (NULL == (s = read_num(s, 2, &tm.tm_min))) {
418
+ return Qnil;
419
+ }
420
+ s++;
421
+ if (NULL == (s = read_num(s, 2, &tm.tm_sec))) {
422
+ return Qnil;
423
+ }
424
+ s++;
425
+
426
+ for (i = 9; 0 < i; i--, s++) {
427
+ if ('0' <= *s && *s <= '9') {
428
+ nsecs = nsecs * 10 + *s - '0';
429
+ } else {
430
+ return Qnil;
431
+ }
432
+ }
433
+ secs = (time_t)timegm(&tm);
434
+ return rb_funcall(rb_time_nano_new(secs, nsecs), oj_utc_id, 0);
435
+ }
436
+
437
+ static VALUE protect_uri(VALUE rstr) {
438
+ return rb_funcall(resolve_uri_class(), oj_parse_id, 1, rstr);
439
+ }
440
+
441
+ static VALUE cstr_to_rstr(ParseInfo pi, const char *str, size_t len) {
442
+ volatile VALUE v = Qnil;
443
+
444
+ if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] && ':' == str[16] &&
445
+ '.' == str[19] && 'Z' == str[29]) {
446
+ if (Qnil != (v = time_parse(str, (int)len))) {
447
+ return v;
448
+ }
449
+ }
450
+ if (36 == len && '-' == str[8] && '-' == str[13] && '-' == str[18] && '-' == str[23] && uuid_check(str, (int)len) &&
451
+ Qnil != resolve_wab_uuid_class()) {
452
+ return rb_funcall(wab_uuid_clas, oj_new_id, 1, rb_str_new(str, len));
453
+ }
454
+ if (7 < len && 0 == strncasecmp("http://", str, 7)) {
455
+ int err = 0;
456
+ v = rb_str_new(str, len);
457
+ volatile VALUE uri = rb_protect(protect_uri, v, &err);
458
+
459
+ if (0 == err) {
460
+ return uri;
461
+ }
462
+ }
463
+ return oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
464
+ }
465
+
466
+ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
467
+ pi->stack.head->val = cstr_to_rstr(pi, str, len);
468
+ TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, pi->stack.head->val);
469
+ }
470
+
471
+ static void add_num(ParseInfo pi, NumInfo ni) {
472
+ if (ni->infinity || ni->nan) {
473
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
474
+ }
475
+ pi->stack.head->val = oj_num_as_value(ni);
476
+ TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, pi->stack.head->val);
477
+ }
478
+
479
+ static VALUE start_hash(ParseInfo pi) {
480
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
481
+ if (Qnil != pi->options.hash_class) {
482
+ return rb_class_new_instance(0, NULL, pi->options.hash_class);
483
+ }
484
+ return rb_hash_new();
485
+ }
486
+
487
+ static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
488
+ volatile VALUE rval = cstr_to_rstr(pi, str, len);
489
+
490
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
491
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rval);
492
+ }
493
+
494
+ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
495
+ volatile VALUE rval = Qnil;
496
+
497
+ if (ni->infinity || ni->nan) {
498
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
499
+ }
500
+ rval = oj_num_as_value(ni);
501
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
502
+ TRACE_PARSE_CALL(pi->options.trace, "set_number", pi, rval);
503
+ }
504
+
505
+ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
506
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
507
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
508
+ }
509
+
510
+ static VALUE start_array(ParseInfo pi) {
511
+ TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
512
+ return rb_ary_new();
513
+ }
514
+
515
+ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
516
+ volatile VALUE rval = cstr_to_rstr(pi, str, len);
517
+
518
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
519
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, rval);
520
+ }
521
+
522
+ static void array_append_num(ParseInfo pi, 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_ary_push(stack_peek(&pi->stack)->val, rval);
530
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
531
+ }
532
+
533
+ static void array_append_value(ParseInfo pi, VALUE value) {
534
+ rb_ary_push(stack_peek(&pi->stack)->val, value);
535
+ TRACE_PARSE_CALL(pi->options.trace, "append_value", pi, value);
536
+ }
537
+
538
+ void oj_set_wab_callbacks(ParseInfo pi) {
539
+ pi->start_hash = start_hash;
540
+ pi->end_hash = hash_end;
541
+ pi->hash_key = noop_hash_key;
542
+ pi->hash_set_cstr = hash_set_cstr;
543
+ pi->hash_set_num = hash_set_num;
544
+ pi->hash_set_value = hash_set_value;
545
+ pi->start_array = start_array;
546
+ pi->end_array = array_end;
547
+ pi->array_append_cstr = array_append_cstr;
548
+ pi->array_append_num = array_append_num;
549
+ pi->array_append_value = array_append_value;
550
+ pi->add_cstr = add_cstr;
551
+ pi->add_num = add_num;
552
+ pi->add_value = add_value;
553
+ pi->expect_value = 1;
554
+ }
555
+
556
+ VALUE
557
+ oj_wab_parse(int argc, VALUE *argv, VALUE self) {
558
+ struct _parseInfo pi;
559
+
560
+ parse_info_init(&pi);
561
+ pi.options = oj_default_options;
562
+ pi.handler = Qnil;
563
+ pi.err_class = Qnil;
564
+ oj_set_wab_callbacks(&pi);
565
+
566
+ if (T_STRING == rb_type(*argv)) {
567
+ return oj_pi_parse(argc, argv, &pi, 0, 0, true);
568
+ } else {
569
+ return oj_pi_sparse(argc, argv, &pi, 0);
570
+ }
571
+ }
572
+
573
+ VALUE
574
+ oj_wab_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
575
+ struct _parseInfo pi;
576
+
577
+ parse_info_init(&pi);
578
+ pi.options = oj_default_options;
579
+ pi.handler = Qnil;
580
+ pi.err_class = Qnil;
581
+ oj_set_wab_callbacks(&pi);
582
+
583
+ return oj_pi_parse(argc, argv, &pi, json, len, true);
584
+ }
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/time'
4
+
5
+ module Oj
6
+ # Exists only to handle the ActiveSupport::TimeWithZone.
7
+ class ActiveSupportHelper
8
+ def self.createTimeWithZone(utc, zone)
9
+ ActiveSupport::TimeWithZone.new(utc - utc.gmt_offset, ActiveSupport::TimeZone[zone])
10
+ end
11
+ end
12
+ end
13
+
14
+ Oj.register_odd(ActiveSupport::TimeWithZone, Oj::ActiveSupportHelper, :createTimeWithZone, :utc, 'time_zone.name')
15
+
16
+ # This is a hack to work around an oddness with DateTime and the ActiveSupport
17
+ # that causes a hang when some methods are called from C. Hour, min(ute),
18
+ # sec(ond) and other methods are special but they can be called from C until
19
+ # activesupport/time is required. After that they can not be even though
20
+ # resond_to? returns true. By defining methods to call super the problem goes
21
+ # away. There is obviously some magic going on under the covers that I don't
22
+ # understand.
23
+ class DateTime
24
+ def hour()
25
+ super
26
+ end
27
+ def min()
28
+ super
29
+ end
30
+ def sec()
31
+ super
32
+ end
33
+ def sec_fraction()
34
+ super
35
+ end
36
+ def offset()
37
+ super
38
+ end
39
+ end
data/lib/oj/bag.rb ADDED
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Oj
4
+
5
+ # A generic class that is used only for storing attributes. It is the base
6
+ # Class for auto-generated classes in the storage system. Instance variables
7
+ # are added using the instance_variable_set() method. All instance variables
8
+ # can be accessed using the variable name (without the @ prefix). No setters
9
+ # are provided as the Class is intended for reading only.
10
+ class Bag
11
+
12
+ # The initializer can take multiple arguments in the form of key values
13
+ # where the key is the variable name and the value is the variable
14
+ # value. This is intended for testing purposes only.
15
+ # @example Oj::Bag.new(:@x => 42, :@y => 57)
16
+ # @param [Hash] args instance variable symbols and their values
17
+ def initialize(args = {})
18
+ args.each do |k, v|
19
+ self.instance_variable_set(k, v)
20
+ end
21
+ end
22
+
23
+ # Replaces the Object.respond_to?() method.
24
+ # @param [Symbol] m method symbol
25
+ # @return [Boolean] true for any method that matches an instance
26
+ # variable reader, otherwise false.
27
+ def respond_to?(m)
28
+ return true if super
29
+
30
+ instance_variables.include?(:"@#{m}")
31
+ end
32
+
33
+ # Handles requests for variable values. Others cause an Exception to be
34
+ # raised.
35
+ # @param [Symbol] m method symbol
36
+ # @return [Boolean] the value of the specified instance variable.
37
+ # @raise [ArgumentError] if an argument is given. Zero arguments expected.
38
+ # @raise [NoMethodError] if the instance variable is not defined.
39
+ def method_missing(m, *args, &block)
40
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 0) to method #{m}") unless args.nil? or args.empty?
41
+
42
+ at_m = :"@#{m}"
43
+ raise NoMethodError.new("undefined method #{m}", m) unless instance_variable_defined?(at_m)
44
+
45
+ instance_variable_get(at_m)
46
+ end
47
+
48
+ # Replaces eql?() with something more reasonable for this Class.
49
+ # @param [Object] other Object to compare self to
50
+ # @return [Boolean] true if each variable and value are the same, otherwise false.
51
+ def eql?(other)
52
+ return false if (other.nil? or self.class != other.class)
53
+
54
+ ova = other.instance_variables
55
+ iv = instance_variables
56
+ return false if ova.size != iv.size
57
+
58
+ iv.all? { |vid| instance_variable_get(vid) != other.instance_variable_get(vid) }
59
+ end
60
+ alias == eql?
61
+
62
+ # Define a new class based on the Oj::Bag class. This is used internally in
63
+ # the Oj module and is available to service wrappers that receive XML
64
+ # requests that include Objects of Classes not defined in the storage
65
+ # process.
66
+ # @param [String] classname Class name or symbol that includes Module names.
67
+ # @return [Object] an instance of the specified Class.
68
+ # @raise [NameError] if the classname is invalid.
69
+ def self.define_class(classname)
70
+ classname = classname.to_s unless classname.is_a?(String)
71
+ tokens = classname.split('::').map(&:to_sym)
72
+ raise NameError.new("Invalid classname '#{classname}") if tokens.empty?
73
+
74
+ m = Object
75
+ tokens[0..-2].each do |sym|
76
+ if m.const_defined?(sym)
77
+ m = m.const_get(sym)
78
+ else
79
+ c = Module.new
80
+ m.const_set(sym, c)
81
+ m = c
82
+ end
83
+ end
84
+ sym = tokens[-1]
85
+ if m.const_defined?(sym)
86
+ c = m.const_get(sym)
87
+ else
88
+ c = Class.new(Oj::Bag)
89
+ m.const_set(sym, c)
90
+ end
91
+ c
92
+ end
93
+
94
+ end # Bag
95
+ end # Oj