1// Copyright 2016 Google Inc. All Rights Reserved. 2// 3// Distributed under MIT license. 4// See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 5 6// Package cbrotli compresses and decompresses data with C-Brotli library. 7package cbrotli 8 9import ( 10 "bytes" 11 "io" 12 13 "github.com/google/brotli/go/cbrotli/internal/decoder" 14 "github.com/google/brotli/go/cbrotli/internal/encoder" 15) 16 17// An internalError reports an error in the (c-)brotli code itself. 18type internalError string 19 20func (e internalError) Error() string { 21 return "cbrotli: internal error: " + string(e) 22} 23 24//------------------------------------------------------------------------------ 25// Encoder 26//------------------------------------------------------------------------------ 27 28// WriterOptions configures Writer. 29type WriterOptions struct { 30 // Quality controls the compression-speed vs compression-density trade-offs. 31 // The higher the quality, the slower the compression. Range is 0 to 11. 32 Quality int 33 // LGWin is the base 2 logarithm of the sliding window size. 34 // Range is 10 to 24. 0 indicates automatic configuration based on Quality. 35 LGWin int 36} 37 38// Writer implements io.WriteCloser, an io.Writer decorator that produces 39// Brotli-encoded data. 40type Writer struct { 41 dst io.Writer 42 encoder encoder.Encoder 43 closed bool 44} 45 46// NewWriter initializes new Writer instance. 47// Close MUST be called to free resources. 48func NewWriter(dst io.Writer, options WriterOptions) *Writer { 49 return &Writer{ 50 dst: dst, 51 encoder: encoder.New(options.Quality, options.LGWin), 52 } 53} 54 55// Close implements io.Closer. Close MUST be invoked to free native resources. 56// Also Close implicitly flushes remaining data to the decorated writer. 57func (z *Writer) Close() error { 58 if z.closed { 59 return nil 60 } 61 defer z.encoder.Close() 62 _, err := z.writeChunk(nil, encoder.Finish) 63 z.closed = true 64 return err 65} 66 67func (z *Writer) writeChunk(p []byte, op encoder.Operation) (int, error) { 68 if z.closed { 69 return 0, internalError("write after close") 70 } 71 var totalBytesConsumed int 72 var err error 73 for { 74 bytesConsumed, output, status := z.encoder.CompressStream(p, op) 75 if status == encoder.Error { 76 err = internalError("encoder failure") 77 break 78 } 79 p = p[bytesConsumed:] 80 totalBytesConsumed += bytesConsumed 81 _, err = z.dst.Write(output) 82 if err != nil { 83 break 84 } 85 if len(p) == 0 && status == encoder.Done { 86 break 87 } 88 } 89 return totalBytesConsumed, err 90} 91 92// Write implements io.Writer. 93func (z *Writer) Write(p []byte) (int, error) { 94 return z.writeChunk(p, encoder.Process) 95} 96 97// Flush outputs encoded data for all input provided to Write. The resulting 98// output can be decoded to match all input before Flush, but the stream is 99// not yet complete until after Close. 100// Flush has a negative impact on compression. 101func (z *Writer) Flush() error { 102 _, err := z.writeChunk(nil, encoder.Finish) 103 return err 104} 105 106// Encode returns content encoded with Brotli. 107func Encode(content []byte, options WriterOptions) ([]byte, error) { 108 var buf bytes.Buffer 109 writer := NewWriter(&buf, options) 110 defer writer.Close() 111 _, err := writer.Write(content) 112 if err != nil { 113 return nil, err 114 } 115 if err := writer.Close(); err != nil { 116 return nil, err 117 } 118 return buf.Bytes(), nil 119} 120 121//------------------------------------------------------------------------------ 122// Decoder 123//------------------------------------------------------------------------------ 124 125// Reader implements io.ReadCloser, an io.Reader decorator that decodes 126// Brotli-encoded data. 127type Reader struct { 128 src io.Reader 129 decoder decoder.Decoder 130 buf []byte // intermediate read buffer pointed to by next 131 eof bool // true if all compressed stream is decoded 132 next []byte // buffered data to be passed to decoder 133 output []byte // data produced by decoder, but not yet consumed 134 srcErr error // last source reader error 135 err error // reader state; nil if it is OK to read further 136 closed bool // true is stream is already closed 137} 138 139// NewReader initializes new Reader instance. 140// Close MUST be called to free resources. 141func NewReader(src io.Reader) *Reader { 142 return &Reader{ 143 src: src, 144 decoder: decoder.New(), 145 buf: make([]byte, 32*1024), 146 eof: false, 147 } 148} 149 150// Close implements io.Closer. Close MUST be invoked to free native resources. 151func (z *Reader) Close() error { 152 if z.closed { 153 return nil 154 } 155 z.decoder.Close() 156 z.err = internalError("read after close") 157 z.closed = true 158 return nil 159} 160 161func isEOF(src io.Reader) bool { 162 n, err := src.Read(make([]byte, 1)) 163 return n == 0 && err == io.EOF 164} 165 166// Read implements io.Reader. 167func (z *Reader) Read(p []byte) (int, error) { 168 // Any error state is unrecoverable. 169 if z.err != nil { 170 return 0, z.err 171 } 172 // See io.Reader documentation. 173 if len(p) == 0 { 174 return 0, nil 175 } 176 177 var totalOutBytes int 178 179 // There is no practical limit for amount of bytes being consumed by decoder 180 // before producing any output. Continue feeding decoder until some data is 181 // produced 182 for { 183 // Push already produced output first. 184 if outBytes := len(z.output); outBytes != 0 { 185 outBytes = copy(p, z.output) 186 p = p[outBytes:] 187 z.output = z.output[outBytes:] 188 totalOutBytes += outBytes 189 // Output buffer is full. 190 if len(p) == 0 { 191 break 192 } 193 continue 194 } 195 // No more produced output left. 196 // If no more output is expected, then we are finished. 197 if z.eof { 198 z.err = io.EOF 199 break 200 } 201 // Replenish buffer (might cause blocking read), only if necessary. 202 if len(z.next) == 0 && totalOutBytes == 0 && z.srcErr != io.EOF { 203 var n int 204 n, z.srcErr = z.src.Read(z.buf) 205 z.next = z.buf[:n] 206 if z.srcErr != nil && z.srcErr != io.EOF { 207 z.err = z.srcErr 208 break 209 } 210 } 211 // Do decoding. 212 consumed, output, status := z.decoder.DecompressStream(z.next) 213 z.output = output 214 z.next = z.next[consumed:] 215 if status == decoder.Error { 216 // When error happens, the remaining output does not matter. 217 z.err = internalError("decoder failure") 218 break 219 } else if status == decoder.Done { 220 // Decoder stream is closed; no further input is expected. 221 if len(z.next) != 0 || (z.srcErr != io.EOF && !isEOF(z.src)) { 222 z.err = internalError("excessive input") 223 break 224 } 225 // No more output is expected; keep pushing output. 226 z.eof = true 227 continue 228 } else { 229 // If can not move any further... 230 if consumed == 0 && len(z.output) == 0 { 231 // Unexpected end of input. 232 if z.srcErr == io.EOF || totalOutBytes == 0 { 233 z.err = io.ErrUnexpectedEOF 234 } 235 // Postpone blocking reads for the next invocation. 236 break 237 } 238 // Continue pushing output. 239 } 240 } 241 return totalOutBytes, z.err 242} 243 244// Decode decodes Brotli encoded data. 245func Decode(encodedData []byte) ([]byte, error) { 246 var buf bytes.Buffer 247 reader := NewReader(bytes.NewReader(encodedData)) 248 defer reader.Close() 249 _, err := io.Copy(&buf, reader) 250 if err != nil { 251 return nil, err 252 } 253 return buf.Bytes(), nil 254} 255