oj 3.13.16 → 3.13.17
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 +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
|