oj 3.10.6 → 3.12.1
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 +36 -68
- data/ext/oj/cache8.c +59 -62
- data/ext/oj/cache8.h +9 -36
- data/ext/oj/circarray.c +36 -42
- data/ext/oj/circarray.h +12 -13
- data/ext/oj/code.c +172 -179
- data/ext/oj/code.h +22 -24
- data/ext/oj/compat.c +176 -181
- data/ext/oj/custom.c +800 -864
- data/ext/oj/dump.c +774 -776
- data/ext/oj/dump.h +50 -55
- data/ext/oj/dump_compat.c +2 -4
- data/ext/oj/dump_leaf.c +118 -162
- data/ext/oj/dump_object.c +610 -632
- data/ext/oj/dump_strict.c +319 -331
- data/ext/oj/encode.h +4 -33
- data/ext/oj/err.c +40 -29
- data/ext/oj/err.h +25 -44
- data/ext/oj/extconf.rb +2 -1
- data/ext/oj/fast.c +1054 -1081
- data/ext/oj/hash.c +102 -97
- data/ext/oj/hash.h +10 -35
- data/ext/oj/hash_test.c +451 -472
- data/ext/oj/mimic_json.c +415 -402
- data/ext/oj/object.c +588 -532
- data/ext/oj/odd.c +124 -132
- data/ext/oj/odd.h +28 -29
- data/ext/oj/oj.c +1186 -906
- data/ext/oj/oj.h +289 -298
- data/ext/oj/parse.c +946 -870
- data/ext/oj/parse.h +81 -79
- data/ext/oj/rails.c +837 -842
- data/ext/oj/rails.h +8 -11
- data/ext/oj/reader.c +139 -147
- data/ext/oj/reader.h +68 -84
- data/ext/oj/resolve.c +44 -47
- data/ext/oj/resolve.h +4 -6
- data/ext/oj/rxclass.c +69 -73
- data/ext/oj/rxclass.h +13 -14
- data/ext/oj/saj.c +453 -484
- data/ext/oj/scp.c +88 -113
- data/ext/oj/sparse.c +783 -714
- data/ext/oj/stream_writer.c +123 -157
- data/ext/oj/strict.c +133 -106
- data/ext/oj/string_writer.c +199 -247
- data/ext/oj/trace.c +34 -41
- data/ext/oj/trace.h +15 -15
- data/ext/oj/util.c +104 -104
- data/ext/oj/util.h +4 -3
- data/ext/oj/val_stack.c +48 -76
- data/ext/oj/val_stack.h +80 -115
- data/ext/oj/wab.c +321 -325
- data/lib/oj.rb +0 -8
- data/lib/oj/bag.rb +1 -0
- data/lib/oj/easy_hash.rb +5 -4
- data/lib/oj/mimic.rb +47 -13
- data/lib/oj/version.rb +1 -1
- data/pages/Modes.md +1 -0
- data/pages/Options.md +23 -11
- data/test/activerecord/result_test.rb +7 -2
- data/test/foo.rb +8 -40
- data/test/helper.rb +10 -0
- data/test/json_gem/json_common_interface_test.rb +8 -3
- data/test/json_gem/json_generator_test.rb +15 -3
- data/test/json_gem/test_helper.rb +8 -0
- data/test/perf.rb +1 -1
- data/test/perf_scp.rb +11 -10
- data/test/perf_strict.rb +17 -23
- data/test/prec.rb +23 -0
- data/test/sample_json.rb +1 -1
- data/test/test_compat.rb +16 -3
- data/test/test_custom.rb +11 -0
- data/test/test_fast.rb +32 -2
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +10 -0
- data/test/test_rails.rb +9 -0
- data/test/test_scp.rb +1 -1
- data/test/test_various.rb +4 -2
- metadata +89 -85
data/ext/oj/stream_writer.c
CHANGED
@@ -1,22 +1,18 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
5
3
|
|
6
4
|
#include <errno.h>
|
7
|
-
|
8
5
|
#include <ruby.h>
|
9
6
|
|
10
7
|
#include "encode.h"
|
11
8
|
|
12
|
-
extern VALUE
|
9
|
+
extern VALUE Oj;
|
13
10
|
|
14
|
-
static void
|
15
|
-
|
16
|
-
StreamWriter sw;
|
11
|
+
static void stream_writer_free(void *ptr) {
|
12
|
+
StreamWriter sw;
|
17
13
|
|
18
14
|
if (0 == ptr) {
|
19
|
-
|
15
|
+
return;
|
20
16
|
}
|
21
17
|
sw = (StreamWriter)ptr;
|
22
18
|
xfree(sw->sw.out.buf);
|
@@ -24,41 +20,38 @@ stream_writer_free(void *ptr) {
|
|
24
20
|
xfree(ptr);
|
25
21
|
}
|
26
22
|
|
27
|
-
static void
|
28
|
-
|
29
|
-
sw->sw.out.cur = sw->sw.out.buf;
|
23
|
+
static void stream_writer_reset_buf(StreamWriter sw) {
|
24
|
+
sw->sw.out.cur = sw->sw.out.buf;
|
30
25
|
*sw->sw.out.cur = '\0';
|
31
26
|
}
|
32
27
|
|
33
|
-
static void
|
34
|
-
|
35
|
-
ssize_t size = sw->sw.out.cur - sw->sw.out.buf;
|
28
|
+
static void stream_writer_write(StreamWriter sw) {
|
29
|
+
ssize_t size = sw->sw.out.cur - sw->sw.out.buf;
|
36
30
|
|
37
31
|
switch (sw->type) {
|
38
32
|
case STRING_IO:
|
39
33
|
case STREAM_IO: {
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
34
|
+
volatile VALUE rs = rb_str_new(sw->sw.out.buf, size);
|
35
|
+
|
36
|
+
// Oddly enough, when pushing ASCII characters with UTF-8 encoding or
|
37
|
+
// even ASCII-8BIT does not change the output encoding. Pushing any
|
38
|
+
// non-ASCII no matter what the encoding changes the output encoding
|
39
|
+
// to ASCII-8BIT if it the string is not forced to UTF-8 here.
|
40
|
+
rs = oj_encode(rs);
|
41
|
+
rb_funcall(sw->stream, oj_write_id, 1, rs);
|
42
|
+
break;
|
49
43
|
}
|
50
44
|
case FILE_IO:
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
default:
|
56
|
-
rb_raise(rb_eArgError, "expected an IO Object.");
|
45
|
+
if (size != write(sw->fd, sw->sw.out.buf, size)) {
|
46
|
+
rb_raise(rb_eIOError, "Write failed. [_%d_:%s]\n", errno, strerror(errno));
|
47
|
+
}
|
48
|
+
break;
|
49
|
+
default: rb_raise(rb_eArgError, "expected an IO Object.");
|
57
50
|
}
|
58
51
|
stream_writer_reset_buf(sw);
|
59
52
|
}
|
60
53
|
|
61
|
-
static VALUE
|
54
|
+
static VALUE buffer_size_sym = Qundef;
|
62
55
|
|
63
56
|
/* Document-method: new
|
64
57
|
* call-seq: new(io, options)
|
@@ -76,62 +69,60 @@ static VALUE buffer_size_sym = Qundef;
|
|
76
69
|
* - *io* [_IO_] stream to write to
|
77
70
|
* - *options* [_Hash_] formating options
|
78
71
|
*/
|
79
|
-
static VALUE
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
VALUE
|
84
|
-
|
85
|
-
StreamWriter sw;
|
72
|
+
static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
|
73
|
+
StreamWriterType type = STREAM_IO;
|
74
|
+
int fd = 0;
|
75
|
+
VALUE stream = argv[0];
|
76
|
+
VALUE clas = rb_obj_class(stream);
|
77
|
+
StreamWriter sw;
|
86
78
|
#if !IS_WINDOWS
|
87
|
-
VALUE
|
79
|
+
VALUE s;
|
88
80
|
#endif
|
89
|
-
|
81
|
+
|
90
82
|
if (oj_stringio_class == clas) {
|
91
|
-
|
83
|
+
type = STRING_IO;
|
92
84
|
#if !IS_WINDOWS
|
93
85
|
} else if (rb_respond_to(stream, oj_fileno_id) &&
|
94
|
-
|
95
|
-
|
96
|
-
type = FILE_IO;
|
86
|
+
Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) && 0 != (fd = FIX2INT(s))) {
|
87
|
+
type = FILE_IO;
|
97
88
|
#endif
|
98
89
|
} else if (rb_respond_to(stream, oj_write_id)) {
|
99
|
-
|
90
|
+
type = STREAM_IO;
|
100
91
|
} else {
|
101
|
-
|
92
|
+
rb_raise(rb_eArgError, "expected an IO Object.");
|
102
93
|
}
|
103
94
|
sw = ALLOC(struct _streamWriter);
|
104
95
|
if (2 == argc && T_HASH == rb_type(argv[1])) {
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
96
|
+
volatile VALUE v;
|
97
|
+
int buf_size = 0;
|
98
|
+
|
99
|
+
if (Qundef == buffer_size_sym) {
|
100
|
+
buffer_size_sym = ID2SYM(rb_intern("buffer_size"));
|
101
|
+
rb_gc_register_address(&buffer_size_sym);
|
102
|
+
}
|
103
|
+
if (Qnil != (v = rb_hash_lookup(argv[1], buffer_size_sym))) {
|
113
104
|
#ifdef RUBY_INTEGER_UNIFICATION
|
114
|
-
|
115
|
-
|
116
|
-
|
105
|
+
if (rb_cInteger != rb_obj_class(v)) {
|
106
|
+
rb_raise(rb_eArgError, ":buffer size must be a Integer.");
|
107
|
+
}
|
117
108
|
#else
|
118
|
-
|
119
|
-
|
120
|
-
|
109
|
+
if (T_FIXNUM != rb_type(v)) {
|
110
|
+
rb_raise(rb_eArgError, ":buffer size must be a Integer.");
|
111
|
+
}
|
121
112
|
#endif
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
113
|
+
buf_size = FIX2INT(v);
|
114
|
+
}
|
115
|
+
oj_str_writer_init(&sw->sw, buf_size);
|
116
|
+
oj_parse_options(argv[1], &sw->sw.opts);
|
117
|
+
sw->flush_limit = buf_size;
|
127
118
|
} else {
|
128
|
-
|
129
|
-
|
119
|
+
oj_str_writer_init(&sw->sw, 4096);
|
120
|
+
sw->flush_limit = 0;
|
130
121
|
}
|
131
122
|
sw->sw.out.indent = sw->sw.opts.indent;
|
132
|
-
sw->stream
|
133
|
-
sw->type
|
134
|
-
sw->fd
|
123
|
+
sw->stream = stream;
|
124
|
+
sw->type = type;
|
125
|
+
sw->fd = fd;
|
135
126
|
|
136
127
|
return Data_Wrap_Struct(oj_stream_writer_class, 0, stream_writer_free, sw);
|
137
128
|
}
|
@@ -145,14 +136,13 @@ stream_writer_new(int argc, VALUE *argv, VALUE self) {
|
|
145
136
|
*
|
146
137
|
* - *key* [_String_] the key pending for the next push
|
147
138
|
*/
|
148
|
-
static VALUE
|
149
|
-
|
150
|
-
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
139
|
+
static VALUE stream_writer_push_key(VALUE self, VALUE key) {
|
140
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
151
141
|
|
152
142
|
rb_check_type(key, T_STRING);
|
153
143
|
oj_str_writer_push_key(&sw->sw, StringValuePtr(key));
|
154
144
|
if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
|
155
|
-
|
145
|
+
stream_writer_write(sw);
|
156
146
|
}
|
157
147
|
return Qnil;
|
158
148
|
}
|
@@ -165,28 +155,23 @@ stream_writer_push_key(VALUE self, VALUE key) {
|
|
165
155
|
*
|
166
156
|
* - *key* [_String_] the key if adding to an object in the JSON document
|
167
157
|
*/
|
168
|
-
static VALUE
|
169
|
-
|
170
|
-
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
158
|
+
static VALUE stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
|
159
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
171
160
|
|
172
161
|
switch (argc) {
|
173
|
-
case 0:
|
174
|
-
oj_str_writer_push_object(&sw->sw, 0);
|
175
|
-
break;
|
162
|
+
case 0: oj_str_writer_push_object(&sw->sw, 0); break;
|
176
163
|
case 1:
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
default:
|
185
|
-
rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
|
186
|
-
break;
|
164
|
+
if (Qnil == argv[0]) {
|
165
|
+
oj_str_writer_push_object(&sw->sw, 0);
|
166
|
+
} else {
|
167
|
+
rb_check_type(argv[0], T_STRING);
|
168
|
+
oj_str_writer_push_object(&sw->sw, StringValuePtr(argv[0]));
|
169
|
+
}
|
170
|
+
break;
|
171
|
+
default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); break;
|
187
172
|
}
|
188
173
|
if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
|
189
|
-
|
174
|
+
stream_writer_write(sw);
|
190
175
|
}
|
191
176
|
return Qnil;
|
192
177
|
}
|
@@ -199,28 +184,23 @@ stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
|
|
199
184
|
*
|
200
185
|
* - *key* [_String_] the key if adding to an object in the JSON document
|
201
186
|
*/
|
202
|
-
static VALUE
|
203
|
-
|
204
|
-
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
187
|
+
static VALUE stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
|
188
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
205
189
|
|
206
190
|
switch (argc) {
|
207
|
-
case 0:
|
208
|
-
oj_str_writer_push_array(&sw->sw, 0);
|
209
|
-
break;
|
191
|
+
case 0: oj_str_writer_push_array(&sw->sw, 0); break;
|
210
192
|
case 1:
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
default:
|
219
|
-
rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
|
220
|
-
break;
|
193
|
+
if (Qnil == argv[0]) {
|
194
|
+
oj_str_writer_push_array(&sw->sw, 0);
|
195
|
+
} else {
|
196
|
+
rb_check_type(argv[0], T_STRING);
|
197
|
+
oj_str_writer_push_array(&sw->sw, StringValuePtr(argv[0]));
|
198
|
+
}
|
199
|
+
break;
|
200
|
+
default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); break;
|
221
201
|
}
|
222
202
|
if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
|
223
|
-
|
203
|
+
stream_writer_write(sw);
|
224
204
|
}
|
225
205
|
return Qnil;
|
226
206
|
}
|
@@ -232,28 +212,23 @@ stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
|
|
232
212
|
* - *value* [_Object_] value to add to the JSON document
|
233
213
|
* - *key* [_String_] the key if adding to an object in the JSON document
|
234
214
|
*/
|
235
|
-
static VALUE
|
236
|
-
|
237
|
-
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
215
|
+
static VALUE stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
|
216
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
238
217
|
|
239
218
|
switch (argc) {
|
240
|
-
case 1:
|
241
|
-
oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
|
242
|
-
break;
|
219
|
+
case 1: oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); break;
|
243
220
|
case 2:
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
default:
|
252
|
-
rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'.");
|
253
|
-
break;
|
221
|
+
if (Qnil == argv[1]) {
|
222
|
+
oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
|
223
|
+
} else {
|
224
|
+
rb_check_type(argv[1], T_STRING);
|
225
|
+
oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
|
226
|
+
}
|
227
|
+
break;
|
228
|
+
default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); break;
|
254
229
|
}
|
255
230
|
if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
|
256
|
-
|
231
|
+
stream_writer_write(sw);
|
257
232
|
}
|
258
233
|
return Qnil;
|
259
234
|
}
|
@@ -267,29 +242,26 @@ stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
|
|
267
242
|
* - *value* [_Object_] value to add to the JSON document
|
268
243
|
* - *key* [_String_] the key if adding to an object in the JSON document
|
269
244
|
*/
|
270
|
-
static VALUE
|
271
|
-
|
272
|
-
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
245
|
+
static VALUE stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
|
246
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
273
247
|
|
274
248
|
rb_check_type(argv[0], T_STRING);
|
275
249
|
switch (argc) {
|
276
|
-
case 1:
|
277
|
-
oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
|
278
|
-
break;
|
250
|
+
case 1: oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); break;
|
279
251
|
case 2:
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
252
|
+
if (Qnil == argv[1]) {
|
253
|
+
oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
|
254
|
+
} else {
|
255
|
+
rb_check_type(argv[1], T_STRING);
|
256
|
+
oj_str_writer_push_json((StrWriter)DATA_PTR(self),
|
257
|
+
StringValuePtr(*argv),
|
258
|
+
StringValuePtr(argv[1]));
|
259
|
+
}
|
260
|
+
break;
|
261
|
+
default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); break;
|
290
262
|
}
|
291
263
|
if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
|
292
|
-
|
264
|
+
stream_writer_write(sw);
|
293
265
|
}
|
294
266
|
return Qnil;
|
295
267
|
}
|
@@ -300,13 +272,12 @@ stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
|
|
300
272
|
* Pops up a level in the JSON document closing the array or object that is
|
301
273
|
* currently open.
|
302
274
|
*/
|
303
|
-
static VALUE
|
304
|
-
|
305
|
-
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
275
|
+
static VALUE stream_writer_pop(VALUE self) {
|
276
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
306
277
|
|
307
278
|
oj_str_writer_pop(&sw->sw);
|
308
279
|
if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
|
309
|
-
|
280
|
+
stream_writer_write(sw);
|
310
281
|
}
|
311
282
|
return Qnil;
|
312
283
|
}
|
@@ -317,9 +288,8 @@ stream_writer_pop(VALUE self) {
|
|
317
288
|
* Pops all level in the JSON document closing all the array or object that is
|
318
289
|
* currently open.
|
319
290
|
*/
|
320
|
-
static VALUE
|
321
|
-
|
322
|
-
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
291
|
+
static VALUE stream_writer_pop_all(VALUE self) {
|
292
|
+
StreamWriter sw = (StreamWriter)DATA_PTR(self);
|
323
293
|
|
324
294
|
oj_str_writer_pop_all(&sw->sw);
|
325
295
|
stream_writer_write(sw);
|
@@ -332,22 +302,20 @@ stream_writer_pop_all(VALUE self) {
|
|
332
302
|
*
|
333
303
|
* Flush any remaining characters in the buffer.
|
334
304
|
*/
|
335
|
-
static VALUE
|
336
|
-
stream_writer_flush(VALUE self) {
|
305
|
+
static VALUE stream_writer_flush(VALUE self) {
|
337
306
|
stream_writer_write((StreamWriter)DATA_PTR(self));
|
338
307
|
|
339
308
|
return Qnil;
|
340
309
|
}
|
341
310
|
|
342
311
|
/* Document-class: Oj::StreamWriter
|
343
|
-
*
|
312
|
+
*
|
344
313
|
* Supports building a JSON document one element at a time. Build the IO stream
|
345
314
|
* document by pushing values into the document. Pushing an array or an object
|
346
315
|
* will create that element in the JSON document and subsequent pushes will add
|
347
316
|
* the elements to that array or object until a pop() is called.
|
348
317
|
*/
|
349
|
-
void
|
350
|
-
oj_stream_writer_init() {
|
318
|
+
void oj_stream_writer_init() {
|
351
319
|
oj_stream_writer_class = rb_define_class_under(Oj, "StreamWriter", rb_cObject);
|
352
320
|
rb_define_module_function(oj_stream_writer_class, "new", stream_writer_new, -1);
|
353
321
|
rb_define_method(oj_stream_writer_class, "push_key", stream_writer_push_key, 1);
|
@@ -359,5 +327,3 @@ oj_stream_writer_init() {
|
|
359
327
|
rb_define_method(oj_stream_writer_class, "pop_all", stream_writer_pop_all, 0);
|
360
328
|
rb_define_method(oj_stream_writer_class, "flush", stream_writer_flush, 0);
|
361
329
|
}
|
362
|
-
|
363
|
-
|
data/ext/oj/strict.c
CHANGED
@@ -1,210 +1,237 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
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.
|
5
3
|
|
6
|
-
#include <stdlib.h>
|
7
4
|
#include <stdio.h>
|
5
|
+
#include <stdlib.h>
|
8
6
|
#include <string.h>
|
9
7
|
#include <unistd.h>
|
10
8
|
|
11
|
-
#include "
|
9
|
+
#include "encode.h"
|
12
10
|
#include "err.h"
|
11
|
+
#include "hash.h"
|
12
|
+
#include "oj.h"
|
13
13
|
#include "parse.h"
|
14
|
-
#include "encode.h"
|
15
14
|
#include "trace.h"
|
16
15
|
|
17
|
-
|
18
|
-
|
16
|
+
VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str) {
|
17
|
+
volatile VALUE rstr = Qnil;
|
18
|
+
|
19
|
+
if (len <= cache_str) {
|
20
|
+
VALUE *slot;
|
21
|
+
|
22
|
+
if (Qnil == (rstr = oj_str_hash_get(str, len, &slot))) {
|
23
|
+
rstr = rb_str_new(str, len);
|
24
|
+
rstr = oj_encode(rstr);
|
25
|
+
*slot = rstr;
|
26
|
+
rb_gc_register_address(slot);
|
27
|
+
}
|
28
|
+
} else {
|
29
|
+
rstr = rb_str_new(str, len);
|
30
|
+
rstr = oj_encode(rstr);
|
31
|
+
}
|
32
|
+
return rstr;
|
33
|
+
}
|
34
|
+
|
35
|
+
VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
|
36
|
+
volatile VALUE rkey = parent->key_val;
|
37
|
+
|
38
|
+
if (Qundef != rkey) {
|
39
|
+
return rkey;
|
40
|
+
}
|
41
|
+
if (Yes != pi->options.cache_keys) {
|
42
|
+
rkey = rb_str_new(parent->key, parent->klen);
|
43
|
+
rkey = oj_encode(rkey);
|
44
|
+
if (Yes == pi->options.sym_key) {
|
45
|
+
rkey = rb_str_intern(rkey);
|
46
|
+
}
|
47
|
+
return rkey;
|
48
|
+
}
|
49
|
+
VALUE *slot;
|
50
|
+
|
51
|
+
if (Yes == pi->options.sym_key) {
|
52
|
+
if (Qnil == (rkey = oj_sym_hash_get(parent->key, parent->klen, &slot))) {
|
53
|
+
rkey = rb_str_new(parent->key, parent->klen);
|
54
|
+
rkey = oj_encode(rkey);
|
55
|
+
rkey = rb_str_intern(rkey);
|
56
|
+
*slot = rkey;
|
57
|
+
rb_gc_register_address(slot);
|
58
|
+
}
|
59
|
+
} else {
|
60
|
+
if (Qnil == (rkey = oj_str_hash_get(parent->key, parent->klen, &slot))) {
|
61
|
+
rkey = rb_str_new(parent->key, parent->klen);
|
62
|
+
rkey = oj_encode(rkey);
|
63
|
+
*slot = rkey;
|
64
|
+
rb_gc_register_address(slot);
|
65
|
+
}
|
66
|
+
}
|
67
|
+
return rkey;
|
68
|
+
}
|
69
|
+
|
70
|
+
static void hash_end(ParseInfo pi) {
|
19
71
|
if (Yes == pi->options.trace) {
|
20
|
-
|
72
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
21
73
|
}
|
22
74
|
}
|
23
75
|
|
24
|
-
static void
|
25
|
-
array_end(ParseInfo pi) {
|
76
|
+
static void array_end(ParseInfo pi) {
|
26
77
|
if (Yes == pi->options.trace) {
|
27
|
-
|
78
|
+
oj_trace_parse_array_end(pi, __FILE__, __LINE__);
|
28
79
|
}
|
29
80
|
}
|
30
81
|
|
31
|
-
static VALUE
|
32
|
-
noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
82
|
+
static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
33
83
|
return Qundef;
|
34
84
|
}
|
35
85
|
|
36
|
-
static void
|
37
|
-
add_value(ParseInfo pi, VALUE val) {
|
86
|
+
static void add_value(ParseInfo pi, VALUE val) {
|
38
87
|
if (Yes == pi->options.trace) {
|
39
|
-
|
88
|
+
oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
|
40
89
|
}
|
41
90
|
pi->stack.head->val = val;
|
42
91
|
}
|
43
92
|
|
44
|
-
static void
|
45
|
-
|
46
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
93
|
+
static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
94
|
+
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
47
95
|
|
48
|
-
rstr = oj_encode(rstr);
|
49
96
|
pi->stack.head->val = rstr;
|
50
97
|
if (Yes == pi->options.trace) {
|
51
|
-
|
98
|
+
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
|
52
99
|
}
|
53
100
|
}
|
54
101
|
|
55
|
-
static void
|
56
|
-
add_num(ParseInfo pi, NumInfo ni) {
|
102
|
+
static void add_num(ParseInfo pi, NumInfo ni) {
|
57
103
|
if (ni->infinity || ni->nan) {
|
58
|
-
|
104
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
59
105
|
}
|
60
106
|
pi->stack.head->val = oj_num_as_value(ni);
|
61
107
|
if (Yes == pi->options.trace) {
|
62
|
-
|
108
|
+
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
|
63
109
|
}
|
64
110
|
}
|
65
111
|
|
66
|
-
static VALUE
|
67
|
-
start_hash(ParseInfo pi) {
|
112
|
+
static VALUE start_hash(ParseInfo pi) {
|
68
113
|
if (Qnil != pi->options.hash_class) {
|
69
|
-
|
114
|
+
return rb_class_new_instance(0, NULL, pi->options.hash_class);
|
70
115
|
}
|
71
116
|
if (Yes == pi->options.trace) {
|
72
|
-
|
117
|
+
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
73
118
|
}
|
74
119
|
return rb_hash_new();
|
75
120
|
}
|
76
121
|
|
77
|
-
static
|
78
|
-
|
79
|
-
volatile VALUE rkey = parent->key_val;
|
122
|
+
static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
|
123
|
+
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
80
124
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
rkey = oj_encode(rkey);
|
85
|
-
if (Yes == pi->options.sym_key) {
|
86
|
-
rkey = rb_str_intern(rkey);
|
87
|
-
}
|
88
|
-
return rkey;
|
89
|
-
}
|
90
|
-
|
91
|
-
static void
|
92
|
-
hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
|
93
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
94
|
-
|
95
|
-
rstr = oj_encode(rstr);
|
96
|
-
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rstr);
|
125
|
+
rb_hash_aset(stack_peek(&pi->stack)->val,
|
126
|
+
oj_calc_hash_key(pi, parent),
|
127
|
+
rstr);
|
97
128
|
if (Yes == pi->options.trace) {
|
98
|
-
|
129
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
|
99
130
|
}
|
100
131
|
}
|
101
132
|
|
102
|
-
static void
|
103
|
-
|
104
|
-
|
105
|
-
|
133
|
+
static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
|
134
|
+
volatile VALUE v;
|
135
|
+
|
106
136
|
if (ni->infinity || ni->nan) {
|
107
|
-
|
137
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
108
138
|
}
|
109
139
|
v = oj_num_as_value(ni);
|
110
|
-
rb_hash_aset(stack_peek(&pi->stack)->val,
|
140
|
+
rb_hash_aset(stack_peek(&pi->stack)->val,
|
141
|
+
oj_calc_hash_key(pi, parent),
|
142
|
+
v);
|
111
143
|
if (Yes == pi->options.trace) {
|
112
|
-
|
144
|
+
oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v);
|
113
145
|
}
|
114
146
|
}
|
115
147
|
|
116
|
-
static void
|
117
|
-
|
118
|
-
|
148
|
+
static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
149
|
+
rb_hash_aset(stack_peek(&pi->stack)->val,
|
150
|
+
oj_calc_hash_key(pi, parent),
|
151
|
+
value);
|
119
152
|
if (Yes == pi->options.trace) {
|
120
|
-
|
153
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
121
154
|
}
|
122
155
|
}
|
123
156
|
|
124
|
-
static VALUE
|
125
|
-
start_array(ParseInfo pi) {
|
157
|
+
static VALUE start_array(ParseInfo pi) {
|
126
158
|
if (Yes == pi->options.trace) {
|
127
|
-
|
159
|
+
oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
|
128
160
|
}
|
129
161
|
return rb_ary_new();
|
130
162
|
}
|
131
163
|
|
132
|
-
static void
|
133
|
-
|
134
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
164
|
+
static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
165
|
+
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
135
166
|
|
136
|
-
rstr = oj_encode(rstr);
|
137
167
|
rb_ary_push(stack_peek(&pi->stack)->val, rstr);
|
138
168
|
if (Yes == pi->options.trace) {
|
139
|
-
|
169
|
+
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
|
140
170
|
}
|
141
171
|
}
|
142
172
|
|
143
|
-
static void
|
144
|
-
|
145
|
-
|
146
|
-
|
173
|
+
static void array_append_num(ParseInfo pi, NumInfo ni) {
|
174
|
+
volatile VALUE v;
|
175
|
+
|
147
176
|
if (ni->infinity || ni->nan) {
|
148
|
-
|
177
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
149
178
|
}
|
150
179
|
v = oj_num_as_value(ni);
|
151
180
|
rb_ary_push(stack_peek(&pi->stack)->val, v);
|
152
181
|
if (Yes == pi->options.trace) {
|
153
|
-
|
182
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, v);
|
154
183
|
}
|
155
184
|
}
|
156
185
|
|
157
|
-
static void
|
158
|
-
array_append_value(ParseInfo pi, VALUE value) {
|
186
|
+
static void array_append_value(ParseInfo pi, VALUE value) {
|
159
187
|
rb_ary_push(stack_peek(&pi->stack)->val, value);
|
160
188
|
if (Yes == pi->options.trace) {
|
161
|
-
|
162
|
-
}
|
163
|
-
}
|
164
|
-
|
165
|
-
void
|
166
|
-
|
167
|
-
pi->
|
168
|
-
pi->
|
169
|
-
pi->
|
170
|
-
pi->
|
171
|
-
pi->
|
172
|
-
pi->
|
173
|
-
pi->
|
174
|
-
pi->
|
175
|
-
pi->
|
176
|
-
pi->array_append_num = array_append_num;
|
189
|
+
oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
void oj_set_strict_callbacks(ParseInfo pi) {
|
194
|
+
pi->start_hash = start_hash;
|
195
|
+
pi->end_hash = hash_end;
|
196
|
+
pi->hash_key = noop_hash_key;
|
197
|
+
pi->hash_set_cstr = hash_set_cstr;
|
198
|
+
pi->hash_set_num = hash_set_num;
|
199
|
+
pi->hash_set_value = hash_set_value;
|
200
|
+
pi->start_array = start_array;
|
201
|
+
pi->end_array = array_end;
|
202
|
+
pi->array_append_cstr = array_append_cstr;
|
203
|
+
pi->array_append_num = array_append_num;
|
177
204
|
pi->array_append_value = array_append_value;
|
178
|
-
pi->add_cstr
|
179
|
-
pi->add_num
|
180
|
-
pi->add_value
|
181
|
-
pi->expect_value
|
205
|
+
pi->add_cstr = add_cstr;
|
206
|
+
pi->add_num = add_num;
|
207
|
+
pi->add_value = add_value;
|
208
|
+
pi->expect_value = 1;
|
182
209
|
}
|
183
210
|
|
184
211
|
VALUE
|
185
212
|
oj_strict_parse(int argc, VALUE *argv, VALUE self) {
|
186
|
-
struct _parseInfo
|
213
|
+
struct _parseInfo pi;
|
187
214
|
|
188
215
|
parse_info_init(&pi);
|
189
|
-
pi.options
|
190
|
-
pi.handler
|
216
|
+
pi.options = oj_default_options;
|
217
|
+
pi.handler = Qnil;
|
191
218
|
pi.err_class = Qnil;
|
192
219
|
oj_set_strict_callbacks(&pi);
|
193
220
|
|
194
221
|
if (T_STRING == rb_type(*argv)) {
|
195
|
-
|
222
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, true);
|
196
223
|
} else {
|
197
|
-
|
224
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
198
225
|
}
|
199
226
|
}
|
200
227
|
|
201
228
|
VALUE
|
202
229
|
oj_strict_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
203
|
-
struct _parseInfo
|
230
|
+
struct _parseInfo pi;
|
204
231
|
|
205
232
|
parse_info_init(&pi);
|
206
|
-
pi.options
|
207
|
-
pi.handler
|
233
|
+
pi.options = oj_default_options;
|
234
|
+
pi.handler = Qnil;
|
208
235
|
pi.err_class = Qnil;
|
209
236
|
oj_set_strict_callbacks(&pi);
|
210
237
|
|