diff options
Diffstat (limited to 'vendor/github.com/klauspost/compress/s2/decode_other.go')
-rw-r--r-- | vendor/github.com/klauspost/compress/s2/decode_other.go | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/vendor/github.com/klauspost/compress/s2/decode_other.go b/vendor/github.com/klauspost/compress/s2/decode_other.go new file mode 100644 index 0000000..2cb55c2 --- /dev/null +++ b/vendor/github.com/klauspost/compress/s2/decode_other.go | |||
@@ -0,0 +1,292 @@ | |||
1 | // Copyright 2016 The Snappy-Go Authors. All rights reserved. | ||
2 | // Copyright (c) 2019 Klaus Post. All rights reserved. | ||
3 | // Use of this source code is governed by a BSD-style | ||
4 | // license that can be found in the LICENSE file. | ||
5 | |||
6 | //go:build (!amd64 && !arm64) || appengine || !gc || noasm | ||
7 | // +build !amd64,!arm64 appengine !gc noasm | ||
8 | |||
9 | package s2 | ||
10 | |||
11 | import ( | ||
12 | "fmt" | ||
13 | "strconv" | ||
14 | ) | ||
15 | |||
16 | // decode writes the decoding of src to dst. It assumes that the varint-encoded | ||
17 | // length of the decompressed bytes has already been read, and that len(dst) | ||
18 | // equals that length. | ||
19 | // | ||
20 | // It returns 0 on success or a decodeErrCodeXxx error code on failure. | ||
21 | func s2Decode(dst, src []byte) int { | ||
22 | const debug = false | ||
23 | if debug { | ||
24 | fmt.Println("Starting decode, dst len:", len(dst)) | ||
25 | } | ||
26 | var d, s, length int | ||
27 | offset := 0 | ||
28 | |||
29 | // As long as we can read at least 5 bytes... | ||
30 | for s < len(src)-5 { | ||
31 | // Removing bounds checks is SLOWER, when if doing | ||
32 | // in := src[s:s+5] | ||
33 | // Checked on Go 1.18 | ||
34 | switch src[s] & 0x03 { | ||
35 | case tagLiteral: | ||
36 | x := uint32(src[s] >> 2) | ||
37 | switch { | ||
38 | case x < 60: | ||
39 | s++ | ||
40 | case x == 60: | ||
41 | s += 2 | ||
42 | x = uint32(src[s-1]) | ||
43 | case x == 61: | ||
44 | in := src[s : s+3] | ||
45 | x = uint32(in[1]) | uint32(in[2])<<8 | ||
46 | s += 3 | ||
47 | case x == 62: | ||
48 | in := src[s : s+4] | ||
49 | // Load as 32 bit and shift down. | ||
50 | x = uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24 | ||
51 | x >>= 8 | ||
52 | s += 4 | ||
53 | case x == 63: | ||
54 | in := src[s : s+5] | ||
55 | x = uint32(in[1]) | uint32(in[2])<<8 | uint32(in[3])<<16 | uint32(in[4])<<24 | ||
56 | s += 5 | ||
57 | } | ||
58 | length = int(x) + 1 | ||
59 | if length > len(dst)-d || length > len(src)-s || (strconv.IntSize == 32 && length <= 0) { | ||
60 | if debug { | ||
61 | fmt.Println("corrupt: lit size", length) | ||
62 | } | ||
63 | return decodeErrCodeCorrupt | ||
64 | } | ||
65 | if debug { | ||
66 | fmt.Println("literals, length:", length, "d-after:", d+length) | ||
67 | } | ||
68 | |||
69 | copy(dst[d:], src[s:s+length]) | ||
70 | d += length | ||
71 | s += length | ||
72 | continue | ||
73 | |||
74 | case tagCopy1: | ||
75 | s += 2 | ||
76 | toffset := int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1])) | ||
77 | length = int(src[s-2]) >> 2 & 0x7 | ||
78 | if toffset == 0 { | ||
79 | if debug { | ||
80 | fmt.Print("(repeat) ") | ||
81 | } | ||
82 | // keep last offset | ||
83 | switch length { | ||
84 | case 5: | ||
85 | length = int(src[s]) + 4 | ||
86 | s += 1 | ||
87 | case 6: | ||
88 | in := src[s : s+2] | ||
89 | length = int(uint32(in[0])|(uint32(in[1])<<8)) + (1 << 8) | ||
90 | s += 2 | ||
91 | case 7: | ||
92 | in := src[s : s+3] | ||
93 | length = int((uint32(in[2])<<16)|(uint32(in[1])<<8)|uint32(in[0])) + (1 << 16) | ||
94 | s += 3 | ||
95 | default: // 0-> 4 | ||
96 | } | ||
97 | } else { | ||
98 | offset = toffset | ||
99 | } | ||
100 | length += 4 | ||
101 | case tagCopy2: | ||
102 | in := src[s : s+3] | ||
103 | offset = int(uint32(in[1]) | uint32(in[2])<<8) | ||
104 | length = 1 + int(in[0])>>2 | ||
105 | s += 3 | ||
106 | |||
107 | case tagCopy4: | ||
108 | in := src[s : s+5] | ||
109 | offset = int(uint32(in[1]) | uint32(in[2])<<8 | uint32(in[3])<<16 | uint32(in[4])<<24) | ||
110 | length = 1 + int(in[0])>>2 | ||
111 | s += 5 | ||
112 | } | ||
113 | |||
114 | if offset <= 0 || d < offset || length > len(dst)-d { | ||
115 | if debug { | ||
116 | fmt.Println("corrupt: match, length", length, "offset:", offset, "dst avail:", len(dst)-d, "dst pos:", d) | ||
117 | } | ||
118 | |||
119 | return decodeErrCodeCorrupt | ||
120 | } | ||
121 | |||
122 | if debug { | ||
123 | fmt.Println("copy, length:", length, "offset:", offset, "d-after:", d+length) | ||
124 | } | ||
125 | |||
126 | // Copy from an earlier sub-slice of dst to a later sub-slice. | ||
127 | // If no overlap, use the built-in copy: | ||
128 | if offset > length { | ||
129 | copy(dst[d:d+length], dst[d-offset:]) | ||
130 | d += length | ||
131 | continue | ||
132 | } | ||
133 | |||
134 | // Unlike the built-in copy function, this byte-by-byte copy always runs | ||
135 | // forwards, even if the slices overlap. Conceptually, this is: | ||
136 | // | ||
137 | // d += forwardCopy(dst[d:d+length], dst[d-offset:]) | ||
138 | // | ||
139 | // We align the slices into a and b and show the compiler they are the same size. | ||
140 | // This allows the loop to run without bounds checks. | ||
141 | a := dst[d : d+length] | ||
142 | b := dst[d-offset:] | ||
143 | b = b[:len(a)] | ||
144 | for i := range a { | ||
145 | a[i] = b[i] | ||
146 | } | ||
147 | d += length | ||
148 | } | ||
149 | |||
150 | // Remaining with extra checks... | ||
151 | for s < len(src) { | ||
152 | switch src[s] & 0x03 { | ||
153 | case tagLiteral: | ||
154 | x := uint32(src[s] >> 2) | ||
155 | switch { | ||
156 | case x < 60: | ||
157 | s++ | ||
158 | case x == 60: | ||
159 | s += 2 | ||
160 | if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. | ||
161 | return decodeErrCodeCorrupt | ||
162 | } | ||
163 | x = uint32(src[s-1]) | ||
164 | case x == 61: | ||
165 | s += 3 | ||
166 | if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. | ||
167 | return decodeErrCodeCorrupt | ||
168 | } | ||
169 | x = uint32(src[s-2]) | uint32(src[s-1])<<8 | ||
170 | case x == 62: | ||
171 | s += 4 | ||
172 | if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. | ||
173 | return decodeErrCodeCorrupt | ||
174 | } | ||
175 | x = uint32(src[s-3]) | uint32(src[s-2])<<8 | uint32(src[s-1])<<16 | ||
176 | case x == 63: | ||
177 | s += 5 | ||
178 | if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. | ||
179 | return decodeErrCodeCorrupt | ||
180 | } | ||
181 | x = uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24 | ||
182 | } | ||
183 | length = int(x) + 1 | ||
184 | if length > len(dst)-d || length > len(src)-s || (strconv.IntSize == 32 && length <= 0) { | ||
185 | if debug { | ||
186 | fmt.Println("corrupt: lit size", length) | ||
187 | } | ||
188 | return decodeErrCodeCorrupt | ||
189 | } | ||
190 | if debug { | ||
191 | fmt.Println("literals, length:", length, "d-after:", d+length) | ||
192 | } | ||
193 | |||
194 | copy(dst[d:], src[s:s+length]) | ||
195 | d += length | ||
196 | s += length | ||
197 | continue | ||
198 | |||
199 | case tagCopy1: | ||
200 | s += 2 | ||
201 | if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. | ||
202 | return decodeErrCodeCorrupt | ||
203 | } | ||
204 | length = int(src[s-2]) >> 2 & 0x7 | ||
205 | toffset := int(uint32(src[s-2])&0xe0<<3 | uint32(src[s-1])) | ||
206 | if toffset == 0 { | ||
207 | if debug { | ||
208 | fmt.Print("(repeat) ") | ||
209 | } | ||
210 | // keep last offset | ||
211 | switch length { | ||
212 | case 5: | ||
213 | s += 1 | ||
214 | if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. | ||
215 | return decodeErrCodeCorrupt | ||
216 | } | ||
217 | length = int(uint32(src[s-1])) + 4 | ||
218 | case 6: | ||
219 | s += 2 | ||
220 | if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. | ||
221 | return decodeErrCodeCorrupt | ||
222 | } | ||
223 | length = int(uint32(src[s-2])|(uint32(src[s-1])<<8)) + (1 << 8) | ||
224 | case 7: | ||
225 | s += 3 | ||
226 | if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. | ||
227 | return decodeErrCodeCorrupt | ||
228 | } | ||
229 | length = int(uint32(src[s-3])|(uint32(src[s-2])<<8)|(uint32(src[s-1])<<16)) + (1 << 16) | ||
230 | default: // 0-> 4 | ||
231 | } | ||
232 | } else { | ||
233 | offset = toffset | ||
234 | } | ||
235 | length += 4 | ||
236 | case tagCopy2: | ||
237 | s += 3 | ||
238 | if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. | ||
239 | return decodeErrCodeCorrupt | ||
240 | } | ||
241 | length = 1 + int(src[s-3])>>2 | ||
242 | offset = int(uint32(src[s-2]) | uint32(src[s-1])<<8) | ||
243 | |||
244 | case tagCopy4: | ||
245 | s += 5 | ||
246 | if uint(s) > uint(len(src)) { // The uint conversions catch overflow from the previous line. | ||
247 | return decodeErrCodeCorrupt | ||
248 | } | ||
249 | length = 1 + int(src[s-5])>>2 | ||
250 | offset = int(uint32(src[s-4]) | uint32(src[s-3])<<8 | uint32(src[s-2])<<16 | uint32(src[s-1])<<24) | ||
251 | } | ||
252 | |||
253 | if offset <= 0 || d < offset || length > len(dst)-d { | ||
254 | if debug { | ||
255 | fmt.Println("corrupt: match, length", length, "offset:", offset, "dst avail:", len(dst)-d, "dst pos:", d) | ||
256 | } | ||
257 | return decodeErrCodeCorrupt | ||
258 | } | ||
259 | |||
260 | if debug { | ||
261 | fmt.Println("copy, length:", length, "offset:", offset, "d-after:", d+length) | ||
262 | } | ||
263 | |||
264 | // Copy from an earlier sub-slice of dst to a later sub-slice. | ||
265 | // If no overlap, use the built-in copy: | ||
266 | if offset > length { | ||
267 | copy(dst[d:d+length], dst[d-offset:]) | ||
268 | d += length | ||
269 | continue | ||
270 | } | ||
271 | |||
272 | // Unlike the built-in copy function, this byte-by-byte copy always runs | ||
273 | // forwards, even if the slices overlap. Conceptually, this is: | ||
274 | // | ||
275 | // d += forwardCopy(dst[d:d+length], dst[d-offset:]) | ||
276 | // | ||
277 | // We align the slices into a and b and show the compiler they are the same size. | ||
278 | // This allows the loop to run without bounds checks. | ||
279 | a := dst[d : d+length] | ||
280 | b := dst[d-offset:] | ||
281 | b = b[:len(a)] | ||
282 | for i := range a { | ||
283 | a[i] = b[i] | ||
284 | } | ||
285 | d += length | ||
286 | } | ||
287 | |||
288 | if d != len(dst) { | ||
289 | return decodeErrCodeCorrupt | ||
290 | } | ||
291 | return 0 | ||
292 | } | ||