• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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