blob: 002519f3e7f0be8db207f51469f2e7d1e845ae83 [file] [log] [blame]
William Kurkianea869482019-04-09 15:16:11 -04001// +build !amd64 appengine !gc noasm
2
3package lz4
4
5func decodeBlock(dst, src []byte) (ret int) {
Abhilash S.L3b494632019-07-16 15:51:09 +05306 const hasError = -2
William Kurkianea869482019-04-09 15:16:11 -04007 defer func() {
William Kurkianea869482019-04-09 15:16:11 -04008 if recover() != nil {
Abhilash S.L3b494632019-07-16 15:51:09 +05309 ret = hasError
William Kurkianea869482019-04-09 15:16:11 -040010 }
11 }()
12
13 var si, di int
14 for {
15 // Literals and match lengths (token).
16 b := int(src[si])
17 si++
18
19 // Literals.
20 if lLen := b >> 4; lLen > 0 {
21 switch {
22 case lLen < 0xF && di+18 < len(dst) && si+16 < len(src):
23 // Shortcut 1
24 // if we have enough room in src and dst, and the literals length
25 // is small enough (0..14) then copy all 16 bytes, even if not all
26 // are part of the literals.
27 copy(dst[di:], src[si:si+16])
28 si += lLen
29 di += lLen
30 if mLen := b & 0xF; mLen < 0xF {
31 // Shortcut 2
32 // if the match length (4..18) fits within the literals, then copy
33 // all 18 bytes, even if not all are part of the literals.
34 mLen += 4
35 if offset := int(src[si]) | int(src[si+1])<<8; mLen <= offset {
36 i := di - offset
37 copy(dst[di:], dst[i:i+18])
38 si += 2
39 di += mLen
40 continue
41 }
42 }
43 case lLen == 0xF:
44 for src[si] == 0xFF {
45 lLen += 0xFF
46 si++
47 }
48 lLen += int(src[si])
49 si++
50 fallthrough
51 default:
52 copy(dst[di:di+lLen], src[si:si+lLen])
53 si += lLen
54 di += lLen
55 }
56 }
57 if si >= len(src) {
58 return di
59 }
60
61 offset := int(src[si]) | int(src[si+1])<<8
62 if offset == 0 {
Abhilash S.L3b494632019-07-16 15:51:09 +053063 return hasError
William Kurkianea869482019-04-09 15:16:11 -040064 }
65 si += 2
66
67 // Match.
68 mLen := b & 0xF
69 if mLen == 0xF {
70 for src[si] == 0xFF {
71 mLen += 0xFF
72 si++
73 }
74 mLen += int(src[si])
75 si++
76 }
77 mLen += minMatch
78
79 // Copy the match.
80 expanded := dst[di-offset:]
81 if mLen > offset {
82 // Efficiently copy the match dst[di-offset:di] into the dst slice.
83 bytesToCopy := offset * (mLen / offset)
84 for n := offset; n <= bytesToCopy+offset; n *= 2 {
85 copy(expanded[n:], expanded[:n])
86 }
87 di += bytesToCopy
88 mLen -= bytesToCopy
89 }
90 di += copy(dst[di:di+mLen], expanded[:mLen])
91 }
William Kurkianea869482019-04-09 15:16:11 -040092}