oj 2.18.3 → 3.13.14

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 (182) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1324 -0
  3. data/README.md +51 -204
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +49 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -68
  11. data/ext/oj/circarray.h +16 -42
  12. data/ext/oj/code.c +221 -0
  13. data/ext/oj/code.h +40 -0
  14. data/ext/oj/compat.c +231 -107
  15. data/ext/oj/custom.c +1125 -0
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +935 -2513
  18. data/ext/oj/dump.h +108 -0
  19. data/ext/oj/dump_compat.c +936 -0
  20. data/ext/oj/dump_leaf.c +164 -0
  21. data/ext/oj/dump_object.c +761 -0
  22. data/ext/oj/dump_strict.c +410 -0
  23. data/ext/oj/encode.h +7 -42
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -54
  26. data/ext/oj/err.h +52 -46
  27. data/ext/oj/extconf.rb +21 -30
  28. data/ext/oj/fast.c +1097 -1080
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +893 -0
  32. data/ext/oj/object.c +549 -620
  33. data/ext/oj/odd.c +155 -167
  34. data/ext/oj/odd.h +37 -63
  35. data/ext/oj/oj.c +1661 -2063
  36. data/ext/oj/oj.h +341 -270
  37. data/ext/oj/parse.c +974 -737
  38. data/ext/oj/parse.h +105 -97
  39. data/ext/oj/parser.c +1526 -0
  40. data/ext/oj/parser.h +90 -0
  41. data/ext/oj/rails.c +1504 -0
  42. data/ext/oj/rails.h +18 -0
  43. data/ext/oj/reader.c +141 -163
  44. data/ext/oj/reader.h +75 -113
  45. data/ext/oj/resolve.c +45 -93
  46. data/ext/oj/resolve.h +7 -34
  47. data/ext/oj/rxclass.c +143 -0
  48. data/ext/oj/rxclass.h +26 -0
  49. data/ext/oj/saj.c +447 -511
  50. data/ext/oj/saj2.c +348 -0
  51. data/ext/oj/scp.c +91 -138
  52. data/ext/oj/sparse.c +793 -644
  53. data/ext/oj/stream_writer.c +331 -0
  54. data/ext/oj/strict.c +145 -109
  55. data/ext/oj/string_writer.c +493 -0
  56. data/ext/oj/trace.c +72 -0
  57. data/ext/oj/trace.h +28 -0
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +62 -70
  62. data/ext/oj/val_stack.h +95 -129
  63. data/ext/oj/validate.c +51 -0
  64. data/ext/oj/wab.c +622 -0
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +17 -8
  67. data/lib/oj/error.rb +10 -11
  68. data/lib/oj/json.rb +176 -0
  69. data/lib/oj/mimic.rb +158 -19
  70. data/lib/oj/state.rb +132 -0
  71. data/lib/oj/version.rb +2 -2
  72. data/lib/oj.rb +1 -31
  73. data/pages/Advanced.md +22 -0
  74. data/pages/Compatibility.md +25 -0
  75. data/pages/Custom.md +23 -0
  76. data/pages/Encoding.md +65 -0
  77. data/pages/JsonGem.md +94 -0
  78. data/pages/Modes.md +161 -0
  79. data/pages/Options.md +327 -0
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +167 -0
  82. data/pages/Security.md +20 -0
  83. data/pages/WAB.md +13 -0
  84. data/test/activerecord/result_test.rb +32 -0
  85. data/test/activesupport4/decoding_test.rb +108 -0
  86. data/test/activesupport4/encoding_test.rb +531 -0
  87. data/test/activesupport4/test_helper.rb +41 -0
  88. data/test/activesupport5/abstract_unit.rb +45 -0
  89. data/test/activesupport5/decoding_test.rb +133 -0
  90. data/test/activesupport5/encoding_test.rb +500 -0
  91. data/test/activesupport5/encoding_test_cases.rb +98 -0
  92. data/test/activesupport5/test_helper.rb +72 -0
  93. data/test/activesupport5/time_zone_test_helpers.rb +39 -0
  94. data/test/activesupport6/abstract_unit.rb +44 -0
  95. data/test/activesupport6/decoding_test.rb +133 -0
  96. data/test/activesupport6/encoding_test.rb +507 -0
  97. data/test/activesupport6/encoding_test_cases.rb +98 -0
  98. data/test/activesupport6/test_common.rb +17 -0
  99. data/test/activesupport6/test_helper.rb +163 -0
  100. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  101. data/test/activesupport7/abstract_unit.rb +49 -0
  102. data/test/activesupport7/decoding_test.rb +125 -0
  103. data/test/activesupport7/encoding_test.rb +486 -0
  104. data/test/activesupport7/encoding_test_cases.rb +104 -0
  105. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  106. data/test/bar.rb +9 -0
  107. data/test/baz.rb +16 -0
  108. data/test/bug.rb +11 -46
  109. data/test/foo.rb +69 -16
  110. data/test/helper.rb +10 -1
  111. data/test/isolated/shared.rb +12 -8
  112. data/test/isolated/test_mimic_rails_after.rb +3 -3
  113. data/test/isolated/test_mimic_rails_before.rb +3 -3
  114. data/test/json_gem/json_addition_test.rb +216 -0
  115. data/test/json_gem/json_common_interface_test.rb +153 -0
  116. data/test/json_gem/json_encoding_test.rb +107 -0
  117. data/test/json_gem/json_ext_parser_test.rb +20 -0
  118. data/test/json_gem/json_fixtures_test.rb +35 -0
  119. data/test/json_gem/json_generator_test.rb +397 -0
  120. data/test/json_gem/json_generic_object_test.rb +90 -0
  121. data/test/json_gem/json_parser_test.rb +470 -0
  122. data/test/json_gem/json_string_matching_test.rb +42 -0
  123. data/test/json_gem/test_helper.rb +26 -0
  124. data/test/mem.rb +33 -0
  125. data/test/perf.rb +1 -1
  126. data/test/perf_compat.rb +30 -28
  127. data/test/perf_dump.rb +50 -0
  128. data/test/perf_object.rb +1 -1
  129. data/test/perf_once.rb +58 -0
  130. data/test/perf_parser.rb +189 -0
  131. data/test/perf_scp.rb +11 -10
  132. data/test/perf_strict.rb +30 -19
  133. data/test/perf_wab.rb +131 -0
  134. data/test/prec.rb +23 -0
  135. data/test/sample.rb +0 -1
  136. data/test/sample_json.rb +1 -1
  137. data/test/test_compat.rb +219 -102
  138. data/test/test_custom.rb +533 -0
  139. data/test/test_fast.rb +107 -35
  140. data/test/test_file.rb +19 -25
  141. data/test/test_generate.rb +21 -0
  142. data/test/test_hash.rb +11 -1
  143. data/test/test_integer_range.rb +72 -0
  144. data/test/test_null.rb +376 -0
  145. data/test/test_object.rb +357 -70
  146. data/test/test_parser.rb +27 -0
  147. data/test/test_parser_saj.rb +245 -0
  148. data/test/test_parser_usual.rb +217 -0
  149. data/test/test_rails.rb +35 -0
  150. data/test/test_saj.rb +1 -1
  151. data/test/test_scp.rb +39 -2
  152. data/test/test_strict.rb +186 -7
  153. data/test/test_various.rb +160 -774
  154. data/test/test_wab.rb +307 -0
  155. data/test/test_writer.rb +90 -2
  156. data/test/tests.rb +24 -0
  157. data/test/tests_mimic.rb +14 -0
  158. data/test/tests_mimic_addition.rb +7 -0
  159. data/test/zoo.rb +13 -0
  160. metadata +194 -56
  161. data/ext/oj/hash.c +0 -163
  162. data/ext/oj/hash.h +0 -46
  163. data/ext/oj/hash_test.c +0 -512
  164. data/test/activesupport_datetime_test.rb +0 -23
  165. data/test/bug2.rb +0 -10
  166. data/test/bug3.rb +0 -46
  167. data/test/bug_fast.rb +0 -32
  168. data/test/bug_load.rb +0 -24
  169. data/test/crash.rb +0 -111
  170. data/test/curl/curl_oj.rb +0 -46
  171. data/test/curl/get_oj.rb +0 -24
  172. data/test/curl/just_curl.rb +0 -31
  173. data/test/curl/just_oj.rb +0 -51
  174. data/test/example.rb +0 -11
  175. data/test/io.rb +0 -48
  176. data/test/isolated/test_mimic_rails_datetime.rb +0 -27
  177. data/test/mod.rb +0 -16
  178. data/test/rails.rb +0 -50
  179. data/test/russian.rb +0 -18
  180. data/test/struct.rb +0 -29
  181. data/test/test_serializer.rb +0 -59
  182. data/test/write_timebars.rb +0 -31
