oj 3.11.1 → 3.11.6
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 +4 -4
- data/README.md +6 -1
- data/ext/oj/buf.h +34 -38
- data/ext/oj/cache8.c +59 -62
- data/ext/oj/cache8.h +8 -7
- data/ext/oj/circarray.c +33 -35
- data/ext/oj/circarray.h +11 -9
- data/ext/oj/code.c +170 -174
- data/ext/oj/code.h +21 -20
- data/ext/oj/compat.c +159 -166
- data/ext/oj/custom.c +802 -851
- data/ext/oj/dump.c +766 -778
- data/ext/oj/dump.h +49 -51
- data/ext/oj/dump_compat.c +1 -0
- data/ext/oj/dump_leaf.c +116 -157
- data/ext/oj/dump_object.c +609 -628
- data/ext/oj/dump_strict.c +318 -327
- data/ext/oj/encode.h +3 -4
- data/ext/oj/err.c +39 -25
- data/ext/oj/err.h +24 -15
- data/ext/oj/extconf.rb +2 -1
- data/ext/oj/fast.c +1042 -1041
- data/ext/oj/hash.c +62 -66
- data/ext/oj/hash.h +7 -6
- data/ext/oj/hash_test.c +450 -443
- data/ext/oj/mimic_json.c +412 -402
- data/ext/oj/object.c +559 -528
- data/ext/oj/odd.c +123 -128
- data/ext/oj/odd.h +27 -25
- data/ext/oj/oj.c +1123 -924
- data/ext/oj/oj.h +286 -298
- data/ext/oj/parse.c +938 -930
- data/ext/oj/parse.h +70 -69
- data/ext/oj/rails.c +836 -839
- data/ext/oj/rails.h +7 -7
- data/ext/oj/reader.c +135 -140
- data/ext/oj/reader.h +66 -79
- data/ext/oj/resolve.c +43 -43
- data/ext/oj/resolve.h +3 -2
- data/ext/oj/rxclass.c +67 -68
- data/ext/oj/rxclass.h +12 -10
- data/ext/oj/saj.c +451 -479
- data/ext/oj/scp.c +93 -103
- data/ext/oj/sparse.c +770 -730
- data/ext/oj/stream_writer.c +120 -149
- data/ext/oj/strict.c +71 -86
- data/ext/oj/string_writer.c +198 -243
- data/ext/oj/trace.c +29 -33
- data/ext/oj/trace.h +14 -11
- data/ext/oj/util.c +103 -103
- data/ext/oj/util.h +3 -2
- data/ext/oj/val_stack.c +47 -47
- data/ext/oj/val_stack.h +79 -86
- data/ext/oj/wab.c +291 -309
- data/lib/oj/bag.rb +1 -0
- data/lib/oj/easy_hash.rb +5 -4
- data/lib/oj/mimic.rb +0 -12
- data/lib/oj/version.rb +1 -1
- data/test/activerecord/result_test.rb +7 -2
- data/test/foo.rb +35 -32
- data/test/test_fast.rb +32 -2
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +10 -0
- data/test/test_scp.rb +1 -1
- metadata +4 -2
data/ext/oj/compat.c
CHANGED
@@ -1,295 +1,288 @@
|
|
1
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.
|
2
3
|
|
3
4
|
#include <stdio.h>
|
4
5
|
|
5
|
-
#include "
|
6
|
+
#include "encode.h"
|
6
7
|
#include "err.h"
|
8
|
+
#include "hash.h"
|
9
|
+
#include "oj.h"
|
7
10
|
#include "parse.h"
|
8
11
|
#include "resolve.h"
|
9
|
-
#include "hash.h"
|
10
|
-
#include "encode.h"
|
11
12
|
#include "trace.h"
|
12
13
|
|
13
|
-
static void
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
(int)pi->options.create_id_len == klen &&
|
25
|
-
0 == strncmp(pi->options.create_id, key, klen)) {
|
26
|
-
|
27
|
-
parent->classname = oj_strndup(str, len);
|
28
|
-
parent->clen = len;
|
14
|
+
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
15
|
+
const char * key = kval->key;
|
16
|
+
int klen = kval->klen;
|
17
|
+
Val parent = stack_peek(&pi->stack);
|
18
|
+
volatile VALUE rkey = kval->key_val;
|
19
|
+
|
20
|
+
if (Qundef == rkey && 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;
|
29
25
|
} else {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
26
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
27
|
+
|
28
|
+
if (Qundef == rkey) {
|
29
|
+
rkey = rb_str_new(key, klen);
|
30
|
+
rstr = oj_encode(rstr);
|
31
|
+
rkey = oj_encode(rkey);
|
32
|
+
if (Yes == pi->options.sym_key) {
|
33
|
+
rkey = rb_str_intern(rkey);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
37
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
38
|
+
|
39
|
+
if (Qnil != clas) {
|
40
|
+
rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
41
|
+
}
|
42
|
+
}
|
43
|
+
if (rb_cHash != rb_obj_class(parent->val)) {
|
44
|
+
// The rb_hash_set would still work but the unit tests for the
|
45
|
+
// json gem require the less efficient []= method be called to set
|
46
|
+
// values. Even using the store method to set the values will fail
|
47
|
+
// the unit tests.
|
48
|
+
rb_funcall(parent->val, rb_intern("[]="), 2, rkey, rstr);
|
49
|
+
} else {
|
50
|
+
rb_hash_aset(parent->val, rkey, rstr);
|
51
|
+
}
|
52
|
+
if (Yes == pi->options.trace) {
|
53
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
|
54
|
+
}
|
59
55
|
}
|
60
56
|
}
|
61
57
|
|
62
|
-
static VALUE
|
63
|
-
|
64
|
-
volatile VALUE h;
|
58
|
+
static VALUE start_hash(ParseInfo pi) {
|
59
|
+
volatile VALUE h;
|
65
60
|
|
66
61
|
if (Qnil != pi->options.hash_class) {
|
67
|
-
|
62
|
+
h = rb_class_new_instance(0, NULL, pi->options.hash_class);
|
68
63
|
} else {
|
69
|
-
|
64
|
+
h = rb_hash_new();
|
70
65
|
}
|
71
66
|
if (Yes == pi->options.trace) {
|
72
|
-
|
67
|
+
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
73
68
|
}
|
74
69
|
return h;
|
75
70
|
}
|
76
71
|
|
77
|
-
static void
|
78
|
-
|
79
|
-
Val parent = stack_peek(&pi->stack);
|
72
|
+
static void end_hash(struct _parseInfo *pi) {
|
73
|
+
Val parent = stack_peek(&pi->stack);
|
80
74
|
|
81
75
|
if (0 != parent->classname) {
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
76
|
+
volatile VALUE clas;
|
77
|
+
|
78
|
+
clas = oj_name2class(pi, parent->classname, parent->clen, 0, rb_eArgError);
|
79
|
+
if (Qundef != clas) { // else an error
|
80
|
+
ID creatable = rb_intern("json_creatable?");
|
81
|
+
|
82
|
+
if (!rb_respond_to(clas, creatable) || Qtrue == rb_funcall(clas, creatable, 0)) {
|
83
|
+
parent->val = rb_funcall(clas, oj_json_create_id, 1, parent->val);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
if (0 != parent->classname) {
|
87
|
+
xfree((char *)parent->classname);
|
88
|
+
parent->classname = 0;
|
89
|
+
}
|
96
90
|
}
|
97
91
|
if (Yes == pi->options.trace) {
|
98
|
-
|
92
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
99
93
|
}
|
100
94
|
}
|
101
95
|
|
102
|
-
static VALUE
|
103
|
-
|
104
|
-
volatile VALUE rkey = parent->key_val;
|
96
|
+
static VALUE calc_hash_key(ParseInfo pi, Val parent) {
|
97
|
+
volatile VALUE rkey = parent->key_val;
|
105
98
|
|
106
99
|
if (Qundef == rkey) {
|
107
|
-
|
100
|
+
rkey = rb_str_new(parent->key, parent->klen);
|
108
101
|
}
|
109
102
|
rkey = oj_encode(rkey);
|
110
103
|
if (Yes == pi->options.sym_key) {
|
111
|
-
|
104
|
+
rkey = rb_str_intern(rkey);
|
112
105
|
}
|
113
106
|
return rkey;
|
114
107
|
}
|
115
108
|
|
116
|
-
static void
|
117
|
-
|
118
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
109
|
+
static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
110
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
119
111
|
|
120
112
|
rstr = oj_encode(rstr);
|
121
113
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
122
|
-
|
114
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
123
115
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
116
|
+
if (Qnil != clas) {
|
117
|
+
pi->stack.head->val = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
118
|
+
return;
|
119
|
+
}
|
128
120
|
}
|
129
121
|
pi->stack.head->val = rstr;
|
130
122
|
if (Yes == pi->options.trace) {
|
131
|
-
|
123
|
+
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
|
132
124
|
}
|
133
125
|
}
|
134
126
|
|
135
|
-
static void
|
136
|
-
add_num(ParseInfo pi, NumInfo ni) {
|
127
|
+
static void add_num(ParseInfo pi, NumInfo ni) {
|
137
128
|
pi->stack.head->val = oj_num_as_value(ni);
|
138
129
|
if (Yes == pi->options.trace) {
|
139
|
-
|
130
|
+
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
|
140
131
|
}
|
141
132
|
}
|
142
133
|
|
143
|
-
static void
|
144
|
-
|
145
|
-
volatile VALUE rval = oj_num_as_value(ni);
|
134
|
+
static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
|
135
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
146
136
|
|
147
137
|
if (!oj_use_hash_alt && rb_cHash != rb_obj_class(parent->val)) {
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
138
|
+
// The rb_hash_set would still work but the unit tests for the
|
139
|
+
// json gem require the less efficient []= method be called to set
|
140
|
+
// values. Even using the store method to set the values will fail
|
141
|
+
// the unit tests.
|
142
|
+
rb_funcall(stack_peek(&pi->stack)->val,
|
143
|
+
rb_intern("[]="),
|
144
|
+
2,
|
145
|
+
calc_hash_key(pi, parent),
|
146
|
+
rval);
|
153
147
|
} else {
|
154
|
-
|
148
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
|
155
149
|
}
|
156
150
|
if (Yes == pi->options.trace) {
|
157
|
-
|
151
|
+
oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
|
158
152
|
}
|
159
153
|
}
|
160
154
|
|
161
|
-
static void
|
162
|
-
hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
155
|
+
static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
163
156
|
if (rb_cHash != rb_obj_class(parent->val)) {
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
157
|
+
// The rb_hash_set would still work but the unit tests for the
|
158
|
+
// json gem require the less efficient []= method be called to set
|
159
|
+
// values. Even using the store method to set the values will fail
|
160
|
+
// the unit tests.
|
161
|
+
rb_funcall(stack_peek(&pi->stack)->val,
|
162
|
+
rb_intern("[]="),
|
163
|
+
2,
|
164
|
+
calc_hash_key(pi, parent),
|
165
|
+
value);
|
169
166
|
} else {
|
170
|
-
|
167
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
|
171
168
|
}
|
172
169
|
if (Yes == pi->options.trace) {
|
173
|
-
|
170
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
174
171
|
}
|
175
172
|
}
|
176
173
|
|
177
|
-
static VALUE
|
178
|
-
start_array(ParseInfo pi) {
|
174
|
+
static VALUE start_array(ParseInfo pi) {
|
179
175
|
if (Qnil != pi->options.array_class) {
|
180
|
-
|
176
|
+
return rb_class_new_instance(0, NULL, pi->options.array_class);
|
181
177
|
}
|
182
178
|
if (Yes == pi->options.trace) {
|
183
|
-
|
179
|
+
oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
|
184
180
|
}
|
185
181
|
return rb_ary_new();
|
186
182
|
}
|
187
183
|
|
188
|
-
static void
|
189
|
-
|
190
|
-
|
191
|
-
volatile VALUE rval = oj_num_as_value(ni);
|
184
|
+
static void array_append_num(ParseInfo pi, NumInfo ni) {
|
185
|
+
Val parent = stack_peek(&pi->stack);
|
186
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
192
187
|
|
193
188
|
if (!oj_use_array_alt && rb_cArray != rb_obj_class(parent->val)) {
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
189
|
+
// The rb_ary_push would still work but the unit tests for the json
|
190
|
+
// gem require the less efficient << method be called to push the
|
191
|
+
// values.
|
192
|
+
rb_funcall(parent->val, rb_intern("<<"), 1, rval);
|
198
193
|
} else {
|
199
|
-
|
194
|
+
rb_ary_push(parent->val, rval);
|
200
195
|
}
|
201
196
|
if (Yes == pi->options.trace) {
|
202
|
-
|
197
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
203
198
|
}
|
204
199
|
}
|
205
200
|
|
206
|
-
static void
|
207
|
-
|
208
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
201
|
+
static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
202
|
+
volatile VALUE rstr = rb_str_new(str, len);
|
209
203
|
|
210
204
|
rstr = oj_encode(rstr);
|
211
205
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
212
|
-
|
206
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
213
207
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
208
|
+
if (Qnil != clas) {
|
209
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
|
210
|
+
return;
|
211
|
+
}
|
218
212
|
}
|
219
213
|
rb_ary_push(stack_peek(&pi->stack)->val, rstr);
|
220
214
|
if (Yes == pi->options.trace) {
|
221
|
-
|
215
|
+
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
|
222
216
|
}
|
223
217
|
}
|
224
218
|
|
225
|
-
void
|
226
|
-
oj_set_compat_callbacks(ParseInfo pi) {
|
219
|
+
void oj_set_compat_callbacks(ParseInfo pi) {
|
227
220
|
oj_set_strict_callbacks(pi);
|
228
|
-
pi->start_hash
|
229
|
-
pi->end_hash
|
230
|
-
pi->hash_set_cstr
|
231
|
-
pi->hash_set_num
|
232
|
-
pi->hash_set_value
|
233
|
-
pi->add_num
|
234
|
-
pi->add_cstr
|
221
|
+
pi->start_hash = start_hash;
|
222
|
+
pi->end_hash = end_hash;
|
223
|
+
pi->hash_set_cstr = hash_set_cstr;
|
224
|
+
pi->hash_set_num = hash_set_num;
|
225
|
+
pi->hash_set_value = hash_set_value;
|
226
|
+
pi->add_num = add_num;
|
227
|
+
pi->add_cstr = add_cstr;
|
235
228
|
pi->array_append_cstr = array_append_cstr;
|
236
|
-
pi->start_array
|
237
|
-
pi->array_append_num
|
229
|
+
pi->start_array = start_array;
|
230
|
+
pi->array_append_num = array_append_num;
|
238
231
|
}
|
239
232
|
|
240
233
|
VALUE
|
241
234
|
oj_compat_parse(int argc, VALUE *argv, VALUE self) {
|
242
|
-
struct _parseInfo
|
235
|
+
struct _parseInfo pi;
|
243
236
|
|
244
237
|
parse_info_init(&pi);
|
245
|
-
pi.options
|
246
|
-
pi.handler
|
247
|
-
pi.err_class
|
248
|
-
pi.max_depth
|
249
|
-
pi.options.allow_nan
|
250
|
-
pi.options.nilnil
|
238
|
+
pi.options = oj_default_options;
|
239
|
+
pi.handler = Qnil;
|
240
|
+
pi.err_class = Qnil;
|
241
|
+
pi.max_depth = 0;
|
242
|
+
pi.options.allow_nan = Yes;
|
243
|
+
pi.options.nilnil = Yes;
|
251
244
|
pi.options.empty_string = No;
|
252
245
|
oj_set_compat_callbacks(&pi);
|
253
246
|
|
254
247
|
if (T_STRING == rb_type(*argv)) {
|
255
|
-
|
248
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, false);
|
256
249
|
} else {
|
257
|
-
|
250
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
258
251
|
}
|
259
252
|
}
|
260
253
|
|
261
254
|
VALUE
|
262
255
|
oj_compat_load(int argc, VALUE *argv, VALUE self) {
|
263
|
-
struct _parseInfo
|
256
|
+
struct _parseInfo pi;
|
264
257
|
|
265
258
|
parse_info_init(&pi);
|
266
|
-
pi.options
|
267
|
-
pi.handler
|
268
|
-
pi.err_class
|
269
|
-
pi.max_depth
|
270
|
-
pi.options.allow_nan
|
271
|
-
pi.options.nilnil
|
259
|
+
pi.options = oj_default_options;
|
260
|
+
pi.handler = Qnil;
|
261
|
+
pi.err_class = Qnil;
|
262
|
+
pi.max_depth = 0;
|
263
|
+
pi.options.allow_nan = Yes;
|
264
|
+
pi.options.nilnil = Yes;
|
272
265
|
pi.options.empty_string = Yes;
|
273
266
|
oj_set_compat_callbacks(&pi);
|
274
267
|
|
275
268
|
if (T_STRING == rb_type(*argv)) {
|
276
|
-
|
269
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, false);
|
277
270
|
} else {
|
278
|
-
|
271
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
279
272
|
}
|
280
273
|
}
|
281
274
|
|
282
275
|
VALUE
|
283
276
|
oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
284
|
-
struct _parseInfo
|
277
|
+
struct _parseInfo pi;
|
285
278
|
|
286
279
|
parse_info_init(&pi);
|
287
|
-
pi.options
|
288
|
-
pi.handler
|
289
|
-
pi.err_class
|
290
|
-
pi.max_depth
|
280
|
+
pi.options = oj_default_options;
|
281
|
+
pi.handler = Qnil;
|
282
|
+
pi.err_class = Qnil;
|
283
|
+
pi.max_depth = 0;
|
291
284
|
pi.options.allow_nan = Yes;
|
292
|
-
pi.options.nilnil
|
285
|
+
pi.options.nilnil = Yes;
|
293
286
|
oj_set_compat_callbacks(&pi);
|
294
287
|
|
295
288
|
return oj_pi_parse(argc, argv, &pi, json, len, false);
|