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