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