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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +96 -0
- data/ext/oj/buf.h +103 -0
- data/ext/oj/cache8.c +107 -0
- data/ext/oj/cache8.h +48 -0
- data/ext/oj/circarray.c +68 -0
- data/ext/oj/circarray.h +23 -0
- data/ext/oj/code.c +235 -0
- data/ext/oj/code.h +42 -0
- data/ext/oj/compat.c +299 -0
- data/ext/oj/custom.c +1188 -0
- data/ext/oj/dump.c +1232 -0
- data/ext/oj/dump.h +94 -0
- data/ext/oj/dump_compat.c +973 -0
- data/ext/oj/dump_leaf.c +252 -0
- data/ext/oj/dump_object.c +837 -0
- data/ext/oj/dump_strict.c +433 -0
- data/ext/oj/encode.h +45 -0
- data/ext/oj/err.c +57 -0
- data/ext/oj/err.h +70 -0
- data/ext/oj/extconf.rb +47 -0
- data/ext/oj/fast.c +1771 -0
- data/ext/oj/hash.c +163 -0
- data/ext/oj/hash.h +46 -0
- data/ext/oj/hash_test.c +512 -0
- data/ext/oj/mimic_json.c +873 -0
- data/ext/oj/object.c +771 -0
- data/ext/oj/odd.c +231 -0
- data/ext/oj/odd.h +44 -0
- data/ext/oj/oj.c +1694 -0
- data/ext/oj/oj.h +381 -0
- data/ext/oj/parse.c +1085 -0
- data/ext/oj/parse.h +111 -0
- data/ext/oj/rails.c +1485 -0
- data/ext/oj/rails.h +21 -0
- data/ext/oj/reader.c +231 -0
- data/ext/oj/reader.h +151 -0
- data/ext/oj/resolve.c +102 -0
- data/ext/oj/resolve.h +14 -0
- data/ext/oj/rxclass.c +147 -0
- data/ext/oj/rxclass.h +27 -0
- data/ext/oj/saj.c +714 -0
- data/ext/oj/scp.c +224 -0
- data/ext/oj/sparse.c +910 -0
- data/ext/oj/stream_writer.c +363 -0
- data/ext/oj/strict.c +212 -0
- data/ext/oj/string_writer.c +512 -0
- data/ext/oj/trace.c +79 -0
- data/ext/oj/trace.h +28 -0
- data/ext/oj/util.c +136 -0
- data/ext/oj/util.h +19 -0
- data/ext/oj/val_stack.c +118 -0
- data/ext/oj/val_stack.h +185 -0
- data/ext/oj/wab.c +631 -0
- data/lib/oj.rb +21 -0
- data/lib/oj/active_support_helper.rb +41 -0
- data/lib/oj/bag.rb +88 -0
- data/lib/oj/easy_hash.rb +52 -0
- data/lib/oj/error.rb +22 -0
- data/lib/oj/json.rb +176 -0
- data/lib/oj/mimic.rb +267 -0
- data/lib/oj/saj.rb +66 -0
- data/lib/oj/schandler.rb +142 -0
- data/lib/oj/state.rb +131 -0
- data/lib/oj/version.rb +5 -0
- data/pages/Advanced.md +22 -0
- data/pages/Compatibility.md +25 -0
- data/pages/Custom.md +23 -0
- data/pages/Encoding.md +65 -0
- data/pages/JsonGem.md +79 -0
- data/pages/Modes.md +154 -0
- data/pages/Options.md +266 -0
- data/pages/Rails.md +116 -0
- data/pages/Security.md +20 -0
- data/pages/WAB.md +13 -0
- data/test/_test_active.rb +76 -0
- data/test/_test_active_mimic.rb +96 -0
- data/test/_test_mimic_rails.rb +126 -0
- data/test/activerecord/result_test.rb +27 -0
- data/test/activesupport4/decoding_test.rb +108 -0
- data/test/activesupport4/encoding_test.rb +531 -0
- data/test/activesupport4/test_helper.rb +41 -0
- data/test/activesupport5/decoding_test.rb +125 -0
- data/test/activesupport5/encoding_test.rb +485 -0
- data/test/activesupport5/encoding_test_cases.rb +90 -0
- data/test/activesupport5/test_helper.rb +50 -0
- data/test/activesupport5/time_zone_test_helpers.rb +24 -0
- data/test/big.rb +15 -0
- data/test/files.rb +29 -0
- data/test/foo.rb +33 -0
- data/test/helper.rb +26 -0
- data/test/isolated/shared.rb +308 -0
- data/test/isolated/test_mimic_after.rb +13 -0
- data/test/isolated/test_mimic_alone.rb +12 -0
- data/test/isolated/test_mimic_as_json.rb +45 -0
- data/test/isolated/test_mimic_before.rb +13 -0
- data/test/isolated/test_mimic_define.rb +28 -0
- data/test/isolated/test_mimic_rails_after.rb +22 -0
- data/test/isolated/test_mimic_rails_before.rb +21 -0
- data/test/isolated/test_mimic_redefine.rb +15 -0
- data/test/json_gem/json_addition_test.rb +216 -0
- data/test/json_gem/json_common_interface_test.rb +148 -0
- data/test/json_gem/json_encoding_test.rb +107 -0
- data/test/json_gem/json_ext_parser_test.rb +20 -0
- data/test/json_gem/json_fixtures_test.rb +35 -0
- data/test/json_gem/json_generator_test.rb +383 -0
- data/test/json_gem/json_generic_object_test.rb +90 -0
- data/test/json_gem/json_parser_test.rb +470 -0
- data/test/json_gem/json_string_matching_test.rb +42 -0
- data/test/json_gem/test_helper.rb +18 -0
- data/test/mem.rb +35 -0
- data/test/perf.rb +107 -0
- data/test/perf_compat.rb +130 -0
- data/test/perf_fast.rb +164 -0
- data/test/perf_file.rb +64 -0
- data/test/perf_object.rb +138 -0
- data/test/perf_saj.rb +109 -0
- data/test/perf_scp.rb +151 -0
- data/test/perf_simple.rb +287 -0
- data/test/perf_strict.rb +145 -0
- data/test/perf_wab.rb +131 -0
- data/test/sample.rb +54 -0
- data/test/sample/change.rb +14 -0
- data/test/sample/dir.rb +19 -0
- data/test/sample/doc.rb +36 -0
- data/test/sample/file.rb +48 -0
- data/test/sample/group.rb +16 -0
- data/test/sample/hasprops.rb +16 -0
- data/test/sample/layer.rb +12 -0
- data/test/sample/line.rb +20 -0
- data/test/sample/oval.rb +10 -0
- data/test/sample/rect.rb +10 -0
- data/test/sample/shape.rb +35 -0
- data/test/sample/text.rb +20 -0
- data/test/sample_json.rb +37 -0
- data/test/test_compat.rb +509 -0
- data/test/test_custom.rb +406 -0
- data/test/test_debian.rb +53 -0
- data/test/test_fast.rb +470 -0
- data/test/test_file.rb +239 -0
- data/test/test_gc.rb +49 -0
- data/test/test_hash.rb +29 -0
- data/test/test_integer_range.rb +73 -0
- data/test/test_null.rb +376 -0
- data/test/test_object.rb +1018 -0
- data/test/test_saj.rb +186 -0
- data/test/test_scp.rb +433 -0
- data/test/test_strict.rb +410 -0
- data/test/test_various.rb +739 -0
- data/test/test_wab.rb +307 -0
- data/test/test_writer.rb +380 -0
- data/test/tests.rb +24 -0
- data/test/tests_mimic.rb +14 -0
- data/test/tests_mimic_addition.rb +7 -0
- metadata +359 -0
data/ext/oj/circarray.h
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/* circarray.h
|
|
2
|
+
* Copyright (c) 2012, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef OJ_CIRCARRAY_H
|
|
7
|
+
#define OJ_CIRCARRAY_H
|
|
8
|
+
|
|
9
|
+
#include "ruby.h"
|
|
10
|
+
|
|
11
|
+
typedef struct _circArray {
|
|
12
|
+
VALUE obj_array[1024];
|
|
13
|
+
VALUE *objs;
|
|
14
|
+
unsigned long size; // allocated size or initial array size
|
|
15
|
+
unsigned long cnt;
|
|
16
|
+
} *CircArray;
|
|
17
|
+
|
|
18
|
+
extern CircArray oj_circ_array_new(void);
|
|
19
|
+
extern void oj_circ_array_free(CircArray ca);
|
|
20
|
+
extern void oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id);
|
|
21
|
+
extern VALUE oj_circ_array_get(CircArray ca, unsigned long id);
|
|
22
|
+
|
|
23
|
+
#endif /* OJ_CIRCARRAY_H */
|
data/ext/oj/code.c
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/* code.c
|
|
2
|
+
* Copyright (c) 2017, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "code.h"
|
|
7
|
+
#include "dump.h"
|
|
8
|
+
|
|
9
|
+
inline static VALUE
|
|
10
|
+
resolve_classname(VALUE mod, const char *classname) {
|
|
11
|
+
VALUE clas = Qundef;
|
|
12
|
+
ID ci = rb_intern(classname);
|
|
13
|
+
|
|
14
|
+
if (rb_const_defined_at(mod, ci)) {
|
|
15
|
+
clas = rb_const_get_at(mod, ci);
|
|
16
|
+
}
|
|
17
|
+
return clas;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static VALUE
|
|
21
|
+
path2class(const char *name) {
|
|
22
|
+
char class_name[1024];
|
|
23
|
+
VALUE clas;
|
|
24
|
+
char *end = class_name + sizeof(class_name) - 1;
|
|
25
|
+
char *s;
|
|
26
|
+
const char *n = name;
|
|
27
|
+
|
|
28
|
+
clas = rb_cObject;
|
|
29
|
+
for (s = class_name; '\0' != *n; n++) {
|
|
30
|
+
if (':' == *n) {
|
|
31
|
+
*s = '\0';
|
|
32
|
+
n++;
|
|
33
|
+
if (':' != *n) {
|
|
34
|
+
return Qundef;
|
|
35
|
+
}
|
|
36
|
+
if (Qundef == (clas = resolve_classname(clas, class_name))) {
|
|
37
|
+
return Qundef;
|
|
38
|
+
}
|
|
39
|
+
s = class_name;
|
|
40
|
+
} else if (end <= s) {
|
|
41
|
+
return Qundef;
|
|
42
|
+
} else {
|
|
43
|
+
*s++ = *n;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
*s = '\0';
|
|
47
|
+
|
|
48
|
+
return resolve_classname(clas, class_name);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
bool
|
|
52
|
+
oj_code_dump(Code codes, VALUE obj, int depth, Out out) {
|
|
53
|
+
VALUE clas = rb_obj_class(obj);
|
|
54
|
+
Code c = codes;
|
|
55
|
+
|
|
56
|
+
for (; NULL != c->name; c++) {
|
|
57
|
+
if (Qundef == c->clas) { // indicates not defined
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (Qnil == c->clas) {
|
|
61
|
+
c->clas = path2class(c->name);
|
|
62
|
+
}
|
|
63
|
+
if (clas == c->clas && c->active) {
|
|
64
|
+
c->encode(obj, depth, out);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
VALUE
|
|
72
|
+
oj_code_load(Code codes, VALUE clas, VALUE args) {
|
|
73
|
+
Code c = codes;
|
|
74
|
+
|
|
75
|
+
for (; NULL != c->name; c++) {
|
|
76
|
+
if (Qundef == c->clas) { // indicates not defined
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (Qnil == c->clas) {
|
|
80
|
+
c->clas = path2class(c->name);
|
|
81
|
+
}
|
|
82
|
+
if (clas == c->clas) {
|
|
83
|
+
if (NULL == c->decode) {
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
return c->decode(clas, args);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return Qnil;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
void
|
|
93
|
+
oj_code_set_active(Code codes, VALUE clas, bool active) {
|
|
94
|
+
Code c = codes;
|
|
95
|
+
|
|
96
|
+
for (; NULL != c->name; c++) {
|
|
97
|
+
if (Qundef == c->clas) { // indicates not defined
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (Qnil == c->clas) {
|
|
101
|
+
c->clas = path2class(c->name);
|
|
102
|
+
}
|
|
103
|
+
if (clas == c->clas || Qnil == clas) {
|
|
104
|
+
c->active = active;
|
|
105
|
+
if (Qnil != clas) {
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
bool
|
|
113
|
+
oj_code_has(Code codes, VALUE clas, bool encode) {
|
|
114
|
+
Code c = codes;
|
|
115
|
+
|
|
116
|
+
for (; NULL != c->name; c++) {
|
|
117
|
+
if (Qundef == c->clas) { // indicates not defined
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (Qnil == c->clas) {
|
|
121
|
+
c->clas = path2class(c->name);
|
|
122
|
+
}
|
|
123
|
+
if (clas == c->clas) {
|
|
124
|
+
if (encode) {
|
|
125
|
+
return c->active && NULL != c->encode;
|
|
126
|
+
} else {
|
|
127
|
+
return c->active && NULL != c->decode;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
void
|
|
135
|
+
oj_code_attrs(VALUE obj, Attr attrs, int depth, Out out, bool with_class) {
|
|
136
|
+
int d2 = depth + 1;
|
|
137
|
+
int d3 = d2 + 1;
|
|
138
|
+
size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
|
139
|
+
const char *classname = rb_obj_classname(obj);
|
|
140
|
+
size_t len = strlen(classname);
|
|
141
|
+
size_t size = d2 * out->indent + 10 + len + out->opts->create_id_len + sep_len;
|
|
142
|
+
bool no_comma = true;
|
|
143
|
+
|
|
144
|
+
assure_size(out, size);
|
|
145
|
+
*out->cur++ = '{';
|
|
146
|
+
|
|
147
|
+
if (with_class) {
|
|
148
|
+
fill_indent(out, d2);
|
|
149
|
+
*out->cur++ = '"';
|
|
150
|
+
memcpy(out->cur, out->opts->create_id, out->opts->create_id_len);
|
|
151
|
+
out->cur += out->opts->create_id_len;
|
|
152
|
+
*out->cur++ = '"';
|
|
153
|
+
if (0 < out->opts->dump_opts.before_size) {
|
|
154
|
+
strcpy(out->cur, out->opts->dump_opts.before_sep);
|
|
155
|
+
out->cur += out->opts->dump_opts.before_size;
|
|
156
|
+
}
|
|
157
|
+
*out->cur++ = ':';
|
|
158
|
+
if (0 < out->opts->dump_opts.after_size) {
|
|
159
|
+
strcpy(out->cur, out->opts->dump_opts.after_sep);
|
|
160
|
+
out->cur += out->opts->dump_opts.after_size;
|
|
161
|
+
}
|
|
162
|
+
*out->cur++ = '"';
|
|
163
|
+
memcpy(out->cur, classname, len);
|
|
164
|
+
out->cur += len;
|
|
165
|
+
*out->cur++ = '"';
|
|
166
|
+
no_comma = false;
|
|
167
|
+
}
|
|
168
|
+
size = d3 * out->indent + 2;
|
|
169
|
+
for (; NULL != attrs->name; attrs++) {
|
|
170
|
+
assure_size(out, size + attrs->len + sep_len + 2);
|
|
171
|
+
if (no_comma) {
|
|
172
|
+
no_comma = false;
|
|
173
|
+
} else {
|
|
174
|
+
*out->cur++ = ',';
|
|
175
|
+
}
|
|
176
|
+
fill_indent(out, d2);
|
|
177
|
+
*out->cur++ = '"';
|
|
178
|
+
memcpy(out->cur, attrs->name, attrs->len);
|
|
179
|
+
out->cur += attrs->len;
|
|
180
|
+
*out->cur++ = '"';
|
|
181
|
+
if (0 < out->opts->dump_opts.before_size) {
|
|
182
|
+
strcpy(out->cur, out->opts->dump_opts.before_sep);
|
|
183
|
+
out->cur += out->opts->dump_opts.before_size;
|
|
184
|
+
}
|
|
185
|
+
*out->cur++ = ':';
|
|
186
|
+
if (0 < out->opts->dump_opts.after_size) {
|
|
187
|
+
strcpy(out->cur, out->opts->dump_opts.after_sep);
|
|
188
|
+
out->cur += out->opts->dump_opts.after_size;
|
|
189
|
+
}
|
|
190
|
+
if (Qundef == attrs->value) {
|
|
191
|
+
if (Qundef != attrs->time) {
|
|
192
|
+
switch (out->opts->time_format) {
|
|
193
|
+
case RubyTime: oj_dump_ruby_time(attrs->time, out); break;
|
|
194
|
+
case XmlTime: oj_dump_xml_time(attrs->time, out); break;
|
|
195
|
+
case UnixZTime: oj_dump_time(attrs->time, out, true); break;
|
|
196
|
+
case UnixTime:
|
|
197
|
+
default: oj_dump_time(attrs->time, out, false); break;
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
char buf[32];
|
|
201
|
+
char *b = buf + sizeof(buf) - 1;
|
|
202
|
+
int neg = 0;
|
|
203
|
+
long num = attrs->num;
|
|
204
|
+
|
|
205
|
+
if (0 > num) {
|
|
206
|
+
neg = 1;
|
|
207
|
+
num = -num;
|
|
208
|
+
}
|
|
209
|
+
*b-- = '\0';
|
|
210
|
+
if (0 < num) {
|
|
211
|
+
for (; 0 < num; num /= 10, b--) {
|
|
212
|
+
*b = (num % 10) + '0';
|
|
213
|
+
}
|
|
214
|
+
if (neg) {
|
|
215
|
+
*b = '-';
|
|
216
|
+
} else {
|
|
217
|
+
b++;
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
*b = '0';
|
|
221
|
+
}
|
|
222
|
+
assure_size(out, (sizeof(buf) - (b - buf)));
|
|
223
|
+
for (; '\0' != *b; b++) {
|
|
224
|
+
*out->cur++ = *b;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
} else {
|
|
228
|
+
oj_dump_compat_val(attrs->value, d3, out, true);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
assure_size(out, depth * out->indent + 2);
|
|
232
|
+
fill_indent(out, depth);
|
|
233
|
+
*out->cur++ = '}';
|
|
234
|
+
*out->cur = '\0';
|
|
235
|
+
}
|
data/ext/oj/code.h
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* code.h
|
|
2
|
+
* Copyright (c) 2017, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef OJ_CODE_H
|
|
7
|
+
#define OJ_CODE_H
|
|
8
|
+
|
|
9
|
+
#include <ruby.h>
|
|
10
|
+
|
|
11
|
+
#include "oj.h"
|
|
12
|
+
|
|
13
|
+
typedef void (*EncodeFunc)(VALUE obj, int depth, Out out);
|
|
14
|
+
typedef VALUE (*DecodeFunc)(VALUE clas, VALUE args);
|
|
15
|
+
|
|
16
|
+
typedef struct _code {
|
|
17
|
+
const char *name;
|
|
18
|
+
VALUE clas;
|
|
19
|
+
EncodeFunc encode;
|
|
20
|
+
DecodeFunc decode;
|
|
21
|
+
bool active; // For compat mode.
|
|
22
|
+
} *Code;
|
|
23
|
+
|
|
24
|
+
// Used by encode functions.
|
|
25
|
+
typedef struct _attr {
|
|
26
|
+
const char *name;
|
|
27
|
+
int len;
|
|
28
|
+
VALUE value;
|
|
29
|
+
long num;
|
|
30
|
+
VALUE time;
|
|
31
|
+
} *Attr;
|
|
32
|
+
|
|
33
|
+
extern bool oj_code_dump(Code codes, VALUE obj, int depth, Out out);
|
|
34
|
+
extern VALUE oj_code_load(Code codes, VALUE clas, VALUE args);
|
|
35
|
+
extern void oj_code_set_active(Code codes, VALUE clas, bool active);
|
|
36
|
+
extern bool oj_code_has(Code codes, VALUE clas, bool encode);
|
|
37
|
+
|
|
38
|
+
extern void oj_code_attrs(VALUE obj, Attr attrs, int depth, Out out, bool with_class);
|
|
39
|
+
|
|
40
|
+
extern struct _code oj_compat_codes[];
|
|
41
|
+
|
|
42
|
+
#endif /* OJ_CODE_H */
|
data/ext/oj/compat.c
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/* compat.c
|
|
2
|
+
* Copyright (c) 2012, Peter Ohler
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include <stdio.h>
|
|
7
|
+
|
|
8
|
+
#include "oj.h"
|
|
9
|
+
#include "err.h"
|
|
10
|
+
#include "parse.h"
|
|
11
|
+
#include "resolve.h"
|
|
12
|
+
#include "hash.h"
|
|
13
|
+
#include "encode.h"
|
|
14
|
+
#include "trace.h"
|
|
15
|
+
|
|
16
|
+
static void
|
|
17
|
+
hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
|
18
|
+
const char *key = kval->key;
|
|
19
|
+
int klen = kval->klen;
|
|
20
|
+
Val parent = stack_peek(&pi->stack);
|
|
21
|
+
volatile VALUE rkey = kval->key_val;
|
|
22
|
+
|
|
23
|
+
if (Qundef == rkey &&
|
|
24
|
+
Yes == pi->options.create_ok &&
|
|
25
|
+
NULL != pi->options.create_id &&
|
|
26
|
+
*pi->options.create_id == *key &&
|
|
27
|
+
(int)pi->options.create_id_len == klen &&
|
|
28
|
+
0 == strncmp(pi->options.create_id, key, klen)) {
|
|
29
|
+
|
|
30
|
+
parent->classname = oj_strndup(str, len);
|
|
31
|
+
parent->clen = len;
|
|
32
|
+
} else {
|
|
33
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
|
34
|
+
|
|
35
|
+
if (Qundef == rkey) {
|
|
36
|
+
rkey = rb_str_new(key, klen);
|
|
37
|
+
rstr = oj_encode(rstr);
|
|
38
|
+
rkey = oj_encode(rkey);
|
|
39
|
+
if (Yes == pi->options.sym_key) {
|
|
40
|
+
rkey = rb_str_intern(rkey);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
44
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
|
45
|
+
|
|
46
|
+
if (Qnil != clas) {
|
|
47
|
+
rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (rb_cHash != rb_obj_class(parent->val)) {
|
|
51
|
+
// The rb_hash_set would still work but the unit tests for the
|
|
52
|
+
// json gem require the less efficient []= method be called to set
|
|
53
|
+
// values. Even using the store method to set the values will fail
|
|
54
|
+
// the unit tests.
|
|
55
|
+
rb_funcall(parent->val, rb_intern("[]="), 2, rkey, rstr);
|
|
56
|
+
} else {
|
|
57
|
+
rb_hash_aset(parent->val, rkey, rstr);
|
|
58
|
+
}
|
|
59
|
+
if (Yes == pi->options.trace) {
|
|
60
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static VALUE
|
|
66
|
+
start_hash(ParseInfo pi) {
|
|
67
|
+
volatile VALUE h;
|
|
68
|
+
|
|
69
|
+
if (Qnil != pi->options.hash_class) {
|
|
70
|
+
h = rb_class_new_instance(0, NULL, pi->options.hash_class);
|
|
71
|
+
} else {
|
|
72
|
+
h = rb_hash_new();
|
|
73
|
+
}
|
|
74
|
+
if (Yes == pi->options.trace) {
|
|
75
|
+
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
|
76
|
+
}
|
|
77
|
+
return h;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static void
|
|
81
|
+
end_hash(struct _parseInfo *pi) {
|
|
82
|
+
Val parent = stack_peek(&pi->stack);
|
|
83
|
+
|
|
84
|
+
if (0 != parent->classname) {
|
|
85
|
+
volatile VALUE clas;
|
|
86
|
+
|
|
87
|
+
clas = oj_name2class(pi, parent->classname, parent->clen, 0, rb_eArgError);
|
|
88
|
+
if (Qundef != clas) { // else an error
|
|
89
|
+
ID creatable = rb_intern("json_creatable?");
|
|
90
|
+
|
|
91
|
+
if (!rb_respond_to(clas, creatable) || Qtrue == rb_funcall(clas, creatable, 0)) {
|
|
92
|
+
parent->val = rb_funcall(clas, oj_json_create_id, 1, parent->val);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (0 != parent->classname) {
|
|
96
|
+
xfree((char*)parent->classname);
|
|
97
|
+
parent->classname = 0;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (Yes == pi->options.trace) {
|
|
101
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static VALUE
|
|
106
|
+
calc_hash_key(ParseInfo pi, Val parent) {
|
|
107
|
+
volatile VALUE rkey = parent->key_val;
|
|
108
|
+
|
|
109
|
+
if (Qundef == rkey) {
|
|
110
|
+
rkey = rb_str_new(parent->key, parent->klen);
|
|
111
|
+
}
|
|
112
|
+
rkey = oj_encode(rkey);
|
|
113
|
+
if (Yes == pi->options.sym_key) {
|
|
114
|
+
rkey = rb_str_intern(rkey);
|
|
115
|
+
}
|
|
116
|
+
return rkey;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static void
|
|
120
|
+
add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
121
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
|
122
|
+
|
|
123
|
+
rstr = oj_encode(rstr);
|
|
124
|
+
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
125
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
|
126
|
+
|
|
127
|
+
if (Qnil != clas) {
|
|
128
|
+
pi->stack.head->val = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
pi->stack.head->val = rstr;
|
|
133
|
+
if (Yes == pi->options.trace) {
|
|
134
|
+
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static void
|
|
139
|
+
add_num(ParseInfo pi, NumInfo ni) {
|
|
140
|
+
pi->stack.head->val = oj_num_as_value(ni);
|
|
141
|
+
if (Yes == pi->options.trace) {
|
|
142
|
+
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
static void
|
|
147
|
+
hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
|
|
148
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
|
149
|
+
|
|
150
|
+
if (!oj_use_hash_alt && rb_cHash != rb_obj_class(parent->val)) {
|
|
151
|
+
// The rb_hash_set would still work but the unit tests for the
|
|
152
|
+
// json gem require the less efficient []= method be called to set
|
|
153
|
+
// values. Even using the store method to set the values will fail
|
|
154
|
+
// the unit tests.
|
|
155
|
+
rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent), rval);
|
|
156
|
+
} else {
|
|
157
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
|
|
158
|
+
}
|
|
159
|
+
if (Yes == pi->options.trace) {
|
|
160
|
+
oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
static void
|
|
165
|
+
hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
|
166
|
+
if (rb_cHash != rb_obj_class(parent->val)) {
|
|
167
|
+
// The rb_hash_set would still work but the unit tests for the
|
|
168
|
+
// json gem require the less efficient []= method be called to set
|
|
169
|
+
// values. Even using the store method to set the values will fail
|
|
170
|
+
// the unit tests.
|
|
171
|
+
rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent), value);
|
|
172
|
+
} else {
|
|
173
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
|
|
174
|
+
}
|
|
175
|
+
if (Yes == pi->options.trace) {
|
|
176
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
static VALUE
|
|
181
|
+
start_array(ParseInfo pi) {
|
|
182
|
+
if (Qnil != pi->options.array_class) {
|
|
183
|
+
return rb_class_new_instance(0, NULL, pi->options.array_class);
|
|
184
|
+
}
|
|
185
|
+
if (Yes == pi->options.trace) {
|
|
186
|
+
oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
|
|
187
|
+
}
|
|
188
|
+
return rb_ary_new();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
static void
|
|
192
|
+
array_append_num(ParseInfo pi, NumInfo ni) {
|
|
193
|
+
Val parent = stack_peek(&pi->stack);
|
|
194
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
|
195
|
+
|
|
196
|
+
if (!oj_use_array_alt && rb_cArray != rb_obj_class(parent->val)) {
|
|
197
|
+
// The rb_ary_push would still work but the unit tests for the json
|
|
198
|
+
// gem require the less efficient << method be called to push the
|
|
199
|
+
// values.
|
|
200
|
+
rb_funcall(parent->val, rb_intern("<<"), 1, rval);
|
|
201
|
+
} else {
|
|
202
|
+
rb_ary_push(parent->val, rval);
|
|
203
|
+
}
|
|
204
|
+
if (Yes == pi->options.trace) {
|
|
205
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static void
|
|
210
|
+
array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
211
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
|
212
|
+
|
|
213
|
+
rstr = oj_encode(rstr);
|
|
214
|
+
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
|
215
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
|
216
|
+
|
|
217
|
+
if (Qnil != clas) {
|
|
218
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rstr);
|
|
223
|
+
if (Yes == pi->options.trace) {
|
|
224
|
+
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
void
|
|
229
|
+
oj_set_compat_callbacks(ParseInfo pi) {
|
|
230
|
+
oj_set_strict_callbacks(pi);
|
|
231
|
+
pi->start_hash = start_hash;
|
|
232
|
+
pi->end_hash = end_hash;
|
|
233
|
+
pi->hash_set_cstr = hash_set_cstr;
|
|
234
|
+
pi->hash_set_num = hash_set_num;
|
|
235
|
+
pi->hash_set_value = hash_set_value;
|
|
236
|
+
pi->add_num = add_num;
|
|
237
|
+
pi->add_cstr = add_cstr;
|
|
238
|
+
pi->array_append_cstr = array_append_cstr;
|
|
239
|
+
pi->start_array = start_array;
|
|
240
|
+
pi->array_append_num = array_append_num;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
VALUE
|
|
244
|
+
oj_compat_parse(int argc, VALUE *argv, VALUE self) {
|
|
245
|
+
struct _parseInfo pi;
|
|
246
|
+
|
|
247
|
+
parse_info_init(&pi);
|
|
248
|
+
pi.options = oj_default_options;
|
|
249
|
+
pi.handler = Qnil;
|
|
250
|
+
pi.err_class = Qnil;
|
|
251
|
+
pi.max_depth = 0;
|
|
252
|
+
pi.options.allow_nan = Yes;
|
|
253
|
+
pi.options.nilnil = Yes;
|
|
254
|
+
pi.options.empty_string = No;
|
|
255
|
+
oj_set_compat_callbacks(&pi);
|
|
256
|
+
|
|
257
|
+
if (T_STRING == rb_type(*argv)) {
|
|
258
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, false);
|
|
259
|
+
} else {
|
|
260
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
VALUE
|
|
265
|
+
oj_compat_load(int argc, VALUE *argv, VALUE self) {
|
|
266
|
+
struct _parseInfo pi;
|
|
267
|
+
|
|
268
|
+
parse_info_init(&pi);
|
|
269
|
+
pi.options = oj_default_options;
|
|
270
|
+
pi.handler = Qnil;
|
|
271
|
+
pi.err_class = Qnil;
|
|
272
|
+
pi.max_depth = 0;
|
|
273
|
+
pi.options.allow_nan = Yes;
|
|
274
|
+
pi.options.nilnil = Yes;
|
|
275
|
+
pi.options.empty_string = Yes;
|
|
276
|
+
oj_set_compat_callbacks(&pi);
|
|
277
|
+
|
|
278
|
+
if (T_STRING == rb_type(*argv)) {
|
|
279
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, false);
|
|
280
|
+
} else {
|
|
281
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
VALUE
|
|
286
|
+
oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
|
287
|
+
struct _parseInfo pi;
|
|
288
|
+
|
|
289
|
+
parse_info_init(&pi);
|
|
290
|
+
pi.options = oj_default_options;
|
|
291
|
+
pi.handler = Qnil;
|
|
292
|
+
pi.err_class = Qnil;
|
|
293
|
+
pi.max_depth = 0;
|
|
294
|
+
pi.options.allow_nan = Yes;
|
|
295
|
+
pi.options.nilnil = Yes;
|
|
296
|
+
oj_set_compat_callbacks(&pi);
|
|
297
|
+
|
|
298
|
+
return oj_pi_parse(argc, argv, &pi, json, len, false);
|
|
299
|
+
}
|