github.com/balzaczyy/golucene@v0.0.0-20151210033525-d0be9ee89713/core/codec/compressing/lz4.go (about) 1 package compressing 2 3 // codec/compressing/LZ4.java 4 5 const ( 6 MIN_MATCH = 4 // minimum length of a match 7 MAX_DISTANCE = 1 << 16 // maximum distance of a reference 8 LAST_LITERALS = 5 // the last 5 bytes mus tbe encoded as literals 9 ) 10 11 type DataInput interface { 12 ReadByte() (b byte, err error) 13 ReadBytes(buf []byte) error 14 } 15 16 /* 17 Decompress at least decompressedLen bytes into dest[]. Please 18 note that dest[] must be large enough to be able to hold all 19 decompressed data (meaning that you need to know the total 20 decompressed length) 21 */ 22 func LZ4Decompress(compressed DataInput, decompressedLen int, dest []byte) (length int, err error) { 23 dOff, destEnd := 0, len(dest) 24 25 for { 26 // literals 27 var token int 28 token, err = asInt(compressed.ReadByte()) 29 if literalLen := int(uint(token) >> 4); literalLen != 0 { 30 if literalLen == 0x0F { 31 var b byte = 0xFF 32 for b == 0XFF { 33 b, err = compressed.ReadByte() 34 if err != nil { 35 return 36 } 37 literalLen += int(uint8(b)) 38 } 39 } 40 err = compressed.ReadBytes(dest[dOff : dOff+literalLen]) 41 if err != nil { 42 return 43 } 44 dOff += literalLen 45 } 46 47 if dOff >= decompressedLen { 48 break 49 } 50 51 // matches 52 var matchDec int 53 matchDec, err = asInt(compressed.ReadByte()) 54 if err != nil { 55 return 56 } 57 if b, err := asInt(compressed.ReadByte()); err == nil { 58 matchDec = matchDec | (b << 8) 59 } else { 60 return 0, err 61 } 62 assert(matchDec > 0) 63 64 matchLen := token & 0x0F 65 if matchLen == 0x0F { 66 var b byte = 0xFF 67 for b == 0xFF { 68 b, err = compressed.ReadByte() 69 if err != nil { 70 return 71 } 72 matchLen += int(b) 73 } 74 } 75 matchLen += MIN_MATCH 76 77 // copying a multiple of 8 bytes can make decompression from 5% to 10% faster 78 fastLen := int((int64(matchLen) + 7) & 0xFFFFFFF8) 79 if matchDec < matchLen || dOff+fastLen > destEnd { 80 // overlap -> naive incremental copy 81 for ref, end := dOff-matchDec, dOff+matchLen; dOff < end; { 82 dest[dOff] = dest[ref] 83 ref++ 84 dOff++ 85 } 86 } else { 87 // no overlap -> arraycopy 88 copy(dest[dOff:], dest[dOff-matchDec:dOff-matchDec+fastLen]) 89 dOff += matchLen 90 } 91 92 if dOff >= decompressedLen { 93 break 94 } 95 } 96 97 return dOff, nil 98 } 99 100 func asInt(b byte, err error) (n int, err2 error) { 101 return int(b), err 102 }