github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/klauspost/compress/zlib/writer.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package zlib 6 7 import ( 8 "fmt" 9 "hash" 10 "hash/adler32" 11 "io" 12 13 "github.com/insionng/yougam/libraries/klauspost/compress/flate" 14 ) 15 16 // These constants are copied from the flate package, so that code that imports 17 // "compress/zlib" does not also have to import "compress/flate". 18 const ( 19 NoCompression = flate.NoCompression 20 BestSpeed = flate.BestSpeed 21 BestCompression = flate.BestCompression 22 DefaultCompression = flate.DefaultCompression 23 ConstantCompression = flate.ConstantCompression 24 ) 25 26 // A Writer takes data written to it and writes the compressed 27 // form of that data to an underlying writer (see NewWriter). 28 type Writer struct { 29 w io.Writer 30 level int 31 dict []byte 32 compressor *flate.Writer 33 digest hash.Hash32 34 err error 35 scratch [4]byte 36 wroteHeader bool 37 } 38 39 // NewWriter creates a new Writer. 40 // Writes to the returned Writer are compressed and written to w. 41 // 42 // It is the caller's responsibility to call Close on the WriteCloser when done. 43 // Writes may be buffered and not flushed until Close. 44 func NewWriter(w io.Writer) *Writer { 45 z, _ := NewWriterLevelDict(w, DefaultCompression, nil) 46 return z 47 } 48 49 // NewWriterLevel is like NewWriter but specifies the compression level instead 50 // of assuming DefaultCompression. 51 // 52 // The compression level can be DefaultCompression, NoCompression, or any 53 // integer value between BestSpeed and BestCompression inclusive. The error 54 // returned will be nil if the level is valid. 55 func NewWriterLevel(w io.Writer, level int) (*Writer, error) { 56 return NewWriterLevelDict(w, level, nil) 57 } 58 59 // NewWriterLevelDict is like NewWriterLevel but specifies a dictionary to 60 // compress with. 61 // 62 // The dictionary may be nil. If not, its contents should not be modified until 63 // the Writer is closed. 64 func NewWriterLevelDict(w io.Writer, level int, dict []byte) (*Writer, error) { 65 if level < ConstantCompression || level > BestCompression { 66 return nil, fmt.Errorf("zlib: invalid compression level: %d", level) 67 } 68 return &Writer{ 69 w: w, 70 level: level, 71 dict: dict, 72 }, nil 73 } 74 75 // Reset clears the state of the Writer z such that it is equivalent to its 76 // initial state from NewWriterLevel or NewWriterLevelDict, but instead writing 77 // to w. 78 func (z *Writer) Reset(w io.Writer) { 79 z.w = w 80 // z.level and z.dict left unchanged. 81 if z.compressor != nil { 82 z.compressor.Reset(w) 83 } 84 if z.digest != nil { 85 z.digest.Reset() 86 } 87 z.err = nil 88 z.scratch = [4]byte{} 89 z.wroteHeader = false 90 } 91 92 // writeHeader writes the ZLIB header. 93 func (z *Writer) writeHeader() (err error) { 94 z.wroteHeader = true 95 // ZLIB has a two-byte header (as documented in RFC 1950). 96 // The first four bits is the CINFO (compression info), which is 7 for the default deflate window size. 97 // The next four bits is the CM (compression method), which is 8 for deflate. 98 z.scratch[0] = 0x78 99 // The next two bits is the FLEVEL (compression level). The four values are: 100 // 0=fastest, 1=fast, 2=default, 3=best. 101 // The next bit, FDICT, is set if a dictionary is given. 102 // The final five FCHECK bits form a mod-31 checksum. 103 switch z.level { 104 case -2, 0, 1: 105 z.scratch[1] = 0 << 6 106 case 2, 3, 4, 5: 107 z.scratch[1] = 1 << 6 108 case 6, -1: 109 z.scratch[1] = 2 << 6 110 case 7, 8, 9: 111 z.scratch[1] = 3 << 6 112 default: 113 panic("unreachable") 114 } 115 if z.dict != nil { 116 z.scratch[1] |= 1 << 5 117 } 118 z.scratch[1] += uint8(31 - (uint16(z.scratch[0])<<8+uint16(z.scratch[1]))%31) 119 if _, err = z.w.Write(z.scratch[0:2]); err != nil { 120 return err 121 } 122 if z.dict != nil { 123 // The next four bytes are the Adler-32 checksum of the dictionary. 124 checksum := adler32.Checksum(z.dict) 125 z.scratch[0] = uint8(checksum >> 24) 126 z.scratch[1] = uint8(checksum >> 16) 127 z.scratch[2] = uint8(checksum >> 8) 128 z.scratch[3] = uint8(checksum >> 0) 129 if _, err = z.w.Write(z.scratch[0:4]); err != nil { 130 return err 131 } 132 } 133 if z.compressor == nil { 134 // Initialize deflater unless the Writer is being reused 135 // after a Reset call. 136 z.compressor, err = flate.NewWriterDict(z.w, z.level, z.dict) 137 if err != nil { 138 return err 139 } 140 z.digest = adler32.New() 141 } 142 return nil 143 } 144 145 // Write writes a compressed form of p to the underlying io.Writer. The 146 // compressed bytes are not necessarily flushed until the Writer is closed or 147 // explicitly flushed. 148 func (z *Writer) Write(p []byte) (n int, err error) { 149 if !z.wroteHeader { 150 z.err = z.writeHeader() 151 } 152 if z.err != nil { 153 return 0, z.err 154 } 155 if len(p) == 0 { 156 return 0, nil 157 } 158 n, err = z.compressor.Write(p) 159 if err != nil { 160 z.err = err 161 return 162 } 163 z.digest.Write(p) 164 return 165 } 166 167 // Flush flushes the Writer to its underlying io.Writer. 168 func (z *Writer) Flush() error { 169 if !z.wroteHeader { 170 z.err = z.writeHeader() 171 } 172 if z.err != nil { 173 return z.err 174 } 175 z.err = z.compressor.Flush() 176 return z.err 177 } 178 179 // Close closes the Writer, flushing any unwritten data to the underlying 180 // io.Writer, but does not close the underlying io.Writer. 181 func (z *Writer) Close() error { 182 if !z.wroteHeader { 183 z.err = z.writeHeader() 184 } 185 if z.err != nil { 186 return z.err 187 } 188 z.err = z.compressor.Close() 189 if z.err != nil { 190 return z.err 191 } 192 checksum := z.digest.Sum32() 193 // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952). 194 z.scratch[0] = uint8(checksum >> 24) 195 z.scratch[1] = uint8(checksum >> 16) 196 z.scratch[2] = uint8(checksum >> 8) 197 z.scratch[3] = uint8(checksum >> 0) 198 _, z.err = z.w.Write(z.scratch[0:4]) 199 return z.err 200 }