oj 3.16.3 → 3.17.4
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/CHANGELOG.md +99 -0
- data/README.md +0 -16
- data/ext/oj/compat.c +3 -3
- data/ext/oj/custom.c +17 -11
- data/ext/oj/dump.c +619 -88
- data/ext/oj/dump.h +9 -2
- data/ext/oj/dump_compat.c +16 -9
- data/ext/oj/dump_leaf.c +1 -1
- data/ext/oj/dump_object.c +52 -27
- data/ext/oj/dump_strict.c +20 -14
- data/ext/oj/extconf.rb +11 -9
- data/ext/oj/fast.c +90 -65
- data/ext/oj/intern.c +1 -1
- data/ext/oj/mimic_json.c +14 -8
- data/ext/oj/object.c +18 -12
- data/ext/oj/oj.c +426 -11
- data/ext/oj/oj.h +60 -52
- data/ext/oj/parse.c +252 -48
- data/ext/oj/parse.h +0 -1
- data/ext/oj/parser.c +179 -47
- data/ext/oj/parser.h +4 -2
- data/ext/oj/rails.c +57 -36
- data/ext/oj/reader.c +17 -5
- data/ext/oj/rxclass.c +17 -1
- data/ext/oj/rxclass.h +2 -1
- data/ext/oj/safe.c +230 -0
- data/ext/oj/safe.h +79 -0
- data/ext/oj/saj.c +55 -20
- data/ext/oj/scp.c +3 -6
- data/ext/oj/simd.h +219 -0
- data/ext/oj/sparse.c +15 -3
- data/ext/oj/stream_writer.c +19 -14
- data/ext/oj/strict.c +2 -4
- data/ext/oj/string_writer.c +26 -14
- data/ext/oj/usual.c +37 -35
- data/ext/oj/wab.c +5 -4
- data/lib/oj/mimic.rb +1 -5
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/version.rb +1 -1
- data/pages/Encoding.md +1 -1
- metadata +22 -100
- data/test/_test_active.rb +0 -75
- data/test/_test_active_mimic.rb +0 -95
- data/test/_test_mimic_rails.rb +0 -123
- data/test/activerecord/result_test.rb +0 -31
- data/test/activesupport6/abstract_unit.rb +0 -44
- data/test/activesupport6/decoding_test.rb +0 -133
- data/test/activesupport6/encoding_test.rb +0 -507
- data/test/activesupport6/encoding_test_cases.rb +0 -98
- data/test/activesupport6/test_common.rb +0 -17
- data/test/activesupport6/test_helper.rb +0 -163
- data/test/activesupport6/time_zone_test_helpers.rb +0 -39
- data/test/activesupport7/abstract_unit.rb +0 -49
- data/test/activesupport7/decoding_test.rb +0 -125
- data/test/activesupport7/encoding_test.rb +0 -486
- data/test/activesupport7/encoding_test_cases.rb +0 -104
- data/test/activesupport7/time_zone_test_helpers.rb +0 -47
- data/test/files.rb +0 -29
- data/test/foo.rb +0 -14
- data/test/helper.rb +0 -39
- data/test/isolated/shared.rb +0 -309
- data/test/isolated/test_mimic_after.rb +0 -13
- data/test/isolated/test_mimic_alone.rb +0 -12
- data/test/isolated/test_mimic_as_json.rb +0 -45
- data/test/isolated/test_mimic_before.rb +0 -13
- data/test/isolated/test_mimic_define.rb +0 -28
- data/test/isolated/test_mimic_rails_after.rb +0 -22
- data/test/isolated/test_mimic_rails_before.rb +0 -21
- data/test/isolated/test_mimic_redefine.rb +0 -15
- data/test/json_gem/json_addition_test.rb +0 -216
- data/test/json_gem/json_common_interface_test.rb +0 -155
- data/test/json_gem/json_encoding_test.rb +0 -107
- data/test/json_gem/json_ext_parser_test.rb +0 -21
- data/test/json_gem/json_fixtures_test.rb +0 -36
- data/test/json_gem/json_generator_test.rb +0 -413
- data/test/json_gem/json_generic_object_test.rb +0 -90
- data/test/json_gem/json_parser_test.rb +0 -477
- data/test/json_gem/json_string_matching_test.rb +0 -42
- data/test/json_gem/test_helper.rb +0 -30
- data/test/mem.rb +0 -34
- data/test/perf.rb +0 -102
- data/test/perf_compat.rb +0 -128
- data/test/perf_dump.rb +0 -50
- data/test/perf_fast.rb +0 -162
- data/test/perf_file.rb +0 -62
- data/test/perf_object.rb +0 -134
- data/test/perf_once.rb +0 -59
- data/test/perf_parser.rb +0 -183
- data/test/perf_saj.rb +0 -101
- data/test/perf_scp.rb +0 -140
- data/test/perf_simple.rb +0 -289
- data/test/perf_strict.rb +0 -137
- data/test/perf_wab.rb +0 -129
- data/test/prec.rb +0 -23
- data/test/sample/change.rb +0 -13
- data/test/sample/dir.rb +0 -18
- data/test/sample/doc.rb +0 -35
- data/test/sample/file.rb +0 -47
- data/test/sample/group.rb +0 -15
- data/test/sample/hasprops.rb +0 -15
- data/test/sample/layer.rb +0 -11
- data/test/sample/line.rb +0 -20
- data/test/sample/oval.rb +0 -10
- data/test/sample/rect.rb +0 -9
- data/test/sample/shape.rb +0 -34
- data/test/sample/text.rb +0 -19
- data/test/sample.rb +0 -54
- data/test/sample_json.rb +0 -37
- data/test/test_compat.rb +0 -567
- data/test/test_custom.rb +0 -555
- data/test/test_debian.rb +0 -50
- data/test/test_fast.rb +0 -526
- data/test/test_file.rb +0 -250
- data/test/test_gc.rb +0 -60
- data/test/test_generate.rb +0 -21
- data/test/test_hash.rb +0 -39
- data/test/test_integer_range.rb +0 -72
- data/test/test_null.rb +0 -376
- data/test/test_object.rb +0 -1030
- data/test/test_parser.rb +0 -11
- data/test/test_parser_debug.rb +0 -27
- data/test/test_parser_saj.rb +0 -337
- data/test/test_parser_usual.rb +0 -227
- data/test/test_rails.rb +0 -35
- data/test/test_saj.rb +0 -188
- data/test/test_scp.rb +0 -431
- data/test/test_strict.rb +0 -441
- data/test/test_various.rb +0 -801
- data/test/test_wab.rb +0 -311
- data/test/test_writer.rb +0 -380
- data/test/tests.rb +0 -33
- data/test/tests_mimic.rb +0 -23
- data/test/tests_mimic_addition.rb +0 -16
data/ext/oj/parser.c
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#include <fcntl.h>
|
|
6
6
|
|
|
7
7
|
#include "oj.h"
|
|
8
|
+
#include "simd.h"
|
|
8
9
|
|
|
9
10
|
#define DEBUG 0
|
|
10
11
|
|
|
@@ -75,7 +76,7 @@ enum {
|
|
|
75
76
|
|
|
76
77
|
/*
|
|
77
78
|
0123456789abcdef0123456789abcdef */
|
|
78
|
-
static const char value_map[
|
|
79
|
+
static const char value_map[258] = "\
|
|
79
80
|
X........ab..a..................\
|
|
80
81
|
a.i..........f..ghhhhhhhhh......\
|
|
81
82
|
...........................k.m..\
|
|
@@ -85,7 +86,7 @@ a.i..........f..ghhhhhhhhh......\
|
|
|
85
86
|
................................\
|
|
86
87
|
................................v";
|
|
87
88
|
|
|
88
|
-
static const char null_map[
|
|
89
|
+
static const char null_map[258] = "\
|
|
89
90
|
................................\
|
|
90
91
|
............o...................\
|
|
91
92
|
................................\
|
|
@@ -95,7 +96,7 @@ static const char null_map[257] = "\
|
|
|
95
96
|
................................\
|
|
96
97
|
................................N";
|
|
97
98
|
|
|
98
|
-
static const char true_map[
|
|
99
|
+
static const char true_map[258] = "\
|
|
99
100
|
................................\
|
|
100
101
|
............o...................\
|
|
101
102
|
................................\
|
|
@@ -105,7 +106,7 @@ static const char true_map[257] = "\
|
|
|
105
106
|
................................\
|
|
106
107
|
................................T";
|
|
107
108
|
|
|
108
|
-
static const char false_map[
|
|
109
|
+
static const char false_map[258] = "\
|
|
109
110
|
................................\
|
|
110
111
|
............o...................\
|
|
111
112
|
................................\
|
|
@@ -115,7 +116,7 @@ static const char false_map[257] = "\
|
|
|
115
116
|
................................\
|
|
116
117
|
................................F";
|
|
117
118
|
|
|
118
|
-
static const char comma_map[
|
|
119
|
+
static const char comma_map[258] = "\
|
|
119
120
|
.........ab..a..................\
|
|
120
121
|
a.i..........f..ghhhhhhhhh......\
|
|
121
122
|
...........................k....\
|
|
@@ -125,7 +126,7 @@ a.i..........f..ghhhhhhhhh......\
|
|
|
125
126
|
................................\
|
|
126
127
|
................................,";
|
|
127
128
|
|
|
128
|
-
static const char after_map[
|
|
129
|
+
static const char after_map[258] = "\
|
|
129
130
|
X........ab..a..................\
|
|
130
131
|
a...........o...................\
|
|
131
132
|
.............................m..\
|
|
@@ -135,7 +136,7 @@ a...........o...................\
|
|
|
135
136
|
................................\
|
|
136
137
|
................................a";
|
|
137
138
|
|
|
138
|
-
static const char key1_map[
|
|
139
|
+
static const char key1_map[258] = "\
|
|
139
140
|
.........ab..a..................\
|
|
140
141
|
a.p.............................\
|
|
141
142
|
................................\
|
|
@@ -145,7 +146,7 @@ a.p.............................\
|
|
|
145
146
|
................................\
|
|
146
147
|
................................K";
|
|
147
148
|
|
|
148
|
-
static const char key_map[
|
|
149
|
+
static const char key_map[258] = "\
|
|
149
150
|
.........ab..a..................\
|
|
150
151
|
a.p.............................\
|
|
151
152
|
................................\
|
|
@@ -155,7 +156,7 @@ a.p.............................\
|
|
|
155
156
|
................................\
|
|
156
157
|
................................k";
|
|
157
158
|
|
|
158
|
-
static const char colon_map[
|
|
159
|
+
static const char colon_map[258] = "\
|
|
159
160
|
.........ab..a..................\
|
|
160
161
|
a.........................q.....\
|
|
161
162
|
................................\
|
|
@@ -165,7 +166,7 @@ a.........................q.....\
|
|
|
165
166
|
................................\
|
|
166
167
|
................................:";
|
|
167
168
|
|
|
168
|
-
static const char neg_map[
|
|
169
|
+
static const char neg_map[258] = "\
|
|
169
170
|
................................\
|
|
170
171
|
................O---------......\
|
|
171
172
|
................................\
|
|
@@ -175,7 +176,7 @@ static const char neg_map[257] = "\
|
|
|
175
176
|
................................\
|
|
176
177
|
................................-";
|
|
177
178
|
|
|
178
|
-
static const char zero_map[
|
|
179
|
+
static const char zero_map[258] = "\
|
|
179
180
|
.........rs..r..................\
|
|
180
181
|
r...........u.t.................\
|
|
181
182
|
.............................H..\
|
|
@@ -185,7 +186,7 @@ r...........u.t.................\
|
|
|
185
186
|
................................\
|
|
186
187
|
................................0";
|
|
187
188
|
|
|
188
|
-
static const char digit_map[
|
|
189
|
+
static const char digit_map[258] = "\
|
|
189
190
|
.........rs..r..................\
|
|
190
191
|
r...........u.t.NNNNNNNNNN......\
|
|
191
192
|
.....w.......................H..\
|
|
@@ -195,7 +196,7 @@ r...........u.t.NNNNNNNNNN......\
|
|
|
195
196
|
................................\
|
|
196
197
|
................................d";
|
|
197
198
|
|
|
198
|
-
static const char dot_map[
|
|
199
|
+
static const char dot_map[258] = "\
|
|
199
200
|
................................\
|
|
200
201
|
................vvvvvvvvvv......\
|
|
201
202
|
................................\
|
|
@@ -205,7 +206,7 @@ static const char dot_map[257] = "\
|
|
|
205
206
|
................................\
|
|
206
207
|
.................................";
|
|
207
208
|
|
|
208
|
-
static const char frac_map[
|
|
209
|
+
static const char frac_map[258] = "\
|
|
209
210
|
.........rs..r..................\
|
|
210
211
|
r...........u...vvvvvvvvvv......\
|
|
211
212
|
.....w.......................H..\
|
|
@@ -215,7 +216,7 @@ r...........u...vvvvvvvvvv......\
|
|
|
215
216
|
................................\
|
|
216
217
|
................................f";
|
|
217
218
|
|
|
218
|
-
static const char exp_sign_map[
|
|
219
|
+
static const char exp_sign_map[258] = "\
|
|
219
220
|
................................\
|
|
220
221
|
...........x.x..yyyyyyyyyy......\
|
|
221
222
|
................................\
|
|
@@ -225,7 +226,7 @@ static const char exp_sign_map[257] = "\
|
|
|
225
226
|
................................\
|
|
226
227
|
................................x";
|
|
227
228
|
|
|
228
|
-
static const char exp_zero_map[
|
|
229
|
+
static const char exp_zero_map[258] = "\
|
|
229
230
|
................................\
|
|
230
231
|
................yyyyyyyyyy......\
|
|
231
232
|
................................\
|
|
@@ -235,7 +236,7 @@ static const char exp_zero_map[257] = "\
|
|
|
235
236
|
................................\
|
|
236
237
|
................................z";
|
|
237
238
|
|
|
238
|
-
static const char exp_map[
|
|
239
|
+
static const char exp_map[258] = "\
|
|
239
240
|
.........rs..r..................\
|
|
240
241
|
r...........u...yyyyyyyyyy......\
|
|
241
242
|
.............................H..\
|
|
@@ -245,7 +246,7 @@ r...........u...yyyyyyyyyy......\
|
|
|
245
246
|
................................\
|
|
246
247
|
................................X";
|
|
247
248
|
|
|
248
|
-
static const char big_digit_map[
|
|
249
|
+
static const char big_digit_map[258] = "\
|
|
249
250
|
.........rs..r..................\
|
|
250
251
|
r...........u.D.CCCCCCCCCC......\
|
|
251
252
|
.....J.......................H..\
|
|
@@ -255,7 +256,7 @@ r...........u.D.CCCCCCCCCC......\
|
|
|
255
256
|
................................\
|
|
256
257
|
................................D";
|
|
257
258
|
|
|
258
|
-
static const char big_dot_map[
|
|
259
|
+
static const char big_dot_map[258] = "\
|
|
259
260
|
................................\
|
|
260
261
|
................IIIIIIIIII......\
|
|
261
262
|
................................\
|
|
@@ -265,7 +266,7 @@ static const char big_dot_map[257] = "\
|
|
|
265
266
|
................................\
|
|
266
267
|
................................o";
|
|
267
268
|
|
|
268
|
-
static const char big_frac_map[
|
|
269
|
+
static const char big_frac_map[258] = "\
|
|
269
270
|
.........rs..r..................\
|
|
270
271
|
r...........u...IIIIIIIIII......\
|
|
271
272
|
.....J.......................H..\
|
|
@@ -275,7 +276,7 @@ r...........u...IIIIIIIIII......\
|
|
|
275
276
|
................................\
|
|
276
277
|
................................g";
|
|
277
278
|
|
|
278
|
-
static const char big_exp_sign_map[
|
|
279
|
+
static const char big_exp_sign_map[258] = "\
|
|
279
280
|
................................\
|
|
280
281
|
...........K.K..LLLLLLLLLL......\
|
|
281
282
|
................................\
|
|
@@ -285,7 +286,7 @@ static const char big_exp_sign_map[257] = "\
|
|
|
285
286
|
................................\
|
|
286
287
|
................................B";
|
|
287
288
|
|
|
288
|
-
static const char big_exp_zero_map[
|
|
289
|
+
static const char big_exp_zero_map[258] = "\
|
|
289
290
|
................................\
|
|
290
291
|
................LLLLLLLLLL......\
|
|
291
292
|
................................\
|
|
@@ -295,7 +296,7 @@ static const char big_exp_zero_map[257] = "\
|
|
|
295
296
|
................................\
|
|
296
297
|
................................Z";
|
|
297
298
|
|
|
298
|
-
static const char big_exp_map[
|
|
299
|
+
static const char big_exp_map[258] = "\
|
|
299
300
|
.........rs..r..................\
|
|
300
301
|
r...........u...LLLLLLLLLL......\
|
|
301
302
|
.............................H..\
|
|
@@ -305,7 +306,7 @@ r...........u...LLLLLLLLLL......\
|
|
|
305
306
|
................................\
|
|
306
307
|
................................Y";
|
|
307
308
|
|
|
308
|
-
static const char string_map[
|
|
309
|
+
static const char string_map[258] = "\
|
|
309
310
|
................................\
|
|
310
311
|
RRzRRRRRRRRRRRRRRRRRRRRRRRRRRRRR\
|
|
311
312
|
RRRRRRRRRRRRRRRRRRRRRRRRRRRRARRR\
|
|
@@ -315,7 +316,7 @@ RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR\
|
|
|
315
316
|
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\
|
|
316
317
|
PPPPPPPPPPPPPPPPQQQQQQQQ........s";
|
|
317
318
|
|
|
318
|
-
static const char esc_map[
|
|
319
|
+
static const char esc_map[258] = "\
|
|
319
320
|
................................\
|
|
320
321
|
..B............B................\
|
|
321
322
|
............................B...\
|
|
@@ -325,7 +326,7 @@ static const char esc_map[257] = "\
|
|
|
325
326
|
................................\
|
|
326
327
|
................................~";
|
|
327
328
|
|
|
328
|
-
static const char esc_byte_map[
|
|
329
|
+
static const char esc_byte_map[258] = "\
|
|
329
330
|
................................\
|
|
330
331
|
..\"............/................\
|
|
331
332
|
............................\\...\
|
|
@@ -335,7 +336,7 @@ static const char esc_byte_map[257] = "\
|
|
|
335
336
|
................................\
|
|
336
337
|
................................b";
|
|
337
338
|
|
|
338
|
-
static const char u_map[
|
|
339
|
+
static const char u_map[258] = "\
|
|
339
340
|
................................\
|
|
340
341
|
................EEEEEEEEEE......\
|
|
341
342
|
.EEEEEE.........................\
|
|
@@ -345,7 +346,7 @@ static const char u_map[257] = "\
|
|
|
345
346
|
................................\
|
|
346
347
|
................................u";
|
|
347
348
|
|
|
348
|
-
static const char utf_map[
|
|
349
|
+
static const char utf_map[258] = "\
|
|
349
350
|
................................\
|
|
350
351
|
................................\
|
|
351
352
|
................................\
|
|
@@ -355,7 +356,7 @@ SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS\
|
|
|
355
356
|
................................\
|
|
356
357
|
................................8";
|
|
357
358
|
|
|
358
|
-
static const char space_map[
|
|
359
|
+
static const char space_map[258] = "\
|
|
359
360
|
.........ab..a..................\
|
|
360
361
|
a...............................\
|
|
361
362
|
................................\
|
|
@@ -365,7 +366,7 @@ a...............................\
|
|
|
365
366
|
................................\
|
|
366
367
|
................................S";
|
|
367
368
|
|
|
368
|
-
static const char trail_map[
|
|
369
|
+
static const char trail_map[258] = "\
|
|
369
370
|
.........ab..a..................\
|
|
370
371
|
a...............................\
|
|
371
372
|
................................\
|
|
@@ -375,7 +376,7 @@ a...............................\
|
|
|
375
376
|
................................\
|
|
376
377
|
................................R";
|
|
377
378
|
|
|
378
|
-
static const byte hex_map[
|
|
379
|
+
static const byte hex_map[257] = "\
|
|
379
380
|
................................\
|
|
380
381
|
................\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09......\
|
|
381
382
|
.\x0a\x0b\x0c\x0d\x0e\x0f.........................\
|
|
@@ -594,9 +595,64 @@ static void big_change(ojParser p) {
|
|
|
594
595
|
}
|
|
595
596
|
}
|
|
596
597
|
|
|
597
|
-
|
|
598
|
+
// Scan forward over string content, returning the first byte that is not
|
|
599
|
+
// STR_OK in string_map. This is a pure drop-in for the scalar loop
|
|
600
|
+
//
|
|
601
|
+
// for (; STR_OK == string_map[*b]; b++) {}
|
|
602
|
+
//
|
|
603
|
+
// and must return the exact same stop position. The stop set (bytes whose
|
|
604
|
+
// string_map class is not 'R'/STR_OK) is:
|
|
605
|
+
//
|
|
606
|
+
// * control bytes 0x00..0x1F (class '.', also stops at the NUL terminator)
|
|
607
|
+
// * the quote 0x22 '"' (class 'z')
|
|
608
|
+
// * the backslash 0x5C '\' (class 'A')
|
|
609
|
+
// * every high byte 0x80..0xFF (UTF-8 lead/continuation, classes M/P/Q/'.')
|
|
610
|
+
//
|
|
611
|
+
// Note this differs from parse.c's string_scan_neon, which stops only on
|
|
612
|
+
// \0 \\ " -- parser.c hands multi-byte UTF-8 to its state machine, so the
|
|
613
|
+
// scanner must stop on the high bytes too. The predictor below is derived from
|
|
614
|
+
// string_map, not copied from parse.c.
|
|
615
|
+
//
|
|
616
|
+
// The NEON path only loads a full 16-byte vector when [b, b+16) stays within
|
|
617
|
+
// [., end), so it never reads past the string's allocation; the sub-16-byte
|
|
618
|
+
// tail (and the whole scan on non-NEON builds) uses the scalar loop, which
|
|
619
|
+
// stops naturally at the guaranteed NUL terminator.
|
|
620
|
+
static inline const byte *oj_scan_str_simd(const byte *b, const byte *end) {
|
|
621
|
+
#ifdef HAVE_SIMD_NEON
|
|
622
|
+
if (SIMD_NEON == SIMD_Impl) {
|
|
623
|
+
const uint8x16_t quote = vdupq_n_u8('"');
|
|
624
|
+
const uint8x16_t bslash = vdupq_n_u8('\\');
|
|
625
|
+
const uint8x16_t space = vdupq_n_u8(0x20);
|
|
626
|
+
const uint8x16_t high = vdupq_n_u8(0x80);
|
|
627
|
+
|
|
628
|
+
while (b + sizeof(uint8x16_t) <= end) {
|
|
629
|
+
const uint8x16_t chunk = vld1q_u8((const uint8_t *)b);
|
|
630
|
+
// special lane == 0xFF for any byte that stops the scan.
|
|
631
|
+
const uint8x16_t special = vorrq_u8(vorrq_u8(vceqq_u8(chunk, quote), vceqq_u8(chunk, bslash)),
|
|
632
|
+
vorrq_u8(vcltq_u8(chunk, space), vcgeq_u8(chunk, high)));
|
|
633
|
+
// Reduce to a 64-bit mask with 4 bits per lane (same idiom as
|
|
634
|
+
// parse.c's string_scan_neon) and locate the first set lane.
|
|
635
|
+
const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(special), 4);
|
|
636
|
+
uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0);
|
|
637
|
+
if (0 != mask) {
|
|
638
|
+
mask &= 0x8888888888888888ull;
|
|
639
|
+
return b + (OJ_CTZ64(mask) >> 2);
|
|
640
|
+
}
|
|
641
|
+
b += sizeof(uint8x16_t);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
#else
|
|
645
|
+
(void)end;
|
|
646
|
+
#endif
|
|
647
|
+
for (; STR_OK == string_map[*b]; b++) {
|
|
648
|
+
}
|
|
649
|
+
return b;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
static void parse(ojParser p, const byte *json, size_t len, bool more) {
|
|
598
653
|
const byte *start;
|
|
599
|
-
const byte *b
|
|
654
|
+
const byte *b = json;
|
|
655
|
+
const byte *end = json + len;
|
|
600
656
|
int i;
|
|
601
657
|
|
|
602
658
|
p->line = 1;
|
|
@@ -629,12 +685,14 @@ static void parse(ojParser p, const byte *json) {
|
|
|
629
685
|
b++;
|
|
630
686
|
p->key.tail = p->key.head;
|
|
631
687
|
start = b;
|
|
632
|
-
|
|
633
|
-
}
|
|
688
|
+
b = oj_scan_str_simd(b, end);
|
|
634
689
|
buf_append_string(&p->key, (const char *)start, b - start);
|
|
635
690
|
if ('"' == *b) {
|
|
636
691
|
p->map = colon_map;
|
|
637
692
|
break;
|
|
693
|
+
} else if ('\0' == *b && !more) {
|
|
694
|
+
parse_error(p, "quoted string not terminated");
|
|
695
|
+
break;
|
|
638
696
|
}
|
|
639
697
|
b--;
|
|
640
698
|
p->map = string_map;
|
|
@@ -651,14 +709,16 @@ static void parse(ojParser p, const byte *json) {
|
|
|
651
709
|
b++;
|
|
652
710
|
start = b;
|
|
653
711
|
p->buf.tail = p->buf.head;
|
|
654
|
-
|
|
655
|
-
}
|
|
712
|
+
b = oj_scan_str_simd(b, end);
|
|
656
713
|
buf_append_string(&p->buf, (const char *)start, b - start);
|
|
657
714
|
if ('"' == *b) {
|
|
658
715
|
p->cur = b - json;
|
|
659
716
|
p->funcs[p->stack[p->depth]].add_str(p);
|
|
660
717
|
p->map = (0 == p->depth) ? value_map : after_map;
|
|
661
718
|
break;
|
|
719
|
+
} else if ('\0' == *b && !more) {
|
|
720
|
+
parse_error(p, "quoted string not terminated");
|
|
721
|
+
break;
|
|
662
722
|
}
|
|
663
723
|
b--;
|
|
664
724
|
p->map = string_map;
|
|
@@ -668,6 +728,10 @@ static void parse(ojParser p, const byte *json) {
|
|
|
668
728
|
p->cur = b - json;
|
|
669
729
|
p->funcs[p->stack[p->depth]].open_object(p);
|
|
670
730
|
p->depth++;
|
|
731
|
+
if ((int)sizeof(p->stack) <= p->depth) {
|
|
732
|
+
parse_error(p, "too deeply nested");
|
|
733
|
+
break;
|
|
734
|
+
}
|
|
671
735
|
p->stack[p->depth] = OBJECT_FUN;
|
|
672
736
|
p->map = key1_map;
|
|
673
737
|
break;
|
|
@@ -690,6 +754,10 @@ static void parse(ojParser p, const byte *json) {
|
|
|
690
754
|
p->cur = b - json;
|
|
691
755
|
p->funcs[p->stack[p->depth]].open_array(p);
|
|
692
756
|
p->depth++;
|
|
757
|
+
if ((int)sizeof(p->stack) <= p->depth) {
|
|
758
|
+
parse_error(p, "too deeply nested");
|
|
759
|
+
break;
|
|
760
|
+
}
|
|
693
761
|
p->stack[p->depth] = ARRAY_FUN;
|
|
694
762
|
p->map = value_map;
|
|
695
763
|
break;
|
|
@@ -891,8 +959,7 @@ static void parse(ojParser p, const byte *json) {
|
|
|
891
959
|
break;
|
|
892
960
|
case STR_OK:
|
|
893
961
|
start = b;
|
|
894
|
-
|
|
895
|
-
}
|
|
962
|
+
b = oj_scan_str_simd(b, end);
|
|
896
963
|
if (':' == p->next_map[256]) {
|
|
897
964
|
buf_append_string(&p->key, (const char *)start, b - start);
|
|
898
965
|
} else {
|
|
@@ -1114,9 +1181,6 @@ static void parse(ojParser p, const byte *json) {
|
|
|
1114
1181
|
p->map = trail_map;
|
|
1115
1182
|
}
|
|
1116
1183
|
}
|
|
1117
|
-
if (0 < p->depth) {
|
|
1118
|
-
parse_error(p, "parse error, not closed");
|
|
1119
|
-
}
|
|
1120
1184
|
if (0 == p->depth) {
|
|
1121
1185
|
switch (p->map[256]) {
|
|
1122
1186
|
case '0':
|
|
@@ -1164,7 +1228,7 @@ static void parser_mark(void *ptr) {
|
|
|
1164
1228
|
}
|
|
1165
1229
|
}
|
|
1166
1230
|
|
|
1167
|
-
|
|
1231
|
+
const rb_data_type_t oj_parser_type = {
|
|
1168
1232
|
"Oj/parser",
|
|
1169
1233
|
{
|
|
1170
1234
|
parser_mark,
|
|
@@ -1179,6 +1243,8 @@ extern void oj_set_parser_validator(ojParser p);
|
|
|
1179
1243
|
extern void oj_set_parser_saj(ojParser p);
|
|
1180
1244
|
extern void oj_set_parser_usual(ojParser p);
|
|
1181
1245
|
extern void oj_set_parser_debug(ojParser p);
|
|
1246
|
+
extern void oj_set_parser_safe(ojParser p, VALUE options);
|
|
1247
|
+
extern void oj_safe_init(VALUE parser_class);
|
|
1182
1248
|
|
|
1183
1249
|
static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
|
|
1184
1250
|
ojParser p = (ojParser)ptr;
|
|
@@ -1357,6 +1423,34 @@ static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
|
|
|
1357
1423
|
return p->option(p, key, rv);
|
|
1358
1424
|
}
|
|
1359
1425
|
|
|
1426
|
+
static void validate_primitives_are_complete(ojParser p) {
|
|
1427
|
+
if (0 >= p->ri) {
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
switch (p->map[256]) {
|
|
1432
|
+
case 'N': parse_error(p, "expected null"); break;
|
|
1433
|
+
case 'F': parse_error(p, "expected false"); break;
|
|
1434
|
+
case 'T': parse_error(p, "expected true"); break;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
static void validate_non_primitives_are_complete(ojParser p) {
|
|
1439
|
+
if (0 >= p->depth) {
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
if (OBJECT_FUN == p->stack[p->depth]) {
|
|
1443
|
+
parse_error(p, "Object is not closed");
|
|
1444
|
+
} else {
|
|
1445
|
+
parse_error(p, "Array is not closed");
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
static void validate_document_end(ojParser p) {
|
|
1450
|
+
validate_primitives_are_complete(p);
|
|
1451
|
+
validate_non_primitives_are_complete(p);
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1360
1454
|
/* Document-method: parse(json)
|
|
1361
1455
|
* call-seq: parse(json)
|
|
1362
1456
|
*
|
|
@@ -1366,13 +1460,20 @@ static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
|
|
|
1366
1460
|
*/
|
|
1367
1461
|
static VALUE parser_parse(VALUE self, VALUE json) {
|
|
1368
1462
|
ojParser p;
|
|
1369
|
-
|
|
1463
|
+
int frozen = OBJ_FROZEN(json);
|
|
1464
|
+
const byte *ptr;
|
|
1465
|
+
|
|
1466
|
+
if (!frozen) {
|
|
1467
|
+
rb_str_freeze(json);
|
|
1468
|
+
}
|
|
1469
|
+
ptr = (const byte *)StringValuePtr(json);
|
|
1370
1470
|
|
|
1371
1471
|
TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
|
|
1372
1472
|
|
|
1373
1473
|
parser_reset(p);
|
|
1374
1474
|
p->start(p);
|
|
1375
|
-
parse(p, ptr);
|
|
1475
|
+
parse(p, ptr, (size_t)RSTRING_LEN(json), false);
|
|
1476
|
+
validate_document_end(p);
|
|
1376
1477
|
|
|
1377
1478
|
return p->result(p);
|
|
1378
1479
|
}
|
|
@@ -1392,7 +1493,13 @@ static VALUE load(VALUE self) {
|
|
|
1392
1493
|
while (true) {
|
|
1393
1494
|
rb_funcall(p->reader, oj_readpartial_id, 2, INT2NUM(16385), rbuf);
|
|
1394
1495
|
if (0 < RSTRING_LEN(rbuf)) {
|
|
1395
|
-
parse(p, (byte *)StringValuePtr(rbuf));
|
|
1496
|
+
parse(p, (byte *)StringValuePtr(rbuf), (size_t)RSTRING_LEN(rbuf), true);
|
|
1497
|
+
}
|
|
1498
|
+
if (Qtrue == rb_funcall(p->reader, oj_eofq_id, 0)) {
|
|
1499
|
+
if (0 < p->depth) {
|
|
1500
|
+
parse_error(p, "parse error, not closed");
|
|
1501
|
+
}
|
|
1502
|
+
break;
|
|
1396
1503
|
}
|
|
1397
1504
|
}
|
|
1398
1505
|
return Qtrue;
|
|
@@ -1456,7 +1563,7 @@ static VALUE parser_file(VALUE self, VALUE filename) {
|
|
|
1456
1563
|
while (true) {
|
|
1457
1564
|
if (0 < (rsize = read(fd, buf, size))) {
|
|
1458
1565
|
buf[rsize] = '\0';
|
|
1459
|
-
parse(p, buf);
|
|
1566
|
+
parse(p, buf, rsize, true);
|
|
1460
1567
|
}
|
|
1461
1568
|
if (rsize <= 0) {
|
|
1462
1569
|
if (0 != rsize) {
|
|
@@ -1567,6 +1674,28 @@ static VALUE parser_validate(VALUE self) {
|
|
|
1567
1674
|
return validate_parser;
|
|
1568
1675
|
}
|
|
1569
1676
|
|
|
1677
|
+
static VALUE parser_safe(int argc, VALUE *argv, VALUE self) {
|
|
1678
|
+
VALUE options;
|
|
1679
|
+
|
|
1680
|
+
if (1 == argc) {
|
|
1681
|
+
options = argv[0];
|
|
1682
|
+
|
|
1683
|
+
Check_Type(options, T_HASH);
|
|
1684
|
+
} else {
|
|
1685
|
+
options = rb_hash_new();
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
ojParser p = OJ_R_ALLOC(struct _ojParser);
|
|
1689
|
+
|
|
1690
|
+
memset(p, 0, sizeof(struct _ojParser));
|
|
1691
|
+
buf_init(&p->key);
|
|
1692
|
+
buf_init(&p->buf);
|
|
1693
|
+
p->map = value_map;
|
|
1694
|
+
oj_set_parser_safe(p, options);
|
|
1695
|
+
|
|
1696
|
+
return TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1570
1699
|
/* Document-class: Oj::Parser
|
|
1571
1700
|
*
|
|
1572
1701
|
* A reusable parser that makes use of named delegates to determine the
|
|
@@ -1594,4 +1723,7 @@ void oj_parser_init(void) {
|
|
|
1594
1723
|
rb_define_module_function(parser_class, "usual", parser_usual, 0);
|
|
1595
1724
|
rb_define_module_function(parser_class, "saj", parser_saj, 0);
|
|
1596
1725
|
rb_define_module_function(parser_class, "validate", parser_validate, 0);
|
|
1726
|
+
rb_define_module_function(parser_class, "safe", parser_safe, -1);
|
|
1727
|
+
|
|
1728
|
+
oj_safe_init(parser_class);
|
|
1597
1729
|
}
|
data/ext/oj/parser.h
CHANGED
|
@@ -32,9 +32,9 @@ typedef struct _num {
|
|
|
32
32
|
long double dub;
|
|
33
33
|
int64_t fixnum; // holds all digits
|
|
34
34
|
uint32_t len;
|
|
35
|
-
int16_t div;
|
|
35
|
+
int16_t div; // 10^div
|
|
36
36
|
int16_t exp;
|
|
37
|
-
uint8_t shift;
|
|
37
|
+
uint8_t shift; // shift of fixnum to get decimal
|
|
38
38
|
bool neg;
|
|
39
39
|
bool exp_neg;
|
|
40
40
|
// for numbers as strings, reuse buf
|
|
@@ -42,6 +42,8 @@ typedef struct _num {
|
|
|
42
42
|
|
|
43
43
|
struct _ojParser;
|
|
44
44
|
|
|
45
|
+
extern const rb_data_type_t oj_parser_type;
|
|
46
|
+
|
|
45
47
|
typedef struct _funcs {
|
|
46
48
|
void (*add_null)(struct _ojParser *p);
|
|
47
49
|
void (*add_true)(struct _ojParser *p);
|