skip.mx raw
1 package filter
2
3 import (
4 "smesh.lol/pkg/lol/errorf"
5 )
6
7 func skipJSONValue(b []byte) (val []byte, r []byte, err error) {
8 if len(b) == 0 {
9 err = errorf.E([]byte("empty input"))
10 return
11 }
12 start := 0
13 end := 0
14 switch b[0] {
15 case '{':
16 end, err = findMatchingBrace(b, '{', '}')
17 case '[':
18 end, err = findMatchingBrace(b, '[', ']')
19 case '"':
20 end, err = findClosingQuote(b)
21 case 't':
22 if len(b) >= 4 && string(b[:4]) == "true" {
23 end = 4
24 } else {
25 err = errorf.E([]byte("invalid JSON value starting with 't'"))
26 }
27 case 'f':
28 if len(b) >= 5 && string(b[:5]) == "false" {
29 end = 5
30 } else {
31 err = errorf.E([]byte("invalid JSON value starting with 'f'"))
32 }
33 case 'n':
34 if len(b) >= 4 && string(b[:4]) == "null" {
35 end = 4
36 } else {
37 err = errorf.E([]byte("invalid JSON value starting with 'n'"))
38 }
39 case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
40 end = scanNumber(b)
41 default:
42 err = errorf.E([]byte("invalid JSON value starting with '%c'"), b[0])
43 }
44 if err != nil {
45 return
46 }
47 val = b[start:end]
48 r = b[end:]
49 return
50 }
51
52 func findMatchingBrace(b []byte, open, close byte) (end int, err error) {
53 if len(b) == 0 || b[0] != open {
54 err = errorf.E([]byte("expected '%c'"), open)
55 return
56 }
57 depth := 0
58 inString := false
59 escaped := false
60 for i := 0; i < len(b); i++ {
61 c := b[i]
62 if escaped {
63 escaped = false
64 continue
65 }
66 if c == '\\' && inString {
67 escaped = true
68 continue
69 }
70 if c == '"' {
71 inString = !inString
72 continue
73 }
74 if inString {
75 continue
76 }
77 if c == open {
78 depth++
79 } else if c == close {
80 depth--
81 if depth == 0 {
82 end = i + 1
83 return
84 }
85 }
86 }
87 err = errorf.E([]byte("unmatched '%c'"), open)
88 return
89 }
90
91 func findClosingQuote(b []byte) (end int, err error) {
92 if len(b) == 0 || b[0] != '"' {
93 err = errorf.E([]byte("expected '\"'"))
94 return
95 }
96 escaped := false
97 for i := 1; i < len(b); i++ {
98 c := b[i]
99 if escaped {
100 escaped = false
101 continue
102 }
103 if c == '\\' {
104 escaped = true
105 continue
106 }
107 if c == '"' {
108 end = i + 1
109 return
110 }
111 }
112 err = errorf.E([]byte("unclosed string"))
113 return
114 }
115
116 func scanNumber(b []byte) (end int) {
117 for i := 0; i < len(b); i++ {
118 c := b[i]
119 if (c >= '0' && c <= '9') || c == '-' || c == '+' || c == '.' || c == 'e' || c == 'E' {
120 continue
121 }
122 end = i
123 return
124 }
125 end = len(b)
126 return
127 }
128