blob: b83a19a46681775fe65fc28cc652db10297dee49 [file] [log] [blame]
Scott Bakereee8dd82019-09-24 12:52:34 -07001// +build !amd64 appengine !gc noasm
2
3package lz4
4
5func decodeBlock(dst, src []byte) (ret int) {
6 defer func() {
7 // It is now faster to let the runtime panic and recover on out of bound slice access
8 // than checking indices as we go along.
9 if recover() != nil {
10 ret = -2
11 }
12 }()
13
14 var si, di int
15 for {
16 // Literals and match lengths (token).
17 b := int(src[si])
18 si++
19
20 // Literals.
21 if lLen := b >> 4; lLen > 0 {
22 switch {
23 case lLen < 0xF && di+18 < len(dst) && si+16 < len(src):
24 // Shortcut 1
25 // if we have enough room in src and dst, and the literals length
26 // is small enough (0..14) then copy all 16 bytes, even if not all
27 // are part of the literals.
28 copy(dst[di:], src[si:si+16])
29 si += lLen
30 di += lLen
31 if mLen := b & 0xF; mLen < 0xF {
32 // Shortcut 2
33 // if the match length (4..18) fits within the literals, then copy
34 // all 18 bytes, even if not all are part of the literals.
35 mLen += 4
36 if offset := int(src[si]) | int(src[si+1])<<8; mLen <= offset {
37 i := di - offset
38 copy(dst[di:], dst[i:i+18])
39 si += 2
40 di += mLen
41 continue
42 }
43 }
44 case lLen == 0xF:
45 for src[si] == 0xFF {
46 lLen += 0xFF
47 si++
48 }
49 lLen += int(src[si])
50 si++
51 fallthrough
52 default:
53 copy(dst[di:di+lLen], src[si:si+lLen])
54 si += lLen
55 di += lLen
56 }
57 }
58 if si >= len(src) {
59 return di
60 }
61
62 offset := int(src[si]) | int(src[si+1])<<8
63 if offset == 0 {
64 return -2
65 }
66 si += 2
67
68 // Match.
69 mLen := b & 0xF
70 if mLen == 0xF {
71 for src[si] == 0xFF {
72 mLen += 0xFF
73 si++
74 }
75 mLen += int(src[si])
76 si++
77 }
78 mLen += minMatch
79
80 // Copy the match.
81 expanded := dst[di-offset:]
82 if mLen > offset {
83 // Efficiently copy the match dst[di-offset:di] into the dst slice.
84 bytesToCopy := offset * (mLen / offset)
85 for n := offset; n <= bytesToCopy+offset; n *= 2 {
86 copy(expanded[n:], expanded[:n])
87 }
88 di += bytesToCopy
89 mLen -= bytesToCopy
90 }
91 di += copy(dst[di:di+mLen], expanded[:mLen])
92 }
93
94 return di
95}