mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 00:11:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			519 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
			
		
		
	
	
			519 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
		
			Vendored
		
	
	
	
package unsnap
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"encoding/binary"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"io/ioutil"
 | 
						|
	"os"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"hash/crc32"
 | 
						|
 | 
						|
	snappy "github.com/golang/snappy"
 | 
						|
	// The C library can be used, but this makes the binary dependent
 | 
						|
	// lots of extraneous c-libraries; it is no longer stand-alone. Yuck.
 | 
						|
	//
 | 
						|
	// Therefore we comment out the "dgryski/go-csnappy" path and use the
 | 
						|
	// "github.com/golang/snappy/snappy" above instead. If you are
 | 
						|
	// performance limited and can deal with distributing more libraries,
 | 
						|
	// then this is easy to swap.
 | 
						|
	//
 | 
						|
	// If you swap, note that some of the tests won't pass
 | 
						|
	// because snappy-go produces slightly different (but still
 | 
						|
	// conformant) encodings on some data. Here are bindings
 | 
						|
	// to the C-snappy:
 | 
						|
	// snappy "github.com/dgryski/go-csnappy"
 | 
						|
)
 | 
						|
 | 
						|
// SnappyFile: create a drop-in-replacement/wrapper for an *os.File that handles doing the unsnappification online as more is read from it
 | 
						|
 | 
						|
type SnappyFile struct {
 | 
						|
	Fname string
 | 
						|
 | 
						|
	Reader io.Reader
 | 
						|
	Writer io.Writer
 | 
						|
 | 
						|
	// allow clients to substitute us for an os.File and just switch
 | 
						|
	// off compression if they don't want it.
 | 
						|
	SnappyEncodeDecodeOff bool // if true, we bypass straight to Filep
 | 
						|
 | 
						|
	EncBuf FixedSizeRingBuf // holds any extra that isn't yet returned, encoded
 | 
						|
	DecBuf FixedSizeRingBuf // holds any extra that isn't yet returned, decoded
 | 
						|
 | 
						|
	// for writing to stream-framed snappy
 | 
						|
	HeaderChunkWritten bool
 | 
						|
 | 
						|
	// Sanity check: we can only read, or only write, to one SnappyFile.
 | 
						|
	// EncBuf and DecBuf are used differently in each mode. Verify
 | 
						|
	// that we are consistent with this flag.
 | 
						|
	Writing bool
 | 
						|
}
 | 
						|
 | 
						|
var total int
 | 
						|
 | 
						|
// for debugging, show state of buffers
 | 
						|
func (f *SnappyFile) Dump() {
 | 
						|
	fmt.Printf("EncBuf has length %d and contents:\n%s\n", len(f.EncBuf.Bytes()), string(f.EncBuf.Bytes()))
 | 
						|
	fmt.Printf("DecBuf has length %d and contents:\n%s\n", len(f.DecBuf.Bytes()), string(f.DecBuf.Bytes()))
 | 
						|
}
 | 
						|
 | 
						|
