Home | History | Annotate | Download | only in cbrotli
      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.
      7 package cbrotli
      8 
      9 import (
     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.
     18 type internalError string
     19 
     20 func (e internalError) Error() string {
     21 	return "cbrotli: internal error: " + string(e)
     22 }
     23 
     24 //------------------------------------------------------------------------------
     25 // Encoder
     26 //------------------------------------------------------------------------------
     27 
     28 // WriterOptions configures Writer.
     29 type 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.
     40 type 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.
     48 func 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.
     57 func (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 
     67 func (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.
     93 func (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.
    101 func (z *Writer) Flush() error {
    102 	_, err := z.writeChunk(nil, encoder.Finish)
    103 	return err
    104 }
    105 
    106 // Encode returns content encoded with Brotli.
    107 func 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.
    127 type 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.
    141 func 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.
    151 func (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 
    161 func 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.
    167 func (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.
    245 func 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