oj 3.13.16 → 3.13.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/ext/oj/buf.h +4 -0
- data/ext/oj/parse.c +48 -39
- data/ext/oj/parser.c +29 -26
- data/ext/oj/validate.c +21 -26
- data/lib/oj/version.rb +1 -1
- data/test/bar.rb +3 -8
- data/test/test_compat.rb +9 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b2ba7c6f3821ac59250c2893d01269cd45bb2ec5eb4b06babccf480a07fb8862
|
4
|
+
data.tar.gz: 666b047d4ac8f5637e6b1e8ca995bceb105197eabc4664936cc72986280684c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85005fe527745233220a680adf9bf3c24bb711abbe6b6758ccff236398c7f1218c9bc586eea7954388548772b17073e5540595d160948e19fffb94e535363ea4
|
7
|
+
data.tar.gz: 5b8b227c2d7e8156adb1adccff99ca18a8f2735ec3b7af9f8ee3f2b747427459c497ae738fe6c941d3df6e5131342677b1e8c08f208edeb7988697f80499339d
|
data/CHANGELOG.md
CHANGED
data/ext/oj/buf.h
CHANGED
@@ -39,6 +39,10 @@ inline static const char *buf_str(Buf buf) {
|
|
39
39
|
}
|
40
40
|
|
41
41
|
inline static void buf_append_string(Buf buf, const char *s, size_t slen) {
|
42
|
+
if (0 == slen) {
|
43
|
+
return;
|
44
|
+
}
|
45
|
+
|
42
46
|
if (buf->end <= buf->tail + slen) {
|
43
47
|
size_t len = buf->end - buf->head;
|
44
48
|
size_t toff = buf->tail - buf->head;
|
data/ext/oj/parse.c
CHANGED
@@ -183,6 +183,36 @@ static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
|
183
183
|
}
|
184
184
|
}
|
185
185
|
|
186
|
+
static inline const char *scan_string_noSIMD(const char *str, const char *end) {
|
187
|
+
for (; '"' != *str; str++) {
|
188
|
+
if (end <= str || '\0' == *str || '\\' == *str) {
|
189
|
+
break;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
return str;
|
193
|
+
}
|
194
|
+
|
195
|
+
#if defined(OJ_USE_SSE4_2)
|
196
|
+
#include <nmmintrin.h>
|
197
|
+
|
198
|
+
static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
199
|
+
static const char chars[16] = "\x00\\\"";
|
200
|
+
const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
|
201
|
+
const char *_end = (const char *)(end - 16);
|
202
|
+
|
203
|
+
for (; str <= _end; str += 16) {
|
204
|
+
const __m128i string = _mm_loadu_si128((const __m128i *)str);
|
205
|
+
const int r = _mm_cmpestri(terminate, 3, string, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
|
206
|
+
if (r != 16) {
|
207
|
+
str = (char*)(str + r);
|
208
|
+
return str;
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
212
|
+
return scan_string_noSIMD(str, end);
|
213
|
+
}
|
214
|
+
#endif
|
215
|
+
|
186
216
|
// entered at /
|
187
217
|
static void read_escaped_str(ParseInfo pi, const char *start) {
|
188
218
|
struct _buf buf;
|
@@ -192,11 +222,15 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
192
222
|
Val parent = stack_peek(&pi->stack);
|
193
223
|
|
194
224
|
buf_init(&buf);
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
225
|
+
buf_append_string(&buf, start, cnt);
|
226
|
+
|
227
|
+
for (s = pi->cur; '"' != *s;) {
|
228
|
+
#if defined(OJ_USE_SSE4_2)
|
229
|
+
const char *scanned = scan_string_SIMD(s, pi->end);
|
230
|
+
#else
|
231
|
+
const char *scanned = scan_string_noSIMD(s, pi->end);
|
232
|
+
#endif
|
233
|
+
if (scanned >= pi->end) {
|
200
234
|
oj_set_error_at(pi,
|
201
235
|
oj_parse_error_class,
|
202
236
|
__FILE__,
|
@@ -204,7 +238,12 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
204
238
|
"quoted string not terminated");
|
205
239
|
buf_cleanup(&buf);
|
206
240
|
return;
|
207
|
-
}
|
241
|
+
}
|
242
|
+
|
243
|
+
buf_append_string(&buf, s, (size_t)(scanned - s));
|
244
|
+
s = scanned;
|
245
|
+
|
246
|
+
if ('\\' == *s) {
|
208
247
|
s++;
|
209
248
|
switch (*s) {
|
210
249
|
case 'n': buf_append(&buf, '\n'); break;
|
@@ -273,8 +312,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
273
312
|
buf_cleanup(&buf);
|
274
313
|
return;
|
275
314
|
}
|
276
|
-
|
277
|
-
buf_append(&buf, *s);
|
315
|
+
s++;
|
278
316
|
}
|
279
317
|
}
|
280
318
|
if (0 == parent) {
|
@@ -327,43 +365,14 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
327
365
|
buf_cleanup(&buf);
|
328
366
|
}
|
329
367
|
|
330
|
-
static inline void scan_string_noSIMD(ParseInfo pi) {
|
331
|
-
for (; '"' != *pi->cur; pi->cur++) {
|
332
|
-
if (pi->end <= pi->cur || '\0' == *pi->cur || '\\' == *pi->cur) {
|
333
|
-
return;
|
334
|
-
}
|
335
|
-
}
|
336
|
-
}
|
337
|
-
|
338
|
-
#if defined(OJ_USE_SSE4_2)
|
339
|
-
#include <nmmintrin.h>
|
340
|
-
|
341
|
-
static inline void scan_string_SIMD(ParseInfo pi) {
|
342
|
-
static const char chars[16] = "\x00\\\"";
|
343
|
-
const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
|
344
|
-
const char *end = (const char *)(pi->end - 16);
|
345
|
-
|
346
|
-
for (; pi->cur <= end; pi->cur += 16) {
|
347
|
-
const __m128i string = _mm_loadu_si128((const __m128i *)pi->cur);
|
348
|
-
const int r = _mm_cmpestri(terminate, 3, string, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
|
349
|
-
if (r != 16) {
|
350
|
-
pi->cur = (const char*)(pi->cur + r);
|
351
|
-
return;
|
352
|
-
}
|
353
|
-
}
|
354
|
-
|
355
|
-
scan_string_noSIMD(pi);
|
356
|
-
}
|
357
|
-
#endif
|
358
|
-
|
359
368
|
static void read_str(ParseInfo pi) {
|
360
369
|
const char *str = pi->cur;
|
361
370
|
Val parent = stack_peek(&pi->stack);
|
362
371
|
|
363
372
|
#if defined(OJ_USE_SSE4_2)
|
364
|
-
scan_string_SIMD(pi);
|
373
|
+
pi->cur = scan_string_SIMD(pi->cur, pi->end);
|
365
374
|
#else
|
366
|
-
scan_string_noSIMD(pi);
|
375
|
+
pi->cur = scan_string_noSIMD(pi->cur, pi->end);
|
367
376
|
#endif
|
368
377
|
if (RB_UNLIKELY(pi->end <= pi->cur)) {
|
369
378
|
oj_set_error_at(pi,
|
data/ext/oj/parser.c
CHANGED
@@ -600,7 +600,7 @@ static void parse(ojParser p, const byte *json) {
|
|
600
600
|
int i;
|
601
601
|
|
602
602
|
p->line = 1;
|
603
|
-
p->col
|
603
|
+
p->col = -1;
|
604
604
|
#if DEBUG
|
605
605
|
printf("*** parse - mode: %c %s\n", p->map[256], (const char *)json);
|
606
606
|
#endif
|
@@ -655,7 +655,7 @@ static void parse(ojParser p, const byte *json) {
|
|
655
655
|
}
|
656
656
|
buf_append_string(&p->buf, (const char *)start, b - start);
|
657
657
|
if ('"' == *b) {
|
658
|
-
|
658
|
+
p->cur = b - json;
|
659
659
|
p->funcs[p->stack[p->depth]].add_str(p);
|
660
660
|
p->map = (0 == p->depth) ? value_map : after_map;
|
661
661
|
break;
|
@@ -665,14 +665,14 @@ static void parse(ojParser p, const byte *json) {
|
|
665
665
|
p->next_map = (0 == p->depth) ? value_map : after_map;
|
666
666
|
break;
|
667
667
|
case OPEN_OBJECT:
|
668
|
-
|
668
|
+
p->cur = b - json;
|
669
669
|
p->funcs[p->stack[p->depth]].open_object(p);
|
670
670
|
p->depth++;
|
671
671
|
p->stack[p->depth] = OBJECT_FUN;
|
672
672
|
p->map = key1_map;
|
673
673
|
break;
|
674
674
|
case NUM_CLOSE_OBJECT:
|
675
|
-
|
675
|
+
p->cur = b - json;
|
676
676
|
calc_num(p);
|
677
677
|
// flow through
|
678
678
|
case CLOSE_OBJECT:
|
@@ -683,18 +683,18 @@ static void parse(ojParser p, const byte *json) {
|
|
683
683
|
return;
|
684
684
|
}
|
685
685
|
p->depth--;
|
686
|
-
|
686
|
+
p->cur = b - json;
|
687
687
|
p->funcs[p->stack[p->depth]].close_object(p);
|
688
688
|
break;
|
689
689
|
case OPEN_ARRAY:
|
690
|
-
|
690
|
+
p->cur = b - json;
|
691
691
|
p->funcs[p->stack[p->depth]].open_array(p);
|
692
692
|
p->depth++;
|
693
693
|
p->stack[p->depth] = ARRAY_FUN;
|
694
694
|
p->map = value_map;
|
695
695
|
break;
|
696
696
|
case NUM_CLOSE_ARRAY:
|
697
|
-
|
697
|
+
p->cur = b - json;
|
698
698
|
calc_num(p);
|
699
699
|
// flow through
|
700
700
|
case CLOSE_ARRAY:
|
@@ -705,11 +705,11 @@ static void parse(ojParser p, const byte *json) {
|
|
705
705
|
return;
|
706
706
|
}
|
707
707
|
p->depth--;
|
708
|
-
|
708
|
+
p->cur = b - json;
|
709
709
|
p->funcs[p->stack[p->depth]].close_array(p);
|
710
710
|
break;
|
711
711
|
case NUM_COMMA:
|
712
|
-
|
712
|
+
p->cur = b - json;
|
713
713
|
calc_num(p);
|
714
714
|
if (0 < p->depth && OBJECT_FUN == p->stack[p->depth]) {
|
715
715
|
p->map = key_map;
|
@@ -872,13 +872,13 @@ static void parse(ojParser p, const byte *json) {
|
|
872
872
|
p->map = big_exp_map;
|
873
873
|
break;
|
874
874
|
case NUM_SPC:
|
875
|
-
|
876
|
-
|
877
|
-
|
875
|
+
p->cur = b - json;
|
876
|
+
calc_num(p);
|
877
|
+
break;
|
878
878
|
case NUM_NEWLINE:
|
879
|
-
|
880
|
-
|
881
|
-
|
879
|
+
p->cur = b - json;
|
880
|
+
calc_num(p);
|
881
|
+
b++;
|
882
882
|
#ifdef SPACE_JUMP
|
883
883
|
// for (uint32_t *sj = (uint32_t*)b; 0x20202020 == *sj; sj++) { b += 4; }
|
884
884
|
for (uint16_t *sj = (uint16_t *)b; 0x2020 == *sj; sj++) {
|
@@ -899,7 +899,7 @@ static void parse(ojParser p, const byte *json) {
|
|
899
899
|
buf_append_string(&p->buf, (const char *)start, b - start);
|
900
900
|
}
|
901
901
|
if ('"' == *b) {
|
902
|
-
|
902
|
+
p->cur = b - json;
|
903
903
|
p->funcs[p->stack[p->depth]].add_str(p);
|
904
904
|
p->map = p->next_map;
|
905
905
|
break;
|
@@ -908,7 +908,7 @@ static void parse(ojParser p, const byte *json) {
|
|
908
908
|
break;
|
909
909
|
case STR_SLASH: p->map = esc_map; break;
|
910
910
|
case STR_QUOTE:
|
911
|
-
|
911
|
+
p->cur = b - json;
|
912
912
|
p->funcs[p->stack[p->depth]].add_str(p);
|
913
913
|
p->map = p->next_map;
|
914
914
|
break;
|
@@ -986,7 +986,7 @@ static void parse(ojParser p, const byte *json) {
|
|
986
986
|
case VAL_NULL:
|
987
987
|
if ('u' == b[1] && 'l' == b[2] && 'l' == b[3]) {
|
988
988
|
b += 3;
|
989
|
-
|
989
|
+
p->cur = b - json;
|
990
990
|
p->funcs[p->stack[p->depth]].add_null(p);
|
991
991
|
p->map = (0 == p->depth) ? value_map : after_map;
|
992
992
|
break;
|
@@ -1012,7 +1012,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1012
1012
|
case VAL_TRUE:
|
1013
1013
|
if ('r' == b[1] && 'u' == b[2] && 'e' == b[3]) {
|
1014
1014
|
b += 3;
|
1015
|
-
|
1015
|
+
p->cur = b - json;
|
1016
1016
|
p->funcs[p->stack[p->depth]].add_true(p);
|
1017
1017
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1018
1018
|
break;
|
@@ -1038,7 +1038,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1038
1038
|
case VAL_FALSE:
|
1039
1039
|
if ('a' == b[1] && 'l' == b[2] && 's' == b[3] && 'e' == b[4]) {
|
1040
1040
|
b += 4;
|
1041
|
-
|
1041
|
+
p->cur = b - json;
|
1042
1042
|
p->funcs[p->stack[p->depth]].add_false(p);
|
1043
1043
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1044
1044
|
break;
|
@@ -1072,7 +1072,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1072
1072
|
parse_error(p, "expected null");
|
1073
1073
|
return;
|
1074
1074
|
}
|
1075
|
-
|
1075
|
+
p->cur = b - json;
|
1076
1076
|
p->funcs[p->stack[p->depth]].add_null(p);
|
1077
1077
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1078
1078
|
}
|
@@ -1084,7 +1084,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1084
1084
|
parse_error(p, "expected false");
|
1085
1085
|
return;
|
1086
1086
|
}
|
1087
|
-
|
1087
|
+
p->cur = b - json;
|
1088
1088
|
p->funcs[p->stack[p->depth]].add_false(p);
|
1089
1089
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1090
1090
|
}
|
@@ -1096,7 +1096,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1096
1096
|
parse_error(p, "expected true");
|
1097
1097
|
return;
|
1098
1098
|
}
|
1099
|
-
|
1099
|
+
p->cur = b - json;
|
1100
1100
|
p->funcs[p->stack[p->depth]].add_true(p);
|
1101
1101
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1102
1102
|
}
|
@@ -1114,6 +1114,9 @@ static void parse(ojParser p, const byte *json) {
|
|
1114
1114
|
p->map = trail_map;
|
1115
1115
|
}
|
1116
1116
|
}
|
1117
|
+
if (0 < p->depth) {
|
1118
|
+
parse_error(p, "parse error, not closed");
|
1119
|
+
}
|
1117
1120
|
if (0 == p->depth) {
|
1118
1121
|
switch (p->map[256]) {
|
1119
1122
|
case '0':
|
@@ -1125,9 +1128,9 @@ static void parse(ojParser p, const byte *json) {
|
|
1125
1128
|
case 'g':
|
1126
1129
|
case 'B':
|
1127
1130
|
case 'Y':
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
+
p->cur = b - json;
|
1132
|
+
calc_num(p);
|
1133
|
+
break;
|
1131
1134
|
}
|
1132
1135
|
}
|
1133
1136
|
return;
|
data/ext/oj/validate.c
CHANGED
@@ -2,50 +2,45 @@
|
|
2
2
|
|
3
3
|
#include "parser.h"
|
4
4
|
|
5
|
-
static void
|
6
|
-
noop(ojParser p) {
|
5
|
+
static void noop(ojParser p) {
|
7
6
|
}
|
8
7
|
|
9
|
-
static VALUE
|
10
|
-
option(ojParser p, const char *key, VALUE value) {
|
8
|
+
static VALUE option(ojParser p, const char *key, VALUE value) {
|
11
9
|
rb_raise(rb_eArgError, "%s is not an option for the validate delegate", key);
|
12
10
|
return Qnil;
|
13
11
|
}
|
14
12
|
|
15
|
-
static VALUE
|
16
|
-
result(ojParser p) {
|
13
|
+
static VALUE result(ojParser p) {
|
17
14
|
return Qnil;
|
18
15
|
}
|
19
16
|
|
20
|
-
static void
|
21
|
-
dfree(ojParser p) {
|
17
|
+
static void dfree(ojParser p) {
|
22
18
|
}
|
23
19
|
|
24
|
-
static void
|
25
|
-
mark(ojParser p) {
|
20
|
+
static void mark(ojParser p) {
|
26
21
|
}
|
27
22
|
|
28
23
|
void oj_set_parser_validator(ojParser p) {
|
29
|
-
p->
|
30
|
-
Funcs end = p->funcs + 3;
|
24
|
+
Funcs end = p->funcs + 3;
|
31
25
|
Funcs f;
|
26
|
+
p->ctx = NULL;
|
32
27
|
|
33
28
|
for (f = p->funcs; f < end; f++) {
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
29
|
+
f->add_null = noop;
|
30
|
+
f->add_true = noop;
|
31
|
+
f->add_false = noop;
|
32
|
+
f->add_int = noop;
|
33
|
+
f->add_float = noop;
|
34
|
+
f->add_big = noop;
|
35
|
+
f->add_str = noop;
|
36
|
+
f->open_array = noop;
|
37
|
+
f->close_array = noop;
|
38
|
+
f->open_object = noop;
|
39
|
+
f->close_object = noop;
|
45
40
|
}
|
46
41
|
p->option = option;
|
47
42
|
p->result = result;
|
48
|
-
p->free
|
49
|
-
p->mark
|
50
|
-
p->start
|
43
|
+
p->free = dfree;
|
44
|
+
p->mark = mark;
|
45
|
+
p->start = noop;
|
51
46
|
}
|
data/lib/oj/version.rb
CHANGED
data/test/bar.rb
CHANGED
@@ -6,11 +6,6 @@ $: << File.join(File.dirname(__FILE__), "../ext")
|
|
6
6
|
|
7
7
|
require 'oj'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
"inf_test" => Float::INFINITY,
|
13
|
-
"minus_inf_test" => -Float::INFINITY,
|
14
|
-
"min_test" => Float::MIN,
|
15
|
-
"max_test" => Float::MAX,
|
16
|
-
}, mode: :object) # => {"float_test":0.25,"nan_test":3.3e14159265358979323846
|
9
|
+
p = Oj::Parser.validate
|
10
|
+
# p = Oj::Parser.new(:debug)
|
11
|
+
p.parse(%|{|)
|
data/test/test_compat.rb
CHANGED
@@ -504,6 +504,15 @@ class CompatJuice < Minitest::Test
|
|
504
504
|
assert_equal("ぴーたー", Oj.load(json)['a'])
|
505
505
|
end
|
506
506
|
|
507
|
+
def test_parse_large_escaped_string
|
508
|
+
invalid_json = %|{"a":\"aaaa\\nbbbb\\rcccc\\tddd\\feee\\bf\/\\\\\\u3074\\u30fc\\u305f\\u30fc }|
|
509
|
+
error = assert_raises() { Oj.load(invalid_json) }
|
510
|
+
assert(error.message.include?('quoted string not terminated'))
|
511
|
+
|
512
|
+
json = "\"aaaa\\nbbbb\\rcccc\\tddd\\feee\\bf\/\\\\\\u3074\\u30fc\\u305f\\u30fc \""
|
513
|
+
assert_equal("aaaa\nbbbb\rcccc\tddd\feee\bf/\\ぴーたー ", Oj.load(json))
|
514
|
+
end
|
515
|
+
|
507
516
|
def dump_and_load(obj, trace=false)
|
508
517
|
json = Oj.dump(obj)
|
509
518
|
puts json if trace
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.13.
|
4
|
+
version: 3.13.17
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Ohler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-07-
|
11
|
+
date: 2022-07-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|