Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
3.2 KiB
118 lines
3.2 KiB
package brotli |
|
|
|
import ( |
|
"errors" |
|
"io" |
|
) |
|
|
|
const ( |
|
BestSpeed = 0 |
|
BestCompression = 11 |
|
DefaultCompression = 6 |
|
) |
|
|
|
// 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") |
|
) |
|
|
|
// Writes to the returned writer are compressed and written to dst. |
|
// It is the caller's responsibility to call Close on the Writer when done. |
|
// Writes may be buffered and not flushed until Close. |
|
func NewWriter(dst io.Writer) *Writer { |
|
return NewWriterLevel(dst, DefaultCompression) |
|
} |
|
|
|
// NewWriterLevel is like NewWriter but specifies the compression level instead |
|
// of assuming DefaultCompression. |
|
// The compression level can be DefaultCompression or any integer value between |
|
// BestSpeed and BestCompression inclusive. |
|
func NewWriterLevel(dst io.Writer, level int) *Writer { |
|
return NewWriterOptions(dst, WriterOptions{ |
|
Quality: level, |
|
}) |
|
} |
|
|
|
// NewWriterOptions is like NewWriter but specifies WriterOptions |
|
func NewWriterOptions(dst io.Writer, options WriterOptions) *Writer { |
|
w := new(Writer) |
|
w.options = options |
|
w.Reset(dst) |
|
return w |
|
} |
|
|
|
// Reset discards the Writer's state and makes it equivalent to the result of |
|
// its original state from NewWriter or NewWriterLevel, but writing to dst |
|
// instead. This permits reusing a Writer rather than allocating a new one. |
|
func (w *Writer) Reset(dst io.Writer) { |
|
encoderInitState(w) |
|
w.params.quality = w.options.Quality |
|
if w.options.LGWin > 0 { |
|
w.params.lgwin = uint(w.options.LGWin) |
|
} |
|
w.dst = dst |
|
} |
|
|
|
func (w *Writer) writeChunk(p []byte, op int) (n int, err error) { |
|
if w.dst == nil { |
|
return 0, errWriterClosed |
|
} |
|
if w.err != nil { |
|
return 0, w.err |
|
} |
|
|
|
for { |
|
availableIn := uint(len(p)) |
|
nextIn := p |
|
success := encoderCompressStream(w, op, &availableIn, &nextIn) |
|
bytesConsumed := len(p) - int(availableIn) |
|
p = p[bytesConsumed:] |
|
n += bytesConsumed |
|
if !success { |
|
return n, errEncode |
|
} |
|
|
|
if len(p) == 0 || w.err != nil { |
|
return n, w.err |
|
} |
|
} |
|
} |
|
|
|
// 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, operationFlush) |
|
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, operationFinish) |
|
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, operationProcess) |
|
} |
|
|
|
type nopCloser struct { |
|
io.Writer |
|
} |
|
|
|
func (nopCloser) Close() error { return nil }
|
|
|