gitea/vendor/github.com/glycerine/go-unsnap-stream/snap.go

101 lines
2.3 KiB
Go

package unsnap
import (
"encoding/binary"
// no c lib dependency
snappy "github.com/golang/snappy"
// or, use the C wrapper for speed
//snappy "github.com/dgryski/go-csnappy"
)
// add Write() method for SnappyFile (see unsnap.go)
// reference for snappy framing/streaming format:
// http://code.google.com/p/snappy/source/browse/trunk/framing_format.txt
// ?spec=svn68&r=71
//
// Write writes len(p) bytes from p to the underlying data stream.
// It returns the number of bytes written from p (0 <= n <= len(p)) and
// any error encountered that caused the write to stop early. Write
// must return a non-nil error if it returns n < len(p).
//
func (sf *SnappyFile) Write(p []byte) (n int, err error) {
if sf.SnappyEncodeDecodeOff {
return sf.Writer.Write(p)
}
if !sf.Writing {
panic("Writing on a read-only SnappyFile")
}
// encoding in snappy can apparently go beyond the original size, beware.
// so our buffers must be sized 2*max snappy chunk => 2 * CHUNK_MAX(65536)
sf.DecBuf.Reset()
sf.EncBuf.Reset()
if !sf.HeaderChunkWritten {
sf.HeaderChunkWritten = true
_, err = sf.Writer.Write(SnappyStreamHeaderMagic)
if err != nil {
return
}
}
var chunk []byte
var chunk_type byte
var crc uint32
for len(p) > 0 {
// chunk points to input p by default, unencoded input.
chunk = p[:IntMin(len(p), CHUNK_MAX)]
crc = masked_crc32c(chunk)
writeme := chunk[:]
// first write to EncBuf, as a temp, in case we want
// to discard and send uncompressed instead.
compressed_chunk := snappy.Encode(sf.EncBuf.GetEndmostWritableSlice(), chunk)
if len(compressed_chunk) <= int((1-_COMPRESSION_THRESHOLD)*float64(len(chunk))) {
writeme = compressed_chunk
chunk_type = _COMPRESSED_CHUNK
} else {
// keep writeme pointing at original chunk (uncompressed)
chunk_type = _UNCOMPRESSED_CHUNK
}
const crc32Sz = 4
var tag32 uint32 = uint32(chunk_type) + (uint32(len(writeme)+crc32Sz) << 8)
err = binary.Write(sf.Writer, binary.LittleEndian, tag32)
if err != nil {
return
}
err = binary.Write(sf.Writer, binary.LittleEndian, crc)
if err != nil {
return
}
_, err = sf.Writer.Write(writeme)
if err != nil {
return
}
n += len(chunk)
p = p[len(chunk):]
}
return n, nil
}
func IntMin(a int, b int) int {
if a < b {
return a
}
return b
}