oj 3.7.12

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 (156) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +96 -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 +1188 -0
  13. data/ext/oj/dump.c +1232 -0
  14. data/ext/oj/dump.h +94 -0
  15. data/ext/oj/dump_compat.c +973 -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 +873 -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 +1694 -0
  32. data/ext/oj/oj.h +381 -0
  33. data/ext/oj/parse.c +1085 -0
  34. data/ext/oj/parse.h +111 -0
  35. data/ext/oj/rails.c +1485 -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 +512 -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 +154 -0
  73. data/pages/Options.md +266 -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/big.rb +15 -0
  90. data/test/files.rb +29 -0
  91. data/test/foo.rb +33 -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/mem.rb +35 -0
  113. data/test/perf.rb +107 -0
  114. data/test/perf_compat.rb +130 -0
  115. data/test/perf_fast.rb +164 -0
  116. data/test/perf_file.rb +64 -0
  117. data/test/perf_object.rb +138 -0
  118. data/test/perf_saj.rb +109 -0
  119. data/test/perf_scp.rb +151 -0
  120. data/test/perf_simple.rb +287 -0
  121. data/test/perf_strict.rb +145 -0
  122. data/test/perf_wab.rb +131 -0
  123. data/test/sample.rb +54 -0
  124. data/test/sample/change.rb +14 -0
  125. data/test/sample/dir.rb +19 -0
  126. data/test/sample/doc.rb +36 -0
  127. data/test/sample/file.rb +48 -0
  128. data/test/sample/group.rb +16 -0
  129. data/test/sample/hasprops.rb +16 -0
  130. data/test/sample/layer.rb +12 -0
  131. data/test/sample/line.rb +20 -0
  132. data/test/sample/oval.rb +10 -0
  133. data/test/sample/rect.rb +10 -0
  134. data/test/sample/shape.rb +35 -0
  135. data/test/sample/text.rb +20 -0
  136. data/test/sample_json.rb +37 -0
  137. data/test/test_compat.rb +509 -0
  138. data/test/test_custom.rb +406 -0
  139. data/test/test_debian.rb +53 -0
  140. data/test/test_fast.rb +470 -0
  141. data/test/test_file.rb +239 -0
  142. data/test/test_gc.rb +49 -0
  143. data/test/test_hash.rb +29 -0
  144. data/test/test_integer_range.rb +73 -0
  145. data/test/test_null.rb +376 -0
  146. data/test/test_object.rb +1018 -0
  147. data/test/test_saj.rb +186 -0
  148. data/test/test_scp.rb +433 -0
  149. data/test/test_strict.rb +410 -0
  150. data/test/test_various.rb +739 -0
  151. data/test/test_wab.rb +307 -0
  152. data/test/test_writer.rb +380 -0
  153. data/test/tests.rb +24 -0
  154. data/test/tests_mimic.rb +14 -0
  155. data/test/tests_mimic_addition.rb +7 -0
  156. metadata +359 -0
@@ -0,0 +1,771 @@
1
+ /* object.c
2
+ * Copyright (c) 2012, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include <stdint.h>
7
+ #include <stdio.h>
8
+ #include <time.h>
9
+
10
+ #include "oj.h"
11
+ #include "err.h"
12
+ #include "parse.h"
13
+ #include "resolve.h"
14
+ #include "hash.h"
15
+ #include "odd.h"
16
+ #include "encode.h"
17
+ #include "trace.h"
18
+ #include "util.h"
19
+
20
+ inline static long
21
+ read_long(const char *str, size_t len) {
22
+ long n = 0;
23
+
24
+ for (; 0 < len; str++, len--) {
25
+ if ('0' <= *str && *str <= '9') {
26
+ n = n * 10 + (*str - '0');
27
+ } else {
28
+ return -1;
29
+ }
30
+ }
31
+ return n;
32
+ }
33
+
34
+ static VALUE
35
+ calc_hash_key(ParseInfo pi, Val kval, char k1) {
36
+ volatile VALUE rkey;
37
+
38
+ if (':' == k1) {
39
+ rkey = rb_str_new(kval->key + 1, kval->klen - 1);
40
+ rkey = oj_encode(rkey);
41
+ rkey = rb_funcall(rkey, oj_to_sym_id, 0);
42
+ } else {
43
+ rkey = rb_str_new(kval->key, kval->klen);
44
+ rkey = oj_encode(rkey);
45
+ if (Yes == pi->options.sym_key) {
46
+ rkey = rb_str_intern(rkey);
47
+ }
48
+ }
49
+ return rkey;
50
+ }
51
+
52
+ static VALUE
53
+ str_to_value(ParseInfo pi, const char *str, size_t len, const char *orig) {
54
+ volatile VALUE rstr = Qnil;
55
+
56
+ if (':' == *orig && 0 < len) {
57
+ rstr = rb_str_new(str + 1, len - 1);
58
+ rstr = oj_encode(rstr);
59
+ rstr = rb_funcall(rstr, oj_to_sym_id, 0);
60
+ } else if (pi->circ_array && 3 <= len && '^' == *orig && 'r' == orig[1]) {
61
+ long i = read_long(str + 2, len - 2);
62
+
63
+ if (0 > i) {
64
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a valid ID number");
65
+ return Qnil;
66
+ }
67
+ rstr = oj_circ_array_get(pi->circ_array, i);
68
+ } else {
69
+ rstr = rb_str_new(str, len);
70
+ rstr = oj_encode(rstr);
71
+ }
72
+ return rstr;
73
+ }
74
+
75
+ #if (RUBY_VERSION_MAJOR == 1 && RUBY_VERSION_MINOR == 8)
76
+ static VALUE
77
+ oj_parse_xml_time(const char *str, int len) {
78
+ return rb_funcall(rb_cTime, oj_parse_id, 1, rb_str_new(str, len));
79
+ }
80
+ #else
81
+ // The much faster approach (4x faster)
82
+ static int
83
+ parse_num(const char *str, const char *end, int cnt) {
84
+ int n = 0;
85
+ char c;
86
+ int i;
87
+
88
+ for (i = cnt; 0 < i; i--, str++) {
89
+ c = *str;
90
+ if (end <= str || c < '0' || '9' < c) {
91
+ return -1;
92
+ }
93
+ n = n * 10 + (c - '0');
94
+ }
95
+ return n;
96
+ }
97
+
98
+ VALUE
99
+ oj_parse_xml_time(const char *str, int len) {
100
+ VALUE args[8];
101
+ const char *end = str + len;
102
+ int n;
103
+
104
+ // year
105
+ if (0 > (n = parse_num(str, end, 4))) {
106
+ return Qnil;
107
+ }
108
+ str += 4;
109
+ args[0] = LONG2NUM(n);
110
+ if ('-' != *str++) {
111
+ return Qnil;
112
+ }
113
+ // month
114
+ if (0 > (n = parse_num(str, end, 2))) {
115
+ return Qnil;
116
+ }
117
+ str += 2;
118
+ args[1] = LONG2NUM(n);
119
+ if ('-' != *str++) {
120
+ return Qnil;
121
+ }
122
+ // day
123
+ if (0 > (n = parse_num(str, end, 2))) {
124
+ return Qnil;
125
+ }
126
+ str += 2;
127
+ args[2] = LONG2NUM(n);
128
+ if ('T' != *str++) {
129
+ return Qnil;
130
+ }
131
+ // hour
132
+ if (0 > (n = parse_num(str, end, 2))) {
133
+ return Qnil;
134
+ }
135
+ str += 2;
136
+ args[3] = LONG2NUM(n);
137
+ if (':' != *str++) {
138
+ return Qnil;
139
+ }
140
+ // minute
141
+ if (0 > (n = parse_num(str, end, 2))) {
142
+ return Qnil;
143
+ }
144
+ str += 2;
145
+ args[4] = LONG2NUM(n);
146
+ if (':' != *str++) {
147
+ return Qnil;
148
+ }
149
+ // second
150
+ if (0 > (n = parse_num(str, end, 2))) {
151
+ return Qnil;
152
+ }
153
+ str += 2;
154
+ if (str == end) {
155
+ args[5] = LONG2NUM(n);
156
+ args[6] = LONG2NUM(0);
157
+ } else {
158
+ char c = *str++;
159
+
160
+ if ('.' == c) {
161
+ long long nsec = 0;
162
+
163
+ for (; str < end; str++) {
164
+ c = *str;
165
+ if (c < '0' || '9' < c) {
166
+ str++;
167
+ break;
168
+ }
169
+ nsec = nsec * 10 + (c - '0');
170
+ }
171
+ args[5] = rb_float_new((double)n + ((double)nsec + 0.5) / 1000000000.0);
172
+ } else {
173
+ args[5] = rb_ll2inum(n);
174
+ }
175
+ if (end < str) {
176
+ args[6] = LONG2NUM(0);
177
+ } else {
178
+ if ('Z' == c) {
179
+ return rb_funcall2(rb_cTime, oj_utc_id, 6, args);
180
+ } else if ('+' == c) {
181
+ int hr = parse_num(str, end, 2);
182
+ int min;
183
+
184
+ str += 2;
185
+ if (0 > hr || ':' != *str++) {
186
+ return Qnil;
187
+ }
188
+ min = parse_num(str, end, 2);
189
+ if (0 > min) {
190
+ return Qnil;
191
+ }
192
+ args[6] = LONG2NUM(hr * 3600 + min * 60);
193
+ } else if ('-' == c) {
194
+ int hr = parse_num(str, end, 2);
195
+ int min;
196
+
197
+ str += 2;
198
+ if (0 > hr || ':' != *str++) {
199
+ return Qnil;
200
+ }
201
+ min = parse_num(str, end, 2);
202
+ if (0 > min) {
203
+ return Qnil;
204
+ }
205
+ args[6] = LONG2NUM(-(hr * 3600 + min * 60));
206
+ } else {
207
+ args[6] = LONG2NUM(0);
208
+ }
209
+ }
210
+ }
211
+ return rb_funcall2(rb_cTime, oj_new_id, 7, args);
212
+ }
213
+ #endif
214
+
215
+ static int
216
+ hat_cstr(ParseInfo pi, Val parent, Val kval, const char *str, size_t len) {
217
+ const char *key = kval->key;
218
+ int klen = kval->klen;
219
+
220
+ if (2 == klen) {
221
+ switch (key[1]) {
222
+ case 'o': // object
223
+ { // name2class sets an error if the class is not found or created
224
+ VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
225
+
226
+ if (Qundef != clas) {
227
+ parent->val = rb_obj_alloc(clas);
228
+ }
229
+ }
230
+ break;
231
+ case 'O': // odd object
232
+ {
233
+ Odd odd = oj_get_oddc(str, len);
234
+
235
+ if (0 == odd) {
236
+ return 0;
237
+ }
238
+ parent->val = odd->clas;
239
+ parent->odd_args = oj_odd_alloc_args(odd);
240
+ }
241
+ break;
242
+ case 'm':
243
+ parent->val = rb_str_new(str + 1, len - 1);
244
+ parent->val = oj_encode(parent->val);
245
+ parent->val = rb_funcall(parent->val, oj_to_sym_id, 0);
246
+ break;
247
+ case 's':
248
+ parent->val = rb_str_new(str, len);
249
+ parent->val = oj_encode(parent->val);
250
+ break;
251
+ case 'c': // class
252
+ {
253
+ VALUE clas = oj_name2class(pi, str, len, Yes == pi->options.auto_define, rb_eArgError);
254
+
255
+ if (Qundef == clas) {
256
+ return 0;
257
+ } else {
258
+ parent->val = clas;
259
+ }
260
+ }
261
+ break;
262
+ case 't': // time
263
+ parent->val = oj_parse_xml_time(str, (int)len);
264
+ break;
265
+ default:
266
+ return 0;
267
+ break;
268
+ }
269
+ return 1; // handled
270
+ }
271
+ return 0;
272
+ }
273
+
274
+ static int
275
+ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
276
+ if (2 == kval->klen) {
277
+ switch (kval->key[1]) {
278
+ case 't': // time as a float
279
+ {
280
+ int64_t nsec = ni->num * 1000000000LL / ni->div;
281
+
282
+ if (ni->neg) {
283
+ ni->i = -ni->i;
284
+ if (0 < nsec) {
285
+ ni->i--;
286
+ nsec = 1000000000LL - nsec;
287
+ }
288
+ }
289
+ if (86400 == ni->exp) { // UTC time
290
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
291
+ // Since the ruby C routines alway create local time, the
292
+ // offset and then a conversion to UTC keeps makes the time
293
+ // match the expected value.
294
+ parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
295
+ } else if (ni->hasExp) {
296
+ int64_t t = (int64_t)(ni->i + ni->exp);
297
+ struct _timeInfo ti;
298
+ VALUE args[8];
299
+
300
+ sec_as_time(t, &ti);
301
+ args[0] = LONG2NUM((long)(ti.year));
302
+ args[1] = LONG2NUM(ti.mon);
303
+ args[2] = LONG2NUM(ti.day);
304
+ args[3] = LONG2NUM(ti.hour);
305
+ args[4] = LONG2NUM(ti.min);
306
+ args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
307
+ args[6] = LONG2NUM(ni->exp);
308
+ parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
309
+ } else {
310
+ parent->val = rb_time_nano_new(ni->i, (long)nsec);
311
+ }
312
+ }
313
+ break;
314
+ case 'i': // circular index
315
+ if (!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
316
+ if (Qnil == parent->val) {
317
+ parent->val = rb_hash_new();
318
+ }
319
+ oj_circ_array_set(pi->circ_array, parent->val, ni->i);
320
+ } else {
321
+ return 0;
322
+ }
323
+ break;
324
+ default:
325
+ return 0;
326
+ break;
327
+ }
328
+ return 1; // handled
329
+ }
330
+ return 0;
331
+ }
332
+
333
+ static int
334
+ hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, volatile VALUE value) {
335
+ if (T_ARRAY == rb_type(value)) {
336
+ int len = (int)RARRAY_LEN(value);
337
+
338
+ if (2 == klen && 'u' == key[1]) {
339
+ volatile VALUE sc;
340
+ volatile VALUE e1;
341
+ int slen;
342
+
343
+ if (0 == len) {
344
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
345
+ return 1;
346
+ }
347
+ e1 = *RARRAY_PTR(value);
348
+ // check for anonymous Struct
349
+ if (T_ARRAY == rb_type(e1)) {
350
+ VALUE args[1024];
351
+ volatile VALUE rstr;
352
+ int i, cnt = (int)RARRAY_LEN(e1);
353
+
354
+ for (i = 0; i < cnt; i++) {
355
+ rstr = rb_ary_entry(e1, i);
356
+ args[i] = rb_funcall(rstr, oj_to_sym_id, 0);
357
+ }
358
+ sc = rb_funcall2(rb_cStruct, oj_new_id, cnt, args);
359
+ } else {
360
+ // If struct is not defined then we let this fail and raise an exception.
361
+ sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
362
+ }
363
+ // Create a properly initialized struct instance without calling the initialize method.
364
+ parent->val = rb_obj_alloc(sc);
365
+ // If the JSON array has more entries than the struct class allows, we record an error.
366
+ #ifdef RSTRUCT_LEN
367
+ #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
368
+ slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
369
+ #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
370
+ slen = (int)RSTRUCT_LEN(parent->val);
371
+ #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
372
+ #else
373
+ slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
374
+ #endif
375
+ // MRI >= 1.9
376
+ if (len - 1 > slen) {
377
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
378
+ } else {
379
+ int i;
380
+
381
+ for (i = 0; i < len - 1; i++) {
382
+ rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
383
+ }
384
+ }
385
+ return 1;
386
+ } else if (3 <= klen && '#' == key[1]) {
387
+ volatile VALUE *a;
388
+
389
+ if (2 != len) {
390
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
391
+ return 1;
392
+ }
393
+ parent->val = rb_hash_new();
394
+ a = RARRAY_PTR(value);
395
+ rb_hash_aset(parent->val, *a, a[1]);
396
+
397
+ return 1;
398
+ }
399
+ }
400
+ return 0;
401
+ }
402
+
403
+ void
404
+ oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
405
+ const char *key = kval->key;
406
+ int klen = kval->klen;
407
+ ID var_id;
408
+ ID *slot;
409
+
410
+ #if HAVE_LIBPTHREAD
411
+ pthread_mutex_lock(&oj_cache_mutex);
412
+ #else
413
+ rb_mutex_lock(oj_cache_mutex);
414
+ #endif
415
+ if (0 == (var_id = oj_attr_hash_get(key, klen, &slot))) {
416
+ char attr[256];
417
+
418
+ if ((int)sizeof(attr) <= klen + 2) {
419
+ char *buf = ALLOC_N(char, klen + 2);
420
+
421
+ if ('~' == *key) {
422
+ strncpy(buf, key + 1, klen - 1);
423
+ buf[klen - 1] = '\0';
424
+ } else {
425
+ *buf = '@';
426
+ strncpy(buf + 1, key, klen);
427
+ buf[klen + 1] = '\0';
428
+ }
429
+ var_id = rb_intern(buf);
430
+ xfree(buf);
431
+ } else {
432
+ if ('~' == *key) {
433
+ strncpy(attr, key + 1, klen - 1);
434
+ attr[klen - 1] = '\0';
435
+ } else {
436
+ *attr = '@';
437
+ strncpy(attr + 1, key, klen);
438
+ attr[klen + 1] = '\0';
439
+ }
440
+ var_id = rb_intern(attr);
441
+ }
442
+ *slot = var_id;
443
+ }
444
+ #if HAVE_LIBPTHREAD
445
+ pthread_mutex_unlock(&oj_cache_mutex);
446
+ #else
447
+ rb_mutex_unlock(oj_cache_mutex);
448
+ #endif
449
+ rb_ivar_set(parent->val, var_id, value);
450
+ }
451
+
452
+ static void
453
+ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
454
+ const char *key = kval->key;
455
+ int klen = kval->klen;
456
+ Val parent = stack_peek(&pi->stack);
457
+ volatile VALUE rval = Qnil;
458
+
459
+ WHICH_TYPE:
460
+ switch (rb_type(parent->val)) {
461
+ case T_NIL:
462
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
463
+ if ('^' != *key || !hat_cstr(pi, parent, kval, str, len)) {
464
+ parent->val = rb_hash_new();
465
+ goto WHICH_TYPE;
466
+ }
467
+ break;
468
+ case T_HASH:
469
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
470
+ break;
471
+ case T_STRING:
472
+ rval = str_to_value(pi, str, len, orig);
473
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
474
+ rb_funcall(parent->val, oj_replace_id, 1, rval);
475
+ } else {
476
+ oj_set_obj_ivar(parent, kval, rval);
477
+ }
478
+ break;
479
+ case T_OBJECT:
480
+ rval = str_to_value(pi, str, len, orig);
481
+ oj_set_obj_ivar(parent, kval, rval);
482
+ break;
483
+ case T_CLASS:
484
+ if (NULL == parent->odd_args) {
485
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
486
+ return;
487
+ } else {
488
+ rval = str_to_value(pi, str, len, orig);
489
+ if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) {
490
+ char buf[256];
491
+
492
+ if ((int)sizeof(buf) - 1 <= klen) {
493
+ klen = sizeof(buf) - 2;
494
+ }
495
+ memcpy(buf, key, klen);
496
+ buf[klen] = '\0';
497
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
498
+ }
499
+ }
500
+ break;
501
+ default:
502
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
503
+ return;
504
+ }
505
+ if (Yes == pi->options.trace) {
506
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
507
+ }
508
+ }
509
+
510
+ static void
511
+ hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
512
+ const char *key = kval->key;
513
+ int klen = kval->klen;
514
+ Val parent = stack_peek(&pi->stack);
515
+ volatile VALUE rval = Qnil;
516
+
517
+ WHICH_TYPE:
518
+ switch (rb_type(parent->val)) {
519
+ case T_NIL:
520
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
521
+ if ('^' != *key || !hat_num(pi, parent, kval, ni)) {
522
+ parent->val = rb_hash_new();
523
+ goto WHICH_TYPE;
524
+ }
525
+ break;
526
+ case T_HASH:
527
+ rval = oj_num_as_value(ni);
528
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
529
+ break;
530
+ case T_OBJECT:
531
+ if (2 == klen && '^' == *key && 'i' == key[1] &&
532
+ !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
533
+ oj_circ_array_set(pi->circ_array, parent->val, ni->i);
534
+ } else {
535
+ rval = oj_num_as_value(ni);
536
+ oj_set_obj_ivar(parent, kval, rval);
537
+ }
538
+ break;
539
+ case T_CLASS:
540
+ if (NULL == parent->odd_args) {
541
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
542
+ return;
543
+ } else {
544
+ rval = oj_num_as_value(ni);
545
+ if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) {
546
+ char buf[256];
547
+
548
+ if ((int)sizeof(buf) - 1 <= klen) {
549
+ klen = sizeof(buf) - 2;
550
+ }
551
+ memcpy(buf, key, klen);
552
+ buf[klen] = '\0';
553
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
554
+ }
555
+ }
556
+ break;
557
+ default:
558
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
559
+ return;
560
+ }
561
+ if (Yes == pi->options.trace) {
562
+ oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
563
+ }
564
+ }
565
+
566
+ static void
567
+ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
568
+ const char *key = kval->key;
569
+ int klen = kval->klen;
570
+ Val parent = stack_peek(&pi->stack);
571
+
572
+ WHICH_TYPE:
573
+ switch (rb_type(parent->val)) {
574
+ case T_NIL:
575
+ parent->odd_args = NULL; // make sure it is NULL in case not odd
576
+ if ('^' != *key || !hat_value(pi, parent, key, klen, value)) {
577
+ parent->val = rb_hash_new();
578
+ goto WHICH_TYPE;
579
+ }
580
+ break;
581
+ case T_HASH:
582
+ if (rb_cHash != rb_obj_class(parent->val)) {
583
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
584
+ rb_funcall(parent->val, oj_replace_id, 1, value);
585
+ } else {
586
+ oj_set_obj_ivar(parent, kval, value);
587
+ }
588
+ } else {
589
+ if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
590
+ long len = RARRAY_LEN(value);
591
+ volatile VALUE *a = RARRAY_PTR(value);
592
+
593
+ if (2 != len) {
594
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
595
+ return;
596
+ }
597
+ rb_hash_aset(parent->val, *a, a[1]);
598
+ } else {
599
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), value);
600
+ }
601
+ }
602
+ break;
603
+ case T_ARRAY:
604
+ if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
605
+ rb_funcall(parent->val, oj_replace_id, 1, value);
606
+ } else {
607
+ oj_set_obj_ivar(parent, kval, value);
608
+ }
609
+ break;
610
+ case T_STRING: // for subclassed strings
611
+ case T_OBJECT:
612
+ oj_set_obj_ivar(parent, kval, value);
613
+ break;
614
+ case T_MODULE:
615
+ case T_CLASS:
616
+ if (NULL == parent->odd_args) {
617
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
618
+ return;
619
+ } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, value)) {
620
+ char buf[256];
621
+
622
+ if ((int)sizeof(buf) - 1 <= klen) {
623
+ klen = sizeof(buf) - 2;
624
+ }
625
+ memcpy(buf, key, klen);
626
+ buf[klen] = '\0';
627
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
628
+ }
629
+ break;
630
+ default:
631
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
632
+ return;
633
+ }
634
+ if (Yes == pi->options.trace) {
635
+ oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
636
+ }
637
+ }
638
+
639
+ static VALUE
640
+ start_hash(ParseInfo pi) {
641
+ if (Yes == pi->options.trace) {
642
+ oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
643
+ }
644
+ return Qnil;
645
+ }
646
+
647
+ static void
648
+ end_hash(ParseInfo pi) {
649
+ Val parent = stack_peek(&pi->stack);
650
+
651
+ if (Qnil == parent->val) {
652
+ parent->val = rb_hash_new();
653
+ } else if (NULL != parent->odd_args) {
654
+ OddArgs oa = parent->odd_args;
655
+
656
+ parent->val = rb_funcall2(oa->odd->create_obj, oa->odd->create_op, oa->odd->attr_cnt, oa->args);
657
+ oj_odd_free(oa);
658
+ parent->odd_args = NULL;
659
+ }
660
+ if (Yes == pi->options.trace) {
661
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
662
+ }
663
+ }
664
+
665
+ static void
666
+ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
667
+ volatile VALUE rval = Qnil;
668
+
669
+ if (3 <= len && 0 != pi->circ_array) {
670
+ if ('i' == str[1]) {
671
+ long i = read_long(str + 2, len - 2);
672
+
673
+ if (0 < i) {
674
+ oj_circ_array_set(pi->circ_array, stack_peek(&pi->stack)->val, i);
675
+ return;
676
+ }
677
+ } else if ('r' == str[1]) {
678
+ long i = read_long(str + 2, len - 2);
679
+
680
+ if (0 < i) {
681
+ rb_ary_push(stack_peek(&pi->stack)->val, oj_circ_array_get(pi->circ_array, i));
682
+ return;
683
+ }
684
+
685
+ }
686
+ }
687
+ rval = str_to_value(pi, str, len, orig);
688
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
689
+ if (Yes == pi->options.trace) {
690
+ oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
691
+ }
692
+ }
693
+
694
+ static void
695
+ array_append_num(ParseInfo pi, NumInfo ni) {
696
+ volatile VALUE rval = oj_num_as_value(ni);
697
+
698
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
699
+ if (Yes == pi->options.trace) {
700
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
701
+ }
702
+ }
703
+
704
+ static void
705
+ add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
706
+ pi->stack.head->val = str_to_value(pi, str, len, orig);
707
+ if (Yes == pi->options.trace) {
708
+ oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
709
+ }
710
+ }
711
+
712
+ static void
713
+ add_num(ParseInfo pi, NumInfo ni) {
714
+ pi->stack.head->val = oj_num_as_value(ni);
715
+ if (Yes == pi->options.trace) {
716
+ oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
717
+ }
718
+ }
719
+
720
+ void
721
+ oj_set_object_callbacks(ParseInfo pi) {
722
+ oj_set_strict_callbacks(pi);
723
+ pi->end_hash = end_hash;
724
+ pi->start_hash = start_hash;
725
+ pi->hash_set_cstr = hash_set_cstr;
726
+ pi->hash_set_num = hash_set_num;
727
+ pi->hash_set_value = hash_set_value;
728
+ pi->add_cstr = add_cstr;
729
+ pi->add_num = add_num;
730
+ pi->array_append_cstr = array_append_cstr;
731
+ pi->array_append_num = array_append_num;
732
+ }
733
+
734
+ VALUE
735
+ oj_object_parse(int argc, VALUE *argv, VALUE self) {
736
+ struct _parseInfo pi;
737
+
738
+ parse_info_init(&pi);
739
+ pi.options = oj_default_options;
740
+ pi.handler = Qnil;
741
+ pi.err_class = Qnil;
742
+ oj_set_object_callbacks(&pi);
743
+
744
+ if (T_STRING == rb_type(*argv)) {
745
+ return oj_pi_parse(argc, argv, &pi, 0, 0, 1);
746
+ } else {
747
+ return oj_pi_sparse(argc, argv, &pi, 0);
748
+ }
749
+ }
750
+
751
+ VALUE
752
+ oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
753
+ struct _parseInfo pi;
754
+
755
+ parse_info_init(&pi);
756
+ pi.options = oj_default_options;
757
+ pi.handler = Qnil;
758
+ pi.err_class = Qnil;
759
+ oj_set_strict_callbacks(&pi);
760
+ pi.end_hash = end_hash;
761
+ pi.start_hash = start_hash;
762
+ pi.hash_set_cstr = hash_set_cstr;
763
+ pi.hash_set_num = hash_set_num;
764
+ pi.hash_set_value = hash_set_value;
765
+ pi.add_cstr = add_cstr;
766
+ pi.add_num = add_num;
767
+ pi.array_append_cstr = array_append_cstr;
768
+ pi.array_append_num = array_append_num;
769
+
770
+ return oj_pi_parse(argc, argv, &pi, json, len, 1);
771
+ }