forked from andybalholm/brotli
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make BrotliEncoderState into a Writer.
- Loading branch information
1 parent
69a32ec
commit f036cd0
Showing
2 changed files
with
123 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package brotli | ||
|
||
import ( | ||
"errors" | ||
"io" | ||
) | ||
|
||
// WriterOptions configures Writer. | ||
type WriterOptions struct { | ||
// Quality controls the compression-speed vs compression-density trade-offs. | ||
// The higher the quality, the slower the compression. Range is 0 to 11. | ||
Quality int | ||
// LGWin is the base 2 logarithm of the sliding window size. | ||
// Range is 10 to 24. 0 indicates automatic configuration based on Quality. | ||
LGWin int | ||
} | ||
|
||
var ( | ||
errEncode = errors.New("brotli: encode error") | ||
errWriterClosed = errors.New("brotli: Writer is closed") | ||
) | ||
|
||
// NewWriter initializes new Writer instance. | ||
func NewWriter(dst io.Writer, options WriterOptions) *Writer { | ||
w := new(Writer) | ||
BrotliEncoderInitState(w) | ||
BrotliEncoderSetParameter(w, BROTLI_PARAM_QUALITY, uint32(options.Quality)) | ||
if options.LGWin > 0 { | ||
BrotliEncoderSetParameter(w, BROTLI_PARAM_LGWIN, uint32(options.LGWin)) | ||
} | ||
w.dst = dst | ||
return w | ||
} | ||
|
||
func (w *Writer) writeChunk(p []byte, op int) (n int, err error) { | ||
if w.dst == nil { | ||
return 0, errWriterClosed | ||
} | ||
|
||
for { | ||
availableIn := uint(len(p)) | ||
nextIn := p | ||
availableOut := uint(0) | ||
success := BrotliEncoderCompressStream(w, op, &availableIn, &nextIn, &availableOut, nil, nil) | ||
bytesConsumed := len(p) - int(availableIn) | ||
p = p[bytesConsumed:] | ||
n += bytesConsumed | ||
if !success { | ||
return n, errEncode | ||
} | ||
|
||
var outputDataSize uint | ||
outputData := BrotliEncoderTakeOutput(w, &outputDataSize) | ||
outputData = outputData[:outputDataSize] | ||
|
||
if outputDataSize > 0 { | ||
_, err = w.dst.Write(outputData) | ||
if err != nil { | ||
return n, err | ||
} | ||
} | ||
if len(p) == 0 && !BrotliEncoderHasMoreOutput(w) { | ||
return n, nil | ||
} | ||
} | ||
} | ||
|
||
// Flush outputs encoded data for all input provided to Write. The resulting | ||
// output can be decoded to match all input before Flush, but the stream is | ||
// not yet complete until after Close. | ||
// Flush has a negative impact on compression. | ||
func (w *Writer) Flush() error { | ||
_, err := w.writeChunk(nil, BROTLI_OPERATION_FLUSH) | ||
return err | ||
} | ||
|
||
// Close flushes remaining data to the decorated writer. | ||
func (w *Writer) Close() error { | ||
// If stream is already closed, it is reported by `writeChunk`. | ||
_, err := w.writeChunk(nil, BROTLI_OPERATION_FINISH) | ||
w.dst = nil | ||
return err | ||
} | ||
|
||
// Write implements io.Writer. Flush or Close must be called to ensure that the | ||
// encoded bytes are actually flushed to the underlying Writer. | ||
func (w *Writer) Write(p []byte) (n int, err error) { | ||
return w.writeChunk(p, BROTLI_OPERATION_PROCESS) | ||
} |