123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- package snappy
- import (
- "encoding/binary"
- "errors"
- "io"
- )
- const maxOffset = 1 << 15
- func emitLiteral(dst, lit []byte) int {
- i, n := 0, uint(len(lit)-1)
- switch {
- case n < 60:
- dst[0] = uint8(n)<<2 | tagLiteral
- i = 1
- case n < 1<<8:
- dst[0] = 60<<2 | tagLiteral
- dst[1] = uint8(n)
- i = 2
- case n < 1<<16:
- dst[0] = 61<<2 | tagLiteral
- dst[1] = uint8(n)
- dst[2] = uint8(n >> 8)
- i = 3
- case n < 1<<24:
- dst[0] = 62<<2 | tagLiteral
- dst[1] = uint8(n)
- dst[2] = uint8(n >> 8)
- dst[3] = uint8(n >> 16)
- i = 4
- case int64(n) < 1<<32:
- dst[0] = 63<<2 | tagLiteral
- dst[1] = uint8(n)
- dst[2] = uint8(n >> 8)
- dst[3] = uint8(n >> 16)
- dst[4] = uint8(n >> 24)
- i = 5
- default:
- panic("snappy: source buffer is too long")
- }
- if copy(dst[i:], lit) != len(lit) {
- panic("snappy: destination buffer is too short")
- }
- return i + len(lit)
- }
- func emitCopy(dst []byte, offset, length int) int {
- i := 0
- for length > 0 {
- x := length - 4
- if 0 <= x && x < 1<<3 && offset < 1<<11 {
- dst[i+0] = uint8(offset>>8)&0x07<<5 | uint8(x)<<2 | tagCopy1
- dst[i+1] = uint8(offset)
- i += 2
- break
- }
- x = length
- if x > 1<<6 {
- x = 1 << 6
- }
- dst[i+0] = uint8(x-1)<<2 | tagCopy2
- dst[i+1] = uint8(offset)
- dst[i+2] = uint8(offset >> 8)
- i += 3
- length -= x
- }
- return i
- }
- func Encode(dst, src []byte) []byte {
- if n := MaxEncodedLen(len(src)); len(dst) < n {
- dst = make([]byte, n)
- }
-
- d := binary.PutUvarint(dst, uint64(len(src)))
-
- if len(src) <= 4 {
- if len(src) != 0 {
- d += emitLiteral(dst[d:], src)
- }
- return dst[:d]
- }
-
- const maxTableSize = 1 << 14
- shift, tableSize := uint(32-8), 1<<8
- for tableSize < maxTableSize && tableSize < len(src) {
- shift--
- tableSize *= 2
- }
- var table [maxTableSize]int
-
- var (
- s int
- t int
- lit int
- )
- for uint(s+3) < uint(len(src)) {
-
- b0, b1, b2, b3 := src[s], src[s+1], src[s+2], src[s+3]
- h := uint32(b0) | uint32(b1)<<8 | uint32(b2)<<16 | uint32(b3)<<24
- p := &table[(h*0x1e35a7bd)>>shift]
-
-
-
-
- t, *p = *p-1, s+1
-
- if t < 0 || s-t >= maxOffset || b0 != src[t] || b1 != src[t+1] || b2 != src[t+2] || b3 != src[t+3] {
-
- s += 1 + (s-lit)>>5
- continue
- }
-
- if lit != s {
- d += emitLiteral(dst[d:], src[lit:s])
- }
-
- s0 := s
- s, t = s+4, t+4
- for s < len(src) && src[s] == src[t] {
- s++
- t++
- }
-
- d += emitCopy(dst[d:], s-t, s-s0)
- lit = s
- }
-
- if lit != len(src) {
- d += emitLiteral(dst[d:], src[lit:])
- }
- return dst[:d]
- }
- func MaxEncodedLen(srcLen int) int {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- return 32 + srcLen + srcLen/6
- }
- var errClosed = errors.New("snappy: Writer is closed")
- func NewWriter(w io.Writer) *Writer {
- return &Writer{
- w: w,
- obuf: make([]byte, obufLen),
- }
- }
- func NewBufferedWriter(w io.Writer) *Writer {
- return &Writer{
- w: w,
- ibuf: make([]byte, 0, maxUncompressedChunkLen),
- obuf: make([]byte, obufLen),
- }
- }
- type Writer struct {
- w io.Writer
- err error
-
-
-
-
-
- ibuf []byte
-
- obuf []byte
-
- wroteStreamHeader bool
- }
- func (w *Writer) Reset(writer io.Writer) {
- w.w = writer
- w.err = nil
- if w.ibuf != nil {
- w.ibuf = w.ibuf[:0]
- }
- w.wroteStreamHeader = false
- }
- func (w *Writer) Write(p []byte) (nRet int, errRet error) {
- if w.ibuf == nil {
-
-
-
-
- return w.write(p)
- }
-
-
- for len(p) > (cap(w.ibuf)-len(w.ibuf)) && w.err == nil {
- var n int
- if len(w.ibuf) == 0 {
-
-
- n, _ = w.write(p)
- } else {
- n = copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
- w.ibuf = w.ibuf[:len(w.ibuf)+n]
- w.Flush()
- }
- nRet += n
- p = p[n:]
- }
- if w.err != nil {
- return nRet, w.err
- }
- n := copy(w.ibuf[len(w.ibuf):cap(w.ibuf)], p)
- w.ibuf = w.ibuf[:len(w.ibuf)+n]
- nRet += n
- return nRet, nil
- }
- func (w *Writer) write(p []byte) (nRet int, errRet error) {
- if w.err != nil {
- return 0, w.err
- }
- for len(p) > 0 {
- obufStart := len(magicChunk)
- if !w.wroteStreamHeader {
- w.wroteStreamHeader = true
- copy(w.obuf, magicChunk)
- obufStart = 0
- }
- var uncompressed []byte
- if len(p) > maxUncompressedChunkLen {
- uncompressed, p = p[:maxUncompressedChunkLen], p[maxUncompressedChunkLen:]
- } else {
- uncompressed, p = p, nil
- }
- checksum := crc(uncompressed)
-
-
- compressed := Encode(w.obuf[obufHeaderLen:], uncompressed)
- chunkType := uint8(chunkTypeCompressedData)
- chunkLen := 4 + len(compressed)
- obufEnd := obufHeaderLen + len(compressed)
- if len(compressed) >= len(uncompressed)-len(uncompressed)/8 {
- chunkType = chunkTypeUncompressedData
- chunkLen = 4 + len(uncompressed)
- obufEnd = obufHeaderLen
- }
-
- w.obuf[len(magicChunk)+0] = chunkType
- w.obuf[len(magicChunk)+1] = uint8(chunkLen >> 0)
- w.obuf[len(magicChunk)+2] = uint8(chunkLen >> 8)
- w.obuf[len(magicChunk)+3] = uint8(chunkLen >> 16)
- w.obuf[len(magicChunk)+4] = uint8(checksum >> 0)
- w.obuf[len(magicChunk)+5] = uint8(checksum >> 8)
- w.obuf[len(magicChunk)+6] = uint8(checksum >> 16)
- w.obuf[len(magicChunk)+7] = uint8(checksum >> 24)
- if _, err := w.w.Write(w.obuf[obufStart:obufEnd]); err != nil {
- w.err = err
- return nRet, err
- }
- if chunkType == chunkTypeUncompressedData {
- if _, err := w.w.Write(uncompressed); err != nil {
- w.err = err
- return nRet, err
- }
- }
- nRet += len(uncompressed)
- }
- return nRet, nil
- }
- func (w *Writer) Flush() error {
- if w.err != nil {
- return w.err
- }
- if len(w.ibuf) == 0 {
- return nil
- }
- w.write(w.ibuf)
- w.ibuf = w.ibuf[:0]
- return w.err
- }
- func (w *Writer) Close() error {
- w.Flush()
- ret := w.err
- if w.err == nil {
- w.err = errClosed
- }
- return ret
- }
|