data/ext/oj/wab.c ADDED
@@ -0,0 +1,622 @@
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
+ #include <unistd.h>
9
+
10
+ #include "dump.h"
11
+ #include "encode.h"
12
+ #include "err.h"
13
+ #include "intern.h"
14
+ #include "oj.h"
15
+ #include "parse.h"
16
+ #include "trace.h"
17
+ #include "util.h"
18
+
19
+ // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
20
+ #define OJ_INFINITY (1.0 / 0.0)
21
+
22
+ static char hex_chars[256] = "\
23
+ ................................\
24
+ ................xxxxxxxxxx......\
25
+ .xxxxxx.........................\
26
+ .xxxxxx.........................\
27
+ ................................\
28
+ ................................\
29
+ ................................\
30
+ ................................";
31
+
32
+ static VALUE wab_uuid_clas = Qundef;
33
+ static VALUE uri_clas = Qundef;
34
+ static VALUE uri_http_clas = Qundef;
35
+
36
+ ///// dump functions /////
37
+
38
+ static VALUE resolve_wab_uuid_class(void) {
39
+ if (Qundef == wab_uuid_clas) {
40
+ volatile VALUE wab_module;
41
+
42
+ wab_uuid_clas = Qnil;
43
+ if (rb_const_defined_at(rb_cObject, rb_intern("WAB"))) {
44
+ wab_module = rb_const_get_at(rb_cObject, rb_intern("WAB"));
45
+ if (rb_const_defined_at(wab_module, rb_intern("UUID"))) {
46
+ wab_uuid_clas = rb_const_get(wab_module, rb_intern("UUID"));
47
+ }
48
+ }
49
+ }
50
+ return wab_uuid_clas;
51
+ }
52
+
53
+ static VALUE resolve_uri_class(void) {
54
+ if (Qundef == uri_clas) {
55
+ uri_clas = Qnil;
56
+ if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) {
57
+ uri_clas = rb_const_get_at(rb_cObject, rb_intern("URI"));
58
+ }
59
+ }
60
+ return uri_clas;
61
+ }
62
+
63
+ static VALUE resolve_uri_http_class(void) {
64
+ if (Qundef == uri_http_clas) {
65
+ volatile VALUE uri_module;
66
+
67
+ uri_http_clas = Qnil;
68
+ if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) {
69
+ uri_module = rb_const_get_at(rb_cObject, rb_intern("URI"));
70
+ if (rb_const_defined_at(uri_module, rb_intern("HTTP"))) {
71
+ uri_http_clas = rb_const_get(uri_module, rb_intern("HTTP"));
72
+ }
73
+ }
74
+ }
75
+ return uri_http_clas;
76
+ }
77
+
78
+ static void raise_wab(VALUE obj) {
79
+ rb_raise(rb_eTypeError,
80
+ "Failed to dump %s Object to JSON in wab mode.\n",
81
+ rb_class2name(rb_obj_class(obj)));
82
+ }
83
+
84
+ // Removed dependencies on math due to problems with CentOS 5.4.
85
+ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
86
+ char buf[64];
87
+ char * b;
88
+ double d = rb_num2dbl(obj);
89
+ int cnt = 0;
90
+
91
+ if (0.0 == d) {
92
+ b = buf;
93
+ *b++ = '0';
94
+ *b++ = '.';
95
+ *b++ = '0';
96
+ *b++ = '\0';
97
+ cnt = 3;
98
+ } else {
99
+ if (OJ_INFINITY == d || -OJ_INFINITY == d || isnan(d)) {
100
+ raise_wab(obj);
101
+ } else if (d == (double)(long long int)d) {
102
+ cnt = snprintf(buf, sizeof(buf), "%.1f", d);
103
+ } else {
104
+ cnt = snprintf(buf, sizeof(buf), "%0.16g", d);
105
+ }
106
+ }
107
+ assure_size(out, cnt);
108
+ for (b = buf; '\0' != *b; b++) {
109
+ *out->cur++ = *b;
110
+ }
111
+ *out->cur = '\0';
112
+ }
113
+
114
+ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
115
+ size_t size;
116
+ int i, cnt;
117
+ int d2 = depth + 1;
118
+
119
+ cnt = (int)RARRAY_LEN(a);
120
+ *out->cur++ = '[';
121
+ size = 2;
122
+ assure_size(out, size);
123
+ if (0 == cnt) {
124
+ *out->cur++ = ']';
125
+ } else {
126
+ size = d2 * out->indent + 2;
127
+ assure_size(out, size * cnt);
128
+ cnt--;
129
+ for (i = 0; i <= cnt; i++) {
130
+ fill_indent(out, d2);
131
+ oj_dump_wab_val(RARRAY_AREF(a, i), d2, out);
132
+ if (i < cnt) {
133
+ *out->cur++ = ',';
134
+ }
135
+ }
136
+ size = depth * out->indent + 1;
137
+ assure_size(out, size);
138
+ fill_indent(out, depth);
139
+ *out->cur++ = ']';
140
+ }
141
+ *out->cur = '\0';
142
+ }
143
+
144
+ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
145
+ Out out = (Out)ov;
146
+ int depth = out->depth;
147
+ long size;
148
+ int rtype = rb_type(key);
149
+
150
+ if (rtype != T_SYMBOL) {
151
+ rb_raise(rb_eTypeError,
152
+ "In :wab mode all Hash keys must be Symbols, not %s.\n",
153
+ rb_class2name(rb_obj_class(key)));
154
+ }
155
+ size = depth * out->indent + 1;
156
+ assure_size(out, size);
157
+ fill_indent(out, depth);
158
+ oj_dump_sym(key, 0, out, false);
159
+ *out->cur++ = ':';
160
+ oj_dump_wab_val(value, depth, out);
161
+ out->depth = depth;
162
+ *out->cur++ = ',';
163
+
164
+ return ST_CONTINUE;
165
+ }
166
+
167
+ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
168
+ int cnt;
169
+ size_t size;
170
+
171
+ cnt = (int)RHASH_SIZE(obj);
172
+ size = depth * out->indent + 2;
173
+ assure_size(out, 2);
174
+ *out->cur++ = '{';
175
+ if (0 == cnt) {
176
+ *out->cur++ = '}';
177
+ } else {
178
+ out->depth = depth + 1;
179
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
180
+ if (',' == *(out->cur - 1)) {
181
+ out->cur--; // backup to overwrite last comma
182
+ }
183
+ assure_size(out, size);
184
+ fill_indent(out, depth);
185
+ *out->cur++ = '}';
186
+ }
187
+ *out->cur = '\0';
188
+ }
189
+
190
+ static void dump_time(VALUE obj, Out out) {
191
+ char buf[64];
192
+ struct _timeInfo ti;
193
+ int len;
194
+ time_t sec;
195
+ long long nsec;
196
+
197
+ #ifdef HAVE_RB_TIME_TIMESPEC
198
+ if (16 <= sizeof(struct timespec)) {
199
+ struct timespec ts = rb_time_timespec(obj);
200
+
201
+ sec = ts.tv_sec;
202
+ nsec = ts.tv_nsec;
203
+ } else {
204
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
205
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
206
+ }
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
+ #endif
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 = rb_funcall(obj, oj_to_s_id, 0);
235
+
236
+ oj_dump_raw(RSTRING_PTR(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 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 VALUE calc_hash_key(ParseInfo pi, Val parent) {
297
+ volatile VALUE rkey = parent->key_val;
298
+
299
+ if (Qundef != rkey) {
300
+ rkey = oj_encode(rkey);
301
+ rkey = rb_str_intern(rkey);
302
+
303
+ return rkey;
304
+ }
305
+ if (Yes == pi->options.cache_keys) {
306
+ rkey = oj_sym_intern(parent->key, parent->klen);
307
+ } else {
308
+ #if HAVE_RB_ENC_INTERNED_STR
309
+ rkey = rb_enc_interned_str(parent->key, parent->klen, oj_utf8_encoding);
310
+ #else
311
+ rkey = rb_utf8_str_new(parent->key, parent->klen);
312
+ rkey = rb_str_intern(rkey);
313
+ OBJ_FREEZE(rkey);
314
+ #endif
315
+ }
316
+ return rkey;
317
+ }
318
+
319
+ static void hash_end(ParseInfo pi) {
320
+ if (Yes == pi->options.trace) {
321
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
322
+ }
323
+ }
324
+
325
+ static void array_end(ParseInfo pi) {
326
+ if (Yes == pi->options.trace) {
327
+ oj_trace_parse_array_end(pi, __FILE__, __LINE__);
328
+ }
329
+ }
330
+
331
+ static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
332
+ return Qundef;
333
+ }
334
+
335
+ static void add_value(ParseInfo pi, VALUE val) {
336
+ if (Yes == pi->options.trace) {
337
+ oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
338
+ }
339
+ pi->stack.head->val = val;
340
+ }
341
+
342
+ // 123e4567-e89b-12d3-a456-426655440000
343
+ static bool uuid_check(const char *str, int len) {
344
+ int i;
345
+
346
+ for (i = 0; i < 8; i++, str++) {
347
+ if ('x' != hex_chars[*(uint8_t *)str]) {
348
+ return false;
349
+ }
350
+ }
351
+ str++;
352
+ for (i = 0; i < 4; i++, str++) {
353
+ if ('x' != hex_chars[*(uint8_t *)str]) {
354
+ return false;
355
+ }
356
+ }
357
+ str++;
358
+ for (i = 0; i < 4; i++, str++) {
359
+ if ('x' != hex_chars[*(uint8_t *)str]) {
360
+ return false;
361
+ }
362
+ }
363
+ str++;
364
+ for (i = 0; i < 4; i++, str++) {
365
+ if ('x' != hex_chars[*(uint8_t *)str]) {
366
+ return false;
367
+ }
368
+ }
369
+ str++;
370
+ for (i = 0; i < 12; i++, str++) {
371
+ if ('x' != hex_chars[*(uint8_t *)str]) {
372
+ return false;
373
+ }
374
+ }
375
+ return true;
376
+ }
377
+
378
+ static const char *read_num(const char *s, int len, int *vp) {
379
+ uint32_t v = 0;
380
+
381
+ for (; 0 < len; len--, s++) {
382
+ if ('0' <= *s && *s <= '9') {
383
+ v = v * 10 + *s - '0';
384
+ } else {
385
+ return NULL;
386
+ }
387
+ }
388
+ *vp = (int)v;
389
+
390
+ return s;
391
+ }
392
+
393
+ static VALUE time_parse(const char *s, int len) {
394
+ struct tm tm;
395
+ bool neg = false;
396
+ long nsecs = 0;
397
+ int i;
398
+ time_t secs;
399
+
400
+ memset(&tm, 0, sizeof(tm));
401
+ if ('-' == *s) {
402
+ s++;
403
+ neg = true;
404
+ }
405
+ if (NULL == (s = read_num(s, 4, &tm.tm_year))) {
406
+ return Qnil;
407
+ }
408
+ if (neg) {
409
+ tm.tm_year = -tm.tm_year;
410
+ neg = false;
411
+ }
412
+ tm.tm_year -= 1900;
413
+ s++;
414
+ if (NULL == (s = read_num(s, 2, &tm.tm_mon))) {
415
+ return Qnil;
416
+ }
417
+ tm.tm_mon--;
418
+ s++;
419
+ if (NULL == (s = read_num(s, 2, &tm.tm_mday))) {
420
+ return Qnil;
421
+ }
422
+ s++;
423
+ if (NULL == (s = read_num(s, 2, &tm.tm_hour))) {
424
+ return Qnil;
425
+ }
426
+ s++;
427
+ if (NULL == (s = read_num(s, 2, &tm.tm_min))) {
428
+ return Qnil;
429
+ }
430
+ s++;
431
+ if (NULL == (s = read_num(s, 2, &tm.tm_sec))) {
432
+ return Qnil;
433
+ }
434
+ s++;
435
+
436
+ for (i = 9; 0 < i; i--, s++) {
437
+ if ('0' <= *s && *s <= '9') {
438
+ nsecs = nsecs * 10 + *s - '0';
439
+ } else {
440
+ return Qnil;
441
+ }
442
+ }
443
+ #if IS_WINDOWS
444
+ secs = (time_t)mktime(&tm);
445
+ memset(&tm, 0, sizeof(tm));
446
+ tm.tm_year = 70;
447
+ tm.tm_mday = 1;
448
+ secs -= (time_t)mktime(&tm);
449
+ #else
450
+ secs = (time_t)timegm(&tm);
451
+ #endif
452
+ return rb_funcall(rb_time_nano_new(secs, nsecs), oj_utc_id, 0);
453
+ }
454
+
455
+ static VALUE protect_uri(VALUE rstr) {
456
+ return rb_funcall(resolve_uri_class(), oj_parse_id, 1, rstr);
457
+ }
458
+
459
+ static VALUE cstr_to_rstr(ParseInfo pi, const char *str, size_t len) {
460
+ volatile VALUE v = Qnil;
461
+
462
+ if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] &&
463
+ ':' == str[16] && '.' == str[19] && 'Z' == str[29]) {
464
+ if (Qnil != (v = time_parse(str, (int)len))) {
465
+ return v;
466
+ }
467
+ }
468
+ if (36 == len && '-' == str[8] && '-' == str[13] && '-' == str[18] && '-' == str[23] &&
469
+ uuid_check(str, (int)len) && Qnil != resolve_wab_uuid_class()) {
470
+ return rb_funcall(wab_uuid_clas, oj_new_id, 1, rb_str_new(str, len));
471
+ }
472
+ if (7 < len && 0 == strncasecmp("http://", str, 7)) {
473
+ int err = 0;
474
+ v = rb_str_new(str, len);
475
+ volatile VALUE uri = rb_protect(protect_uri, v, &err);
476
+
477
+ if (0 == err) {
478
+ return uri;
479
+ }
480
+ }
481
+ return oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
482
+ }
483
+
484
+ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
485
+ pi->stack.head->val = cstr_to_rstr(pi, str, len);
486
+ if (Yes == pi->options.trace) {
487
+ oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
488
+ }
489
+ }
490
+
491
+ static void add_num(ParseInfo pi, NumInfo ni) {
492
+ if (ni->infinity || ni->nan) {
493
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
494
+ }
495
+ pi->stack.head->val = oj_num_as_value(ni);
496
+ if (Yes == pi->options.trace) {
497
+ oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
498
+ }
499
+ }
500
+
501
+ static VALUE start_hash(ParseInfo pi) {
502
+ if (Yes == pi->options.trace) {
503
+ oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
504
+ }
505
+ if (Qnil != pi->options.hash_class) {
506
+ return rb_class_new_instance(0, NULL, pi->options.hash_class);
507
+ }
508
+ return rb_hash_new();
509
+ }
510
+
511
+ static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
512
+ volatile VALUE rval = cstr_to_rstr(pi, str, len);
513
+
514
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
515
+ if (Yes == pi->options.trace) {
516
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
517
+ }
518
+ }
519
+
520
+ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
521
+ volatile VALUE rval = Qnil;
522
+
523
+ if (ni->infinity || ni->nan) {
524
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
525
+ }
526
+ rval = oj_num_as_value(ni);
527
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
528
+ if (Yes == pi->options.trace) {
529
+ oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
530
+ }
531
+ }
532
+
533
+ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
534
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
535
+ if (Yes == pi->options.trace) {
536
+ oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
537
+ }
538
+ }
539
+
540
+ static VALUE start_array(ParseInfo pi) {
541
+ if (Yes == pi->options.trace) {
542
+ oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
543
+ }
544
+ return rb_ary_new();
545
+ }
546
+
547
+ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
548
+ volatile VALUE rval = cstr_to_rstr(pi, str, len);
549
+
550
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
551
+ if (Yes == pi->options.trace) {
552
+ oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, rval);
553
+ }
554
+ }
555
+
556
+ static void array_append_num(ParseInfo pi, NumInfo ni) {
557
+ volatile VALUE rval = Qnil;
558
+
559
+ if (ni->infinity || ni->nan) {
560
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
561
+ }
562
+ rval = oj_num_as_value(ni);
563
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
564
+ if (Yes == pi->options.trace) {
565
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
566
+ }
567
+ }
568
+
569
+ static void array_append_value(ParseInfo pi, VALUE value) {
570
+ rb_ary_push(stack_peek(&pi->stack)->val, value);
571
+ if (Yes == pi->options.trace) {
572
+ oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
573
+ }
574
+ }
575
+
576
+ void oj_set_wab_callbacks(ParseInfo pi) {
577
+ pi->start_hash = start_hash;
578
+ pi->end_hash = hash_end;
579
+ pi->hash_key = noop_hash_key;
580
+ pi->hash_set_cstr = hash_set_cstr;
581
+ pi->hash_set_num = hash_set_num;
582
+ pi->hash_set_value = hash_set_value;
583
+ pi->start_array = start_array;
584
+ pi->end_array = array_end;
585
+ pi->array_append_cstr = array_append_cstr;
586
+ pi->array_append_num = array_append_num;
587
+ pi->array_append_value = array_append_value;
588
+ pi->add_cstr = add_cstr;
589
+ pi->add_num = add_num;
590
+ pi->add_value = add_value;
591
+ pi->expect_value = 1;
592
+ }
593
+
594
+ VALUE
595
+ oj_wab_parse(int argc, VALUE *argv, VALUE self) {
596
+ struct _parseInfo pi;
597
+
598
+ parse_info_init(&pi);
599
+ pi.options = oj_default_options;
600
+ pi.handler = Qnil;
601
+ pi.err_class = Qnil;
602
+ oj_set_wab_callbacks(&pi);
603
+
604
+ if (T_STRING == rb_type(*argv)) {
605
+ return oj_pi_parse(argc, argv, &pi, 0, 0, true);
606
+ } else {
607
+ return oj_pi_sparse(argc, argv, &pi, 0);
608
+ }
609
+ }
610
+
611
+ VALUE
612
+ oj_wab_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
613
+ struct _parseInfo pi;
614
+
615
+ parse_info_init(&pi);
616
+ pi.options = oj_default_options;
617
+ pi.handler = Qnil;
618
+ pi.err_class = Qnil;
619
+ oj_set_wab_callbacks(&pi);
620
+
621
+ return oj_pi_parse(argc, argv, &pi, json, len, true);
622
+ }
data/lib/oj/bag.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module Oj
3
4
 
