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  }