100 lines
		
	
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			100 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
 | |
| }
 | 