data/lib/oj/easy_hash.rb CHANGED
@@ -12,13 +12,14 @@ module Oj
12
12
 
13
13
  # Replaces the Object.respond_to?() method.
14
14
  # @param [Symbol] m method symbol
15
+ # @param [Boolean] include_all whether to include private and protected methods in the search
15
16
  # @return [Boolean] true for any method that matches an instance
16
17
  # variable reader, otherwise false.
17
- def respond_to?(m)
18
+ def respond_to?(m, include_all = false)
18
19
  return true if super
19
- return true if has_key?(key)
20
- return true if has_key?(key.to_s)
21
- has_key?(key.to_sym)
20
+ return true if has_key?(m)
21
+ return true if has_key?(m.to_s)
22
+ has_key?(m.to_sym)
22
23
  end
23
24
 
24
25
  def [](key)
@@ -33,10 +34,18 @@ module Oj
33
34
  # @raise [ArgumentError] if an argument is given. Zero arguments expected.
34
35
  # @raise [NoMethodError] if the instance variable is not defined.
35
36
  def method_missing(m, *args, &block)
36
- raise ArgumentError.new("wrong number of arguments (#{args.size} for 0 with #{m}) to method #{m}") unless args.nil? or args.empty?
37
- return fetch(m, nil) if has_key?(m)
38
- return fetch(m.to_s, nil) if has_key?(m.to_s)
39
- return fetch(m.to_sym, nil) if has_key?(m.to_sym)
37
+ if m.to_s.end_with?('=')
38
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 1 with #{m}) to method #{m}") if args.nil? or 1 != args.length
39
+ m = m[0..-2]
40
+ return store(m.to_s, args[0]) if has_key?(m.to_s)
41
+ return store(m.to_sym, args[0]) if has_key?(m.to_sym)
42
+ return store(m, args[0])
43
+ else
44
+ raise ArgumentError.new("wrong number of arguments (#{args.size} for 0 with #{m}) to method #{m}") unless args.nil? or args.empty?
45
+ return fetch(m, nil) if has_key?(m)
46
+ return fetch(m.to_s, nil) if has_key?(m.to_s)
47
+ return fetch(m.to_sym, nil) if has_key?(m.to_sym)
48
+ end
40
49
  raise NoMethodError.new("undefined method #{m}", m)
41
50
  end
42
51
 
data/lib/oj/error.rb CHANGED
@@ -1,23 +1,22 @@
1
1
 
2
2
  module Oj
3
3
 
4
- class Error < StandardError
5
- end # Error
4
+ # Inherit Error class from StandardError.
5
+ Error = Class.new(StandardError)
6
+
7
+ # Following classes inherit from the Error class.
8
+ # -----------------------------------------------
6
9
 
7
10
  # An Exception that is raised as a result of a parse error while parsing a JSON document.
8
- class ParseError < Error
9
- end # ParseError
11
+ ParseError = Class.new(Error)
10
12
 
11
13
  # An Exception that is raised as a result of a path being too deep.
12
- class DepthError < Error
13
- end # DepthError
14
+ DepthError = Class.new(Error)
14
15
 
15
16
  # An Exception that is raised if a file fails to load.
16
- class LoadError < Error
17
- end # LoadError
17
+ LoadError = Class.new(Error)
18
18
 
19
- # An Exception that is raised if there is a conflict with mimicing JSON
20
- class MimicError < Error
21
- end # MimicError
19
+ # An Exception that is raised if there is a conflict with mimicking JSON
20
+ MimicError = Class.new(Error)
22
21
 
23
22
  end # Oj