forked from forgejo/forgejo
Vendor Update Go Libs (#13444)
* denisenkom/go-mssqldb untagged -> v0.9.0 * github.com/editorconfig/editorconfig-core-go v2.3.7 -> v2.3.8 * github.com/go-testfixtures/testfixtures v3.4.0 -> v3.4.1 * github.com/mholt/archiver v3.3.2 -> v3.5.0 * github.com/olivere/elastic v7.0.20 -> v7.0.21 * github.com/urfave/cli v1.22.4 -> v1.22.5 * github.com/xanzy/go-gitlab v0.38.1 -> v0.39.0 * github.com/yuin/goldmark-meta untagged -> v1.0.0 * github.com/ethantkoenig/rupture 0a76f03a811a -> c3b3b810dc77 * github.com/jaytaylor/html2text 8fb95d837f7d -> 3577fbdbcff7 * github.com/kballard/go-shellquote cd60e84ee657 -> 95032a82bc51 * github.com/msteinert/pam 02ccfbfaf0cc -> 913b8f8cdf8b * github.com/unknwon/paginater 7748a72e0141 -> 042474bd0eae * CI.restart() Co-authored-by: techknowlogick <techknowlogick@gitea.io>
This commit is contained in:
parent
eebaa81f43
commit
30ce3731a1
184 changed files with 12387 additions and 2975 deletions
23
vendor/github.com/pierrec/lz4/v3/debug.go
generated
vendored
23
vendor/github.com/pierrec/lz4/v3/debug.go
generated
vendored
|
@ -1,23 +0,0 @@
|
|||
// +build lz4debug
|
||||
|
||||
package lz4
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
const debugFlag = true
|
||||
|
||||
func debug(args ...interface{}) {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
file = filepath.Base(file)
|
||||
|
||||
f := fmt.Sprintf("LZ4: %s:%d %s", file, line, args[0])
|
||||
if f[len(f)-1] != '\n' {
|
||||
f += "\n"
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, f, args[1:]...)
|
||||
}
|
7
vendor/github.com/pierrec/lz4/v3/debug_stub.go
generated
vendored
7
vendor/github.com/pierrec/lz4/v3/debug_stub.go
generated
vendored
|
@ -1,7 +0,0 @@
|
|||
// +build !lz4debug
|
||||
|
||||
package lz4
|
||||
|
||||
const debugFlag = false
|
||||
|
||||
func debug(args ...interface{}) {}
|
30
vendor/github.com/pierrec/lz4/v3/errors.go
generated
vendored
30
vendor/github.com/pierrec/lz4/v3/errors.go
generated
vendored
|
@ -1,30 +0,0 @@
|
|||
package lz4
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
rdebug "runtime/debug"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrInvalidSourceShortBuffer is returned by UncompressBlock or CompressBLock when a compressed
|
||||
// block is corrupted or the destination buffer is not large enough for the uncompressed data.
|
||||
ErrInvalidSourceShortBuffer = errors.New("lz4: invalid source or destination buffer too short")
|
||||
// ErrInvalid is returned when reading an invalid LZ4 archive.
|
||||
ErrInvalid = errors.New("lz4: bad magic number")
|
||||
// ErrBlockDependency is returned when attempting to decompress an archive created with block dependency.
|
||||
ErrBlockDependency = errors.New("lz4: block dependency not supported")
|
||||
// ErrUnsupportedSeek is returned when attempting to Seek any way but forward from the current position.
|
||||
ErrUnsupportedSeek = errors.New("lz4: can only seek forward from io.SeekCurrent")
|
||||
)
|
||||
|
||||
func recoverBlock(e *error) {
|
||||
if r := recover(); r != nil && *e == nil {
|
||||
if debugFlag {
|
||||
fmt.Fprintln(os.Stderr, r)
|
||||
rdebug.PrintStack()
|
||||
}
|
||||
*e = ErrInvalidSourceShortBuffer
|
||||
}
|
||||
}
|
12
vendor/github.com/pierrec/lz4/v3/go.mod
generated
vendored
12
vendor/github.com/pierrec/lz4/v3/go.mod
generated
vendored
|
@ -1,12 +0,0 @@
|
|||
module github.com/pierrec/lz4/v3
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
code.cloudfoundry.org/bytefmt v0.0.0-20190710193110-1eb035ffe2b6
|
||||
github.com/frankban/quicktest v1.4.0
|
||||
github.com/onsi/ginkgo v1.8.0 // indirect
|
||||
github.com/onsi/gomega v1.5.0 // indirect
|
||||
github.com/pierrec/cmdflag v0.0.2
|
||||
github.com/schollz/progressbar/v2 v2.13.2
|
||||
)
|
52
vendor/github.com/pierrec/lz4/v3/go.sum
generated
vendored
52
vendor/github.com/pierrec/lz4/v3/go.sum
generated
vendored
|
@ -1,52 +0,0 @@
|
|||
code.cloudfoundry.org/bytefmt v0.0.0-20190710193110-1eb035ffe2b6 h1:tW+ztA4A9UT9xnco5wUjW1oNi35k22eUEn9tNpPYVwE=
|
||||
code.cloudfoundry.org/bytefmt v0.0.0-20190710193110-1eb035ffe2b6/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/frankban/quicktest v1.4.0 h1:rCSCih1FnSWJEel/eub9wclBSqpF2F/PuvxUWGWnbO8=
|
||||
github.com/frankban/quicktest v1.4.0/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pierrec/cmdflag v0.0.2 h1:ybjGJnPr/aURn2IKWjO49znx9N0DL6YfGsIxN0PYuVY=
|
||||
github.com/pierrec/cmdflag v0.0.2/go.mod h1:a3zKGZ3cdQUfxjd0RGMLZr8xI3nvpJOB+m6o/1X5BmU=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/schollz/progressbar/v2 v2.13.2 h1:3L9bP5KQOGEnFP8P5V8dz+U0yo5I29iY5Oa9s9EAwn0=
|
||||
github.com/schollz/progressbar/v2 v2.13.2/go.mod h1:6YZjqdthH6SCZKv2rqGryrxPtfmRB/DWZxSMfCXPyD8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
113
vendor/github.com/pierrec/lz4/v3/lz4.go
generated
vendored
113
vendor/github.com/pierrec/lz4/v3/lz4.go
generated
vendored
|
@ -1,113 +0,0 @@
|
|||
// Package lz4 implements reading and writing lz4 compressed data (a frame),
|
||||
// as specified in http://fastcompression.blogspot.fr/2013/04/lz4-streaming-format-final.html.
|
||||
//
|
||||
// Although the block level compression and decompression functions are exposed and are fully compatible
|
||||
// with the lz4 block format definition, they are low level and should not be used directly.
|
||||
// For a complete description of an lz4 compressed block, see:
|
||||
// http://fastcompression.blogspot.fr/2011/05/lz4-explained.html
|
||||
//
|
||||
// See https://github.com/Cyan4973/lz4 for the reference C implementation.
|
||||
//
|
||||
package lz4
|
||||
|
||||
import "math/bits"
|
||||
|
||||
import "sync"
|
||||
|
||||
const (
|
||||
// Extension is the LZ4 frame file name extension
|
||||
Extension = ".lz4"
|
||||
// Version is the LZ4 frame format version
|
||||
Version = 1
|
||||
|
||||
frameMagic uint32 = 0x184D2204
|
||||
frameSkipMagic uint32 = 0x184D2A50
|
||||
|
||||
// The following constants are used to setup the compression algorithm.
|
||||
minMatch = 4 // the minimum size of the match sequence size (4 bytes)
|
||||
winSizeLog = 16 // LZ4 64Kb window size limit
|
||||
winSize = 1 << winSizeLog
|
||||
winMask = winSize - 1 // 64Kb window of previous data for dependent blocks
|
||||
compressedBlockFlag = 1 << 31
|
||||
compressedBlockMask = compressedBlockFlag - 1
|
||||
|
||||
// hashLog determines the size of the hash table used to quickly find a previous match position.
|
||||
// Its value influences the compression speed and memory usage, the lower the faster,
|
||||
// but at the expense of the compression ratio.
|
||||
// 16 seems to be the best compromise for fast compression.
|
||||
hashLog = 16
|
||||
htSize = 1 << hashLog
|
||||
|
||||
mfLimit = 10 + minMatch // The last match cannot start within the last 14 bytes.
|
||||
)
|
||||
|
||||
// map the block max size id with its value in bytes: 64Kb, 256Kb, 1Mb and 4Mb.
|
||||
const (
|
||||
blockSize64K = 1 << (16 + 2*iota)
|
||||
blockSize256K
|
||||
blockSize1M
|
||||
blockSize4M
|
||||
)
|
||||
|
||||
var (
|
||||
// Keep a pool of buffers for each valid block sizes.
|
||||
bsMapValue = [...]*sync.Pool{
|
||||
newBufferPool(2 * blockSize64K),
|
||||
newBufferPool(2 * blockSize256K),
|
||||
newBufferPool(2 * blockSize1M),
|
||||
newBufferPool(2 * blockSize4M),
|
||||
}
|
||||
)
|
||||
|
||||
// newBufferPool returns a pool for buffers of the given size.
|
||||
func newBufferPool(size int) *sync.Pool {
|
||||
return &sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, size)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// getBuffer returns a buffer to its pool.
|
||||
func getBuffer(size int) []byte {
|
||||
idx := blockSizeValueToIndex(size) - 4
|
||||
return bsMapValue[idx].Get().([]byte)
|
||||
}
|
||||
|
||||
// putBuffer returns a buffer to its pool.
|
||||
func putBuffer(size int, buf []byte) {
|
||||
if cap(buf) > 0 {
|
||||
idx := blockSizeValueToIndex(size) - 4
|
||||
bsMapValue[idx].Put(buf[:cap(buf)])
|
||||
}
|
||||
}
|
||||
func blockSizeIndexToValue(i byte) int {
|
||||
return 1 << (16 + 2*uint(i))
|
||||
}
|
||||
func isValidBlockSize(size int) bool {
|
||||
const blockSizeMask = blockSize64K | blockSize256K | blockSize1M | blockSize4M
|
||||
|
||||
return size&blockSizeMask > 0 && bits.OnesCount(uint(size)) == 1
|
||||
}
|
||||
func blockSizeValueToIndex(size int) byte {
|
||||
return 4 + byte(bits.TrailingZeros(uint(size)>>16)/2)
|
||||
}
|
||||
|
||||
// Header describes the various flags that can be set on a Writer or obtained from a Reader.
|
||||
// The default values match those of the LZ4 frame format definition
|
||||
// (http://fastcompression.blogspot.com/2013/04/lz4-streaming-format-final.html).
|
||||
//
|
||||
// NB. in a Reader, in case of concatenated frames, the Header values may change between Read() calls.
|
||||
// It is the caller's responsibility to check them if necessary.
|
||||
type Header struct {
|
||||
BlockChecksum bool // Compressed blocks checksum flag.
|
||||
NoChecksum bool // Frame checksum flag.
|
||||
BlockMaxSize int // Size of the uncompressed data block (one of [64KB, 256KB, 1MB, 4MB]). Default=4MB.
|
||||
Size uint64 // Frame total size. It is _not_ computed by the Writer.
|
||||
CompressionLevel int // Compression level (higher is better, use 0 for fastest compression).
|
||||
done bool // Header processed flag (Read or Write and checked).
|
||||
}
|
||||
|
||||
func (h *Header) Reset() {
|
||||
h.done = false
|
||||
}
|
29
vendor/github.com/pierrec/lz4/v3/lz4_go1.10.go
generated
vendored
29
vendor/github.com/pierrec/lz4/v3/lz4_go1.10.go
generated
vendored
|
@ -1,29 +0,0 @@
|
|||
//+build go1.10
|
||||
|
||||
package lz4
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (h Header) String() string {
|
||||
var s strings.Builder
|
||||
|
||||
s.WriteString(fmt.Sprintf("%T{", h))
|
||||
if h.BlockChecksum {
|
||||
s.WriteString("BlockChecksum: true ")
|
||||
}
|
||||
if h.NoChecksum {
|
||||
s.WriteString("NoChecksum: true ")
|
||||
}
|
||||
if bs := h.BlockMaxSize; bs != 0 && bs != 4<<20 {
|
||||
s.WriteString(fmt.Sprintf("BlockMaxSize: %d ", bs))
|
||||
}
|
||||
if l := h.CompressionLevel; l != 0 {
|
||||
s.WriteString(fmt.Sprintf("CompressionLevel: %d ", l))
|
||||
}
|
||||
s.WriteByte('}')
|
||||
|
||||
return s.String()
|
||||
}
|
29
vendor/github.com/pierrec/lz4/v3/lz4_notgo1.10.go
generated
vendored
29
vendor/github.com/pierrec/lz4/v3/lz4_notgo1.10.go
generated
vendored
|
@ -1,29 +0,0 @@
|
|||
//+build !go1.10
|
||||
|
||||
package lz4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (h Header) String() string {
|
||||
var s bytes.Buffer
|
||||
|
||||
s.WriteString(fmt.Sprintf("%T{", h))
|
||||
if h.BlockChecksum {
|
||||
s.WriteString("BlockChecksum: true ")
|
||||
}
|
||||
if h.NoChecksum {
|
||||
s.WriteString("NoChecksum: true ")
|
||||
}
|
||||
if bs := h.BlockMaxSize; bs != 0 && bs != 4<<20 {
|
||||
s.WriteString(fmt.Sprintf("BlockMaxSize: %d ", bs))
|
||||
}
|
||||
if l := h.CompressionLevel; l != 0 {
|
||||
s.WriteString(fmt.Sprintf("CompressionLevel: %d ", l))
|
||||
}
|
||||
s.WriteByte('}')
|
||||
|
||||
return s.String()
|
||||
}
|
335
vendor/github.com/pierrec/lz4/v3/reader.go
generated
vendored
335
vendor/github.com/pierrec/lz4/v3/reader.go
generated
vendored
|
@ -1,335 +0,0 @@
|
|||
package lz4
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/pierrec/lz4/v3/internal/xxh32"
|
||||
)
|
||||
|
||||
// Reader implements the LZ4 frame decoder.
|
||||
// The Header is set after the first call to Read().
|
||||
// The Header may change between Read() calls in case of concatenated frames.
|
||||
type Reader struct {
|
||||
Header
|
||||
// Handler called when a block has been successfully read.
|
||||
// It provides the number of bytes read.
|
||||
OnBlockDone func(size int)
|
||||
|
||||
buf [8]byte // Scrap buffer.
|
||||
pos int64 // Current position in src.
|
||||
src io.Reader // Source.
|
||||
zdata []byte // Compressed data.
|
||||
data []byte // Uncompressed data.
|
||||
idx int // Index of unread bytes into data.
|
||||
checksum xxh32.XXHZero // Frame hash.
|
||||
skip int64 // Bytes to skip before next read.
|
||||
dpos int64 // Position in dest
|
||||
}
|
||||
|
||||
// NewReader returns a new LZ4 frame decoder.
|
||||
// No access to the underlying io.Reader is performed.
|
||||
func NewReader(src io.Reader) *Reader {
|
||||
r := &Reader{src: src}
|
||||
return r
|
||||
}
|
||||
|
||||
// readHeader checks the frame magic number and parses the frame descriptoz.
|
||||
// Skippable frames are supported even as a first frame although the LZ4
|
||||
// specifications recommends skippable frames not to be used as first frames.
|
||||
func (z *Reader) readHeader(first bool) error {
|
||||
defer z.checksum.Reset()
|
||||
|
||||
buf := z.buf[:]
|
||||
for {
|
||||
magic, err := z.readUint32()
|
||||
if err != nil {
|
||||
z.pos += 4
|
||||
if !first && err == io.ErrUnexpectedEOF {
|
||||
return io.EOF
|
||||
}
|
||||
return err
|
||||
}
|
||||
if magic == frameMagic {
|
||||
break
|
||||
}
|
||||
if magic>>8 != frameSkipMagic>>8 {
|
||||
return ErrInvalid
|
||||
}
|
||||
skipSize, err := z.readUint32()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
z.pos += 4
|
||||
m, err := io.CopyN(ioutil.Discard, z.src, int64(skipSize))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
z.pos += m
|
||||
}
|
||||
|
||||
// Header.
|
||||
if _, err := io.ReadFull(z.src, buf[:2]); err != nil {
|
||||
return err
|
||||
}
|
||||
z.pos += 8
|
||||
|
||||
b := buf[0]
|
||||
if v := b >> 6; v != Version {
|
||||
return fmt.Errorf("lz4: invalid version: got %d; expected %d", v, Version)
|
||||
}
|
||||
if b>>5&1 == 0 {
|
||||
return ErrBlockDependency
|
||||
}
|
||||
z.BlockChecksum = b>>4&1 > 0
|
||||
frameSize := b>>3&1 > 0
|
||||
z.NoChecksum = b>>2&1 == 0
|
||||
|
||||
bmsID := buf[1] >> 4 & 0x7
|
||||
if bmsID < 4 || bmsID > 7 {
|
||||
return fmt.Errorf("lz4: invalid block max size ID: %d", bmsID)
|
||||
}
|
||||
bSize := blockSizeIndexToValue(bmsID - 4)
|
||||
z.BlockMaxSize = bSize
|
||||
|
||||
// Allocate the compressed/uncompressed buffers.
|
||||
// The compressed buffer cannot exceed the uncompressed one.
|
||||
if n := 2 * bSize; cap(z.zdata) < n {
|
||||
z.zdata = make([]byte, n, n)
|
||||
}
|
||||
if debugFlag {
|
||||
debug("header block max size id=%d size=%d", bmsID, bSize)
|
||||
}
|
||||
z.zdata = z.zdata[:bSize]
|
||||
z.data = z.zdata[:cap(z.zdata)][bSize:]
|
||||
z.idx = len(z.data)
|
||||
|
||||
_, _ = z.checksum.Write(buf[0:2])
|
||||
|
||||
if frameSize {
|
||||
buf := buf[:8]
|
||||
if _, err := io.ReadFull(z.src, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
z.Size = binary.LittleEndian.Uint64(buf)
|
||||
z.pos += 8
|
||||
_, _ = z.checksum.Write(buf)
|
||||
}
|
||||
|
||||
// Header checksum.
|
||||
if _, err := io.ReadFull(z.src, buf[:1]); err != nil {
|
||||
return err
|
||||
}
|
||||
z.pos++
|
||||
if h := byte(z.checksum.Sum32() >> 8 & 0xFF); h != buf[0] {
|
||||
return fmt.Errorf("lz4: invalid header checksum: got %x; expected %x", buf[0], h)
|
||||
}
|
||||
|
||||
z.Header.done = true
|
||||
if debugFlag {
|
||||
debug("header read: %v", z.Header)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read decompresses data from the underlying source into the supplied buffer.
|
||||
//
|
||||
// Since there can be multiple streams concatenated, Header values may
|
||||
// change between calls to Read(). If that is the case, no data is actually read from
|
||||
// the underlying io.Reader, to allow for potential input buffer resizing.
|
||||
func (z *Reader) Read(buf []byte) (int, error) {
|
||||
if debugFlag {
|
||||
debug("Read buf len=%d", len(buf))
|
||||
}
|
||||
if !z.Header.done {
|
||||
if err := z.readHeader(true); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if debugFlag {
|
||||
debug("header read OK compressed buffer %d / %d uncompressed buffer %d : %d index=%d",
|
||||
len(z.zdata), cap(z.zdata), len(z.data), cap(z.data), z.idx)
|
||||
}
|
||||
}
|
||||
|
||||
if len(buf) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if z.idx == len(z.data) {
|
||||
// No data ready for reading, process the next block.
|
||||
if debugFlag {
|
||||
debug("reading block from writer")
|
||||
}
|
||||
// Reset uncompressed buffer
|
||||
z.data = z.zdata[:cap(z.zdata)][len(z.zdata):]
|
||||
|
||||
// Block length: 0 = end of frame, highest bit set: uncompressed.
|
||||
bLen, err := z.readUint32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
z.pos += 4
|
||||
|
||||
if bLen == 0 {
|
||||
// End of frame reached.
|
||||
if !z.NoChecksum {
|
||||
// Validate the frame checksum.
|
||||
checksum, err := z.readUint32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if debugFlag {
|
||||
debug("frame checksum got=%x / want=%x", z.checksum.Sum32(), checksum)
|
||||
}
|
||||
z.pos += 4
|
||||
if h := z.checksum.Sum32(); checksum != h {
|
||||
return 0, fmt.Errorf("lz4: invalid frame checksum: got %x; expected %x", h, checksum)
|
||||
}
|
||||
}
|
||||
|
||||
// Get ready for the next concatenated frame and keep the position.
|
||||
pos := z.pos
|
||||
z.Reset(z.src)
|
||||
z.pos = pos
|
||||
|
||||
// Since multiple frames can be concatenated, check for more.
|
||||
return 0, z.readHeader(false)
|
||||
}
|
||||
|
||||
if debugFlag {
|
||||
debug("raw block size %d", bLen)
|
||||
}
|
||||
if bLen&compressedBlockFlag > 0 {
|
||||
// Uncompressed block.
|
||||
bLen &= compressedBlockMask
|
||||
if debugFlag {
|
||||
debug("uncompressed block size %d", bLen)
|
||||
}
|
||||
if int(bLen) > cap(z.data) {
|
||||
return 0, fmt.Errorf("lz4: invalid block size: %d", bLen)
|
||||
}
|
||||
z.data = z.data[:bLen]
|
||||
if _, err := io.ReadFull(z.src, z.data); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
z.pos += int64(bLen)
|
||||
if z.OnBlockDone != nil {
|
||||
z.OnBlockDone(int(bLen))
|
||||
}
|
||||
|
||||
if z.BlockChecksum {
|
||||
checksum, err := z.readUint32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
z.pos += 4
|
||||
|
||||
if h := xxh32.ChecksumZero(z.data); h != checksum {
|
||||
return 0, fmt.Errorf("lz4: invalid block checksum: got %x; expected %x", h, checksum)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Compressed block.
|
||||
if debugFlag {
|
||||
debug("compressed block size %d", bLen)
|
||||
}
|
||||
if int(bLen) > cap(z.data) {
|
||||
return 0, fmt.Errorf("lz4: invalid block size: %d", bLen)
|
||||
}
|
||||
zdata := z.zdata[:bLen]
|
||||
if _, err := io.ReadFull(z.src, zdata); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
z.pos += int64(bLen)
|
||||
|
||||
if z.BlockChecksum {
|
||||
checksum, err := z.readUint32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
z.pos += 4
|
||||
|
||||
if h := xxh32.ChecksumZero(zdata); h != checksum {
|
||||
return 0, fmt.Errorf("lz4: invalid block checksum: got %x; expected %x", h, checksum)
|
||||
}
|
||||
}
|
||||
|
||||
n, err := UncompressBlock(zdata, z.data)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
z.data = z.data[:n]
|
||||
if z.OnBlockDone != nil {
|
||||
z.OnBlockDone(n)
|
||||
}
|
||||
}
|
||||
|
||||
if !z.NoChecksum {
|
||||
_, _ = z.checksum.Write(z.data)
|
||||
if debugFlag {
|
||||
debug("current frame checksum %x", z.checksum.Sum32())
|
||||
}
|
||||
}
|
||||
z.idx = 0
|
||||
}
|
||||
|
||||
if z.skip > int64(len(z.data[z.idx:])) {
|
||||
z.skip -= int64(len(z.data[z.idx:]))
|
||||
z.dpos += int64(len(z.data[z.idx:]))
|
||||
z.idx = len(z.data)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
z.idx += int(z.skip)
|
||||
z.dpos += z.skip
|
||||
z.skip = 0
|
||||
|
||||
n := copy(buf, z.data[z.idx:])
|
||||
z.idx += n
|
||||
z.dpos += int64(n)
|
||||
if debugFlag {
|
||||
debug("copied %d bytes to input", n)
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Seek implements io.Seeker, but supports seeking forward from the current
|
||||
// position only. Any other seek will return an error. Allows skipping output
|
||||
// bytes which aren't needed, which in some scenarios is faster than reading
|
||||
// and discarding them.
|
||||
// Note this may cause future calls to Read() to read 0 bytes if all of the
|
||||
// data they would have returned is skipped.
|
||||
func (z *Reader) Seek(offset int64, whence int) (int64, error) {
|
||||
if offset < 0 || whence != io.SeekCurrent {
|
||||
return z.dpos + z.skip, ErrUnsupportedSeek
|
||||
}
|
||||
z.skip += offset
|
||||
return z.dpos + z.skip, nil
|
||||
}
|
||||
|
||||
// Reset discards the Reader's state and makes it equivalent to the
|
||||
// result of its original state from NewReader, but reading from r instead.
|
||||
// This permits reusing a Reader rather than allocating a new one.
|
||||
func (z *Reader) Reset(r io.Reader) {
|
||||
z.Header = Header{}
|
||||
z.pos = 0
|
||||
z.src = r
|
||||
z.zdata = z.zdata[:0]
|
||||
z.data = z.data[:0]
|
||||
z.idx = 0
|
||||
z.checksum.Reset()
|
||||
}
|
||||
|
||||
// readUint32 reads an uint32 into the supplied buffer.
|
||||
// The idea is to make use of the already allocated buffers avoiding additional allocations.
|
||||
func (z *Reader) readUint32() (uint32, error) {
|
||||
buf := z.buf[:4]
|
||||
_, err := io.ReadFull(z.src, buf)
|
||||
x := binary.LittleEndian.Uint32(buf)
|
||||
return x, err
|
||||
}
|
409
vendor/github.com/pierrec/lz4/v3/writer.go
generated
vendored
409
vendor/github.com/pierrec/lz4/v3/writer.go
generated
vendored
|
@ -1,409 +0,0 @@
|
|||
package lz4
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
|
||||
"github.com/pierrec/lz4/v3/internal/xxh32"
|
||||
)
|
||||
|
||||
// zResult contains the results of compressing a block.
|
||||
type zResult struct {
|
||||
size uint32 // Block header
|
||||
data []byte // Compressed data
|
||||
checksum uint32 // Data checksum
|
||||
}
|
||||
|
||||
// Writer implements the LZ4 frame encoder.
|
||||
type Writer struct {
|
||||
Header
|
||||
// Handler called when a block has been successfully written out.
|
||||
// It provides the number of bytes written.
|
||||
OnBlockDone func(size int)
|
||||
|
||||
buf [19]byte // magic number(4) + header(flags(2)+[Size(8)+DictID(4)]+checksum(1)) does not exceed 19 bytes
|
||||
dst io.Writer // Destination.
|
||||
checksum xxh32.XXHZero // Frame checksum.
|
||||
data []byte // Data to be compressed + buffer for compressed data.
|
||||
idx int // Index into data.
|
||||
hashtable [winSize]int // Hash table used in CompressBlock().
|
||||
|
||||
// For concurrency.
|
||||
c chan chan zResult // Channel for block compression goroutines and writer goroutine.
|
||||
err error // Any error encountered while writing to the underlying destination.
|
||||
}
|
||||
|
||||
// NewWriter returns a new LZ4 frame encoder.
|
||||
// No access to the underlying io.Writer is performed.
|
||||
// The supplied Header is checked at the first Write.
|
||||
// It is ok to change it before the first Write but then not until a Reset() is performed.
|
||||
func NewWriter(dst io.Writer) *Writer {
|
||||
z := new(Writer)
|
||||
z.Reset(dst)
|
||||
return z
|
||||
}
|
||||
|
||||
// WithConcurrency sets the number of concurrent go routines used for compression.
|
||||
// A negative value sets the concurrency to GOMAXPROCS.
|
||||
func (z *Writer) WithConcurrency(n int) *Writer {
|
||||
switch {
|
||||
case n == 0 || n == 1:
|
||||
z.c = nil
|
||||
return z
|
||||
case n < 0:
|
||||
n = runtime.GOMAXPROCS(0)
|
||||
}
|
||||
z.c = make(chan chan zResult, n)
|
||||
// Writer goroutine managing concurrent block compression goroutines.
|
||||
go func() {
|
||||
// Process next block compression item.
|
||||
for c := range z.c {
|
||||
// Read the next compressed block result.
|
||||
// Waiting here ensures that the blocks are output in the order they were sent.
|
||||
// The incoming channel is always closed as it indicates to the caller that
|
||||
// the block has been processed.
|
||||
res := <-c
|
||||
n := len(res.data)
|
||||
if n == 0 {
|
||||
// Notify the block compression routine that we are done with its result.
|
||||
// This is used when a sentinel block is sent to terminate the compression.
|
||||
close(c)
|
||||
return
|
||||
}
|
||||
// Write the block.
|
||||
if err := z.writeUint32(res.size); err != nil && z.err == nil {
|
||||
z.err = err
|
||||
}
|
||||
if _, err := z.dst.Write(res.data); err != nil && z.err == nil {
|
||||
z.err = err
|
||||
}
|
||||
if z.BlockChecksum {
|
||||
if err := z.writeUint32(res.checksum); err != nil && z.err == nil {
|
||||
z.err = err
|
||||
}
|
||||
}
|
||||
if isCompressed := res.size&compressedBlockFlag == 0; isCompressed {
|
||||
// It is now safe to release the buffer as no longer in use by any goroutine.
|
||||
putBuffer(cap(res.data), res.data)
|
||||
}
|
||||
if h := z.OnBlockDone; h != nil {
|
||||
h(n)
|
||||
}
|
||||
close(c)
|
||||
}
|
||||
}()
|
||||
return z
|
||||
}
|
||||
|
||||
// newBuffers instantiates new buffers which size matches the one in Header.
|
||||
// The returned buffers are for decompression and compression respectively.
|
||||
func (z *Writer) newBuffers() {
|
||||
bSize := z.Header.BlockMaxSize
|
||||
buf := getBuffer(bSize)
|
||||
z.data = buf[:bSize] // Uncompressed buffer is the first half.
|
||||
}
|
||||
|
||||
// freeBuffers puts the writer's buffers back to the pool.
|
||||
func (z *Writer) freeBuffers() {
|
||||
// Put the buffer back into the pool, if any.
|
||||
putBuffer(z.Header.BlockMaxSize, z.data)
|
||||
z.data = nil
|
||||
}
|
||||
|
||||
// writeHeader builds and writes the header (magic+header) to the underlying io.Writer.
|
||||
func (z *Writer) writeHeader() error {
|
||||
// Default to 4Mb if BlockMaxSize is not set.
|
||||
if z.Header.BlockMaxSize == 0 {
|
||||
z.Header.BlockMaxSize = blockSize4M
|
||||
}
|
||||
// The only option that needs to be validated.
|
||||
bSize := z.Header.BlockMaxSize
|
||||
if !isValidBlockSize(z.Header.BlockMaxSize) {
|
||||
return fmt.Errorf("lz4: invalid block max size: %d", bSize)
|
||||
}
|
||||
// Allocate the compressed/uncompressed buffers.
|
||||
// The compressed buffer cannot exceed the uncompressed one.
|
||||
z.newBuffers()
|
||||
z.idx = 0
|
||||
|
||||
// Size is optional.
|
||||
buf := z.buf[:]
|
||||
|
||||
// Set the fixed size data: magic number, block max size and flags.
|
||||
binary.LittleEndian.PutUint32(buf[0:], frameMagic)
|
||||
flg := byte(Version << 6)
|
||||
flg |= 1 << 5 // No block dependency.
|
||||
if z.Header.BlockChecksum {
|
||||
flg |= 1 << 4
|
||||
}
|
||||
if z.Header.Size > 0 {
|
||||
flg |= 1 << 3
|
||||
}
|
||||
if !z.Header.NoChecksum {
|
||||
flg |= 1 << 2
|
||||
}
|
||||
buf[4] = flg
|
||||
buf[5] = blockSizeValueToIndex(z.Header.BlockMaxSize) << 4
|
||||
|
||||
// Current buffer size: magic(4) + flags(1) + block max size (1).
|
||||
n := 6
|
||||
// Optional items.
|
||||
if z.Header.Size > 0 {
|
||||
binary.LittleEndian.PutUint64(buf[n:], z.Header.Size)
|
||||
n += 8
|
||||
}
|
||||
|
||||
// The header checksum includes the flags, block max size and optional Size.
|
||||
buf[n] = byte(xxh32.ChecksumZero(buf[4:n]) >> 8 & 0xFF)
|
||||
z.checksum.Reset()
|
||||
|
||||
// Header ready, write it out.
|
||||
if _, err := z.dst.Write(buf[0 : n+1]); err != nil {
|
||||
return err
|
||||
}
|
||||
z.Header.done = true
|
||||
if debugFlag {
|
||||
debug("wrote header %v", z.Header)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write compresses data from the supplied buffer into the underlying io.Writer.
|
||||
// Write does not return until the data has been written.
|
||||
func (z *Writer) Write(buf []byte) (int, error) {
|
||||
if !z.Header.done {
|
||||
if err := z.writeHeader(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if debugFlag {
|
||||
debug("input buffer len=%d index=%d", len(buf), z.idx)
|
||||
}
|
||||
|
||||
zn := len(z.data)
|
||||
var n int
|
||||
for len(buf) > 0 {
|
||||
if z.idx == 0 && len(buf) >= zn {
|
||||
// Avoid a copy as there is enough data for a block.
|
||||
if err := z.compressBlock(buf[:zn]); err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += zn
|
||||
buf = buf[zn:]
|
||||
continue
|
||||
}
|
||||
// Accumulate the data to be compressed.
|
||||
m := copy(z.data[z.idx:], buf)
|
||||
n += m
|
||||
z.idx += m
|
||||
buf = buf[m:]
|
||||
if debugFlag {
|
||||
debug("%d bytes copied to buf, current index %d", n, z.idx)
|
||||
}
|
||||
|
||||
if z.idx < len(z.data) {
|
||||
// Buffer not filled.
|
||||
if debugFlag {
|
||||
debug("need more data for compression")
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Buffer full.
|
||||
if err := z.compressBlock(z.data); err != nil {
|
||||
return n, err
|
||||
}
|
||||
z.idx = 0
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// compressBlock compresses a block.
|
||||
func (z *Writer) compressBlock(data []byte) error {
|
||||
if !z.NoChecksum {
|
||||
_, _ = z.checksum.Write(data)
|
||||
}
|
||||
|
||||
if z.c != nil {
|
||||
c := make(chan zResult)
|
||||
z.c <- c // Send now to guarantee order
|
||||
go writerCompressBlock(c, z.Header, data)
|
||||
return nil
|
||||
}
|
||||
|
||||
zdata := z.data[z.Header.BlockMaxSize:cap(z.data)]
|
||||
// The compressed block size cannot exceed the input's.
|
||||
var zn int
|
||||
|
||||
if level := z.Header.CompressionLevel; level != 0 {
|
||||
zn, _ = CompressBlockHC(data, zdata, level)
|
||||
} else {
|
||||
zn, _ = CompressBlock(data, zdata, z.hashtable[:])
|
||||
}
|
||||
|
||||
var bLen uint32
|
||||
if debugFlag {
|
||||
debug("block compression %d => %d", len(data), zn)
|
||||
}
|
||||
if zn > 0 && zn < len(data) {
|
||||
// Compressible and compressed size smaller than uncompressed: ok!
|
||||
bLen = uint32(zn)
|
||||
zdata = zdata[:zn]
|
||||
} else {
|
||||
// Uncompressed block.
|
||||
bLen = uint32(len(data)) | compressedBlockFlag
|
||||
zdata = data
|
||||
}
|
||||
if debugFlag {
|
||||
debug("block compression to be written len=%d data len=%d", bLen, len(zdata))
|
||||
}
|
||||
|
||||
// Write the block.
|
||||
if err := z.writeUint32(bLen); err != nil {
|
||||
return err
|
||||
}
|
||||
written, err := z.dst.Write(zdata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if h := z.OnBlockDone; h != nil {
|
||||
h(written)
|
||||
}
|
||||
|
||||
if !z.BlockChecksum {
|
||||
if debugFlag {
|
||||
debug("current frame checksum %x", z.checksum.Sum32())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
checksum := xxh32.ChecksumZero(zdata)
|
||||
if debugFlag {
|
||||
debug("block checksum %x", checksum)
|
||||
defer func() { debug("current frame checksum %x", z.checksum.Sum32()) }()
|
||||
}
|
||||
return z.writeUint32(checksum)
|
||||
}
|
||||
|
||||
// Flush flushes any pending compressed data to the underlying writer.
|
||||
// Flush does not return until the data has been written.
|
||||
// If the underlying writer returns an error, Flush returns that error.
|
||||
func (z *Writer) Flush() error {
|
||||
if debugFlag {
|
||||
debug("flush with index %d", z.idx)
|
||||
}
|
||||
if z.idx == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
data := z.data[:z.idx]
|
||||
z.idx = 0
|
||||
if z.c == nil {
|
||||
return z.compressBlock(data)
|
||||
}
|
||||
if !z.NoChecksum {
|
||||
_, _ = z.checksum.Write(data)
|
||||
}
|
||||
c := make(chan zResult)
|
||||
z.c <- c
|
||||
writerCompressBlock(c, z.Header, data)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (z *Writer) close() error {
|
||||
if z.c == nil {
|
||||
return nil
|
||||
}
|
||||
// Send a sentinel block (no data to compress) to terminate the writer main goroutine.
|
||||
c := make(chan zResult)
|
||||
z.c <- c
|
||||
c <- zResult{}
|
||||
// Wait for the main goroutine to complete.
|
||||
<-c
|
||||
// At this point the main goroutine has shut down or is about to return.
|
||||
z.c = nil
|
||||
return z.err
|
||||
}
|
||||
|
||||
// Close closes the Writer, flushing any unwritten data to the underlying io.Writer, but does not close the underlying io.Writer.
|
||||
func (z *Writer) Close() error {
|
||||
if !z.Header.done {
|
||||
if err := z.writeHeader(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := z.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := z.close(); err != nil {
|
||||
return err
|
||||
}
|
||||
z.freeBuffers()
|
||||
|
||||
if debugFlag {
|
||||
debug("writing last empty block")
|
||||
}
|
||||
if err := z.writeUint32(0); err != nil {
|
||||
return err
|
||||
}
|
||||
if z.NoChecksum {
|
||||
return nil
|
||||
}
|
||||
checksum := z.checksum.Sum32()
|
||||
if debugFlag {
|
||||
debug("stream checksum %x", checksum)
|
||||
}
|
||||
return z.writeUint32(checksum)
|
||||
}
|
||||
|
||||
// Reset clears the state of the Writer z such that it is equivalent to its
|
||||
// initial state from NewWriter, but instead writing to w.
|
||||
// No access to the underlying io.Writer is performed.
|
||||
func (z *Writer) Reset(w io.Writer) {
|
||||
n := cap(z.c)
|
||||
_ = z.close()
|
||||
z.freeBuffers()
|
||||
z.Header.Reset()
|
||||
z.dst = w
|
||||
z.checksum.Reset()
|
||||
z.idx = 0
|
||||
z.err = nil
|
||||
z.WithConcurrency(n)
|
||||
}
|
||||
|
||||
// writeUint32 writes a uint32 to the underlying writer.
|
||||
func (z *Writer) writeUint32(x uint32) error {
|
||||
buf := z.buf[:4]
|
||||
binary.LittleEndian.PutUint32(buf, x)
|
||||
_, err := z.dst.Write(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// writerCompressBlock compresses data into a pooled buffer and writes its result
|
||||
// out to the input channel.
|
||||
func writerCompressBlock(c chan zResult, header Header, data []byte) {
|
||||
zdata := getBuffer(header.BlockMaxSize)
|
||||
// The compressed block size cannot exceed the input's.
|
||||
var zn int
|
||||
if level := header.CompressionLevel; level != 0 {
|
||||
zn, _ = CompressBlockHC(data, zdata, level)
|
||||
} else {
|
||||
var hashTable [winSize]int
|
||||
zn, _ = CompressBlock(data, zdata, hashTable[:])
|
||||
}
|
||||
var res zResult
|
||||
if zn > 0 && zn < len(data) {
|
||||
res.size = uint32(zn)
|
||||
res.data = zdata[:zn]
|
||||
} else {
|
||||
res.size = uint32(len(data)) | compressedBlockFlag
|
||||
res.data = data
|
||||
}
|
||||
if header.BlockChecksum {
|
||||
res.checksum = xxh32.ChecksumZero(res.data)
|
||||
}
|
||||
c <- res
|
||||
}
|
|
@ -1,19 +1,14 @@
|
|||
language: go
|
||||
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
- GO111MODULE=off
|
||||
|
||||
go:
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- master
|
||||
- 1.13.x
|
||||
- 1.14.x
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- go: master
|
||||
|
||||
sudo: false
|
||||
|
0
vendor/github.com/pierrec/lz4/v3/LICENSE → vendor/github.com/pierrec/lz4/v4/LICENSE
generated
vendored
0
vendor/github.com/pierrec/lz4/v3/LICENSE → vendor/github.com/pierrec/lz4/v4/LICENSE
generated
vendored
|
@ -15,7 +15,7 @@ The implementation is based on the reference C [one](https://github.com/lz4/lz4)
|
|||
Assuming you have the go toolchain installed:
|
||||
|
||||
```
|
||||
go get github.com/pierrec/lz4/v3
|
||||
go get github.com/pierrec/lz4
|
||||
```
|
||||
|
||||
There is a command line interface tool to compress and decompress LZ4 files.
|
3
vendor/github.com/pierrec/lz4/v4/go.mod
generated
vendored
Normal file
3
vendor/github.com/pierrec/lz4/v4/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
module github.com/pierrec/lz4/v4
|
||||
|
||||
go 1.14
|
3
vendor/github.com/pierrec/lz4/v4/go.sum
generated
vendored
Normal file
3
vendor/github.com/pierrec/lz4/v4/go.sum
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
github.com/pierrec/lz4 v1.0.1 h1:w6GMGWSsCI04fTM8wQRdnW74MuJISakuUU0onU0TYB4=
|
||||
github.com/pierrec/lz4 v2.6.0+incompatible h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A=
|
||||
github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
|
@ -1,28 +1,46 @@
|
|||
package lz4
|
||||
package lz4block
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math/bits"
|
||||
"sync"
|
||||
|
||||
"github.com/pierrec/lz4/v4/internal/lz4errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// The following constants are used to setup the compression algorithm.
|
||||
minMatch = 4 // the minimum size of the match sequence size (4 bytes)
|
||||
winSizeLog = 16 // LZ4 64Kb window size limit
|
||||
winSize = 1 << winSizeLog
|
||||
winMask = winSize - 1 // 64Kb window of previous data for dependent blocks
|
||||
|
||||
// hashLog determines the size of the hash table used to quickly find a previous match position.
|
||||
// Its value influences the compression speed and memory usage, the lower the faster,
|
||||
// but at the expense of the compression ratio.
|
||||
// 16 seems to be the best compromise for fast compression.
|
||||
hashLog = 16
|
||||
htSize = 1 << hashLog
|
||||
|
||||
mfLimit = 10 + minMatch // The last match cannot start within the last 14 bytes.
|
||||
)
|
||||
|
||||
func recoverBlock(e *error) {
|
||||
if r := recover(); r != nil && *e == nil {
|
||||
*e = lz4errors.ErrInvalidSourceShortBuffer
|
||||
}
|
||||
}
|
||||
|
||||
// blockHash hashes the lower 6 bytes into a value < htSize.
|
||||
func blockHash(x uint64) uint32 {
|
||||
const prime6bytes = 227718039650203
|
||||
return uint32(((x << (64 - 48)) * prime6bytes) >> (64 - hashLog))
|
||||
}
|
||||
|
||||
// CompressBlockBound returns the maximum size of a given buffer of size n, when not compressible.
|
||||
func CompressBlockBound(n int) int {
|
||||
return n + n/255 + 16
|
||||
}
|
||||
|
||||
// UncompressBlock uncompresses the source buffer into the destination one,
|
||||
// and returns the uncompressed size.
|
||||
//
|
||||
// The destination buffer must be sized appropriately.
|
||||
//
|
||||
// An error is returned if the source data is invalid or the destination buffer is too small.
|
||||
func UncompressBlock(src, dst []byte) (int, error) {
|
||||
if len(src) == 0 {
|
||||
return 0, nil
|
||||
|
@ -30,24 +48,57 @@ func UncompressBlock(src, dst []byte) (int, error) {
|
|||
if di := decodeBlock(dst, src); di >= 0 {
|
||||
return di, nil
|
||||
}
|
||||
return 0, ErrInvalidSourceShortBuffer
|
||||
return 0, lz4errors.ErrInvalidSourceShortBuffer
|
||||
}
|
||||
|
||||
// CompressBlock compresses the source buffer into the destination one.
|
||||
// This is the fast version of LZ4 compression and also the default one.
|
||||
//
|
||||
// The argument hashTable is scratch space for a hash table used by the
|
||||
// compressor. If provided, it should have length at least 1<<16. If it is
|
||||
// shorter (or nil), CompressBlock allocates its own hash table.
|
||||
//
|
||||
// The size of the compressed data is returned.
|
||||
//
|
||||
// If the destination buffer size is lower than CompressBlockBound and
|
||||
// the compressed size is 0 and no error, then the data is incompressible.
|
||||
//
|
||||
// An error is returned if the destination buffer is too small.
|
||||
func CompressBlock(src, dst []byte, hashTable []int) (_ int, err error) {
|
||||
defer recoverBlock(&err)
|
||||
type Compressor struct {
|
||||
// Offsets are at most 64kiB, so we can store only the lower 16 bits of
|
||||
// match positions: effectively, an offset from some 64kiB block boundary.
|
||||
//
|
||||
// When we retrieve such an offset, we interpret it as relative to the last
|
||||
// block boundary si &^ 0xffff, or the one before, (si &^ 0xffff) - 0x10000,
|
||||
// depending on which of these is inside the current window. If a table
|
||||
// entry was generated more than 64kiB back in the input, we find out by
|
||||
// inspecting the input stream.
|
||||
table [htSize]uint16
|
||||
|
||||
needsReset bool
|
||||
}
|
||||
|
||||
// Get returns the position of a presumptive match for the hash h.
|
||||
// The match may be a false positive due to a hash collision or an old entry.
|
||||
// If si < winSize, the return value may be negative.
|
||||
func (c *Compressor) get(h uint32, si int) int {
|
||||
h &= htSize - 1
|
||||
i := int(c.table[h])
|
||||
i += si &^ winMask
|
||||
if i >= si {
|
||||
// Try previous 64kiB block (negative when in first block).
|
||||
i -= winSize
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func (c *Compressor) put(h uint32, si int) {
|
||||
h &= htSize - 1
|
||||
c.table[h] = uint16(si)
|
||||
}
|
||||
|
||||
var compressorPool = sync.Pool{New: func() interface{} { return new(Compressor) }}
|
||||
|
||||
func CompressBlock(src, dst []byte) (int, error) {
|
||||
c := compressorPool.Get().(*Compressor)
|
||||
n, err := c.CompressBlock(src, dst)
|
||||
compressorPool.Put(c)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *Compressor) CompressBlock(src, dst []byte) (int, error) {
|
||||
if c.needsReset {
|
||||
// Zero out reused table to avoid non-deterministic output (issue #65).
|
||||
c.table = [htSize]uint16{}
|
||||
}
|
||||
c.needsReset = true // Only false on first call.
|
||||
|
||||
// Return 0, nil only if the destination buffer size is < CompressBlockBound.
|
||||
isNotCompressible := len(dst) < CompressBlockBound(len(src))
|
||||
|
@ -56,14 +107,6 @@ func CompressBlock(src, dst []byte, hashTable []int) (_ int, err error) {
|
|||
// This significantly speeds up incompressible data and usually has very small impact on compression.
|
||||
// bytes to skip = 1 + (bytes since last match >> adaptSkipLog)
|
||||
const adaptSkipLog = 7
|
||||
if len(hashTable) < htSize {
|
||||
htIface := htPool.Get()
|
||||
defer htPool.Put(htIface)
|
||||
hashTable = (*(htIface).(*[htSize]int))[:]
|
||||
}
|
||||
// Prove to the compiler the table has at least htSize elements.
|
||||
// The compiler can see that "uint32() >> hashShift" cannot be out of bounds.
|
||||
hashTable = hashTable[:htSize]
|
||||
|
||||
// si: Current position of the search.
|
||||
// anchor: Position of the current literals.
|
||||
|
@ -82,33 +125,30 @@ func CompressBlock(src, dst []byte, hashTable []int) (_ int, err error) {
|
|||
|
||||
// We check a match at s, s+1 and s+2 and pick the first one we get.
|
||||
// Checking 3 only requires us to load the source one.
|
||||
ref := hashTable[h]
|
||||
ref2 := hashTable[h2]
|
||||
hashTable[h] = si
|
||||
hashTable[h2] = si + 1
|
||||
ref := c.get(h, si)
|
||||
ref2 := c.get(h2, si)
|
||||
c.put(h, si)
|
||||
c.put(h2, si+1)
|
||||
|
||||
offset := si - ref
|
||||
|
||||
// If offset <= 0 we got an old entry in the hash table.
|
||||
if offset <= 0 || offset >= winSize || // Out of window.
|
||||
uint32(match) != binary.LittleEndian.Uint32(src[ref:]) { // Hash collision on different matches.
|
||||
if offset <= 0 || offset >= winSize || uint32(match) != binary.LittleEndian.Uint32(src[ref:]) {
|
||||
// No match. Start calculating another hash.
|
||||
// The processor can usually do this out-of-order.
|
||||
h = blockHash(match >> 16)
|
||||
ref = hashTable[h]
|
||||
ref3 := c.get(h, si+2)
|
||||
|
||||
// Check the second match at si+1
|
||||
si += 1
|
||||
offset = si - ref2
|
||||
|
||||
if offset <= 0 || offset >= winSize ||
|
||||
uint32(match>>8) != binary.LittleEndian.Uint32(src[ref2:]) {
|
||||
if offset <= 0 || offset >= winSize || uint32(match>>8) != binary.LittleEndian.Uint32(src[ref2:]) {
|
||||
// No match. Check the third match at si+2
|
||||
si += 1
|
||||
offset = si - ref
|
||||
hashTable[h] = si
|
||||
offset = si - ref3
|
||||
c.put(h, si)
|
||||
|
||||
if offset <= 0 || offset >= winSize ||
|
||||
uint32(match>>16) != binary.LittleEndian.Uint32(src[ref:]) {
|
||||
if offset <= 0 || offset >= winSize || uint32(match>>16) != binary.LittleEndian.Uint32(src[ref3:]) {
|
||||
// Skip one extra byte (at si+3) before we check 3 matches again.
|
||||
si += 2 + (si-anchor)>>adaptSkipLog
|
||||
continue
|
||||
|
@ -169,20 +209,28 @@ func CompressBlock(src, dst []byte, hashTable []int) (_ int, err error) {
|
|||
di++
|
||||
|
||||
// Literals.
|
||||
if di+lLen > len(dst) {
|
||||
return 0, lz4errors.ErrInvalidSourceShortBuffer
|
||||
}
|
||||
copy(dst[di:di+lLen], src[anchor:anchor+lLen])
|
||||
di += lLen + 2
|
||||
anchor = si
|
||||
|
||||
// Encode offset.
|
||||
_ = dst[di] // Bound check elimination.
|
||||
if di > len(dst) {
|
||||
return 0, lz4errors.ErrInvalidSourceShortBuffer
|
||||
}
|
||||
dst[di-2], dst[di-1] = byte(offset), byte(offset>>8)
|
||||
|
||||
// Encode match length part 2.
|
||||
if mLen >= 0xF {
|
||||
for mLen -= 0xF; mLen >= 0xFF; mLen -= 0xFF {
|
||||
for mLen -= 0xF; mLen >= 0xFF && di < len(dst); mLen -= 0xFF {
|
||||
dst[di] = 0xFF
|
||||
di++
|
||||
}
|
||||
if di >= len(dst) {
|
||||
return 0, lz4errors.ErrInvalidSourceShortBuffer
|
||||
}
|
||||
dst[di] = byte(mLen)
|
||||
di++
|
||||
}
|
||||
|
@ -192,7 +240,7 @@ func CompressBlock(src, dst []byte, hashTable []int) (_ int, err error) {
|
|||
}
|
||||
// Hash match end-2
|
||||
h = blockHash(binary.LittleEndian.Uint64(src[si-2:]))
|
||||
hashTable[h] = si - 2
|
||||
c.put(h, si-2)
|
||||
}
|
||||
|
||||
lastLiterals:
|
||||
|
@ -202,16 +250,22 @@ lastLiterals:
|
|||
}
|
||||
|
||||
// Last literals.
|
||||
if di >= len(dst) {
|
||||
return 0, lz4errors.ErrInvalidSourceShortBuffer
|
||||
}
|
||||
lLen := len(src) - anchor
|
||||
if lLen < 0xF {
|
||||
dst[di] = byte(lLen << 4)
|
||||
} else {
|
||||
dst[di] = 0xF0
|
||||
di++
|
||||
for lLen -= 0xF; lLen >= 0xFF; lLen -= 0xFF {
|
||||
for lLen -= 0xF; lLen >= 0xFF && di < len(dst); lLen -= 0xFF {
|
||||
dst[di] = 0xFF
|
||||
di++
|
||||
}
|
||||
if di >= len(dst) {
|
||||
return 0, lz4errors.ErrInvalidSourceShortBuffer
|
||||
}
|
||||
dst[di] = byte(lLen)
|
||||
}
|
||||
di++
|
||||
|
@ -221,35 +275,43 @@ lastLiterals:
|
|||
// Incompressible.
|
||||
return 0, nil
|
||||
}
|
||||
if di+len(src)-anchor > len(dst) {
|
||||
return 0, lz4errors.ErrInvalidSourceShortBuffer
|
||||
}
|
||||
di += copy(dst[di:di+len(src)-anchor], src[anchor:])
|
||||
return di, nil
|
||||
}
|
||||
|
||||
// Pool of hash tables for CompressBlock.
|
||||
var htPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return new([htSize]int)
|
||||
},
|
||||
}
|
||||
|
||||
// blockHash hashes 4 bytes into a value < winSize.
|
||||
func blockHashHC(x uint32) uint32 {
|
||||
const hasher uint32 = 2654435761 // Knuth multiplicative hash.
|
||||
return x * hasher >> (32 - winSizeLog)
|
||||
}
|
||||
|
||||
// CompressBlockHC compresses the source buffer src into the destination dst
|
||||
// with max search depth (use 0 or negative value for no max).
|
||||
//
|
||||
// CompressBlockHC compression ratio is better than CompressBlock but it is also slower.
|
||||
//
|
||||
// The size of the compressed data is returned.
|
||||
//
|
||||
// If the destination buffer size is lower than CompressBlockBound and
|
||||
// the compressed size is 0 and no error, then the data is incompressible.
|
||||
//
|
||||
// An error is returned if the destination buffer is too small.
|
||||
func CompressBlockHC(src, dst []byte, depth int) (_ int, err error) {
|
||||
type CompressorHC struct {
|
||||
// hashTable: stores the last position found for a given hash
|
||||
// chainTable: stores previous positions for a given hash
|
||||
hashTable, chainTable [htSize]int
|
||||
needsReset bool
|
||||
}
|
||||
|
||||
var compressorHCPool = sync.Pool{New: func() interface{} { return new(CompressorHC) }}
|
||||
|
||||
func CompressBlockHC(src, dst []byte, depth CompressionLevel) (int, error) {
|
||||
c := compressorHCPool.Get().(*CompressorHC)
|
||||
n, err := c.CompressBlock(src, dst, depth)
|
||||
compressorHCPool.Put(c)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *CompressorHC) CompressBlock(src, dst []byte, depth CompressionLevel) (_ int, err error) {
|
||||
if c.needsReset {
|
||||
// Zero out reused table to avoid non-deterministic output (issue #65).
|
||||
c.hashTable = [htSize]int{}
|
||||
c.chainTable = [htSize]int{}
|
||||
}
|
||||
c.needsReset = true // Only false on first call.
|
||||
|
||||
defer recoverBlock(&err)
|
||||
|
||||
// Return 0, nil only if the destination buffer size is < CompressBlockBound.
|
||||
|
@ -261,20 +323,15 @@ func CompressBlockHC(src, dst []byte, depth int) (_ int, err error) {
|
|||
const adaptSkipLog = 7
|
||||
|
||||
var si, di, anchor int
|
||||
|
||||
// hashTable: stores the last position found for a given hash
|
||||
// chainTable: stores previous positions for a given hash
|
||||
var hashTable, chainTable [winSize]int
|
||||
|
||||
if depth <= 0 {
|
||||
depth = winSize
|
||||
}
|
||||
|
||||
sn := len(src) - mfLimit
|
||||
if sn <= 0 {
|
||||
goto lastLiterals
|
||||
}
|
||||
|
||||
if depth == 0 {
|
||||
depth = winSize
|
||||
}
|
||||
|
||||
for si < sn {
|
||||
// Hash the next 4 bytes (sequence).
|
||||
match := binary.LittleEndian.Uint32(src[si:])
|
||||
|
@ -283,7 +340,7 @@ func CompressBlockHC(src, dst []byte, depth int) (_ int, err error) {
|
|||
// Follow the chain until out of window and give the longest match.
|
||||
mLen := 0
|
||||
offset := 0
|
||||
for next, try := hashTable[h], depth; try > 0 && next > 0 && si-next < winSize; next = chainTable[next&winMask] {
|
||||
for next, try := c.hashTable[h], depth; try > 0 && next > 0 && si-next < winSize; next, try = c.chainTable[next&winMask], try-1 {
|
||||
// The first (mLen==0) or next byte (mLen>=minMatch) at current match length
|
||||
// must match to improve on the match length.
|
||||
if src[next+mLen] != src[si+mLen] {
|
||||
|
@ -309,10 +366,9 @@ func CompressBlockHC(src, dst []byte, depth int) (_ int, err error) {
|
|||
mLen = ml
|
||||
offset = si - next
|
||||
// Try another previous position with the same hash.
|
||||
try--
|
||||
}
|
||||
chainTable[si&winMask] = hashTable[h]
|
||||
hashTable[h] = si
|
||||
c.chainTable[si&winMask] = c.hashTable[h]
|
||||
c.hashTable[h] = si
|
||||
|
||||
// No match found.
|
||||
if mLen == 0 {
|
||||
|
@ -331,8 +387,8 @@ func CompressBlockHC(src, dst []byte, depth int) (_ int, err error) {
|
|||
match >>= 8
|
||||
match |= uint32(src[si+3]) << 24
|
||||
h := blockHashHC(match)
|
||||
chainTable[si&winMask] = hashTable[h]
|
||||
hashTable[h] = si
|
||||
c.chainTable[si&winMask] = c.hashTable[h]
|
||||
c.hashTable[h] = si
|
||||
si++
|
||||
}
|
||||
|
88
vendor/github.com/pierrec/lz4/v4/internal/lz4block/blocks.go
generated
vendored
Normal file
88
vendor/github.com/pierrec/lz4/v4/internal/lz4block/blocks.go
generated
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
// Package lz4block provides LZ4 BlockSize types and pools of buffers.
|
||||
package lz4block
|
||||
|
||||
import "sync"
|
||||
|
||||
const (
|
||||
Block64Kb uint32 = 1 << (16 + iota*2)
|
||||
Block256Kb
|
||||
Block1Mb
|
||||
Block4Mb
|
||||
Block8Mb = 2 * Block4Mb
|
||||
legacyBlockSize = Block8Mb + Block8Mb/255 + 16 // CompressBound(Block8Mb)
|
||||
)
|
||||
|
||||
var (
|
||||
BlockPool64K = sync.Pool{New: func() interface{} { return make([]byte, Block64Kb) }}
|
||||
BlockPool256K = sync.Pool{New: func() interface{} { return make([]byte, Block256Kb) }}
|
||||
BlockPool1M = sync.Pool{New: func() interface{} { return make([]byte, Block1Mb) }}
|
||||
BlockPool4M = sync.Pool{New: func() interface{} { return make([]byte, Block4Mb) }}
|
||||
BlockPool8M = sync.Pool{New: func() interface{} { return make([]byte, legacyBlockSize) }}
|
||||
)
|
||||
|
||||
func Index(b uint32) BlockSizeIndex {
|
||||
switch b {
|
||||
case Block64Kb:
|
||||
return 4
|
||||
case Block256Kb:
|
||||
return 5
|
||||
case Block1Mb:
|
||||
return 6
|
||||
case Block4Mb:
|
||||
return 7
|
||||
case Block8Mb: // only valid in legacy mode
|
||||
return 3
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func IsValid(b uint32) bool {
|
||||
return Index(b) > 0
|
||||
}
|
||||
|
||||
type BlockSizeIndex uint8
|
||||
|
||||
func (b BlockSizeIndex) IsValid() bool {
|
||||
switch b {
|
||||
case 4, 5, 6, 7:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b BlockSizeIndex) Get() []byte {
|
||||
var buf interface{}
|
||||
switch b {
|
||||
case 4:
|
||||
buf = BlockPool64K.Get()
|
||||
case 5:
|
||||
buf = BlockPool256K.Get()
|
||||
case 6:
|
||||
buf = BlockPool1M.Get()
|
||||
case 7:
|
||||
buf = BlockPool4M.Get()
|
||||
case 3:
|
||||
buf = BlockPool8M.Get()
|
||||
}
|
||||
return buf.([]byte)
|
||||
}
|
||||
|
||||
func Put(buf []byte) {
|
||||
// Safeguard: do not allow invalid buffers.
|
||||
switch c := cap(buf); uint32(c) {
|
||||
case Block64Kb:
|
||||
BlockPool64K.Put(buf[:c])
|
||||
case Block256Kb:
|
||||
BlockPool256K.Put(buf[:c])
|
||||
case Block1Mb:
|
||||
BlockPool1M.Put(buf[:c])
|
||||
case Block4Mb:
|
||||
BlockPool4M.Put(buf[:c])
|
||||
case legacyBlockSize:
|
||||
BlockPool8M.Put(buf[:c])
|
||||
}
|
||||
}
|
||||
|
||||
type CompressionLevel uint32
|
||||
|
||||
const Fast CompressionLevel = 0
|
|
@ -26,6 +26,8 @@ TEXT ·decodeBlock(SB), NOSPLIT, $64-56
|
|||
|
||||
MOVQ src_base+24(FP), SI
|
||||
MOVQ src_len+32(FP), R9
|
||||
CMPQ R9, $0
|
||||
JE err_corrupt
|
||||
ADDQ SI, R9
|
||||
|
||||
// shortcut ends
|
||||
|
@ -109,8 +111,7 @@ loop:
|
|||
MOVW 16(AX), BX
|
||||
MOVW BX, 16(DI)
|
||||
|
||||
ADDQ $4, DI // minmatch
|
||||
ADDQ CX, DI
|
||||
LEAQ 4(DI)(CX*1), DI // minmatch
|
||||
|
||||
// shortcut complete, load next token
|
||||
JMP loop
|
||||
|
@ -128,8 +129,7 @@ lit_len_loop:
|
|||
JNE lit_len_finalise
|
||||
|
||||
// bounds check src[si+1]
|
||||
MOVQ SI, AX
|
||||
ADDQ $1, AX
|
||||
LEAQ 1(SI), AX
|
||||
CMPQ AX, R9
|
||||
JGT err_short_buf
|
||||
|
||||
|
@ -147,13 +147,11 @@ lit_len_finalise:
|
|||
|
||||
copy_literal:
|
||||
// bounds check src and dst
|
||||
MOVQ SI, AX
|
||||
ADDQ CX, AX
|
||||
LEAQ (SI)(CX*1), AX
|
||||
CMPQ AX, R9
|
||||
JGT err_short_buf
|
||||
|
||||
MOVQ DI, AX
|
||||
ADDQ CX, AX
|
||||
LEAQ (DI)(CX*1), AX
|
||||
CMPQ AX, R8
|
||||
JGT err_short_buf
|
||||
|
||||
|
@ -219,8 +217,7 @@ offset:
|
|||
// free up DX to use for offset
|
||||
MOVQ DX, CX
|
||||
|
||||
MOVQ SI, AX
|
||||
ADDQ $2, AX
|
||||
LEAQ 2(SI), AX
|
||||
CMPQ AX, R9
|
||||
JGT err_short_buf
|
||||
|
||||
|
@ -247,8 +244,7 @@ match_len_loop:
|
|||
JNE match_len_finalise
|
||||
|
||||
// bounds check src[si+1]
|
||||
MOVQ SI, AX
|
||||
ADDQ $1, AX
|
||||
LEAQ 1(SI), AX
|
||||
CMPQ AX, R9
|
||||
JGT err_short_buf
|
||||
|
||||
|
@ -269,8 +265,7 @@ copy_match:
|
|||
|
||||
// check we have match_len bytes left in dst
|
||||
// di+match_len < len(dst)
|
||||
MOVQ DI, AX
|
||||
ADDQ CX, AX
|
||||
LEAQ (DI)(CX*1), AX
|
||||
CMPQ AX, R8
|
||||
JGT err_short_buf
|
||||
|
||||
|
@ -286,8 +281,7 @@ copy_match:
|
|||
JLT err_short_buf
|
||||
|
||||
// if offset + match_len < di
|
||||
MOVQ BX, AX
|
||||
ADDQ CX, AX
|
||||
LEAQ (BX)(CX*1), AX
|
||||
CMPQ DI, AX
|
||||
JGT copy_interior_match
|
||||
|
201
vendor/github.com/pierrec/lz4/v4/internal/lz4block/decode_arm.s
generated
vendored
Normal file
201
vendor/github.com/pierrec/lz4/v4/internal/lz4block/decode_arm.s
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
// +build gc
|
||||
// +build !noasm
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// Register allocation.
|
||||
#define dst R0
|
||||
#define dstorig R1
|
||||
#define src R2
|
||||
#define dstend R3
|
||||
#define srcend R4
|
||||
#define match R5 // Match address.
|
||||
#define token R6
|
||||
#define len R7 // Literal and match lengths.
|
||||
#define offset R6 // Match offset; overlaps with token.
|
||||
#define tmp1 R8
|
||||
#define tmp2 R9
|
||||
#define tmp3 R12
|
||||
|
||||
#define minMatch $4
|
||||
|
||||
// func decodeBlock(dst, src []byte) int
|
||||
TEXT ·decodeBlock(SB), NOFRAME|NOSPLIT, $-4-28
|
||||
MOVW dst_base +0(FP), dst
|
||||
MOVW dst_len +4(FP), dstend
|
||||
MOVW src_base+12(FP), src
|
||||
MOVW src_len +16(FP), srcend
|
||||
|
||||
CMP $0, srcend
|
||||
BEQ shortSrc
|
||||
|
||||
ADD dst, dstend
|
||||
ADD src, srcend
|
||||
|
||||
MOVW dst, dstorig
|
||||
|
||||
loop:
|
||||
// Read token. Extract literal length.
|
||||
MOVBU.P 1(src), token
|
||||
MOVW token >> 4, len
|
||||
CMP $15, len
|
||||
BNE readLitlenDone
|
||||
|
||||
readLitlenLoop:
|
||||
CMP src, srcend
|
||||
BEQ shortSrc
|
||||
MOVBU.P 1(src), tmp1
|
||||
ADD tmp1, len
|
||||
CMP $255, tmp1
|
||||
BEQ readLitlenLoop
|
||||
|
||||
readLitlenDone:
|
||||
CMP $0, len
|
||||
BEQ copyLiteralDone
|
||||
|
||||
// Bounds check dst+len and src+len.
|
||||
ADD dst, len, tmp1
|
||||
CMP dstend, tmp1
|
||||
//BHI shortDst // Uncomment for distinct error codes.
|
||||
ADD src, len, tmp2
|
||||
CMP.LS srcend, tmp2
|
||||
BHI shortSrc
|
||||
|
||||
// Copy literal.
|
||||
CMP $4, len
|
||||
BLO copyLiteralFinish
|
||||
|
||||
// Copy 0-3 bytes until src is aligned.
|
||||
TST $1, src
|
||||
MOVBU.NE.P 1(src), tmp1
|
||||
MOVB.NE.P tmp1, 1(dst)
|
||||
SUB.NE $1, len
|
||||
|
||||
TST $2, src
|
||||
MOVHU.NE.P 2(src), tmp2
|
||||
MOVB.NE.P tmp2, 1(dst)
|
||||
MOVW.NE tmp2 >> 8, tmp1
|
||||
MOVB.NE.P tmp1, 1(dst)
|
||||
SUB.NE $2, len
|
||||
|
||||
B copyLiteralLoopCond
|
||||
|
||||
copyLiteralLoop:
|
||||
// Aligned load, unaligned write.
|
||||
MOVW.P 4(src), tmp1
|
||||
MOVW tmp1 >> 8, tmp2
|
||||
MOVB tmp2, 1(dst)
|
||||
MOVW tmp1 >> 16, tmp3
|
||||
MOVB tmp3, 2(dst)
|
||||
MOVW tmp1 >> 24, tmp2
|
||||
MOVB tmp2, 3(dst)
|
||||
MOVB.P tmp1, 4(dst)
|
||||
copyLiteralLoopCond:
|
||||
// Loop until len-4 < 0.
|
||||
SUB.S $4, len
|
||||
BPL copyLiteralLoop
|
||||
|
||||
// Restore len, which is now negative.
|
||||
ADD $4, len
|
||||
|
||||
copyLiteralFinish:
|
||||
// Copy remaining 0-3 bytes.
|
||||
TST $2, len
|
||||
MOVHU.NE.P 2(src), tmp2
|
||||
MOVB.NE.P tmp2, 1(dst)
|
||||
MOVW.NE tmp2 >> 8, tmp1
|
||||
MOVB.NE.P tmp1, 1(dst)
|
||||
TST $1, len
|
||||
MOVBU.NE.P 1(src), tmp1
|
||||
MOVB.NE.P tmp1, 1(dst)
|
||||
|
||||
copyLiteralDone:
|
||||
CMP src, srcend
|
||||
BEQ end
|
||||
|
||||
// Initial part of match length.
|
||||
// This frees up the token register for reuse as offset.
|
||||
AND $15, token, len
|
||||
|
||||
// Read offset.
|
||||
ADD $2, src
|
||||
CMP srcend, src
|
||||
BHI shortSrc
|
||||
MOVBU -2(src), offset
|
||||
MOVBU -1(src), tmp1
|
||||
ORR tmp1 << 8, offset
|
||||
CMP $0, offset
|
||||
BEQ corrupt
|
||||
|
||||
// Read rest of match length.
|
||||
CMP $15, len
|
||||
BNE readMatchlenDone
|
||||
|
||||
readMatchlenLoop:
|
||||
CMP src, srcend
|
||||
BEQ shortSrc
|
||||
MOVBU.P 1(src), tmp1
|
||||
ADD tmp1, len
|
||||
CMP $255, tmp1
|
||||
BEQ readMatchlenLoop
|
||||
|
||||
readMatchlenDone:
|
||||
ADD minMatch, len
|
||||
|
||||
// Bounds check dst+len and match = dst-offset.
|
||||
ADD dst, len, tmp1
|
||||
CMP dstend, tmp1
|
||||
//BHI shortDst // Uncomment for distinct error codes.
|
||||
SUB offset, dst, match
|
||||
CMP.LS match, dstorig
|
||||
BHI corrupt
|
||||
|
||||
// If the offset is at least four (len is, because of minMatch),
|
||||
// do a four-way unrolled byte copy loop. Using MOVD instead of four
|
||||
// byte loads is much faster, but to remain portable we'd have to
|
||||
// align match first, which in turn is too expensive.
|
||||
CMP $4, offset
|
||||
BLO copyMatch
|
||||
|
||||
SUB $4, len
|
||||
copyMatch4:
|
||||
MOVBU.P 4(match), tmp1
|
||||
MOVB.P tmp1, 4(dst)
|
||||
MOVBU -3(match), tmp2
|
||||
MOVB tmp2, -3(dst)
|
||||
MOVBU -2(match), tmp3
|
||||
MOVB tmp3, -2(dst)
|
||||
MOVBU -1(match), tmp1
|
||||
MOVB tmp1, -1(dst)
|
||||
SUB.S $4, len
|
||||
BPL copyMatch4
|
||||
|
||||
// Restore len, which is now negative.
|
||||
ADD.S $4, len
|
||||
BEQ copyMatchDone
|
||||
|
||||
copyMatch:
|
||||
// Simple byte-at-a-time copy.
|
||||
SUB.S $1, len
|
||||
MOVBU.P 1(match), tmp2
|
||||
MOVB.P tmp2, 1(dst)
|
||||
BNE copyMatch
|
||||
|
||||
copyMatchDone:
|
||||
CMP src, srcend
|
||||
BNE loop
|
||||
|
||||
end:
|
||||
SUB dstorig, dst, tmp1
|
||||
MOVW tmp1, ret+24(FP)
|
||||
RET
|
||||
|
||||
// The three error cases have distinct labels so we can put different
|
||||
// return codes here when debugging, or if the error returns need to
|
||||
// be changed.
|
||||
shortDst:
|
||||
shortSrc:
|
||||
corrupt:
|
||||
MOVW $-1, tmp1
|
||||
MOVW tmp1, ret+24(FP)
|
||||
RET
|
|
@ -1,8 +1,9 @@
|
|||
// +build amd64 arm
|
||||
// +build !appengine
|
||||
// +build gc
|
||||
// +build !noasm
|
||||
|
||||
package lz4
|
||||
package lz4block
|
||||
|
||||
//go:noescape
|
||||
func decodeBlock(dst, src []byte) int
|
|
@ -1,6 +1,6 @@
|
|||
// +build !amd64 appengine !gc noasm
|
||||
// +build !amd64,!arm appengine !gc noasm
|
||||
|
||||
package lz4
|
||||
package lz4block
|
||||
|
||||
func decodeBlock(dst, src []byte) (ret int) {
|
||||
const hasError = -2
|
||||
|
@ -10,16 +10,16 @@ func decodeBlock(dst, src []byte) (ret int) {
|
|||
}
|
||||
}()
|
||||
|
||||
var si, di int
|
||||
var si, di uint
|
||||
for {
|
||||
// Literals and match lengths (token).
|
||||
b := int(src[si])
|
||||
b := uint(src[si])
|
||||
si++
|
||||
|
||||
// Literals.
|
||||
if lLen := b >> 4; lLen > 0 {
|
||||
switch {
|
||||
case lLen < 0xF && si+16 < len(src):
|
||||
case lLen < 0xF && si+16 < uint(len(src)):
|
||||
// Shortcut 1
|
||||
// if we have enough room in src and dst, and the literals length
|
||||
// is small enough (0..14) then copy all 16 bytes, even if not all
|
||||
|
@ -32,13 +32,13 @@ func decodeBlock(dst, src []byte) (ret int) {
|
|||
// if the match length (4..18) fits within the literals, then copy
|
||||
// all 18 bytes, even if not all are part of the literals.
|
||||
mLen += 4
|
||||
if offset := int(src[si]) | int(src[si+1])<<8; mLen <= offset {
|
||||
if offset := uint(src[si]) | uint(src[si+1])<<8; mLen <= offset {
|
||||
i := di - offset
|
||||
end := i + 18
|
||||
if end > len(dst) {
|
||||
if end > uint(len(dst)) {
|
||||
// The remaining buffer may not hold 18 bytes.
|
||||
// See https://github.com/pierrec/lz4/issues/51.
|
||||
end = len(dst)
|
||||
end = uint(len(dst))
|
||||
}
|
||||
copy(dst[di:], dst[i:end])
|
||||
si += 2
|
||||
|
@ -51,7 +51,7 @@ func decodeBlock(dst, src []byte) (ret int) {
|
|||
lLen += 0xFF
|
||||
si++
|
||||
}
|
||||
lLen += int(src[si])
|
||||
lLen += uint(src[si])
|
||||
si++
|
||||
fallthrough
|
||||
default:
|
||||
|
@ -60,11 +60,13 @@ func decodeBlock(dst, src []byte) (ret int) {
|
|||
di += lLen
|
||||
}
|
||||
}
|
||||
if si >= len(src) {
|
||||
return di
|
||||
if si == uint(len(src)) {
|
||||
return int(di)
|
||||
} else if si > uint(len(src)) {
|
||||
return hasError
|
||||
}
|
||||
|
||||
offset := int(src[si]) | int(src[si+1])<<8
|
||||
offset := uint(src[si]) | uint(src[si+1])<<8
|
||||
if offset == 0 {
|
||||
return hasError
|
||||
}
|
||||
|
@ -77,7 +79,7 @@ func decodeBlock(dst, src []byte) (ret int) {
|
|||
mLen += 0xFF
|
||||
si++
|
||||
}
|
||||
mLen += int(src[si])
|
||||
mLen += uint(src[si])
|
||||
si++
|
||||
}
|
||||
mLen += minMatch
|
||||
|
@ -93,6 +95,6 @@ func decodeBlock(dst, src []byte) (ret int) {
|
|||
di += bytesToCopy
|
||||
mLen -= bytesToCopy
|
||||
}
|
||||
di += copy(dst[di:di+mLen], expanded[:mLen])
|
||||
di += uint(copy(dst[di:di+mLen], expanded[:mLen]))
|
||||
}
|
||||
}
|
19
vendor/github.com/pierrec/lz4/v4/internal/lz4errors/errors.go
generated
vendored
Normal file
19
vendor/github.com/pierrec/lz4/v4/internal/lz4errors/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
package lz4errors
|
||||
|
||||
type Error string
|
||||
|
||||
func (e Error) Error() string { return string(e) }
|
||||
|
||||
const (
|
||||
ErrInvalidSourceShortBuffer Error = "lz4: invalid source or destination buffer too short"
|
||||
ErrInvalidFrame Error = "lz4: bad magic number"
|
||||
ErrInternalUnhandledState Error = "lz4: unhandled state"
|
||||
ErrInvalidHeaderChecksum Error = "lz4: invalid header checksum"
|
||||
ErrInvalidBlockChecksum Error = "lz4: invalid block checksum"
|
||||
ErrInvalidFrameChecksum Error = "lz4: invalid frame checksum"
|
||||
ErrOptionInvalidCompressionLevel Error = "lz4: invalid compression level"
|
||||
ErrOptionClosedOrError Error = "lz4: cannot apply options on closed or in error object"
|
||||
ErrOptionInvalidBlockSize Error = "lz4: invalid block size"
|
||||
ErrOptionNotApplicable Error = "lz4: option not applicable"
|
||||
ErrWriterNotClosed Error = "lz4: writer not closed"
|
||||
)
|
331
vendor/github.com/pierrec/lz4/v4/internal/lz4stream/block.go
generated
vendored
Normal file
331
vendor/github.com/pierrec/lz4/v4/internal/lz4stream/block.go
generated
vendored
Normal file
|
@ -0,0 +1,331 @@
|
|||
package lz4stream
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/pierrec/lz4/v4/internal/lz4block"
|
||||
"github.com/pierrec/lz4/v4/internal/lz4errors"
|
||||
"github.com/pierrec/lz4/v4/internal/xxh32"
|
||||
)
|
||||
|
||||
type Blocks struct {
|
||||
Block *FrameDataBlock
|
||||
Blocks chan chan *FrameDataBlock
|
||||
mu sync.Mutex
|
||||
err error
|
||||
}
|
||||
|
||||
func (b *Blocks) initW(f *Frame, dst io.Writer, num int) {
|
||||
if num == 1 {
|
||||
b.Blocks = nil
|
||||
b.Block = NewFrameDataBlock(f)
|
||||
return
|
||||
}
|
||||
b.Block = nil
|
||||
if cap(b.Blocks) != num {
|
||||
b.Blocks = make(chan chan *FrameDataBlock, num)
|
||||
}
|
||||
// goroutine managing concurrent block compression goroutines.
|
||||
go func() {
|
||||
// Process next block compression item.
|
||||
for c := range b.Blocks {
|
||||
// Read the next compressed block result.
|
||||
// Waiting here ensures that the blocks are output in the order they were sent.
|
||||
// The incoming channel is always closed as it indicates to the caller that
|
||||
// the block has been processed.
|
||||
block := <-c
|
||||
if block == nil {
|
||||
// Notify the block compression routine that we are done with its result.
|
||||
// This is used when a sentinel block is sent to terminate the compression.
|
||||
close(c)
|
||||
return
|
||||
}
|
||||
// Do not attempt to write the block upon any previous failure.
|
||||
if b.err == nil {
|
||||
// Write the block.
|
||||
if err := block.Write(f, dst); err != nil {
|
||||
// Keep the first error.
|
||||
b.err = err
|
||||
// All pending compression goroutines need to shut down, so we need to keep going.
|
||||
}
|
||||
}
|
||||
close(c)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (b *Blocks) close(f *Frame, num int) error {
|
||||
if num == 1 {
|
||||
if b.Block != nil {
|
||||
b.Block.Close(f)
|
||||
}
|
||||
err := b.err
|
||||
b.err = nil
|
||||
return err
|
||||
}
|
||||
if b.Blocks == nil {
|
||||
// Not initialized yet.
|
||||
return nil
|
||||
}
|
||||
c := make(chan *FrameDataBlock)
|
||||
b.Blocks <- c
|
||||
c <- nil
|
||||
<-c
|
||||
err := b.err
|
||||
b.err = nil
|
||||
return err
|
||||
}
|
||||
|
||||
// ErrorR returns any error set while uncompressing a stream.
|
||||
func (b *Blocks) ErrorR() error {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
return b.err
|
||||
}
|
||||
|
||||
// initR returns a channel that streams the uncompressed blocks if in concurrent
|
||||
// mode and no error. When the channel is closed, check for any error with b.ErrorR.
|
||||
//
|
||||
// If not in concurrent mode, the uncompressed block is b.Block and the returned error
|
||||
// needs to be checked.
|
||||
func (b *Blocks) initR(f *Frame, num int, src io.Reader) (chan []byte, error) {
|
||||
size := f.Descriptor.Flags.BlockSizeIndex()
|
||||
if num == 1 {
|
||||
b.Blocks = nil
|
||||
b.Block = NewFrameDataBlock(f)
|
||||
return nil, nil
|
||||
}
|
||||
b.Block = nil
|
||||
blocks := make(chan chan []byte, num)
|
||||
// data receives the uncompressed blocks.
|
||||
data := make(chan []byte)
|
||||
// Read blocks from the source sequentially
|
||||
// and uncompress them concurrently.
|
||||
|
||||
// In legacy mode, accrue the uncompress sizes in cum.
|
||||
var cum uint32
|
||||
go func() {
|
||||
var cumx uint32
|
||||
var err error
|
||||
for b.ErrorR() == nil {
|
||||
block := NewFrameDataBlock(f)
|
||||
cumx, err = block.Read(f, src, 0)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
// Recheck for an error as reading may be slow and uncompressing is expensive.
|
||||
if b.ErrorR() != nil {
|
||||
break
|
||||
}
|
||||
c := make(chan []byte)
|
||||
blocks <- c
|
||||
go func() {
|
||||
data, err := block.Uncompress(f, size.Get(), false)
|
||||
if err != nil {
|
||||
b.closeR(err)
|
||||
} else {
|
||||
c <- data
|
||||
}
|
||||
}()
|
||||
}
|
||||
// End the collection loop and the data channel.
|
||||
c := make(chan []byte)
|
||||
blocks <- c
|
||||
c <- nil // signal the collection loop that we are done
|
||||
<-c // wait for the collect loop to complete
|
||||
if f.isLegacy() && cum == cumx {
|
||||
err = io.EOF
|
||||
}
|
||||
b.closeR(err)
|
||||
close(data)
|
||||
}()
|
||||
// Collect the uncompressed blocks and make them available
|
||||
// on the returned channel.
|
||||
go func(leg bool) {
|
||||
defer close(blocks)
|
||||
for c := range blocks {
|
||||
buf := <-c
|
||||
if buf == nil {
|
||||
// Signal to end the loop.
|
||||
close(c)
|
||||
return
|
||||
}
|
||||
// Perform checksum now as the blocks are received in order.
|
||||
if f.Descriptor.Flags.ContentChecksum() {
|
||||
_, _ = f.checksum.Write(buf)
|
||||
}
|
||||
if leg {
|
||||
cum += uint32(len(buf))
|
||||
}
|
||||
data <- buf
|
||||
close(c)
|
||||
}
|
||||
}(f.isLegacy())
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// closeR safely sets the error on b if not already set.
|
||||
func (b *Blocks) closeR(err error) {
|
||||
b.mu.Lock()
|
||||
if b.err == nil {
|
||||
b.err = err
|
||||
}
|
||||
b.mu.Unlock()
|
||||
}
|
||||
|
||||
func NewFrameDataBlock(f *Frame) *FrameDataBlock {
|
||||
buf := f.Descriptor.Flags.BlockSizeIndex().Get()
|
||||
return &FrameDataBlock{Data: buf, data: buf}
|
||||
}
|
||||
|
||||
type FrameDataBlock struct {
|
||||
Size DataBlockSize
|
||||
Data []byte // compressed or uncompressed data (.data or .src)
|
||||
Checksum uint32
|
||||
data []byte // buffer for compressed data
|
||||
src []byte // uncompressed data
|
||||
err error // used in concurrent mode
|
||||
}
|
||||
|
||||
func (b *FrameDataBlock) Close(f *Frame) {
|
||||
b.Size = 0
|
||||
b.Checksum = 0
|
||||
b.err = nil
|
||||
if b.data != nil {
|
||||
// Block was not already closed.
|
||||
lz4block.Put(b.data)
|
||||
b.Data = nil
|
||||
b.data = nil
|
||||
b.src = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Block compression errors are ignored since the buffer is sized appropriately.
|
||||
func (b *FrameDataBlock) Compress(f *Frame, src []byte, level lz4block.CompressionLevel) *FrameDataBlock {
|
||||
data := b.data
|
||||
if f.isLegacy() {
|
||||
data = data[:cap(data)]
|
||||
} else {
|
||||
data = data[:len(src)] // trigger the incompressible flag in CompressBlock
|
||||
}
|
||||
var n int
|
||||
switch level {
|
||||
case lz4block.Fast:
|
||||
n, _ = lz4block.CompressBlock(src, data)
|
||||
default:
|
||||
n, _ = lz4block.CompressBlockHC(src, data, level)
|
||||
}
|
||||
if n == 0 {
|
||||
b.Size.UncompressedSet(true)
|
||||
b.Data = src
|
||||
} else {
|
||||
b.Size.UncompressedSet(false)
|
||||
b.Data = data[:n]
|
||||
}
|
||||
b.Size.sizeSet(len(b.Data))
|
||||
b.src = src // keep track of the source for content checksum
|
||||
|
||||
if f.Descriptor.Flags.BlockChecksum() {
|
||||
b.Checksum = xxh32.ChecksumZero(src)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *FrameDataBlock) Write(f *Frame, dst io.Writer) error {
|
||||
// Write is called in the same order as blocks are compressed,
|
||||
// so content checksum must be done here.
|
||||
if f.Descriptor.Flags.ContentChecksum() {
|
||||
_, _ = f.checksum.Write(b.src)
|
||||
}
|
||||
buf := f.buf[:]
|
||||
binary.LittleEndian.PutUint32(buf, uint32(b.Size))
|
||||
if _, err := dst.Write(buf[:4]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := dst.Write(b.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if b.Checksum == 0 {
|
||||
return nil
|
||||
}
|
||||
binary.LittleEndian.PutUint32(buf, b.Checksum)
|
||||
_, err := dst.Write(buf[:4])
|
||||
return err
|
||||
}
|
||||
|
||||
// Read updates b with the next block data, size and checksum if available.
|
||||
func (b *FrameDataBlock) Read(f *Frame, src io.Reader, cum uint32) (uint32, error) {
|
||||
x, err := f.readUint32(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if f.isLegacy() {
|
||||
switch x {
|
||||
case frameMagicLegacy:
|
||||
// Concatenated legacy frame.
|
||||
return b.Read(f, src, cum)
|
||||
case cum:
|
||||
// Only works in non concurrent mode, for concurrent mode
|
||||
// it is handled separately.
|
||||
// Linux kernel format appends the total uncompressed size at the end.
|
||||
return 0, io.EOF
|
||||
}
|
||||
} else if x == 0 {
|
||||
// Marker for end of stream.
|
||||
return 0, io.EOF
|
||||
}
|
||||
b.Size = DataBlockSize(x)
|
||||
|
||||
size := b.Size.size()
|
||||
if size > cap(b.data) {
|
||||
return x, lz4errors.ErrOptionInvalidBlockSize
|
||||
}
|
||||
b.data = b.data[:size]
|
||||
if _, err := io.ReadFull(src, b.data); err != nil {
|
||||
return x, err
|
||||
}
|
||||
if f.Descriptor.Flags.BlockChecksum() {
|
||||
sum, err := f.readUint32(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
b.Checksum = sum
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
func (b *FrameDataBlock) Uncompress(f *Frame, dst []byte, sum bool) ([]byte, error) {
|
||||
if b.Size.Uncompressed() {
|
||||
n := copy(dst, b.data)
|
||||
dst = dst[:n]
|
||||
} else {
|
||||
n, err := lz4block.UncompressBlock(b.data, dst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dst = dst[:n]
|
||||
}
|
||||
if f.Descriptor.Flags.BlockChecksum() {
|
||||
if c := xxh32.ChecksumZero(dst); c != b.Checksum {
|
||||
err := fmt.Errorf("%w: got %x; expected %x", lz4errors.ErrInvalidBlockChecksum, c, b.Checksum)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if sum && f.Descriptor.Flags.ContentChecksum() {
|
||||
_, _ = f.checksum.Write(dst)
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func (f *Frame) readUint32(r io.Reader) (x uint32, err error) {
|
||||
if _, err = io.ReadFull(r, f.buf[:4]); err != nil {
|
||||
return
|
||||
}
|
||||
x = binary.LittleEndian.Uint32(f.buf[:4])
|
||||
return
|
||||
}
|
200
vendor/github.com/pierrec/lz4/v4/internal/lz4stream/frame.go
generated
vendored
Normal file
200
vendor/github.com/pierrec/lz4/v4/internal/lz4stream/frame.go
generated
vendored
Normal file
|
@ -0,0 +1,200 @@
|
|||
// Package lz4stream provides the types that support reading and writing LZ4 data streams.
|
||||
package lz4stream
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/pierrec/lz4/v4/internal/lz4block"
|
||||
"github.com/pierrec/lz4/v4/internal/lz4errors"
|
||||
"github.com/pierrec/lz4/v4/internal/xxh32"
|
||||
)
|
||||
|
||||
//go:generate go run gen.go
|
||||
|
||||
const (
|
||||
frameMagic uint32 = 0x184D2204
|
||||
frameSkipMagic uint32 = 0x184D2A50
|
||||
frameMagicLegacy uint32 = 0x184C2102
|
||||
)
|
||||
|
||||
func NewFrame() *Frame {
|
||||
return &Frame{}
|
||||
}
|
||||
|
||||
type Frame struct {
|
||||
buf [15]byte // frame descriptor needs at most 4(magic)+4+8+1=11 bytes
|
||||
Magic uint32
|
||||
Descriptor FrameDescriptor
|
||||
Blocks Blocks
|
||||
Checksum uint32
|
||||
checksum xxh32.XXHZero
|
||||
}
|
||||
|
||||
// Reset allows reusing the Frame.
|
||||
// The Descriptor configuration is not modified.
|
||||
func (f *Frame) Reset(num int) {
|
||||
f.Magic = 0
|
||||
f.Descriptor.Checksum = 0
|
||||
f.Descriptor.ContentSize = 0
|
||||
_ = f.Blocks.close(f, num)
|
||||
f.Checksum = 0
|
||||
}
|
||||
|
||||
func (f *Frame) InitW(dst io.Writer, num int, legacy bool) {
|
||||
if legacy {
|
||||
f.Magic = frameMagicLegacy
|
||||
idx := lz4block.Index(lz4block.Block8Mb)
|
||||
f.Descriptor.Flags.BlockSizeIndexSet(idx)
|
||||
} else {
|
||||
f.Magic = frameMagic
|
||||
f.Descriptor.initW()
|
||||
}
|
||||
f.Blocks.initW(f, dst, num)
|
||||
f.checksum.Reset()
|
||||
}
|
||||
|
||||
func (f *Frame) CloseW(dst io.Writer, num int) error {
|
||||
if err := f.Blocks.close(f, num); err != nil {
|
||||
return err
|
||||
}
|
||||
if f.isLegacy() {
|
||||
return nil
|
||||
}
|
||||
buf := f.buf[:0]
|
||||
// End mark (data block size of uint32(0)).
|
||||
buf = append(buf, 0, 0, 0, 0)
|
||||
if f.Descriptor.Flags.ContentChecksum() {
|
||||
buf = f.checksum.Sum(buf)
|
||||
}
|
||||
_, err := dst.Write(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
func (f *Frame) isLegacy() bool {
|
||||
return f.Magic == frameMagicLegacy
|
||||
}
|
||||
|
||||
func (f *Frame) InitR(src io.Reader, num int) (chan []byte, error) {
|
||||
if f.Magic > 0 {
|
||||
// Header already read.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
newFrame:
|
||||
var err error
|
||||
if f.Magic, err = f.readUint32(src); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch m := f.Magic; {
|
||||
case m == frameMagic || m == frameMagicLegacy:
|
||||
// All 16 values of frameSkipMagic are valid.
|
||||
case m>>8 == frameSkipMagic>>8:
|
||||
skip, err := f.readUint32(src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := io.CopyN(ioutil.Discard, src, int64(skip)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
goto newFrame
|
||||
default:
|
||||
return nil, lz4errors.ErrInvalidFrame
|
||||
}
|
||||
if err := f.Descriptor.initR(f, src); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f.checksum.Reset()
|
||||
return f.Blocks.initR(f, num, src)
|
||||
}
|
||||
|
||||
func (f *Frame) CloseR(src io.Reader) (err error) {
|
||||
if f.isLegacy() {
|
||||
return nil
|
||||
}
|
||||
if !f.Descriptor.Flags.ContentChecksum() {
|
||||
return nil
|
||||
}
|
||||
if f.Checksum, err = f.readUint32(src); err != nil {
|
||||
return err
|
||||
}
|
||||
if c := f.checksum.Sum32(); c != f.Checksum {
|
||||
return fmt.Errorf("%w: got %x; expected %x", lz4errors.ErrInvalidFrameChecksum, c, f.Checksum)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type FrameDescriptor struct {
|
||||
Flags DescriptorFlags
|
||||
ContentSize uint64
|
||||
Checksum uint8
|
||||
}
|
||||
|
||||
func (fd *FrameDescriptor) initW() {
|
||||
fd.Flags.VersionSet(1)
|
||||
fd.Flags.BlockIndependenceSet(true)
|
||||
}
|
||||
|
||||
func (fd *FrameDescriptor) Write(f *Frame, dst io.Writer) error {
|
||||
if fd.Checksum > 0 {
|
||||
// Header already written.
|
||||
return nil
|
||||
}
|
||||
|
||||
buf := f.buf[:4]
|
||||
// Write the magic number here even though it belongs to the Frame.
|
||||
binary.LittleEndian.PutUint32(buf, f.Magic)
|
||||
if !f.isLegacy() {
|
||||
buf = buf[:4+2]
|
||||
binary.LittleEndian.PutUint16(buf[4:], uint16(fd.Flags))
|
||||
|
||||
if fd.Flags.Size() {
|
||||
buf = buf[:4+2+8]
|
||||
binary.LittleEndian.PutUint64(buf[4+2:], fd.ContentSize)
|
||||
}
|
||||
fd.Checksum = descriptorChecksum(buf[4:])
|
||||
buf = append(buf, fd.Checksum)
|
||||
}
|
||||
|
||||
_, err := dst.Write(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
func (fd *FrameDescriptor) initR(f *Frame, src io.Reader) error {
|
||||
if f.isLegacy() {
|
||||
idx := lz4block.Index(lz4block.Block8Mb)
|
||||
f.Descriptor.Flags.BlockSizeIndexSet(idx)
|
||||
return nil
|
||||
}
|
||||
// Read the flags and the checksum, hoping that there is not content size.
|
||||
buf := f.buf[:3]
|
||||
if _, err := io.ReadFull(src, buf); err != nil {
|
||||
return err
|
||||
}
|
||||
descr := binary.LittleEndian.Uint16(buf)
|
||||
fd.Flags = DescriptorFlags(descr)
|
||||
if fd.Flags.Size() {
|
||||
// Append the 8 missing bytes.
|
||||
buf = buf[:3+8]
|
||||
if _, err := io.ReadFull(src, buf[3:]); err != nil {
|
||||
return err
|
||||
}
|
||||
fd.ContentSize = binary.LittleEndian.Uint64(buf[2:])
|
||||
}
|
||||
fd.Checksum = buf[len(buf)-1] // the checksum is the last byte
|
||||
buf = buf[:len(buf)-1] // all descriptor fields except checksum
|
||||
if c := descriptorChecksum(buf); fd.Checksum != c {
|
||||
return fmt.Errorf("%w: got %x; expected %x", lz4errors.ErrInvalidHeaderChecksum, c, fd.Checksum)
|
||||
}
|
||||
// Validate the elements that can be.
|
||||
if idx := fd.Flags.BlockSizeIndex(); !idx.IsValid() {
|
||||
return lz4errors.ErrOptionInvalidBlockSize
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func descriptorChecksum(buf []byte) byte {
|
||||
return byte(xxh32.ChecksumZero(buf) >> 8)
|
||||
}
|
103
vendor/github.com/pierrec/lz4/v4/internal/lz4stream/frame_gen.go
generated
vendored
Normal file
103
vendor/github.com/pierrec/lz4/v4/internal/lz4stream/frame_gen.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
// Code generated by `gen.exe`. DO NOT EDIT.
|
||||
|
||||
package lz4stream
|
||||
|
||||
import "github.com/pierrec/lz4/v4/internal/lz4block"
|
||||
|
||||
// DescriptorFlags is defined as follow:
|
||||
// field bits
|
||||
// ----- ----
|
||||
// _ 2
|
||||
// ContentChecksum 1
|
||||
// Size 1
|
||||
// BlockChecksum 1
|
||||
// BlockIndependence 1
|
||||
// Version 2
|
||||
// _ 4
|
||||
// BlockSizeIndex 3
|
||||
// _ 1
|
||||
type DescriptorFlags uint16
|
||||
|
||||
// Getters.
|
||||
func (x DescriptorFlags) ContentChecksum() bool { return x>>2&1 != 0 }
|
||||
func (x DescriptorFlags) Size() bool { return x>>3&1 != 0 }
|
||||
func (x DescriptorFlags) BlockChecksum() bool { return x>>4&1 != 0 }
|
||||
func (x DescriptorFlags) BlockIndependence() bool { return x>>5&1 != 0 }
|
||||
func (x DescriptorFlags) Version() uint16 { return uint16(x >> 6 & 0x3) }
|
||||
func (x DescriptorFlags) BlockSizeIndex() lz4block.BlockSizeIndex {
|
||||
return lz4block.BlockSizeIndex(x >> 12 & 0x7)
|
||||
}
|
||||
|
||||
// Setters.
|
||||
func (x *DescriptorFlags) ContentChecksumSet(v bool) *DescriptorFlags {
|
||||
const b = 1 << 2
|
||||
if v {
|
||||
*x = *x&^b | b
|
||||
} else {
|
||||
*x &^= b
|
||||
}
|
||||
return x
|
||||
}
|
||||
func (x *DescriptorFlags) SizeSet(v bool) *DescriptorFlags {
|
||||
const b = 1 << 3
|
||||
if v {
|
||||
*x = *x&^b | b
|
||||
} else {
|
||||
*x &^= b
|
||||
}
|
||||
return x
|
||||
}
|
||||
func (x *DescriptorFlags) BlockChecksumSet(v bool) *DescriptorFlags {
|
||||
const b = 1 << 4
|
||||
if v {
|
||||
*x = *x&^b | b
|
||||
} else {
|
||||
*x &^= b
|
||||
}
|
||||
return x
|
||||
}
|
||||
func (x *DescriptorFlags) BlockIndependenceSet(v bool) *DescriptorFlags {
|
||||
const b = 1 << 5
|
||||
if v {
|
||||
*x = *x&^b | b
|
||||
} else {
|
||||
*x &^= b
|
||||
}
|
||||
return x
|
||||
}
|
||||
func (x *DescriptorFlags) VersionSet(v uint16) *DescriptorFlags {
|
||||
*x = *x&^(0x3<<6) | (DescriptorFlags(v) & 0x3 << 6)
|
||||
return x
|
||||
}
|
||||
func (x *DescriptorFlags) BlockSizeIndexSet(v lz4block.BlockSizeIndex) *DescriptorFlags {
|
||||
*x = *x&^(0x7<<12) | (DescriptorFlags(v) & 0x7 << 12)
|
||||
return x
|
||||
}
|
||||
|
||||
// Code generated by `gen.exe`. DO NOT EDIT.
|
||||
|
||||
// DataBlockSize is defined as follow:
|
||||
// field bits
|
||||
// ----- ----
|
||||
// size 31
|
||||
// Uncompressed 1
|
||||
type DataBlockSize uint32
|
||||
|
||||
// Getters.
|
||||
func (x DataBlockSize) size() int { return int(x & 0x7FFFFFFF) }
|
||||
func (x DataBlockSize) Uncompressed() bool { return x>>31&1 != 0 }
|
||||
|
||||
// Setters.
|
||||
func (x *DataBlockSize) sizeSet(v int) *DataBlockSize {
|
||||
*x = *x&^0x7FFFFFFF | DataBlockSize(v)&0x7FFFFFFF
|
||||
return x
|
||||
}
|
||||
func (x *DataBlockSize) UncompressedSet(v bool) *DataBlockSize {
|
||||
const b = 1 << 31
|
||||
if v {
|
||||
*x = *x&^b | b
|
||||
} else {
|
||||
*x &^= b
|
||||
}
|
||||
return x
|
||||
}
|
|
@ -20,10 +20,7 @@ const (
|
|||
|
||||
// XXHZero represents an xxhash32 object with seed 0.
|
||||
type XXHZero struct {
|
||||
v1 uint32
|
||||
v2 uint32
|
||||
v3 uint32
|
||||
v4 uint32
|
||||
v [4]uint32
|
||||
totalLen uint64
|
||||
buf [16]byte
|
||||
bufused int
|
||||
|
@ -38,10 +35,10 @@ func (xxh XXHZero) Sum(b []byte) []byte {
|
|||
|
||||
// Reset resets the Hash to its initial state.
|
||||
func (xxh *XXHZero) Reset() {
|
||||
xxh.v1 = prime1plus2
|
||||
xxh.v2 = prime2
|
||||
xxh.v3 = 0
|
||||
xxh.v4 = prime1minus
|
||||
xxh.v[0] = prime1plus2
|
||||
xxh.v[1] = prime2
|
||||
xxh.v[2] = 0
|
||||
xxh.v[3] = prime1minus
|
||||
xxh.totalLen = 0
|
||||
xxh.bufused = 0
|
||||
}
|
||||
|
@ -51,7 +48,7 @@ func (xxh *XXHZero) Size() int {
|
|||
return 4
|
||||
}
|
||||
|
||||
// BlockSize gives the minimum number of bytes accepted by Write().
|
||||
// BlockSizeIndex gives the minimum number of bytes accepted by Write().
|
||||
func (xxh *XXHZero) BlockSize() int {
|
||||
return 1
|
||||
}
|
||||
|
@ -74,44 +71,48 @@ func (xxh *XXHZero) Write(input []byte) (int, error) {
|
|||
return n, nil
|
||||
}
|
||||
|
||||
p := 0
|
||||
// Causes compiler to work directly from registers instead of stack:
|
||||
v1, v2, v3, v4 := xxh.v1, xxh.v2, xxh.v3, xxh.v4
|
||||
if m > 0 {
|
||||
var buf *[16]byte
|
||||
if m != 0 {
|
||||
// some data left from previous update
|
||||
copy(xxh.buf[xxh.bufused:], input[:r])
|
||||
xxh.bufused += len(input) - r
|
||||
buf = &xxh.buf
|
||||
c := copy(buf[m:], input)
|
||||
n -= c
|
||||
input = input[c:]
|
||||
}
|
||||
update(&xxh.v, buf, input)
|
||||
xxh.bufused = copy(xxh.buf[:], input[n-n%16:])
|
||||
|
||||
// fast rotl(13)
|
||||
buf := xxh.buf[:16] // BCE hint.
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Portable version of update. This updates v by processing all of buf
|
||||
// (if not nil) and all full 16-byte blocks of input.
|
||||
func updateGo(v *[4]uint32, buf *[16]byte, input []byte) {
|
||||
// Causes compiler to work directly from registers instead of stack:
|
||||
v1, v2, v3, v4 := v[0], v[1], v[2], v[3]
|
||||
|
||||
if buf != nil {
|
||||
v1 = rol13(v1+binary.LittleEndian.Uint32(buf[:])*prime2) * prime1
|
||||
v2 = rol13(v2+binary.LittleEndian.Uint32(buf[4:])*prime2) * prime1
|
||||
v3 = rol13(v3+binary.LittleEndian.Uint32(buf[8:])*prime2) * prime1
|
||||
v4 = rol13(v4+binary.LittleEndian.Uint32(buf[12:])*prime2) * prime1
|
||||
p = r
|
||||
xxh.bufused = 0
|
||||
}
|
||||
|
||||
for n := n - 16; p <= n; p += 16 {
|
||||
sub := input[p:][:16] //BCE hint for compiler
|
||||
for ; len(input) >= 16; input = input[16:] {
|
||||
sub := input[:16] //BCE hint for compiler
|
||||
v1 = rol13(v1+binary.LittleEndian.Uint32(sub[:])*prime2) * prime1
|
||||
v2 = rol13(v2+binary.LittleEndian.Uint32(sub[4:])*prime2) * prime1
|
||||
v3 = rol13(v3+binary.LittleEndian.Uint32(sub[8:])*prime2) * prime1
|
||||
v4 = rol13(v4+binary.LittleEndian.Uint32(sub[12:])*prime2) * prime1
|
||||
}
|
||||
xxh.v1, xxh.v2, xxh.v3, xxh.v4 = v1, v2, v3, v4
|
||||
|
||||
copy(xxh.buf[xxh.bufused:], input[p:])
|
||||
xxh.bufused += len(input) - p
|
||||
|
||||
return n, nil
|
||||
v[0], v[1], v[2], v[3] = v1, v2, v3, v4
|
||||
}
|
||||
|
||||
// Sum32 returns the 32 bits Hash value.
|
||||
func (xxh *XXHZero) Sum32() uint32 {
|
||||
h32 := uint32(xxh.totalLen)
|
||||
if h32 >= 16 {
|
||||
h32 += rol1(xxh.v1) + rol7(xxh.v2) + rol12(xxh.v3) + rol18(xxh.v4)
|
||||
h32 += rol1(xxh.v[0]) + rol7(xxh.v[1]) + rol12(xxh.v[2]) + rol18(xxh.v[3])
|
||||
} else {
|
||||
h32 += prime5
|
||||
}
|
||||
|
@ -137,8 +138,8 @@ func (xxh *XXHZero) Sum32() uint32 {
|
|||
return h32
|
||||
}
|
||||
|
||||
// ChecksumZero returns the 32bits Hash value.
|
||||
func ChecksumZero(input []byte) uint32 {
|
||||
// Portable version of ChecksumZero.
|
||||
func checksumZeroGo(input []byte) uint32 {
|
||||
n := len(input)
|
||||
h32 := uint32(n)
|
||||
|
||||
|
@ -182,18 +183,6 @@ func ChecksumZero(input []byte) uint32 {
|
|||
return h32
|
||||
}
|
||||
|
||||
// Uint32Zero hashes x with seed 0.
|
||||
func Uint32Zero(x uint32) uint32 {
|
||||
h := prime5 + 4 + x*prime3
|
||||
h = rol17(h) * prime4
|
||||
h ^= h >> 15
|
||||
h *= prime2
|
||||
h ^= h >> 13
|
||||
h *= prime3
|
||||
h ^= h >> 16
|
||||
return h
|
||||
}
|
||||
|
||||
func rol1(u uint32) uint32 {
|
||||
return u<<1 | u>>31
|
||||
}
|
11
vendor/github.com/pierrec/lz4/v4/internal/xxh32/xxh32zero_arm.go
generated
vendored
Normal file
11
vendor/github.com/pierrec/lz4/v4/internal/xxh32/xxh32zero_arm.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
// +build !noasm
|
||||
|
||||
package xxh32
|
||||
|
||||
// ChecksumZero returns the 32-bit hash of input.
|
||||
//
|
||||
//go:noescape
|
||||
func ChecksumZero(input []byte) uint32
|
||||
|
||||
//go:noescape
|
||||
func update(v *[4]uint32, buf *[16]byte, input []byte)
|
259
vendor/github.com/pierrec/lz4/v4/internal/xxh32/xxh32zero_arm.s
generated
vendored
Normal file
259
vendor/github.com/pierrec/lz4/v4/internal/xxh32/xxh32zero_arm.s
generated
vendored
Normal file
|
@ -0,0 +1,259 @@
|
|||
// +build !noasm
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
#define prime1 $2654435761
|
||||
#define prime2 $2246822519
|
||||
#define prime3 $3266489917
|
||||
#define prime4 $668265263
|
||||
#define prime5 $374761393
|
||||
|
||||
#define prime1plus2 $606290984
|
||||
#define prime1minus $1640531535
|
||||
|
||||
// Register allocation.
|
||||
#define p R0
|
||||
#define n R1
|
||||
#define h R2
|
||||
#define v1 R2 // Alias for h.
|
||||
#define v2 R3
|
||||
#define v3 R4
|
||||
#define v4 R5
|
||||
#define x1 R6
|
||||
#define x2 R7
|
||||
#define x3 R8
|
||||
#define x4 R9
|
||||
|
||||
// We need the primes in registers. The 16-byte loop only uses prime{1,2}.
|
||||
#define prime1r R11
|
||||
#define prime2r R12
|
||||
#define prime3r R3 // The rest can alias v{2-4}.
|
||||
#define prime4r R4
|
||||
#define prime5r R5
|
||||
|
||||
// Update round macros. These read from and increment p.
|
||||
|
||||
#define round16aligned \
|
||||
MOVM.IA.W (p), [x1, x2, x3, x4] \
|
||||
\
|
||||
MULA x1, prime2r, v1, v1 \
|
||||
MULA x2, prime2r, v2, v2 \
|
||||
MULA x3, prime2r, v3, v3 \
|
||||
MULA x4, prime2r, v4, v4 \
|
||||
\
|
||||
MOVW v1 @> 19, v1 \
|
||||
MOVW v2 @> 19, v2 \
|
||||
MOVW v3 @> 19, v3 \
|
||||
MOVW v4 @> 19, v4 \
|
||||
\
|
||||
MUL prime1r, v1 \
|
||||
MUL prime1r, v2 \
|
||||
MUL prime1r, v3 \
|
||||
MUL prime1r, v4 \
|
||||
|
||||
#define round16unaligned \
|
||||
MOVBU.P 16(p), x1 \
|
||||
MOVBU -15(p), x2 \
|
||||
ORR x2 << 8, x1 \
|
||||
MOVBU -14(p), x3 \
|
||||
MOVBU -13(p), x4 \
|
||||
ORR x4 << 8, x3 \
|
||||
ORR x3 << 16, x1 \
|
||||
\
|
||||
MULA x1, prime2r, v1, v1 \
|
||||
MOVW v1 @> 19, v1 \
|
||||
MUL prime1r, v1 \
|
||||
\
|
||||
MOVBU -12(p), x1 \
|
||||
MOVBU -11(p), x2 \
|
||||
ORR x2 << 8, x1 \
|
||||
MOVBU -10(p), x3 \
|
||||
MOVBU -9(p), x4 \
|
||||
ORR x4 << 8, x3 \
|
||||
ORR x3 << 16, x1 \
|
||||
\
|
||||
MULA x1, prime2r, v2, v2 \
|
||||
MOVW v2 @> 19, v2 \
|
||||
MUL prime1r, v2 \
|
||||
\
|
||||
MOVBU -8(p), x1 \
|
||||
MOVBU -7(p), x2 \
|
||||
ORR x2 << 8, x1 \
|
||||
MOVBU -6(p), x3 \
|
||||
MOVBU -5(p), x4 \
|
||||
ORR x4 << 8, x3 \
|
||||
ORR x3 << 16, x1 \
|
||||
\
|
||||
MULA x1, prime2r, v3, v3 \
|
||||
MOVW v3 @> 19, v3 \
|
||||
MUL prime1r, v3 \
|
||||
\
|
||||
MOVBU -4(p), x1 \
|
||||
MOVBU -3(p), x2 \
|
||||
ORR x2 << 8, x1 \
|
||||
MOVBU -2(p), x3 \
|
||||
MOVBU -1(p), x4 \
|
||||
ORR x4 << 8, x3 \
|
||||
ORR x3 << 16, x1 \
|
||||
\
|
||||
MULA x1, prime2r, v4, v4 \
|
||||
MOVW v4 @> 19, v4 \
|
||||
MUL prime1r, v4 \
|
||||
|
||||
|
||||
// func ChecksumZero([]byte) uint32
|
||||
TEXT ·ChecksumZero(SB), NOFRAME|NOSPLIT, $-4-16
|
||||
MOVW input_base+0(FP), p
|
||||
MOVW input_len+4(FP), n
|
||||
|
||||
MOVW prime1, prime1r
|
||||
MOVW prime2, prime2r
|
||||
|
||||
// Set up h for n < 16. It's tempting to say {ADD prime5, n, h}
|
||||
// here, but that's a pseudo-op that generates a load through R11.
|
||||
MOVW prime5, prime5r
|
||||
ADD prime5r, n, h
|
||||
CMP $0, n
|
||||
BEQ end
|
||||
|
||||
// We let n go negative so we can do comparisons with SUB.S
|
||||
// instead of separate CMP.
|
||||
SUB.S $16, n
|
||||
BMI loop16done
|
||||
|
||||
MOVW prime1plus2, v1
|
||||
MOVW prime2, v2
|
||||
MOVW $0, v3
|
||||
MOVW prime1minus, v4
|
||||
|
||||
TST $3, p
|
||||
BNE loop16unaligned
|
||||
|
||||
loop16aligned:
|
||||
SUB.S $16, n
|
||||
round16aligned
|
||||
BPL loop16aligned
|
||||
B loop16finish
|
||||
|
||||
loop16unaligned:
|
||||
SUB.S $16, n
|
||||
round16unaligned
|
||||
BPL loop16unaligned
|
||||
|
||||
loop16finish:
|
||||
MOVW v1 @> 31, h
|
||||
ADD v2 @> 25, h
|
||||
ADD v3 @> 20, h
|
||||
ADD v4 @> 14, h
|
||||
|
||||
// h += len(input) with v2 as temporary.
|
||||
MOVW input_len+4(FP), v2
|
||||
ADD v2, h
|
||||
|
||||
loop16done:
|
||||
ADD $16, n // Restore number of bytes left.
|
||||
|
||||
SUB.S $4, n
|
||||
MOVW prime3, prime3r
|
||||
BMI loop4done
|
||||
MOVW prime4, prime4r
|
||||
|
||||
TST $3, p
|
||||
BNE loop4unaligned
|
||||
|
||||
loop4aligned:
|
||||
SUB.S $4, n
|
||||
|
||||
MOVW.P 4(p), x1
|
||||
MULA prime3r, x1, h, h
|
||||
MOVW h @> 15, h
|
||||
MUL prime4r, h
|
||||
|
||||
BPL loop4aligned
|
||||
B loop4done
|
||||
|
||||
loop4unaligned:
|
||||
SUB.S $4, n
|
||||
|
||||
MOVBU.P 4(p), x1
|
||||
MOVBU -3(p), x2
|
||||
ORR x2 << 8, x1
|
||||
MOVBU -2(p), x3
|
||||
ORR x3 << 16, x1
|
||||
MOVBU -1(p), x4
|
||||
ORR x4 << 24, x1
|
||||
|
||||
MULA prime3r, x1, h, h
|
||||
MOVW h @> 15, h
|
||||
MUL prime4r, h
|
||||
|
||||
BPL loop4unaligned
|
||||
|
||||
loop4done:
|
||||
ADD.S $4, n // Restore number of bytes left.
|
||||
BEQ end
|
||||
|
||||
MOVW prime5, prime5r
|
||||
|
||||
loop1:
|
||||
SUB.S $1, n
|
||||
|
||||
MOVBU.P 1(p), x1
|
||||
MULA prime5r, x1, h, h
|
||||
MOVW h @> 21, h
|
||||
MUL prime1r, h
|
||||
|
||||
BNE loop1
|
||||
|
||||
end:
|
||||
MOVW prime3, prime3r
|
||||
EOR h >> 15, h
|
||||
MUL prime2r, h
|
||||
EOR h >> 13, h
|
||||
MUL prime3r, h
|
||||
EOR h >> 16, h
|
||||
|
||||
MOVW h, ret+12(FP)
|
||||
RET
|
||||
|
||||
|
||||
// func update(v *[4]uint64, buf *[16]byte, p []byte)
|
||||
TEXT ·update(SB), NOFRAME|NOSPLIT, $-4-20
|
||||
MOVW v+0(FP), p
|
||||
MOVM.IA (p), [v1, v2, v3, v4]
|
||||
|
||||
MOVW prime1, prime1r
|
||||
MOVW prime2, prime2r
|
||||
|
||||
// Process buf, if not nil.
|
||||
MOVW buf+4(FP), p
|
||||
CMP $0, p
|
||||
BEQ noBuffered
|
||||
|
||||
round16aligned
|
||||
|
||||
noBuffered:
|
||||
MOVW input_base +8(FP), p
|
||||
MOVW input_len +12(FP), n
|
||||
|
||||
SUB.S $16, n
|
||||
BMI end
|
||||
|
||||
TST $3, p
|
||||
BNE loop16unaligned
|
||||
|
||||
loop16aligned:
|
||||
SUB.S $16, n
|
||||
round16aligned
|
||||
BPL loop16aligned
|
||||
B end
|
||||
|
||||
loop16unaligned:
|
||||
SUB.S $16, n
|
||||
round16unaligned
|
||||
BPL loop16unaligned
|
||||
|
||||
end:
|
||||
MOVW v+0(FP), p
|
||||
MOVM.IA [v1, v2, v3, v4], (p)
|
||||
RET
|
10
vendor/github.com/pierrec/lz4/v4/internal/xxh32/xxh32zero_other.go
generated
vendored
Normal file
10
vendor/github.com/pierrec/lz4/v4/internal/xxh32/xxh32zero_other.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
// +build !arm noasm
|
||||
|
||||
package xxh32
|
||||
|
||||
// ChecksumZero returns the 32-bit hash of input.
|
||||
func ChecksumZero(input []byte) uint32 { return checksumZeroGo(input) }
|
||||
|
||||
func update(v *[4]uint32, buf *[16]byte, input []byte) {
|
||||
updateGo(v, buf, input)
|
||||
}
|
147
vendor/github.com/pierrec/lz4/v4/lz4.go
generated
vendored
Normal file
147
vendor/github.com/pierrec/lz4/v4/lz4.go
generated
vendored
Normal file
|
@ -0,0 +1,147 @@
|
|||
// Package lz4 implements reading and writing lz4 compressed data.
|
||||
//
|
||||
// The package supports both the LZ4 stream format,
|
||||
// as specified in http://fastcompression.blogspot.fr/2013/04/lz4-streaming-format-final.html,
|
||||
// and the LZ4 block format, defined at
|
||||
// http://fastcompression.blogspot.fr/2011/05/lz4-explained.html.
|
||||
//
|
||||
// See https://github.com/lz4/lz4 for the reference C implementation.
|
||||
package lz4
|
||||
|
||||
import (
|
||||
"github.com/pierrec/lz4/v4/internal/lz4block"
|
||||
"github.com/pierrec/lz4/v4/internal/lz4errors"
|
||||
)
|
||||
|
||||
func _() {
|
||||
// Safety checks for duplicated elements.
|
||||
var x [1]struct{}
|
||||
_ = x[lz4block.CompressionLevel(Fast)-lz4block.Fast]
|
||||
_ = x[Block64Kb-BlockSize(lz4block.Block64Kb)]
|
||||
_ = x[Block256Kb-BlockSize(lz4block.Block256Kb)]
|
||||
_ = x[Block1Mb-BlockSize(lz4block.Block1Mb)]
|
||||
_ = x[Block4Mb-BlockSize(lz4block.Block4Mb)]
|
||||
}
|
||||
|
||||
// CompressBlockBound returns the maximum size of a given buffer of size n, when not compressible.
|
||||
func CompressBlockBound(n int) int {
|
||||
return lz4block.CompressBlockBound(n)
|
||||
}
|
||||
|
||||
// UncompressBlock uncompresses the source buffer into the destination one,
|
||||
// and returns the uncompressed size.
|
||||
//
|
||||
// The destination buffer must be sized appropriately.
|
||||
//
|
||||
// An error is returned if the source data is invalid or the destination buffer is too small.
|
||||
func UncompressBlock(src, dst []byte) (int, error) {
|
||||
return lz4block.UncompressBlock(src, dst)
|
||||
}
|
||||
|
||||
// A Compressor compresses data into the LZ4 block format.
|
||||
// It uses a fast compression algorithm.
|
||||
//
|
||||
// A Compressor is not safe for concurrent use by multiple goroutines.
|
||||
//
|
||||
// Use a Writer to compress into the LZ4 stream format.
|
||||
type Compressor struct{ c lz4block.Compressor }
|
||||
|
||||
// CompressBlock compresses the source buffer src into the destination dst.
|
||||
//
|
||||
// If compression is successful, the first return value is the size of the
|
||||
// compressed data, which is always >0.
|
||||
//
|
||||
// If dst has length at least CompressBlockBound(len(src)), compression always
|
||||
// succeeds. Otherwise, the first return value is zero. The error return is
|
||||
// non-nil if the compressed data does not fit in dst, but it might fit in a
|
||||
// larger buffer that is still smaller than CompressBlockBound(len(src)). The
|
||||
// return value (0, nil) means the data is likely incompressible and a buffer
|
||||
// of length CompressBlockBound(len(src)) should be passed in.
|
||||
func (c *Compressor) CompressBlock(src, dst []byte) (int, error) {
|
||||
return c.c.CompressBlock(src, dst)
|
||||
}
|
||||
|
||||
// CompressBlock compresses the source buffer into the destination one.
|
||||
// This is the fast version of LZ4 compression and also the default one.
|
||||
//
|
||||
// The argument hashTable is scratch space for a hash table used by the
|
||||
// compressor. If provided, it should have length at least 1<<16. If it is
|
||||
// shorter (or nil), CompressBlock allocates its own hash table.
|
||||
//
|
||||
// The size of the compressed data is returned.
|
||||
//
|
||||
// If the destination buffer size is lower than CompressBlockBound and
|
||||
// the compressed size is 0 and no error, then the data is incompressible.
|
||||
//
|
||||
// An error is returned if the destination buffer is too small.
|
||||
|
||||
// CompressBlock is equivalent to Compressor.CompressBlock.
|
||||
// The final argument is ignored and should be set to nil.
|
||||
//
|
||||
// This function is deprecated. Use a Compressor instead.
|
||||
func CompressBlock(src, dst []byte, _ []int) (int, error) {
|
||||
return lz4block.CompressBlock(src, dst)
|
||||
}
|
||||
|
||||
// A CompressorHC compresses data into the LZ4 block format.
|
||||
// Its compression ratio is potentially better than that of a Compressor,
|
||||
// but it is also slower and requires more memory.
|
||||
//
|
||||
// A Compressor is not safe for concurrent use by multiple goroutines.
|
||||
//
|
||||
// Use a Writer to compress into the LZ4 stream format.
|
||||
type CompressorHC struct {
|
||||
// Level is the maximum search depth for compression.
|
||||
// Values <= 0 mean no maximum.
|
||||
Level CompressionLevel
|
||||
c lz4block.CompressorHC
|
||||
}
|
||||
|
||||
// CompressBlock compresses the source buffer src into the destination dst.
|
||||
//
|
||||
// If compression is successful, the first return value is the size of the
|
||||
// compressed data, which is always >0.
|
||||
//
|
||||
// If dst has length at least CompressBlockBound(len(src)), compression always
|
||||
// succeeds. Otherwise, the first return value is zero. The error return is
|
||||
// non-nil if the compressed data does not fit in dst, but it might fit in a
|
||||
// larger buffer that is still smaller than CompressBlockBound(len(src)). The
|
||||
// return value (0, nil) means the data is likely incompressible and a buffer
|
||||
// of length CompressBlockBound(len(src)) should be passed in.
|
||||
func (c *CompressorHC) CompressBlock(src, dst []byte) (int, error) {
|
||||
return c.c.CompressBlock(src, dst, lz4block.CompressionLevel(c.Level))
|
||||
}
|
||||
|
||||
// CompressBlockHC is equivalent to CompressorHC.CompressBlock.
|
||||
// The final two arguments are ignored and should be set to nil.
|
||||
//
|
||||
// This function is deprecated. Use a CompressorHC instead.
|
||||
func CompressBlockHC(src, dst []byte, depth CompressionLevel, _, _ []int) (int, error) {
|
||||
return lz4block.CompressBlockHC(src, dst, lz4block.CompressionLevel(depth))
|
||||
}
|
||||
|
||||
const (
|
||||
// ErrInvalidSourceShortBuffer is returned by UncompressBlock or CompressBLock when a compressed
|
||||
// block is corrupted or the destination buffer is not large enough for the uncompressed data.
|
||||
ErrInvalidSourceShortBuffer = lz4errors.ErrInvalidSourceShortBuffer
|
||||
// ErrInvalidFrame is returned when reading an invalid LZ4 archive.
|
||||
ErrInvalidFrame = lz4errors.ErrInvalidFrame
|
||||
// ErrInternalUnhandledState is an internal error.
|
||||
ErrInternalUnhandledState = lz4errors.ErrInternalUnhandledState
|
||||
// ErrInvalidHeaderChecksum is returned when reading a frame.
|
||||
ErrInvalidHeaderChecksum = lz4errors.ErrInvalidHeaderChecksum
|
||||
// ErrInvalidBlockChecksum is returned when reading a frame.
|
||||
ErrInvalidBlockChecksum = lz4errors.ErrInvalidBlockChecksum
|
||||
// ErrInvalidFrameChecksum is returned when reading a frame.
|
||||
ErrInvalidFrameChecksum = lz4errors.ErrInvalidFrameChecksum
|
||||
// ErrOptionInvalidCompressionLevel is returned when the supplied compression level is invalid.
|
||||
ErrOptionInvalidCompressionLevel = lz4errors.ErrOptionInvalidCompressionLevel
|
||||
// ErrOptionClosedOrError is returned when an option is applied to a closed or in error object.
|
||||
ErrOptionClosedOrError = lz4errors.ErrOptionClosedOrError
|
||||
// ErrOptionInvalidBlockSize is returned when
|
||||
ErrOptionInvalidBlockSize = lz4errors.ErrOptionInvalidBlockSize
|
||||
// ErrOptionNotApplicable is returned when trying to apply an option to an object not supporting it.
|
||||
ErrOptionNotApplicable = lz4errors.ErrOptionNotApplicable
|
||||
// ErrWriterNotClosed is returned when attempting to reset an unclosed writer.
|
||||
ErrWriterNotClosed = lz4errors.ErrWriterNotClosed
|
||||
)
|
213
vendor/github.com/pierrec/lz4/v4/options.go
generated
vendored
Normal file
213
vendor/github.com/pierrec/lz4/v4/options.go
generated
vendored
Normal file
|
@ -0,0 +1,213 @@
|
|||
package lz4
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pierrec/lz4/v4/internal/lz4block"
|
||||
"github.com/pierrec/lz4/v4/internal/lz4errors"
|
||||
"reflect"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
//go:generate go run golang.org/x/tools/cmd/stringer -type=BlockSize,CompressionLevel -output options_gen.go
|
||||
|
||||
type (
|
||||
applier interface {
|
||||
Apply(...Option) error
|
||||
private()
|
||||
}
|
||||
// Option defines the parameters to setup an LZ4 Writer or Reader.
|
||||
Option func(applier) error
|
||||
)
|
||||
|
||||
// String returns a string representation of the option with its parameter(s).
|
||||
func (o Option) String() string {
|
||||
return o(nil).Error()
|
||||
}
|
||||
|
||||
// Default options.
|
||||
var (
|
||||
DefaultBlockSizeOption = BlockSizeOption(Block4Mb)
|
||||
DefaultChecksumOption = ChecksumOption(true)
|
||||
DefaultConcurrency = ConcurrencyOption(1)
|
||||
defaultOnBlockDone = OnBlockDoneOption(nil)
|
||||
)
|
||||
|
||||
const (
|
||||
Block64Kb BlockSize = 1 << (16 + iota*2)
|
||||
Block256Kb
|
||||
Block1Mb
|
||||
Block4Mb
|
||||
)
|
||||
|
||||
// BlockSizeIndex defines the size of the blocks to be compressed.
|
||||
type BlockSize uint32
|
||||
|
||||
// BlockSizeOption defines the maximum size of compressed blocks (default=Block4Mb).
|
||||
func BlockSizeOption(size BlockSize) Option {
|
||||
return func(a applier) error {
|
||||
switch w := a.(type) {
|
||||
case nil:
|
||||
s := fmt.Sprintf("BlockSizeOption(%s)", size)
|
||||
return lz4errors.Error(s)
|
||||
case *Writer:
|
||||
size := uint32(size)
|
||||
if !lz4block.IsValid(size) {
|
||||
return fmt.Errorf("%w: %d", lz4errors.ErrOptionInvalidBlockSize, size)
|
||||
}
|
||||
w.frame.Descriptor.Flags.BlockSizeIndexSet(lz4block.Index(size))
|
||||
return nil
|
||||
}
|
||||
return lz4errors.ErrOptionNotApplicable
|
||||
}
|
||||
}
|
||||
|
||||
// BlockChecksumOption enables or disables block checksum (default=false).
|
||||
func BlockChecksumOption(flag bool) Option {
|
||||
return func(a applier) error {
|
||||
switch w := a.(type) {
|
||||
case nil:
|
||||
s := fmt.Sprintf("BlockChecksumOption(%v)", flag)
|
||||
return lz4errors.Error(s)
|
||||
case *Writer:
|
||||
w.frame.Descriptor.Flags.BlockChecksumSet(flag)
|
||||
return nil
|
||||
}
|
||||
return lz4errors.ErrOptionNotApplicable
|
||||
}
|
||||
}
|
||||
|
||||
// ChecksumOption enables/disables all blocks or content checksum (default=true).
|
||||
func ChecksumOption(flag bool) Option {
|
||||
return func(a applier) error {
|
||||
switch w := a.(type) {
|
||||
case nil:
|
||||
s := fmt.Sprintf("ChecksumOption(%v)", flag)
|
||||
return lz4errors.Error(s)
|
||||
case *Writer:
|
||||
w.frame.Descriptor.Flags.ContentChecksumSet(flag)
|
||||
return nil
|
||||
}
|
||||
return lz4errors.ErrOptionNotApplicable
|
||||
}
|
||||
}
|
||||
|
||||
// SizeOption sets the size of the original uncompressed data (default=0). It is useful to know the size of the
|
||||
// whole uncompressed data stream.
|
||||
func SizeOption(size uint64) Option {
|
||||
return func(a applier) error {
|
||||
switch w := a.(type) {
|
||||
case nil:
|
||||
s := fmt.Sprintf("SizeOption(%d)", size)
|
||||
return lz4errors.Error(s)
|
||||
case *Writer:
|
||||
w.frame.Descriptor.Flags.SizeSet(size > 0)
|
||||
w.frame.Descriptor.ContentSize = size
|
||||
return nil
|
||||
}
|
||||
return lz4errors.ErrOptionNotApplicable
|
||||
}
|
||||
}
|
||||
|
||||
// ConcurrencyOption sets the number of go routines used for compression.
|
||||
// If n <= 0, then the output of runtime.GOMAXPROCS(0) is used.
|
||||
func ConcurrencyOption(n int) Option {
|
||||
if n <= 0 {
|
||||
n = runtime.GOMAXPROCS(0)
|
||||
}
|
||||
return func(a applier) error {
|
||||
switch rw := a.(type) {
|
||||
case nil:
|
||||
s := fmt.Sprintf("ConcurrencyOption(%d)", n)
|
||||
return lz4errors.Error(s)
|
||||
case *Writer:
|
||||
rw.num = n
|
||||
return nil
|
||||
case *Reader:
|
||||
rw.num = n
|
||||
return nil
|
||||
}
|
||||
return lz4errors.ErrOptionNotApplicable
|
||||
}
|
||||
}
|
||||
|
||||
// CompressionLevel defines the level of compression to use. The higher the better, but slower, compression.
|
||||
type CompressionLevel uint32
|
||||
|
||||
const (
|
||||
Fast CompressionLevel = 0
|
||||
Level1 CompressionLevel = 1 << (8 + iota)
|
||||
Level2
|
||||
Level3
|
||||
Level4
|
||||
Level5
|
||||
Level6
|
||||
Level7
|
||||
Level8
|
||||
Level9
|
||||
)
|
||||
|
||||
// CompressionLevelOption defines the compression level (default=Fast).
|
||||
func CompressionLevelOption(level CompressionLevel) Option {
|
||||
return func(a applier) error {
|
||||
switch w := a.(type) {
|
||||
case nil:
|
||||
s := fmt.Sprintf("CompressionLevelOption(%s)", level)
|
||||
return lz4errors.Error(s)
|
||||
case *Writer:
|
||||
switch level {
|
||||
case Fast, Level1, Level2, Level3, Level4, Level5, Level6, Level7, Level8, Level9:
|
||||
default:
|
||||
return fmt.Errorf("%w: %d", lz4errors.ErrOptionInvalidCompressionLevel, level)
|
||||
}
|
||||
w.level = lz4block.CompressionLevel(level)
|
||||
return nil
|
||||
}
|
||||
return lz4errors.ErrOptionNotApplicable
|
||||
}
|
||||
}
|
||||
|
||||
func onBlockDone(int) {}
|
||||
|
||||
// OnBlockDoneOption is triggered when a block has been processed. For a Writer, it is when is has been compressed,
|
||||
// for a Reader, it is when it has been uncompressed.
|
||||
func OnBlockDoneOption(handler func(size int)) Option {
|
||||
if handler == nil {
|
||||
handler = onBlockDone
|
||||
}
|
||||
return func(a applier) error {
|
||||
switch rw := a.(type) {
|
||||
case nil:
|
||||
s := fmt.Sprintf("OnBlockDoneOption(%s)", reflect.TypeOf(handler).String())
|
||||
return lz4errors.Error(s)
|
||||
case *Writer:
|
||||
rw.handler = handler
|
||||
return nil
|
||||
case *Reader:
|
||||
rw.handler = handler
|
||||
return nil
|
||||
}
|
||||
return lz4errors.ErrOptionNotApplicable
|
||||
}
|
||||
}
|
||||
|
||||
// LegacyOption provides support for writing LZ4 frames in the legacy format.
|
||||
//
|
||||
// See https://github.com/lz4/lz4/blob/dev/doc/lz4_Frame_format.md#legacy-frame.
|
||||
//
|
||||
// NB. compressed Linux kernel images use a tweaked LZ4 legacy format where
|
||||
// the compressed stream is followed by the original (uncompressed) size of
|
||||
// the kernel (https://events.static.linuxfound.org/sites/events/files/lcjpcojp13_klee.pdf).
|
||||
// This is also supported as a special case.
|
||||
func LegacyOption(legacy bool) Option {
|
||||
return func(a applier) error {
|
||||
switch rw := a.(type) {
|
||||
case nil:
|
||||
s := fmt.Sprintf("LegacyOption(%v)", legacy)
|
||||
return lz4errors.Error(s)
|
||||
case *Writer:
|
||||
rw.legacy = legacy
|
||||
return nil
|
||||
}
|
||||
return lz4errors.ErrOptionNotApplicable
|
||||
}
|
||||
}
|
92
vendor/github.com/pierrec/lz4/v4/options_gen.go
generated
vendored
Normal file
92
vendor/github.com/pierrec/lz4/v4/options_gen.go
generated
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
// Code generated by "stringer -type=BlockSize,CompressionLevel -output options_gen.go"; DO NOT EDIT.
|
||||
|
||||
package lz4
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Block64Kb-65536]
|
||||
_ = x[Block256Kb-262144]
|
||||
_ = x[Block1Mb-1048576]
|
||||
_ = x[Block4Mb-4194304]
|
||||
}
|
||||
|
||||
const (
|
||||
_BlockSize_name_0 = "Block64Kb"
|
||||
_BlockSize_name_1 = "Block256Kb"
|
||||
_BlockSize_name_2 = "Block1Mb"
|
||||
_BlockSize_name_3 = "Block4Mb"
|
||||
)
|
||||
|
||||
func (i BlockSize) String() string {
|
||||
switch {
|
||||
case i == 65536:
|
||||
return _BlockSize_name_0
|
||||
case i == 262144:
|
||||
return _BlockSize_name_1
|
||||
case i == 1048576:
|
||||
return _BlockSize_name_2
|
||||
case i == 4194304:
|
||||
return _BlockSize_name_3
|
||||
default:
|
||||
return "BlockSize(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Fast-0]
|
||||
_ = x[Level1-512]
|
||||
_ = x[Level2-1024]
|
||||
_ = x[Level3-2048]
|
||||
_ = x[Level4-4096]
|
||||
_ = x[Level5-8192]
|
||||
_ = x[Level6-16384]
|
||||
_ = x[Level7-32768]
|
||||
_ = x[Level8-65536]
|
||||
_ = x[Level9-131072]
|
||||
}
|
||||
|
||||
const (
|
||||
_CompressionLevel_name_0 = "Fast"
|
||||
_CompressionLevel_name_1 = "Level1"
|
||||
_CompressionLevel_name_2 = "Level2"
|
||||
_CompressionLevel_name_3 = "Level3"
|
||||
_CompressionLevel_name_4 = "Level4"
|
||||
_CompressionLevel_name_5 = "Level5"
|
||||
_CompressionLevel_name_6 = "Level6"
|
||||
_CompressionLevel_name_7 = "Level7"
|
||||
_CompressionLevel_name_8 = "Level8"
|
||||
_CompressionLevel_name_9 = "Level9"
|
||||
)
|
||||
|
||||
func (i CompressionLevel) String() string {
|
||||
switch {
|
||||
case i == 0:
|
||||
return _CompressionLevel_name_0
|
||||
case i == 512:
|
||||
return _CompressionLevel_name_1
|
||||
case i == 1024:
|
||||
return _CompressionLevel_name_2
|
||||
case i == 2048:
|
||||
return _CompressionLevel_name_3
|
||||
case i == 4096:
|
||||
return _CompressionLevel_name_4
|
||||
case i == 8192:
|
||||
return _CompressionLevel_name_5
|
||||
case i == 16384:
|
||||
return _CompressionLevel_name_6
|
||||
case i == 32768:
|
||||
return _CompressionLevel_name_7
|
||||
case i == 65536:
|
||||
return _CompressionLevel_name_8
|
||||
case i == 131072:
|
||||
return _CompressionLevel_name_9
|
||||
default:
|
||||
return "CompressionLevel(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
}
|
243
vendor/github.com/pierrec/lz4/v4/reader.go
generated
vendored
Normal file
243
vendor/github.com/pierrec/lz4/v4/reader.go
generated
vendored
Normal file
|
@ -0,0 +1,243 @@
|
|||
package lz4
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/pierrec/lz4/v4/internal/lz4block"
|
||||
"github.com/pierrec/lz4/v4/internal/lz4errors"
|
||||
"github.com/pierrec/lz4/v4/internal/lz4stream"
|
||||
)
|
||||
|
||||
var readerStates = []aState{
|
||||
noState: newState,
|
||||
errorState: newState,
|
||||
newState: readState,
|
||||
readState: closedState,
|
||||
closedState: newState,
|
||||
}
|
||||
|
||||
// NewReader returns a new LZ4 frame decoder.
|
||||
func NewReader(r io.Reader) *Reader {
|
||||
return newReader(r, false)
|
||||
}
|
||||
|
||||
func newReader(r io.Reader, legacy bool) *Reader {
|
||||
zr := &Reader{frame: lz4stream.NewFrame()}
|
||||
zr.state.init(readerStates)
|
||||
_ = zr.Apply(DefaultConcurrency, defaultOnBlockDone)
|
||||
zr.Reset(r)
|
||||
return zr
|
||||
}
|
||||
|
||||
// Reader allows reading an LZ4 stream.
|
||||
type Reader struct {
|
||||
state _State
|
||||
src io.Reader // source reader
|
||||
num int // concurrency level
|
||||
frame *lz4stream.Frame // frame being read
|
||||
data []byte // block buffer allocated in non concurrent mode
|
||||
reads chan []byte // pending data
|
||||
idx int // size of pending data
|
||||
handler func(int)
|
||||
cum uint32
|
||||
}
|
||||
|
||||
func (*Reader) private() {}
|
||||
|
||||
func (r *Reader) Apply(options ...Option) (err error) {
|
||||
defer r.state.check(&err)
|
||||
switch r.state.state {
|
||||
case newState:
|
||||
case errorState:
|
||||
return r.state.err
|
||||
default:
|
||||
return lz4errors.ErrOptionClosedOrError
|
||||
}
|
||||
for _, o := range options {
|
||||
if err = o(r); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Size returns the size of the underlying uncompressed data, if set in the stream.
|
||||
func (r *Reader) Size() int {
|
||||
switch r.state.state {
|
||||
case readState, closedState:
|
||||
if r.frame.Descriptor.Flags.Size() {
|
||||
return int(r.frame.Descriptor.ContentSize)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (r *Reader) isNotConcurrent() bool {
|
||||
return r.num == 1
|
||||
}
|
||||
|
||||
func (r *Reader) init() error {
|
||||
data, err := r.frame.InitR(r.src, r.num)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.reads = data
|
||||
r.idx = 0
|
||||
size := r.frame.Descriptor.Flags.BlockSizeIndex()
|
||||
r.data = size.Get()
|
||||
r.cum = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reader) Read(buf []byte) (n int, err error) {
|
||||
defer r.state.check(&err)
|
||||
switch r.state.state {
|
||||
case readState:
|
||||
case closedState, errorState:
|
||||
return 0, r.state.err
|
||||
case newState:
|
||||
// First initialization.
|
||||
if err = r.init(); r.state.next(err) {
|
||||
return
|
||||
}
|
||||
default:
|
||||
return 0, r.state.fail()
|
||||
}
|
||||
for len(buf) > 0 {
|
||||
var bn int
|
||||
if r.idx == 0 {
|
||||
if r.isNotConcurrent() {
|
||||
bn, err = r.read(buf)
|
||||
} else {
|
||||
lz4block.Put(r.data)
|
||||
r.data = <-r.reads
|
||||
if len(r.data) == 0 {
|
||||
// No uncompressed data: something went wrong or we are done.
|
||||
err = r.frame.Blocks.ErrorR()
|
||||
}
|
||||
}
|
||||
switch err {
|
||||
case nil:
|
||||
case io.EOF:
|
||||
if er := r.frame.CloseR(r.src); er != nil {
|
||||
err = er
|
||||
}
|
||||
lz4block.Put(r.data)
|
||||
r.data = nil
|
||||
return
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
if bn == 0 {
|
||||
// Fill buf with buffered data.
|
||||
bn = copy(buf, r.data[r.idx:])
|
||||
r.idx += bn
|
||||
if r.idx == len(r.data) {
|
||||
// All data read, get ready for the next Read.
|
||||
r.idx = 0
|
||||
}
|
||||
}
|
||||
buf = buf[bn:]
|
||||
n += bn
|
||||
r.handler(bn)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// read uncompresses the next block as follow:
|
||||
// - if buf has enough room, the block is uncompressed into it directly
|
||||
// and the lenght of used space is returned
|
||||
// - else, the uncompress data is stored in r.data and 0 is returned
|
||||
func (r *Reader) read(buf []byte) (int, error) {
|
||||
block := r.frame.Blocks.Block
|
||||
_, err := block.Read(r.frame, r.src, r.cum)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var direct bool
|
||||
dst := r.data[:cap(r.data)]
|
||||
if len(buf) >= len(dst) {
|
||||
// Uncompress directly into buf.
|
||||
direct = true
|
||||
dst = buf
|
||||
}
|
||||
dst, err = block.Uncompress(r.frame, dst, true)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
r.cum += uint32(len(dst))
|
||||
if direct {
|
||||
return len(dst), nil
|
||||
}
|
||||
r.data = dst
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Reset clears the state of the Reader r such that it is equivalent to its
|
||||
// initial state from NewReader, but instead writing to writer.
|
||||
// No access to reader is performed.
|
||||
//
|
||||
// w.Close must be called before Reset.
|
||||
func (r *Reader) Reset(reader io.Reader) {
|
||||
if r.data != nil {
|
||||
lz4block.Put(r.data)
|
||||
r.data = nil
|
||||
}
|
||||
r.frame.Reset(r.num)
|
||||
r.state.reset()
|
||||
r.src = reader
|
||||
r.reads = nil
|
||||
}
|
||||
|
||||
// WriteTo efficiently uncompresses the data from the Reader underlying source to w.
|
||||
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
||||
switch r.state.state {
|
||||
case closedState, errorState:
|
||||
return 0, r.state.err
|
||||
case newState:
|
||||
if err = r.init(); r.state.next(err) {
|
||||
return
|
||||
}
|
||||
default:
|
||||
return 0, r.state.fail()
|
||||
}
|
||||
defer r.state.nextd(&err)
|
||||
|
||||
var data []byte
|
||||
if r.isNotConcurrent() {
|
||||
size := r.frame.Descriptor.Flags.BlockSizeIndex()
|
||||
data = size.Get()
|
||||
defer lz4block.Put(data)
|
||||
}
|
||||
for {
|
||||
var bn int
|
||||
var dst []byte
|
||||
if r.isNotConcurrent() {
|
||||
bn, err = r.read(data)
|
||||
dst = data[:bn]
|
||||
} else {
|
||||
lz4block.Put(dst)
|
||||
dst = <-r.reads
|
||||
bn = len(dst)
|
||||
if bn == 0 {
|
||||
// No uncompressed data: something went wrong or we are done.
|
||||
err = r.frame.Blocks.ErrorR()
|
||||
}
|
||||
}
|
||||
switch err {
|
||||
case nil:
|
||||
case io.EOF:
|
||||
err = r.frame.CloseR(r.src)
|
||||
return
|
||||
default:
|
||||
return
|
||||
}
|
||||
r.handler(bn)
|
||||
bn, err = w.Write(dst)
|
||||
n += int64(bn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
75
vendor/github.com/pierrec/lz4/v4/state.go
generated
vendored
Normal file
75
vendor/github.com/pierrec/lz4/v4/state.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
package lz4
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/pierrec/lz4/v4/internal/lz4errors"
|
||||
)
|
||||
|
||||
//go:generate go run golang.org/x/tools/cmd/stringer -type=aState -output state_gen.go
|
||||
|
||||
const (
|
||||
noState aState = iota // uninitialized reader
|
||||
errorState // unrecoverable error encountered
|
||||
newState // instantiated object
|
||||
readState // reading data
|
||||
writeState // writing data
|
||||
closedState // all done
|
||||
)
|
||||
|
||||
type (
|
||||
aState uint8
|
||||
_State struct {
|
||||
states []aState
|
||||
state aState
|
||||
err error
|
||||
}
|
||||
)
|
||||
|
||||
func (s *_State) init(states []aState) {
|
||||
s.states = states
|
||||
s.state = states[0]
|
||||
}
|
||||
|
||||
func (s *_State) reset() {
|
||||
s.state = s.states[0]
|
||||
s.err = nil
|
||||
}
|
||||
|
||||
// next sets the state to the next one unless it is passed a non nil error.
|
||||
// It returns whether or not it is in error.
|
||||
func (s *_State) next(err error) bool {
|
||||
if err != nil {
|
||||
s.err = fmt.Errorf("%s: %w", s.state, err)
|
||||
s.state = errorState
|
||||
return true
|
||||
}
|
||||
s.state = s.states[s.state]
|
||||
return false
|
||||
}
|
||||
|
||||
// nextd is like next but for defers.
|
||||
func (s *_State) nextd(errp *error) bool {
|
||||
return errp != nil && s.next(*errp)
|
||||
}
|
||||
|
||||
// check sets s in error if not already in error and if the error is not nil or io.EOF,
|
||||
func (s *_State) check(errp *error) {
|
||||
if s.state == errorState || errp == nil {
|
||||
return
|
||||
}
|
||||
if err := *errp; err != nil {
|
||||
s.err = fmt.Errorf("%w[%s]", err, s.state)
|
||||
if !errors.Is(err, io.EOF) {
|
||||
s.state = errorState
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *_State) fail() error {
|
||||
s.state = errorState
|
||||
s.err = fmt.Errorf("%w[%s]", lz4errors.ErrInternalUnhandledState, s.state)
|
||||
return s.err
|
||||
}
|
28
vendor/github.com/pierrec/lz4/v4/state_gen.go
generated
vendored
Normal file
28
vendor/github.com/pierrec/lz4/v4/state_gen.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Code generated by "stringer -type=aState -output state_gen.go"; DO NOT EDIT.
|
||||
|
||||
package lz4
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[noState-0]
|
||||
_ = x[errorState-1]
|
||||
_ = x[newState-2]
|
||||
_ = x[readState-3]
|
||||
_ = x[writeState-4]
|
||||
_ = x[closedState-5]
|
||||
}
|
||||
|
||||
const _aState_name = "noStateerrorStatenewStatereadStatewriteStateclosedState"
|
||||
|
||||
var _aState_index = [...]uint8{0, 7, 17, 25, 34, 44, 55}
|
||||
|
||||
func (i aState) String() string {
|
||||
if i >= aState(len(_aState_index)-1) {
|
||||
return "aState(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _aState_name[_aState_index[i]:_aState_index[i+1]]
|
||||
}
|
233
vendor/github.com/pierrec/lz4/v4/writer.go
generated
vendored
Normal file
233
vendor/github.com/pierrec/lz4/v4/writer.go
generated
vendored
Normal file
|
@ -0,0 +1,233 @@
|
|||
package lz4
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/pierrec/lz4/v4/internal/lz4block"
|
||||
"github.com/pierrec/lz4/v4/internal/lz4errors"
|
||||
"github.com/pierrec/lz4/v4/internal/lz4stream"
|
||||
)
|
||||
|
||||
var writerStates = []aState{
|
||||
noState: newState,
|
||||
newState: writeState,
|
||||
writeState: closedState,
|
||||
closedState: newState,
|
||||
errorState: newState,
|
||||
}
|
||||
|
||||
// NewWriter returns a new LZ4 frame encoder.
|
||||
func NewWriter(w io.Writer) *Writer {
|
||||
zw := &Writer{frame: lz4stream.NewFrame()}
|
||||
zw.state.init(writerStates)
|
||||
_ = zw.Apply(DefaultBlockSizeOption, DefaultChecksumOption, DefaultConcurrency, defaultOnBlockDone)
|
||||
zw.Reset(w)
|
||||
return zw
|
||||
}
|
||||
|
||||
// Writer allows writing an LZ4 stream.
|
||||
type Writer struct {
|
||||
state _State
|
||||
src io.Writer // destination writer
|
||||
level lz4block.CompressionLevel // how hard to try
|
||||
num int // concurrency level
|
||||
frame *lz4stream.Frame // frame being built
|
||||
data []byte // pending data
|
||||
idx int // size of pending data
|
||||
handler func(int)
|
||||
legacy bool
|
||||
}
|
||||
|
||||
func (*Writer) private() {}
|
||||
|
||||
func (w *Writer) Apply(options ...Option) (err error) {
|
||||
defer w.state.check(&err)
|
||||
switch w.state.state {
|
||||
case newState:
|
||||
case errorState:
|
||||
return w.state.err
|
||||
default:
|
||||
return lz4errors.ErrOptionClosedOrError
|
||||
}
|
||||
for _, o := range options {
|
||||
if err = o(w); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
w.Reset(w.src)
|
||||
return
|
||||
}
|
||||
|
||||
func (w *Writer) isNotConcurrent() bool {
|
||||
return w.num == 1
|
||||
}
|
||||
|
||||
// init sets up the Writer when in newState. It does not change the Writer state.
|
||||
func (w *Writer) init() error {
|
||||
w.frame.InitW(w.src, w.num, w.legacy)
|
||||
if true || !w.isNotConcurrent() {
|
||||
size := w.frame.Descriptor.Flags.BlockSizeIndex()
|
||||
w.data = size.Get()
|
||||
}
|
||||
w.idx = 0
|
||||
return w.frame.Descriptor.Write(w.frame, w.src)
|
||||
}
|
||||
|
||||
func (w *Writer) Write(buf []byte) (n int, err error) {
|
||||
defer w.state.check(&err)
|
||||
switch w.state.state {
|
||||
case writeState:
|
||||
case closedState, errorState:
|
||||
return 0, w.state.err
|
||||
case newState:
|
||||
if err = w.init(); w.state.next(err) {
|
||||
return
|
||||
}
|
||||
default:
|
||||
return 0, w.state.fail()
|
||||
}
|
||||
|
||||
zn := len(w.data)
|
||||
for len(buf) > 0 {
|
||||
if w.idx == 0 && len(buf) >= zn {
|
||||
// Avoid a copy as there is enough data for a block.
|
||||
if err = w.write(buf[:zn], false); err != nil {
|
||||
return
|
||||
}
|
||||
n += zn
|
||||
buf = buf[zn:]
|
||||
continue
|
||||
}
|
||||
// Accumulate the data to be compressed.
|
||||
m := copy(w.data[w.idx:], buf)
|
||||
n += m
|
||||
w.idx += m
|
||||
buf = buf[m:]
|
||||
|
||||
if w.idx < len(w.data) {
|
||||
// Buffer not filled.
|
||||
return
|
||||
}
|
||||
|
||||
// Buffer full.
|
||||
if err = w.write(w.data, true); err != nil {
|
||||
return
|
||||
}
|
||||
if !w.isNotConcurrent() {
|
||||
size := w.frame.Descriptor.Flags.BlockSizeIndex()
|
||||
w.data = size.Get()
|
||||
}
|
||||
w.idx = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (w *Writer) write(data []byte, safe bool) error {
|
||||
if w.isNotConcurrent() {
|
||||
block := w.frame.Blocks.Block
|
||||
err := block.Compress(w.frame, data, w.level).Write(w.frame, w.src)
|
||||
w.handler(len(block.Data))
|
||||
return err
|
||||
}
|
||||
c := make(chan *lz4stream.FrameDataBlock)
|
||||
w.frame.Blocks.Blocks <- c
|
||||
go func(c chan *lz4stream.FrameDataBlock, data []byte, safe bool) {
|
||||
b := lz4stream.NewFrameDataBlock(w.frame)
|
||||
c <- b.Compress(w.frame, data, w.level)
|
||||
<-c
|
||||
w.handler(len(b.Data))
|
||||
b.Close(w.frame)
|
||||
if safe {
|
||||
// safe to put it back as the last usage of it was FrameDataBlock.Write() called before c is closed
|
||||
lz4block.Put(data)
|
||||
}
|
||||
}(c, data, safe)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the Writer, flushing any unwritten data to the underlying io.Writer,
|
||||
// but does not close the underlying io.Writer.
|
||||
func (w *Writer) Close() (err error) {
|
||||
switch w.state.state {
|
||||
case writeState:
|
||||
case errorState:
|
||||
return w.state.err
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
defer w.state.nextd(&err)
|
||||
if w.idx > 0 {
|
||||
// Flush pending data, disable w.data freeing as it is done later on.
|
||||
if err = w.write(w.data[:w.idx], false); err != nil {
|
||||
return err
|
||||
}
|
||||
w.idx = 0
|
||||
}
|
||||
err = w.frame.CloseW(w.src, w.num)
|
||||
// It is now safe to free the buffer.
|
||||
if w.data != nil {
|
||||
lz4block.Put(w.data)
|
||||
w.data = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Reset clears the state of the Writer w such that it is equivalent to its
|
||||
// initial state from NewWriter, but instead writing to writer.
|
||||
// Reset keeps the previous options unless overwritten by the supplied ones.
|
||||
// No access to writer is performed.
|
||||
//
|
||||
// w.Close must be called before Reset or pending data may be dropped.
|
||||
func (w *Writer) Reset(writer io.Writer) {
|
||||
w.frame.Reset(w.num)
|
||||
w.state.reset()
|
||||
w.src = writer
|
||||
}
|
||||
|
||||
// ReadFrom efficiently reads from r and compressed into the Writer destination.
|
||||
func (w *Writer) ReadFrom(r io.Reader) (n int64, err error) {
|
||||
switch w.state.state {
|
||||
case closedState, errorState:
|
||||
return 0, w.state.err
|
||||
case newState:
|
||||
if err = w.init(); w.state.next(err) {
|
||||
return
|
||||
}
|
||||
default:
|
||||
return 0, w.state.fail()
|
||||
}
|
||||
defer w.state.check(&err)
|
||||
|
||||
size := w.frame.Descriptor.Flags.BlockSizeIndex()
|
||||
var done bool
|
||||
var rn int
|
||||
data := size.Get()
|
||||
if w.isNotConcurrent() {
|
||||
// Keep the same buffer for the whole process.
|
||||
defer lz4block.Put(data)
|
||||
}
|
||||
for !done {
|
||||
rn, err = io.ReadFull(r, data)
|
||||
switch err {
|
||||
case nil:
|
||||
case io.EOF, io.ErrUnexpectedEOF: // read may be partial
|
||||
done = true
|
||||
default:
|
||||
return
|
||||
}
|
||||
n += int64(rn)
|
||||
err = w.write(data[:rn], true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
w.handler(rn)
|
||||
if !done && !w.isNotConcurrent() {
|
||||
// The buffer will be returned automatically by go routines (safe=true)
|
||||
// so get a new one fo the next round.
|
||||
data = size.Get()
|
||||
}
|
||||
}
|
||||
err = w.Close()
|
||||
return
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue