oj 3.16.11 → 3.17.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/CHANGELOG.md +133 -0
- data/README.md +0 -16
- data/ext/oj/cache.c +17 -1
- data/ext/oj/cache.h +5 -0
- data/ext/oj/circarray.c +6 -2
- data/ext/oj/compat.c +5 -5
- data/ext/oj/custom.c +12 -5
- data/ext/oj/dump.c +433 -206
- data/ext/oj/dump.h +12 -0
- data/ext/oj/dump_compat.c +17 -5
- data/ext/oj/dump_object.c +25 -10
- data/ext/oj/dump_strict.c +13 -8
- data/ext/oj/extconf.rb +11 -7
- data/ext/oj/fast.c +123 -60
- data/ext/oj/intern.c +7 -2
- data/ext/oj/mimic_json.c +3 -0
- data/ext/oj/object.c +26 -15
- data/ext/oj/odd.c +6 -2
- data/ext/oj/oj.c +511 -22
- data/ext/oj/oj.h +61 -53
- data/ext/oj/parse.c +229 -30
- data/ext/oj/parse.h +0 -1
- data/ext/oj/parser.c +226 -65
- data/ext/oj/rails.c +197 -57
- data/ext/oj/reader.c +18 -6
- data/ext/oj/resolve.c +11 -2
- data/ext/oj/rxclass.c +17 -1
- data/ext/oj/rxclass.h +2 -1
- data/ext/oj/safe.c +244 -0
- data/ext/oj/safe.h +91 -0
- data/ext/oj/saj.c +56 -12
- data/ext/oj/simd.h +210 -1
- data/ext/oj/sparse.c +22 -9
- data/ext/oj/stream_writer.c +16 -1
- data/ext/oj/string_writer.c +23 -7
- data/ext/oj/usual.c +23 -6
- data/ext/oj/util.c +27 -0
- data/ext/oj/util.h +2 -1
- data/ext/oj/val_stack.h +24 -5
- data/ext/oj/wab.c +15 -27
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/pages/Custom.md +2 -3
- data/pages/InstallOptions.md +8 -6
- data/pages/Modes.md +1 -1
- data/pages/Options.md +5 -6
- data/pages/Parser.md +2 -2
- data/pages/Rails.md +6 -0
- data/pages/Security.md +21 -7
- metadata +21 -19
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;
|
|
@@ -824,10 +892,10 @@ static void parse(ojParser p, const byte *json) {
|
|
|
824
892
|
case EXP_DIGIT:
|
|
825
893
|
p->map = exp_map;
|
|
826
894
|
for (; NUM_DIGIT == digit_map[*b]; b++) {
|
|
827
|
-
|
|
895
|
+
int x = p->num.exp * 10 + (*b - '0');
|
|
828
896
|
|
|
829
897
|
if (x <= MAX_EXP) {
|
|
830
|
-
p->num.exp = x;
|
|
898
|
+
p->num.exp = (int16_t)x;
|
|
831
899
|
} else {
|
|
832
900
|
big_change(p);
|
|
833
901
|
p->map = big_exp_map;
|
|
@@ -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 {
|
|
@@ -1176,6 +1243,8 @@ extern void oj_set_parser_validator(ojParser p);
|
|
|
1176
1243
|
extern void oj_set_parser_saj(ojParser p);
|
|
1177
1244
|
extern void oj_set_parser_usual(ojParser p);
|
|
1178
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);
|
|
1179
1248
|
|
|
1180
1249
|
static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
|
|
1181
1250
|
ojParser p = (ojParser)ptr;
|
|
@@ -1213,7 +1282,8 @@ static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
|
|
|
1213
1282
|
* Oj::Parser.new(:usual, cache_keys: true).
|
|
1214
1283
|
*/
|
|
1215
1284
|
static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
1216
|
-
ojParser
|
|
1285
|
+
ojParser p = OJ_R_ALLOC(struct _ojParser);
|
|
1286
|
+
volatile VALUE pv;
|
|
1217
1287
|
|
|
1218
1288
|
#if HAVE_RB_EXT_RACTOR_SAFE
|
|
1219
1289
|
// This doesn't seem to do anything.
|
|
@@ -1223,6 +1293,10 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
|
1223
1293
|
buf_init(&p->key);
|
|
1224
1294
|
buf_init(&p->buf);
|
|
1225
1295
|
p->map = value_map;
|
|
1296
|
+
// Until the parser is wrapped the GC can not free it, so the mode and the
|
|
1297
|
+
// options, both of which raise on a value they do not take, are handled
|
|
1298
|
+
// after the wrap.
|
|
1299
|
+
pv = TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
|
|
1226
1300
|
|
|
1227
1301
|
if (argc < 1) {
|
|
1228
1302
|
oj_set_parser_validator(p);
|
|
@@ -1263,7 +1337,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
|
1263
1337
|
rb_hash_foreach(ropts, opt_cb, (VALUE)p);
|
|
1264
1338
|
}
|
|
1265
1339
|
}
|
|
1266
|
-
return
|
|
1340
|
+
return pv;
|
|
1267
1341
|
}
|
|
1268
1342
|
|
|
1269
1343
|
// Create a new parser without setting the delegate. The parser is
|
|
@@ -1354,6 +1428,34 @@ static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
|
|
|
1354
1428
|
return p->option(p, key, rv);
|
|
1355
1429
|
}
|
|
1356
1430
|
|
|
1431
|
+
static void validate_primitives_are_complete(ojParser p) {
|
|
1432
|
+
if (0 >= p->ri) {
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
switch (p->map[256]) {
|
|
1437
|
+
case 'N': parse_error(p, "expected null"); break;
|
|
1438
|
+
case 'F': parse_error(p, "expected false"); break;
|
|
1439
|
+
case 'T': parse_error(p, "expected true"); break;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
static void validate_non_primitives_are_complete(ojParser p) {
|
|
1444
|
+
if (0 >= p->depth) {
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
if (OBJECT_FUN == p->stack[p->depth]) {
|
|
1448
|
+
parse_error(p, "Object is not closed");
|
|
1449
|
+
} else {
|
|
1450
|
+
parse_error(p, "Array is not closed");
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
static void validate_document_end(ojParser p) {
|
|
1455
|
+
validate_primitives_are_complete(p);
|
|
1456
|
+
validate_non_primitives_are_complete(p);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1357
1459
|
/* Document-method: parse(json)
|
|
1358
1460
|
* call-seq: parse(json)
|
|
1359
1461
|
*
|
|
@@ -1363,13 +1465,20 @@ static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
|
|
|
1363
1465
|
*/
|
|
1364
1466
|
static VALUE parser_parse(VALUE self, VALUE json) {
|
|
1365
1467
|
ojParser p;
|
|
1366
|
-
|
|
1468
|
+
int frozen = OBJ_FROZEN(json);
|
|
1469
|
+
const byte *ptr;
|
|
1470
|
+
|
|
1471
|
+
if (!frozen) {
|
|
1472
|
+
rb_str_freeze(json);
|
|
1473
|
+
}
|
|
1474
|
+
ptr = (const byte *)StringValuePtr(json);
|
|
1367
1475
|
|
|
1368
1476
|
TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
|
|
1369
1477
|
|
|
1370
1478
|
parser_reset(p);
|
|
1371
1479
|
p->start(p);
|
|
1372
|
-
parse(p, ptr);
|
|
1480
|
+
parse(p, ptr, (size_t)RSTRING_LEN(json), false);
|
|
1481
|
+
validate_document_end(p);
|
|
1373
1482
|
|
|
1374
1483
|
return p->result(p);
|
|
1375
1484
|
}
|
|
@@ -1389,7 +1498,7 @@ static VALUE load(VALUE self) {
|
|
|
1389
1498
|
while (true) {
|
|
1390
1499
|
rb_funcall(p->reader, oj_readpartial_id, 2, INT2NUM(16385), rbuf);
|
|
1391
1500
|
if (0 < RSTRING_LEN(rbuf)) {
|
|
1392
|
-
parse(p, (byte *)StringValuePtr(rbuf));
|
|
1501
|
+
parse(p, (byte *)StringValuePtr(rbuf), (size_t)RSTRING_LEN(rbuf), true);
|
|
1393
1502
|
}
|
|
1394
1503
|
if (Qtrue == rb_funcall(p->reader, oj_eofq_id, 0)) {
|
|
1395
1504
|
if (0 < p->depth) {
|
|
@@ -1420,6 +1529,39 @@ static VALUE parser_load(VALUE self, VALUE reader) {
|
|
|
1420
1529
|
return p->result(p);
|
|
1421
1530
|
}
|
|
1422
1531
|
|
|
1532
|
+
struct _fileParse {
|
|
1533
|
+
ojParser p;
|
|
1534
|
+
const char *path;
|
|
1535
|
+
int fd;
|
|
1536
|
+
};
|
|
1537
|
+
|
|
1538
|
+
static VALUE file_parse(VALUE x) {
|
|
1539
|
+
struct _fileParse *fp = (struct _fileParse *)x;
|
|
1540
|
+
byte buf[16385];
|
|
1541
|
+
size_t size = sizeof(buf) - 1;
|
|
1542
|
+
ssize_t rsize;
|
|
1543
|
+
|
|
1544
|
+
while (true) {
|
|
1545
|
+
if (0 > (rsize = read(fp->fd, buf, size))) {
|
|
1546
|
+
rb_raise(rb_eIOError, "error reading from %s", fp->path);
|
|
1547
|
+
}
|
|
1548
|
+
if (0 == rsize) {
|
|
1549
|
+
break;
|
|
1550
|
+
}
|
|
1551
|
+
buf[rsize] = '\0';
|
|
1552
|
+
parse(fp->p, buf, rsize, true);
|
|
1553
|
+
}
|
|
1554
|
+
validate_document_end(fp->p);
|
|
1555
|
+
|
|
1556
|
+
return fp->p->result(fp->p);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
static VALUE file_close(VALUE x) {
|
|
1560
|
+
close(((struct _fileParse *)x)->fd);
|
|
1561
|
+
|
|
1562
|
+
return Qnil;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1423
1565
|
/* Document-method: file(filename)
|
|
1424
1566
|
* call-seq: file(filename)
|
|
1425
1567
|
*
|
|
@@ -1428,9 +1570,10 @@ static VALUE parser_load(VALUE self, VALUE reader) {
|
|
|
1428
1570
|
* Returns the result according to the delegate of the parser.
|
|
1429
1571
|
*/
|
|
1430
1572
|
static VALUE parser_file(VALUE self, VALUE filename) {
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1573
|
+
struct _fileParse fp;
|
|
1574
|
+
ojParser p;
|
|
1575
|
+
const char *path;
|
|
1576
|
+
int fd;
|
|
1434
1577
|
|
|
1435
1578
|
TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
|
|
1436
1579
|
|
|
@@ -1449,26 +1592,15 @@ static VALUE parser_file(VALUE self, VALUE filename) {
|
|
|
1449
1592
|
// Use threaded version.
|
|
1450
1593
|
// TBD only if has pthreads
|
|
1451
1594
|
// TBD parse_large(p, fd);
|
|
1595
|
+
close(fd);
|
|
1452
1596
|
return p->result(p);
|
|
1453
1597
|
}
|
|
1454
1598
|
#endif
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1599
|
+
fp.p = p;
|
|
1600
|
+
fp.path = path;
|
|
1601
|
+
fp.fd = fd;
|
|
1458
1602
|
|
|
1459
|
-
|
|
1460
|
-
if (0 < (rsize = read(fd, buf, size))) {
|
|
1461
|
-
buf[rsize] = '\0';
|
|
1462
|
-
parse(p, buf);
|
|
1463
|
-
}
|
|
1464
|
-
if (rsize <= 0) {
|
|
1465
|
-
if (0 != rsize) {
|
|
1466
|
-
rb_raise(rb_eIOError, "error reading from %s", path);
|
|
1467
|
-
}
|
|
1468
|
-
break;
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
return p->result(p);
|
|
1603
|
+
return rb_ensure(file_parse, (VALUE)&fp, file_close, (VALUE)&fp);
|
|
1472
1604
|
}
|
|
1473
1605
|
|
|
1474
1606
|
/* Document-method: just_one
|
|
@@ -1570,6 +1702,32 @@ static VALUE parser_validate(VALUE self) {
|
|
|
1570
1702
|
return validate_parser;
|
|
1571
1703
|
}
|
|
1572
1704
|
|
|
1705
|
+
static VALUE parser_safe(int argc, VALUE *argv, VALUE self) {
|
|
1706
|
+
VALUE options;
|
|
1707
|
+
|
|
1708
|
+
if (1 == argc) {
|
|
1709
|
+
options = argv[0];
|
|
1710
|
+
|
|
1711
|
+
Check_Type(options, T_HASH);
|
|
1712
|
+
} else {
|
|
1713
|
+
options = rb_hash_new();
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
ojParser p = OJ_R_ALLOC(struct _ojParser);
|
|
1717
|
+
volatile VALUE pv;
|
|
1718
|
+
|
|
1719
|
+
memset(p, 0, sizeof(struct _ojParser));
|
|
1720
|
+
buf_init(&p->key);
|
|
1721
|
+
buf_init(&p->buf);
|
|
1722
|
+
p->map = value_map;
|
|
1723
|
+
// The limits raise on a value that is not an Integer, so the parser has to
|
|
1724
|
+
// be wrapped before they are read.
|
|
1725
|
+
pv = TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
|
|
1726
|
+
oj_set_parser_safe(p, options);
|
|
1727
|
+
|
|
1728
|
+
return pv;
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1573
1731
|
/* Document-class: Oj::Parser
|
|
1574
1732
|
*
|
|
1575
1733
|
* A reusable parser that makes use of named delegates to determine the
|
|
@@ -1597,4 +1755,7 @@ void oj_parser_init(void) {
|
|
|
1597
1755
|
rb_define_module_function(parser_class, "usual", parser_usual, 0);
|
|
1598
1756
|
rb_define_module_function(parser_class, "saj", parser_saj, 0);
|
|
1599
1757
|
rb_define_module_function(parser_class, "validate", parser_validate, 0);
|
|
1758
|
+
rb_define_module_function(parser_class, "safe", parser_safe, -1);
|
|
1759
|
+
|
|
1760
|
+
oj_safe_init(parser_class);
|
|
1600
1761
|
}
|