1
2
3
4
5
6
7
8
9 package s2
10
11 import (
12 "fmt"
13 "strconv"
14 )
15
16
17
18
19
20
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
30 for s < len(src)-5 {
31
32
33
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
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
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:
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
127
128 if offset > length {
129 copy(dst[d:d+length], dst[d-offset:])
130 d += length
131 continue
132 }
133
134
135
136
137
138
139
140
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
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)) {
161 return decodeErrCodeCorrupt
162 }
163 x = uint32(src[s-1])
164 case x == 61:
165 s += 3
166 if uint(s) > uint(len(src)) {
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)) {
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)) {
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)) {
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
211 switch length {
212 case 5:
213 s += 1
214 if uint(s) > uint(len(src)) {
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)) {
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)) {
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:
231 }
232 } else {
233 offset = toffset
234 }
235 length += 4
236 case tagCopy2:
237 s += 3
238 if uint(s) > uint(len(src)) {
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)) {
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
265
266 if offset > length {
267 copy(dst[d:d+length], dst[d-offset:])
268 d += length
269 continue
270 }
271
272
273
274
275
276
277
278
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 }
293
View as plain text