func (f *SnappyFile) Read(p []byte) (n int, err error) {
 | 
						|
 | 
						|
	if f.SnappyEncodeDecodeOff {
 | 
						|
		return f.Reader.Read(p)
 | 
						|
	}
 | 
						|
 | 
						|
	if f.Writing {
 | 
						|
		panic("Reading on a write-only SnappyFile")
 | 
						|
	}
 | 
						|
 | 
						|
	// before we unencrypt more, try to drain the DecBuf first
 | 
						|
	n, _ = f.DecBuf.Read(p)
 | 
						|
	if n > 0 {
 | 
						|
		total += n
 | 
						|
		return n, nil
 | 
						|
	}
 | 
						|
 | 
						|
	//nEncRead, nDecAdded, err := UnsnapOneFrame(f.Filep, &f.EncBuf, &f.DecBuf, f.Fname)
 | 
						|
	_, _, err = UnsnapOneFrame(f.Reader, &f.EncBuf, &f.DecBuf, f.Fname)
 | 
						|
	if err != nil && err != io.EOF {
 | 
						|
		panic(err)
 | 
						|
	}
 | 
						|
 | 
						|
	n, _ = f.DecBuf.Read(p)
 | 
						|
 | 
						|
	if n > 0 {
 | 
						|
		total += n
 | 
						|
		return n, nil
 | 
						|
	}
 | 
						|
	if f.DecBuf.Readable == 0 {
 | 
						|
		if f.DecBuf.Readable == 0 && f.EncBuf.Readable == 0 {
 | 
						|
			// only now (when EncBuf is empty) can we give io.EOF.
 | 
						|
			// Any earlier, and we leave stuff un-decoded!
 | 
						|
			return 0, io.EOF
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return 0, nil
 | 
						|
}
 | 
						|
 | 
						|
func Open(name string) (file *SnappyFile, err error) {
 | 
						|
	fp, err := os.Open(name)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	// encoding in snappy can apparently go beyond the original size, so
 | 
						|
	// we make our buffers big enough, 2*max snappy chunk => 2 * CHUNK_MAX(65536)
 | 
						|
 | 
						|
	snap := NewReader(fp)
 | 
						|
	snap.Fname = name
 | 
						|
	return snap, nil
 | 
						|
}
 | 
						|
 | 
						|
func NewReader(r io.Reader) *SnappyFile {
 | 
						|
	return &SnappyFile{
 | 
						|
		Reader:  r,
 | 
						|
		EncBuf:  *NewFixedSizeRingBuf(CHUNK_MAX * 2), // buffer of snappy encoded bytes
 | 
						|
		DecBuf:  *NewFixedSizeRingBuf(CHUNK_MAX * 2), // buffer of snapppy decoded bytes
 | 
						|
		Writing: false,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func NewWriter(w io.Writer) *SnappyFile {
 | 
						|
	return &SnappyFile{
 | 
						|
		Writer:  w,
 | 
						|
		EncBuf:  *NewFixedSizeRingBuf(65536),     // on writing: temp for testing compression
 | 
						|
		DecBuf:  *NewFixedSizeRingBuf(65536 * 2), // on writing: final buffer of snappy framed and encoded bytes
 | 
						|
		Writing: true,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func Create(name string) (file *SnappyFile, err error) {
 | 
						|
	fp, err := os.Create(name)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	snap := NewWriter(fp)
 | 
						|
	snap.Fname = name
 | 
						|
	return snap, nil
 | 
						|
}
 | 
						|
 | 
						|
func (f *SnappyFile) Close() error {
 | 
						|
	if f.Writing {
 | 
						|
		wc, ok := f.Writer.(io.WriteCloser)
 | 
						|
		if ok {
 | 
						|
			return wc.Close()
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	rc, ok := f.Reader.(io.ReadCloser)
 | 
						|
	if ok {
 | 
						|
		return rc.Close()
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (f *SnappyFile) Sync() error {
 | 
						|
	file, ok := f.Writer.(*os.File)
 | 
						|
	if ok {
 | 
						|
		return file.Sync()
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// for an increment of a frame at a time:
 | 
						|
// read from r into encBuf (encBuf is still encoded, thus the name), and write unsnappified frames into outDecodedBuf
 | 
						|
//  the returned n: number of bytes read from the encrypted encBuf
 | 
						|
func UnsnapOneFrame(r io.Reader, encBuf *FixedSizeRingBuf, outDecodedBuf *FixedSizeRingBuf, fname string) (nEnc int64, nDec int64, err error) {
 | 
						|
	//	b, err := ioutil.ReadAll(r)
 | 
						|
	//	if err != nil {
 | 
						|
	//		panic(err)
 | 
						|
	//	}
 | 
						|
 | 
						|
	nEnc = 0
 | 
						|
	nDec = 0
 | 
						|
 | 
						|
	// read up to 65536 bytes from r into encBuf, at least a snappy frame
 | 
						|
	nread, err := io.CopyN(encBuf, r, 65536) // returns nwrotebytes, err
 | 
						|
	nEnc += nread
 | 
						|
	if err != nil {
 | 
						|
		if err == io.EOF {
 | 
						|
			if nread == 0 {
 | 
						|
				if encBuf.Readable == 0 {
 | 
						|
					return nEnc, nDec, io.EOF
 | 
						|
				}
 | 
						|
				// else we have bytes in encBuf, so decode them!
 | 
						|
				err = nil
 | 
						|
			} else {
 | 
						|
				// continue below, processing the nread bytes
 | 
						|
				err = nil
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			// may be an odd already closed... don't panic on that
 | 
						|
			if strings.Contains(err.Error(), "file already closed") {
 | 
						|
				err = nil
 | 
						|
			} else {
 | 
						|
				panic(err)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// flag for printing chunk size alignment messages
 | 
						|
	verbose := false
 | 
						|
 | 
						|
	const snappyStreamHeaderSz = 10
 | 
						|
	const headerSz = 4
 | 
						|
	const crc32Sz = 4
 | 
						|
	// the magic 18 bytes accounts for the snappy streaming header and the first chunks size and checksum
 | 
						|
	// http://code.google.com/p/snappy/source/browse/trunk/framing_format.txt
 | 
						|
 | 
						|
	chunk := (*encBuf).Bytes()
 | 
						|
 | 
						|
	// however we exit, advance as
 | 
						|
	//	defer func() { (*encBuf).Next(N) }()
 | 
						|
 | 
						|
	// 65536 is the max size of a snappy framed chunk. See
 | 
						|
	// http://code.google.com/p/snappy/source/browse/trunk/framing_format.txt:91
 | 
						|
	// buf := make([]byte, 65536)
 | 
						|
 | 
						|
	//	fmt.Printf("read from file, b is len:%d with value: %#v\n", len(b), b)
 | 
						|
	//	fmt.Printf("read from file, bcut is len:%d with value: %#v\n", len(bcut), bcut)
 | 
						|
 | 
						|
	//fmt.Printf("raw bytes of chunksz are: %v\n", b[11:14])
 | 
						|
 | 
						|
	fourbytes := make([]byte, 4)
 | 
						|
	chunkCount := 0
 | 
						|
 | 
						|
	for nDec < 65536 {
 | 
						|
		if len(chunk) == 0 {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		chunkCount++
 | 
						|
		fourbytes[3] = 0
 | 
						|
		copy(fourbytes, chunk[1:4])
 | 
						|
		chunksz := binary.LittleEndian.Uint32(fourbytes)
 | 
						|
		chunk_type := chunk[0]
 | 
						|
 | 
						|
		switch true {
 | 
						|
		case chunk_type == 0xff:
 | 
						|
			{ // stream identifier
 | 
						|
 | 
						|
				streamHeader := chunk[:snappyStreamHeaderSz]
 | 
						|
				if 0 != bytes.Compare(streamHeader, []byte{0xff, 0x06, 0x00, 0x00, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59}) {
 | 
						|
					panic("file had chunk starting with 0xff but then no magic snappy streaming protocol bytes, aborting.")
 | 
						|
				} else {
 | 
						|
					//fmt.Printf("got streaming snappy magic header just fine.\n")
 | 
						|
				}
 | 
						|
				chunk = chunk[snappyStreamHeaderSz:]
 | 
						|
				(*encBuf).Advance(snappyStreamHeaderSz)
 | 
						|
				nEnc += snappyStreamHeaderSz
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		case chunk_type == 0x00:
 | 
						|
			{ // compressed data
 | 
						|
				if verbose {
 | 
						|
					fmt.Fprintf(os.Stderr, "chunksz is %d  while  total bytes avail are: %d\n", int(chunksz), len(chunk)-4)
 | 
						|
				}
 | 
						|
 | 
						|
				crc := binary.LittleEndian.Uint32(chunk[headerSz:(headerSz + crc32Sz)])
 | 
						|
				section := chunk[(headerSz + crc32Sz):(headerSz + chunksz)]
 | 
						|
 | 
						|
				dec, ok := snappy.Decode(nil, section)
 | 
						|
				if ok != nil {
 | 
						|
					// we've probably truncated a snappy frame at this point
 | 
						|
					// ok=snappy: corrupt input
 | 
						|
					// len(dec) == 0
 | 
						|
					//
 | 
						|
					panic(fmt.Sprintf("could not decode snappy stream: '%s' and len dec=%d and ok=%v\n", fname, len(dec), ok))
 | 
						|
 | 
						|
					// get back to caller with what we've got so far
 | 
						|
					return nEnc, nDec, nil
 | 
						|
				}
 | 
						|
				//	fmt.Printf("ok, b is %#v , %#v\n", ok, dec)
 | 
						|
 | 
						|
				// spit out decoded text
 | 
						|
				// n, err := w.Write(dec)
 | 
						|
				//fmt.Printf("len(dec) = %d,   outDecodedBuf.Readable=%d\n", len(dec), outDecodedBuf.Readable)
 | 
						|
				bnb := bytes.NewBuffer(dec)
 | 
						|
				n, err := io.Copy(outDecodedBuf, bnb)
 | 
						|
				if err != nil {
 | 
						|
					//fmt.Printf("got n=%d, err= %s ; when trying to io.Copy(outDecodedBuf: N=%d, Readable=%d)\n", n, err, outDecodedBuf.N, outDecodedBuf.Readable)
 | 
						|
					panic(err)
 | 
						|
				}
 | 
						|
				if n != int64(len(dec)) {
 | 
						|
					panic("could not write all bytes to outDecodedBuf")
 | 
						|
				}
 | 
						|
				nDec += n
 | 
						|
 | 
						|
				// verify the crc32 rotated checksum
 | 
						|
				m32 := masked_crc32c(dec)
 | 
						|
				if m32 != crc {
 | 
						|
					panic(fmt.Sprintf("crc32 masked failiure. expected: %v but got: %v", crc, m32))
 | 
						|
				} else {
 | 
						|
					//fmt.Printf("\nchecksums match: %v == %v\n", crc, m32)
 | 
						|
				}
 | 
						|
 | 
						|
				// move to next header
 | 
						|
				inc := (headerSz + int(chunksz))
 | 
						|
				chunk = chunk[inc:]
 | 
						|
				(*encBuf).Advance(inc)
 | 
						|
				nEnc += int64(inc)
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		case chunk_type == 0x01:
 | 
						|
			{ // uncompressed data
 | 
						|
 | 
						|
				//n, err := w.Write(chunk[(headerSz+crc32Sz):(headerSz + int(chunksz))])
 | 
						|
				n, err := io.Copy(outDecodedBuf, bytes.NewBuffer(chunk[(headerSz+crc32Sz):(headerSz+int(chunksz))]))
 | 
						|
				if verbose {
 | 
						|
					//fmt.Printf("debug: n=%d  err=%v  chunksz=%d  outDecodedBuf='%v'\n", n, err, chunksz, outDecodedBuf)
 | 
						|
				}
 | 
						|
				if err != nil {
 | 
						|
					panic(err)
 | 
						|
				}
 | 
						|
				if n != int64(chunksz-crc32Sz) {
 | 
						|
					panic("could not write all bytes to stdout")
 | 
						|
				}
 | 
						|
				nDec += n
 | 
						|
 | 
						|
				inc := (headerSz + int(chunksz))
 | 
						|
				chunk = chunk[inc:]
 | 
						|
				(*encBuf).Advance(inc)
 | 
						|
				nEnc += int64(inc)
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		case chunk_type == 0xfe:
 | 
						|
			fallthrough // padding, just skip it
 | 
						|
		case chunk_type >= 0x80 && chunk_type <= 0xfd:
 | 
						|
			{ //  Reserved skippable chunks
 | 
						|
				//fmt.Printf("\nin reserved skippable chunks, at nEnc=%v\n", nEnc)
 | 
						|
				inc := (headerSz + int(chunksz))
 | 
						|
				chunk = chunk[inc:]
 | 
						|
				nEnc += int64(inc)
 | 
						|
				(*encBuf).Advance(inc)
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
		default:
 | 
						|
			panic(fmt.Sprintf("unrecognized/unsupported chunk type %#v", chunk_type))
 | 
						|
		}
 | 
						|
 | 
						|
	} // end for{}
 | 
						|
 | 
						|
	return nEnc, nDec, err
 | 
						|
	//return int64(N), nil
 | 
						|
}
 | 
						|
 | 
						|
// for whole file at once:
 | 
						|
//
 | 
						|
// receive on stdin a stream of bytes in the snappy-streaming framed
 | 
						|
//  format, defined here: http://code.google.com/p/snappy/source/browse/trunk/framing_format.txt
 | 
						|
// Grab each frame, run it through the snappy decoder, and spit out
 | 
						|
//  each frame all joined back-to-back on stdout.
 | 
						|
//
 | 
						|
func Unsnappy(r io.Reader, w io.Writer) (err error) {
 | 
						|
	b, err := ioutil.ReadAll(r)
 | 
						|
	if err != nil {
 | 
						|
		panic(err)
 | 
						|
	}
 | 
						|
 | 
						|
	// flag for printing chunk size alignment messages
 | 
						|
	verbose := false
 | 
						|
 | 
						|
	const snappyStreamHeaderSz = 10
 | 
						|
	const headerSz = 4
 | 
						|
	const crc32Sz = 4
 | 
						|
	// the magic 18 bytes accounts for the snappy streaming header and the first chunks size and checksum
 | 
						|
	// http://code.google.com/p/snappy/source/browse/trunk/framing_format.txt
 | 
						|
 | 
						|
	chunk := b[:]
 | 
						|
 | 
						|
	// 65536 is the max size of a snappy framed chunk. See
 | 
						|
	// http://code.google.com/p/snappy/source/browse/trunk/framing_format.txt:91
 | 
						|
	//buf := make([]byte, 65536)
 | 
						|
 | 
						|
	//	fmt.Printf("read from file, b is len:%d with value: %#v\n", len(b), b)
 | 
						|
	//	fmt.Printf("read from file, bcut is len:%d with value: %#v\n", len(bcut), bcut)
 | 
						|
 | 
						|
	//fmt.Printf("raw bytes of chunksz are: %v\n", b[11:14])
 | 
						|
 | 
						|
	fourbytes := make([]byte, 4)
 | 
						|
	chunkCount := 0
 | 
						|
 | 
						|
	for {
 | 
						|
		if len(chunk) == 0 {
 | 
						|
			break
 | 
						|
		}
 | 
						|
		chunkCount++
 | 
						|
		fourbytes[3] = 0
 | 
						|
		copy(fourbytes, chunk[1:4])
 | 
						|
		chunksz := binary.LittleEndian.Uint32(fourbytes)
 | 
						|
		chunk_type := chunk[0]
 | 
						|
 | 
						|
		switch true {
 | 
						|
		case chunk_type == 0xff:
 | 
						|
			{ // stream identifier
 | 
						|
 | 
						|
				streamHeader := chunk[:snappyStreamHeaderSz]
 | 
						|
				if 0 != bytes.Compare(streamHeader, []byte{0xff, 0x06, 0x00, 0x00, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59}) {
 | 
						|
					panic("file had chunk starting with 0xff but then no magic snappy streaming protocol bytes, aborting.")
 | 
						|
				} else {
 | 
						|
					//fmt.Printf("got streaming snappy magic header just fine.\n")
 | 
						|
				}
 | 
						|
				chunk = chunk[snappyStreamHeaderSz:]
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		case chunk_type == 0x00:
 | 
						|
			{ // compressed data
 | 
						|
				if verbose {
 | 
						|
					fmt.Fprintf(os.Stderr, "chunksz is %d  while  total bytes avail are: %d\n", int(chunksz), len(chunk)-4)
 | 
						|
				}
 | 
						|
 | 
						|
				//crc := binary.LittleEndian.Uint32(chunk[headerSz:(headerSz + crc32Sz)])
 | 
						|
				section := chunk[(headerSz + crc32Sz):(headerSz + chunksz)]
 | 
						|
 | 
						|
				dec, ok := snappy.Decode(nil, section)
 | 
						|
				if ok != nil {
 | 
						|
					panic("could not decode snappy stream")
 | 
						|
				}
 | 
						|
				//	fmt.Printf("ok, b is %#v , %#v\n", ok, dec)
 | 
						|
 | 
						|
				// spit out decoded text
 | 
						|
				n, err := w.Write(dec)
 | 
						|
				if err != nil {
 | 
						|
					panic(err)
 | 
						|
				}
 | 
						|
				if n != len(dec) {
 | 
						|
					panic("could not write all bytes to stdout")
 | 
						|
				}
 | 
						|
 | 
						|
				// TODO: verify the crc32 rotated checksum?
 | 
						|
 | 
						|
				// move to next header
 | 
						|
				chunk = chunk[(headerSz + int(chunksz)):]
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		case chunk_type == 0x01:
 | 
						|
			{ // uncompressed data
 | 
						|
 | 
						|
				//crc := binary.LittleEndian.Uint32(chunk[headerSz:(headerSz + crc32Sz)])
 | 
						|
				section := chunk[(headerSz + crc32Sz):(headerSz + chunksz)]
 | 
						|
 | 
						|
				n, err := w.Write(section)
 | 
						|
				if err != nil {
 | 
						|
					panic(err)
 | 
						|
				}
 | 
						|
				if n != int(chunksz-crc32Sz) {
 | 
						|
					panic("could not write all bytes to stdout")
 | 
						|
				}
 | 
						|
 | 
						|
				chunk = chunk[(headerSz + int(chunksz)):]
 | 
						|
				continue
 | 
						|
			}
 | 
						|
		case chunk_type == 0xfe:
 | 
						|
			fallthrough // padding, just skip it
 | 
						|
		case chunk_type >= 0x80 && chunk_type <= 0xfd:
 | 
						|
			{ //  Reserved skippable chunks
 | 
						|
				chunk = chunk[(headerSz + int(chunksz)):]
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
		default:
 | 
						|
			panic(fmt.Sprintf("unrecognized/unsupported chunk type %#v", chunk_type))
 | 
						|
		}
 | 
						|
 | 
						|
	} // end for{}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// 0xff 0x06 0x00 0x00 sNaPpY
 | 
						|
var SnappyStreamHeaderMagic = []byte{0xff, 0x06, 0x00, 0x00, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59}
 | 
						|
 | 
						|
const CHUNK_MAX = 65536
 | 
						|
const _STREAM_TO_STREAM_BLOCK_SIZE = CHUNK_MAX
 | 
						|
const _STREAM_IDENTIFIER = `sNaPpY`
 | 
						|
const _COMPRESSED_CHUNK = 0x00
 | 
						|
const _UNCOMPRESSED_CHUNK = 0x01
 | 
						|
const _IDENTIFIER_CHUNK = 0xff
 | 
						|
const _RESERVED_UNSKIPPABLE0 = 0x02 // chunk ranges are [inclusive, exclusive)
 | 
						|
const _RESERVED_UNSKIPPABLE1 = 0x80
 | 
						|
const _RESERVED_SKIPPABLE0 = 0x80
 | 
						|
const _RESERVED_SKIPPABLE1 = 0xff
 | 
						|
 | 
						|
// the minimum percent of bytes compression must save to be enabled in automatic
 | 
						|
// mode
 | 
						|
const _COMPRESSION_THRESHOLD = .125
 | 
						|
 | 
						|
var crctab *crc32.Table
 | 
						|
 | 
						|
func init() {
 | 
						|
	crctab = crc32.MakeTable(crc32.Castagnoli) // this is correct table, matches the crc32c.c code used by python
 | 
						|
}
 | 
						|
 | 
						|
func masked_crc32c(data []byte) uint32 {
 | 
						|
 | 
						|
	// see the framing format specification, http://code.google.com/p/snappy/source/browse/trunk/framing_format.txt
 | 
						|
	var crc uint32 = crc32.Checksum(data, crctab)
 | 
						|
	return (uint32((crc>>15)|(crc<<17)) + 0xa282ead8)
 | 
						|
}
 | 
						|
 | 
						|
func ReadSnappyStreamCompressedFile(filename string) ([]byte, error) {
 | 
						|
 | 
						|
	snappyFile, err := Open(filename)
 | 
						|
	if err != nil {
 | 
						|
		return []byte{}, err
 | 
						|
	}
 | 
						|
 | 
						|
	var bb bytes.Buffer
 | 
						|
	_, err = bb.ReadFrom(snappyFile)
 | 
						|
	if err == io.EOF {
 | 
						|
		err = nil
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		panic(err)
 | 
						|
	}
 | 
						|
 | 
						|
	return bb.Bytes(), err
 | 
						|
}
 |