1package unsnap 2 3import ( 4 "encoding/binary" 5 6 // no c lib dependency 7 snappy "github.com/golang/snappy" 8 // or, use the C wrapper for speed 9 //snappy "github.com/dgryski/go-csnappy" 10) 11 12// add Write() method for SnappyFile (see unsnap.go) 13 14// reference for snappy framing/streaming format: 15// http://code.google.com/p/snappy/source/browse/trunk/framing_format.txt 16// ?spec=svn68&r=71 17 18// 19// Write writes len(p) bytes from p to the underlying data stream. 20// It returns the number of bytes written from p (0 <= n <= len(p)) and 21// any error encountered that caused the write to stop early. Write 22// must return a non-nil error if it returns n < len(p). 23// 24func (sf *SnappyFile) Write(p []byte) (n int, err error) { 25 26 if sf.SnappyEncodeDecodeOff { 27 return sf.Writer.Write(p) 28 } 29 30 if !sf.Writing { 31 panic("Writing on a read-only SnappyFile") 32 } 33 34 // encoding in snappy can apparently go beyond the original size, beware. 35 // so our buffers must be sized 2*max snappy chunk => 2 * CHUNK_MAX(65536) 36 37 sf.DecBuf.Reset() 38 sf.EncBuf.Reset() 39 40 if !sf.HeaderChunkWritten { 41 sf.HeaderChunkWritten = true 42 _, err = sf.Writer.Write(SnappyStreamHeaderMagic) 43 if err != nil { 44 return 45 } 46 } 47 var chunk []byte 48 var chunk_type byte 49 var crc uint32 50 51 for len(p) > 0 { 52 53 // chunk points to input p by default, unencoded input. 54 chunk = p[:IntMin(len(p), CHUNK_MAX)] 55 crc = masked_crc32c(chunk) 56 57 writeme := chunk[:] 58 59 // first write to EncBuf, as a temp, in case we want 60 // to discard and send uncompressed instead. 61 compressed_chunk := snappy.Encode(sf.EncBuf.GetEndmostWritableSlice(), chunk) 62 63 if len(compressed_chunk) <= int((1-_COMPRESSION_THRESHOLD)*float64(len(chunk))) { 64 writeme = compressed_chunk 65 chunk_type = _COMPRESSED_CHUNK 66 } else { 67 // keep writeme pointing at original chunk (uncompressed) 68 chunk_type = _UNCOMPRESSED_CHUNK 69 } 70 71 const crc32Sz = 4 72 var tag32 uint32 = uint32(chunk_type) + (uint32(len(writeme)+crc32Sz) << 8) 73 74 err = binary.Write(sf.Writer, binary.LittleEndian, tag32) 75 if err != nil { 76 return 77 } 78 79 err = binary.Write(sf.Writer, binary.LittleEndian, crc) 80 if err != nil { 81 return 82 } 83 84 _, err = sf.Writer.Write(writeme) 85 if err != nil { 86 return 87 } 88 89 n += len(chunk) 90 p = p[len(chunk):] 91 } 92 return n, nil 93} 94 95func IntMin(a int, b int) int { 96 if a < b { 97 return a 98 } 99 return b 100} 101