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,105 @@
1
+ // Copyright (c) 2011 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #include "cache8.h"
5
+
6
+ #include <errno.h>
7
+ #include <stdarg.h>
8
+ #include <stdio.h>
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+
12
+ #include "mem.h"
13
+ #include "ruby.h"
14
+
15
+ #define BITS 4
16
+ #define MASK 0x000000000000000FULL
17
+ #define SLOT_CNT 16
18
+ #define DEPTH 16
19
+
20
+ typedef union {
21
+ struct _cache8 *child;
22
+ slot_t value;
23
+ } Bucket;
24
+
25
+ struct _cache8 {
26
+ Bucket buckets[SLOT_CNT];
27
+ };
28
+
29
+ static void cache8_delete(Cache8 cache, int depth);
30
+ static void slot_print(Cache8 cache, sid_t key, unsigned int depth);
31
+
32
+ void oj_cache8_new(Cache8 *cache) {
33
+ Bucket *b;
34
+ int i;
35
+
36
+ *cache = OJ_R_ALLOC(struct _cache8);
37
+ for (i = SLOT_CNT, b = (*cache)->buckets; 0 < i; i--, b++) {
38
+ b->value = 0;
39
+ }
40
+ }
41
+
42
+ void oj_cache8_delete(Cache8 cache) {
43
+ cache8_delete(cache, 0);
44
+ }
45
+
46
+ static void cache8_delete(Cache8 cache, int depth) {
47
+ Bucket *b;
48
+ unsigned int i;
49
+
50
+ for (i = 0, b = cache->buckets; i < SLOT_CNT; i++, b++) {
51
+ if (0 != b->child) {
52
+ if (DEPTH - 1 != depth) {
53
+ cache8_delete(b->child, depth + 1);
54
+ }
55
+ }
56
+ }
57
+ OJ_R_FREE(cache);
58
+ }
59
+
60
+ slot_t oj_cache8_get(Cache8 cache, sid_t key, slot_t **slot) {
61
+ Bucket *b;
62
+ int i;
63
+ sid_t k8 = (sid_t)key;
64
+ sid_t k;
65
+
66
+ for (i = 64 - BITS; 0 < i; i -= BITS) {
67
+ k = (k8 >> i) & MASK;
68
+ b = cache->buckets + k;
69
+ if (0 == b->child) {
70
+ oj_cache8_new(&b->child);
71
+ }
72
+ cache = b->child;
73
+ }
74
+ *slot = &(cache->buckets + (k8 & MASK))->value;
75
+
76
+ return **slot;
77
+ }
78
+
79
+ void oj_cache8_print(Cache8 cache) {
80
+ /*printf("-------------------------------------------\n"); */
81
+ slot_print(cache, 0, 0);
82
+ }
83
+
84
+ static void slot_print(Cache8 c, sid_t key, unsigned int depth) {
85
+ Bucket *b;
86
+ unsigned int i;
87
+ sid_t k8 = (sid_t)key;
88
+ sid_t k;
89
+
90
+ for (i = 0, b = c->buckets; i < SLOT_CNT; i++, b++) {
91
+ if (0 != b->child) {
92
+ k = (k8 << BITS) | i;
93
+ /*printf("*** key: 0x%016llx depth: %u i: %u\n", k, depth, i); */
94
+ if (DEPTH - 1 == depth) {
95
+ #if IS_WINDOWS
96
+ printf("0x%016lx: %4lu\n", (long unsigned int)k, (long unsigned int)b->value);
97
+ #else
98
+ printf("0x%016llx: %4llu\n", (long long unsigned int)k, (long long unsigned int)b->value);
99
+ #endif
100
+ } else {
101
+ slot_print(b->child, k, depth + 1);
102
+ }
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,21 @@
1
+ // Copyright (c) 2011 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #ifndef OJ_CACHE8_H
5
+ #define OJ_CACHE8_H
6
+
7
+ #include "ruby.h"
8
+ #include "stdint.h"
9
+
10
+ typedef struct _cache8 *Cache8;
11
+ typedef uint64_t slot_t;
12
+ typedef uint64_t sid_t;
13
+
14
+ extern void oj_cache8_new(Cache8 *cache);
15
+ extern void oj_cache8_delete(Cache8 cache);
16
+
17
+ extern slot_t oj_cache8_get(Cache8 cache, sid_t key, slot_t **slot);
18
+
19
+ extern void oj_cache8_print(Cache8 cache);
20
+
21
+ #endif /* OJ_CACHE8_H */
@@ -0,0 +1,64 @@
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 "circarray.h"
5
+
6
+ #include "mem.h"
7
+
8
+ CircArray oj_circ_array_new(void) {
9
+ CircArray ca;
10
+
11
+ if (0 == (ca = OJ_R_ALLOC(struct _circArray))) {
12
+ rb_raise(rb_eNoMemError, "not enough memory\n");
13
+ }
14
+ ca->objs = ca->obj_array;
15
+ ca->size = sizeof(ca->obj_array) / sizeof(VALUE);
16
+ ca->cnt = 0;
17
+
18
+ return ca;
19
+ }
20
+
21
+ void oj_circ_array_free(CircArray ca) {
22
+ if (ca->objs != ca->obj_array) {
23
+ OJ_R_FREE(ca->objs);
24
+ }
25
+ OJ_R_FREE(ca);
26
+ }
27
+
28
+ void oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id) {
29
+ if (0 < id && 0 != ca) {
30
+ unsigned long i;
31
+
32
+ if (ca->size < id) {
33
+ unsigned long cnt = id + 512;
34
+
35
+ if (ca->objs == ca->obj_array) {
36
+ if (0 == (ca->objs = OJ_R_ALLOC_N(VALUE, cnt))) {
37
+ rb_raise(rb_eNoMemError, "not enough memory\n");
38
+ }
39
+ memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt);
40
+ } else {
41
+ OJ_R_REALLOC_N(ca->objs, VALUE, cnt);
42
+ }
43
+ ca->size = cnt;
44
+ }
45
+ id--;
46
+ for (i = ca->cnt; i < id; i++) {
47
+ ca->objs[i] = Qnil;
48
+ }
49
+ ca->objs[id] = obj;
50
+ if (ca->cnt <= id) {
51
+ ca->cnt = id + 1;
52
+ }
53
+ }
54
+ }
55
+
56
+ VALUE
57
+ oj_circ_array_get(CircArray ca, unsigned long id) {
58
+ VALUE obj = Qnil;
59
+
60
+ if (id <= ca->cnt && 0 != ca) {
61
+ obj = ca->objs[id - 1];
62
+ }
63
+ return obj;
64
+ }
@@ -0,0 +1,22 @@
1
+ // Copyright (c) 2012 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for
3
+ // license details.
4
+
5
+ #ifndef OJ_CIRCARRAY_H
6
+ #define OJ_CIRCARRAY_H
7
+
8
+ #include "ruby.h"
9
+
10
+ typedef struct _circArray {
11
+ VALUE obj_array[1024];
12
+ VALUE* objs;
13
+ unsigned long size; // allocated size or initial array size
14
+ unsigned long cnt;
15
+ }* CircArray;
16
+
17
+ extern CircArray oj_circ_array_new(void);
18
+ extern void oj_circ_array_free(CircArray ca);
19
+ extern void oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id);
20
+ extern VALUE oj_circ_array_get(CircArray ca, unsigned long id);
21
+
22
+ #endif /* OJ_CIRCARRAY_H */
@@ -0,0 +1,214 @@
1
+ // Copyright (c) 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #include "code.h"
5
+
6
+ #include "dump.h"
7
+
8
+ inline static VALUE resolve_classname(VALUE mod, const char *classname) {
9
+ VALUE clas = Qundef;
10
+ ID ci = rb_intern(classname);
11
+
12
+ if (rb_const_defined_at(mod, ci)) {
13
+ clas = rb_const_get_at(mod, ci);
14
+ }
15
+ return clas;
16
+ }
17
+
18
+ static VALUE path2class(const char *name) {
19
+ char class_name[1024];
20
+ VALUE clas;
21
+ char *end = class_name + sizeof(class_name) - 1;
22
+ char *s;
23
+ const char *n = name;
24
+
25
+ clas = rb_cObject;
26
+ for (s = class_name; '\0' != *n; n++) {
27
+ if (':' == *n) {
28
+ *s = '\0';
29
+ n++;
30
+ if (':' != *n) {
31
+ return Qundef;
32
+ }
33
+ if (Qundef == (clas = resolve_classname(clas, class_name))) {
34
+ return Qundef;
35
+ }
36
+ s = class_name;
37
+ } else if (end <= s) {
38
+ return Qundef;
39
+ } else {
40
+ *s++ = *n;
41
+ }
42
+ }
43
+ *s = '\0';
44
+
45
+ return resolve_classname(clas, class_name);
46
+ }
47
+
48
+ bool oj_code_dump(Code codes, VALUE obj, int depth, Out out) {
49
+ VALUE clas = rb_obj_class(obj);
50
+ Code c = codes;
51
+
52
+ for (; NULL != c->name; c++) {
53
+ if (Qundef == c->clas) { // indicates not defined
54
+ continue;
55
+ }
56
+ if (Qnil == c->clas) {
57
+ c->clas = path2class(c->name);
58
+ }
59
+ if (clas == c->clas && c->active) {
60
+ c->encode(obj, depth, out);
61
+ return true;
62
+ }
63
+ }
64
+ return false;
65
+ }
66
+
67
+ VALUE
68
+ oj_code_load(Code codes, VALUE clas, VALUE args) {
69
+ Code c = codes;
70
+
71
+ for (; NULL != c->name; c++) {
72
+ if (Qundef == c->clas) { // indicates not defined
73
+ continue;
74
+ }
75
+ if (Qnil == c->clas) {
76
+ c->clas = path2class(c->name);
77
+ }
78
+ if (clas == c->clas) {
79
+ if (NULL == c->decode) {
80
+ break;
81
+ }
82
+ return c->decode(clas, args);
83
+ }
84
+ }
85
+ return Qnil;
86
+ }
87
+
88
+ void oj_code_set_active(Code codes, VALUE clas, bool active) {
89
+ Code c = codes;
90
+
91
+ for (; NULL != c->name; c++) {
92
+ if (Qundef == c->clas) { // indicates not defined
93
+ continue;
94
+ }
95
+ if (Qnil == c->clas) {
96
+ c->clas = path2class(c->name);
97
+ }
98
+ if (clas == c->clas || Qnil == clas) {
99
+ c->active = active;
100
+ if (Qnil != clas) {
101
+ break;
102
+ }
103
+ }
104
+ }
105
+ }
106
+
107
+ bool oj_code_has(Code codes, VALUE clas, bool encode) {
108
+ Code c = codes;
109
+
110
+ for (; NULL != c->name; c++) {
111
+ if (Qundef == c->clas) { // indicates not defined
112
+ continue;
113
+ }
114
+ if (Qnil == c->clas) {
115
+ c->clas = path2class(c->name);
116
+ }
117
+ if (clas == c->clas) {
118
+ if (encode) {
119
+ return c->active && NULL != c->encode;
120
+ } else {
121
+ return c->active && NULL != c->decode;
122
+ }
123
+ }
124
+ }
125
+ return false;
126
+ }
127
+
128
+ void oj_code_attrs(VALUE obj, Attr attrs, int depth, Out out, bool with_class) {
129
+ int d2 = depth + 1;
130
+ int d3 = d2 + 1;
131
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
132
+ const char *classname = rb_obj_classname(obj);
133
+ size_t len = strlen(classname);
134
+ size_t size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len;
135
+ bool no_comma = true;
136
+
137
+ assure_size(out, size);
138
+ *out->cur++ = '{';
139
+
140
+ if (with_class) {
141
+ fill_indent(out, d2);
142
+ *out->cur++ = '"';
143
+ APPEND_CHARS(out->cur, out->opts->create_id, out->opts->create_id_len);
144
+ *out->cur++ = '"';
145
+ if (0 < out->opts->dump_opts.before_size) {
146
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
147
+ }
148
+ *out->cur++ = ':';
149
+ if (0 < out->opts->dump_opts.after_size) {
150
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
151
+ }
152
+ *out->cur++ = '"';
153
+ APPEND_CHARS(out->cur, classname, len);
154
+ *out->cur++ = '"';
155
+ no_comma = false;
156
+ }
157
+ size = d3 * out->indent + 2;
158
+ for (; NULL != attrs->name; attrs++) {
159
+ assure_size(out, size + attrs->len + sep_len + 2);
160
+ if (no_comma) {
161
+ no_comma = false;
162
+ } else {
163
+ *out->cur++ = ',';
164
+ }
165
+ fill_indent(out, d2);
166
+ *out->cur++ = '"';
167
+ APPEND_CHARS(out->cur, attrs->name, attrs->len);
168
+ *out->cur++ = '"';
169
+ if (0 < out->opts->dump_opts.before_size) {
170
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
171
+ }
172
+ *out->cur++ = ':';
173
+ if (0 < out->opts->dump_opts.after_size) {
174
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
175
+ }
176
+ if (Qundef == attrs->value) {
177
+ if (Qundef != attrs->time) {
178
+ switch (out->opts->time_format) {
179
+ case RubyTime: oj_dump_ruby_time(attrs->time, out); break;
180
+ case XmlTime: oj_dump_xml_time(attrs->time, out); break;
181
+ case UnixZTime: oj_dump_time(attrs->time, out, true); break;
182
+ case UnixTime:
183
+ default: oj_dump_time(attrs->time, out, false); break;
184
+ }
185
+ } else {
186
+ char buf[32];
187
+ char *b = buf + sizeof(buf) - 1;
188
+ bool neg = false;
189
+ long num = attrs->num;
190
+ size_t cnt = 0;
191
+
192
+ if (0 > num) {
193
+ neg = true;
194
+ num = -num;
195
+ }
196
+ *b-- = '\0';
197
+ if (0 < num) {
198
+ b = oj_longlong_to_string(num, neg, b);
199
+ } else {
200
+ *b = '0';
201
+ }
202
+ cnt = sizeof(buf) - (b - buf) - 1;
203
+ assure_size(out, cnt);
204
+ APPEND_CHARS(out->cur, b, cnt);
205
+ }
206
+ } else {
207
+ oj_dump_compat_val(attrs->value, d3, out, true);
208
+ }
209
+ }
210
+ assure_size(out, depth * out->indent + 2);
211
+ fill_indent(out, depth);
212
+ *out->cur++ = '}';
213
+ *out->cur = '\0';
214
+ }
@@ -0,0 +1,40 @@
1
+ // Copyright (c) 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #ifndef OJ_CODE_H
5
+ #define OJ_CODE_H
6
+
7
+ #include <ruby.h>
8
+
9
+ #include "oj.h"
10
+
11
+ typedef void (*EncodeFunc)(VALUE obj, int depth, Out out);
12
+ typedef VALUE (*DecodeFunc)(VALUE clas, VALUE args);
13
+
14
+ typedef struct _code {
15
+ const char *name;
16
+ VALUE clas;
17
+ EncodeFunc encode;
18
+ DecodeFunc decode;
19
+ bool active; // For compat mode.
20
+ } *Code;
21
+
22
+ // Used by encode functions.
23
+ typedef struct _attr {
24
+ const char *name;
25
+ int len;
26
+ VALUE value;
27
+ long num;
28
+ VALUE time;
29
+ } *Attr;
30
+
31
+ extern bool oj_code_dump(Code codes, VALUE obj, int depth, Out out);
32
+ extern VALUE oj_code_load(Code codes, VALUE clas, VALUE args);
33
+ extern void oj_code_set_active(Code codes, VALUE clas, bool active);
34
+ extern bool oj_code_has(Code codes, VALUE clas, bool encode);
35
+
36
+ extern void oj_code_attrs(VALUE obj, Attr attrs, int depth, Out out, bool with_class);
37
+
38
+ extern struct _code oj_compat_codes[];
39
+
40
+ #endif /* OJ_CODE_H */
@@ -0,0 +1,239 @@
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
+
6
+ #include "encode.h"
7
+ #include "err.h"
8
+ #include "intern.h"
9
+ #include "mem.h"
10
+ #include "oj.h"
11
+ #include "parse.h"
12
+ #include "resolve.h"
13
+ #include "trace.h"
14
+
15
+ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
16
+ const char *key = kval->key;
17
+ int klen = kval->klen;
18
+ Val parent = stack_peek(&pi->stack);
19
+
20
+ if (Qundef == kval->key_val && Yes == pi->options.create_ok && NULL != pi->options.create_id &&
21
+ *pi->options.create_id == *key && (int)pi->options.create_id_len == klen &&
22
+ 0 == strncmp(pi->options.create_id, key, klen)) {
23
+ parent->classname = oj_strndup(str, len);
24
+ parent->clen = len;
25
+ } else {
26
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
27
+ volatile VALUE rkey = oj_calc_hash_key(pi, kval);
28
+
29
+ if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
30
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
31
+
32
+ if (Qnil != clas) {
33
+ rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
34
+ }
35
+ }
36
+ if (rb_cHash != rb_obj_class(parent->val)) {
37
+ // The rb_hash_set would still work but the unit tests for the
38
+ // json gem require the less efficient []= method be called to set
39
+ // values. Even using the store method to set the values will fail
40
+ // the unit tests.
41
+ rb_funcall(parent->val, rb_intern("[]="), 2, rkey, rstr);
42
+ } else {
43
+ rb_hash_aset(parent->val, rkey, rstr);
44
+ }
45
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rstr);
46
+ }
47
+ }
48
+
49
+ static VALUE start_hash(ParseInfo pi) {
50
+ volatile VALUE h;
51
+
52
+ if (Qnil != pi->options.hash_class) {
53
+ h = rb_class_new_instance(0, NULL, pi->options.hash_class);
54
+ } else {
55
+ h = rb_hash_new();
56
+ }
57
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
58
+ return h;
59
+ }
60
+
61
+ static void end_hash(struct _parseInfo *pi) {
62
+ Val parent = stack_peek(&pi->stack);
63
+
64
+ if (0 != parent->classname) {
65
+ volatile VALUE clas;
66
+
67
+ clas = oj_name2class(pi, parent->classname, parent->clen, 0, rb_eArgError);
68
+ if (Qundef != clas) { // else an error
69
+ ID creatable = rb_intern("json_creatable?");
70
+
71
+ if (!rb_respond_to(clas, creatable) || Qtrue == rb_funcall(clas, creatable, 0)) {
72
+ parent->val = rb_funcall(clas, oj_json_create_id, 1, parent->val);
73
+ }
74
+ }
75
+ if (0 != parent->classname) {
76
+ OJ_R_FREE((char *)parent->classname);
77
+ parent->classname = 0;
78
+ }
79
+ }
80
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
81
+ }
82
+
83
+ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
84
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
85
+
86
+ if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
87
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
88
+
89
+ if (Qnil != clas) {
90
+ pi->stack.head->val = rb_funcall(clas, oj_json_create_id, 1, rstr);
91
+ return;
92
+ }
93
+ }
94
+ pi->stack.head->val = rstr;
95
+ TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, rstr);
96
+ }
97
+
98
+ static void add_num(ParseInfo pi, NumInfo ni) {
99
+ pi->stack.head->val = oj_num_as_value(ni);
100
+ TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, pi->stack.head->val);
101
+ }
102
+
103
+ static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
104
+ volatile VALUE rval = oj_num_as_value(ni);
105
+
106
+ if (rb_cHash != rb_obj_class(parent->val)) {
107
+ // The rb_hash_set would still work but the unit tests for the
108
+ // json gem require the less efficient []= method be called to set
109
+ // values. Even using the store method to set the values will fail
110
+ // the unit tests.
111
+ rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, oj_calc_hash_key(pi, parent), rval);
112
+ } else {
113
+ rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rval);
114
+ }
115
+ TRACE_PARSE_CALL(pi->options.trace, "set_number", pi, rval);
116
+ }
117
+
118
+ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
119
+ if (rb_cHash != rb_obj_class(parent->val)) {
120
+ // The rb_hash_set would still work but the unit tests for the
121
+ // json gem require the less efficient []= method be called to set
122
+ // values. Even using the store method to set the values will fail
123
+ // the unit tests.
124
+ rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, oj_calc_hash_key(pi, parent), value);
125
+ } else {
126
+ rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value);
127
+ }
128
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
129
+ }
130
+
131
+ static VALUE start_array(ParseInfo pi) {
132
+ if (Qnil != pi->options.array_class) {
133
+ return rb_class_new_instance(0, NULL, pi->options.array_class);
134
+ }
135
+ TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
136
+ return rb_ary_new();
137
+ }
138
+
139
+ static void array_append_num(ParseInfo pi, NumInfo ni) {
140
+ Val parent = stack_peek(&pi->stack);
141
+ volatile VALUE rval = oj_num_as_value(ni);
142
+
143
+ if (!oj_use_array_alt && rb_cArray != rb_obj_class(parent->val)) {
144
+ // The rb_ary_push would still work but the unit tests for the json
145
+ // gem require the less efficient << method be called to push the
146
+ // values.
147
+ rb_funcall(parent->val, rb_intern("<<"), 1, rval);
148
+ } else {
149
+ rb_ary_push(parent->val, rval);
150
+ }
151
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
152
+ }
153
+
154
+ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
155
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
156
+
157
+ if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
158
+ VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
159
+
160
+ if (Qnil != clas) {
161
+ rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
162
+ return;
163
+ }
164
+ }
165
+ rb_ary_push(stack_peek(&pi->stack)->val, rstr);
166
+ TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rstr);
167
+ }
168
+
169
+ void oj_set_compat_callbacks(ParseInfo pi) {
170
+ oj_set_strict_callbacks(pi);
171
+ pi->start_hash = start_hash;
172
+ pi->end_hash = end_hash;
173
+ pi->hash_set_cstr = hash_set_cstr;
174
+ pi->hash_set_num = hash_set_num;
175
+ pi->hash_set_value = hash_set_value;
176
+ pi->add_num = add_num;
177
+ pi->add_cstr = add_cstr;
178
+ pi->array_append_cstr = array_append_cstr;
179
+ pi->start_array = start_array;
180
+ pi->array_append_num = array_append_num;
181
+ }
182
+
183
+ VALUE
184
+ oj_compat_parse(int argc, VALUE *argv, VALUE self) {
185
+ struct _parseInfo pi;
186
+
187
+ parse_info_init(&pi);
188
+ pi.options = oj_default_options;
189
+ pi.handler = Qnil;
190
+ pi.err_class = Qnil;
191
+ pi.max_depth = 0;
192
+ pi.options.allow_nan = Yes;
193
+ pi.options.nilnil = Yes;
194
+ pi.options.empty_string = No;
195
+ oj_set_compat_callbacks(&pi);
196
+
197
+ if (T_STRING == rb_type(*argv)) {
198
+ return oj_pi_parse(argc, argv, &pi, 0, 0, false);
199
+ } else {
200
+ return oj_pi_sparse(argc, argv, &pi, 0);
201
+ }
202
+ }
203
+
204
+ VALUE
205
+ oj_compat_load(int argc, VALUE *argv, VALUE self) {
206
+ struct _parseInfo pi;
207
+
208
+ parse_info_init(&pi);
209
+ pi.options = oj_default_options;
210
+ pi.handler = Qnil;
211
+ pi.err_class = Qnil;
212
+ pi.max_depth = 0;
213
+ pi.options.allow_nan = Yes;
214
+ pi.options.nilnil = Yes;
215
+ pi.options.empty_string = Yes;
216
+ oj_set_compat_callbacks(&pi);
217
+
218
+ if (T_STRING == rb_type(*argv)) {
219
+ return oj_pi_parse(argc, argv, &pi, 0, 0, false);
220
+ } else {
221
+ return oj_pi_sparse(argc, argv, &pi, 0);
222
+ }
223
+ }
224
+
225
+ VALUE
226
+ oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
227
+ struct _parseInfo pi;
228
+
229
+ parse_info_init(&pi);
230
+ pi.options = oj_default_options;
231
+ pi.handler = Qnil;
232
+ pi.err_class = Qnil;
233
+ pi.max_depth = 0;
234
+ pi.options.allow_nan = Yes;
235
+ pi.options.nilnil = Yes;
236
+ oj_set_compat_callbacks(&pi);
237
+
238
+ return oj_pi_parse(argc, argv, &pi, json, len, false);
239
+ }