writer.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package brotli
  2. import (
  3. "errors"
  4. "io"
  5. )
  6. const (
  7. BestSpeed = 0
  8. BestCompression = 11
  9. DefaultCompression = 6
  10. )
  11. // WriterOptions configures Writer.
  12. type WriterOptions struct {
  13. // Quality controls the compression-speed vs compression-density trade-offs.
  14. // The higher the quality, the slower the compression. Range is 0 to 11.
  15. Quality int
  16. // LGWin is the base 2 logarithm of the sliding window size.
  17. // Range is 10 to 24. 0 indicates automatic configuration based on Quality.
  18. LGWin int
  19. }
  20. var (
  21. errEncode = errors.New("brotli: encode error")
  22. errWriterClosed = errors.New("brotli: Writer is closed")
  23. )
  24. // Writes to the returned writer are compressed and written to dst.
  25. // It is the caller's responsibility to call Close on the Writer when done.
  26. // Writes may be buffered and not flushed until Close.
  27. func NewWriter(dst io.Writer) *Writer {
  28. return NewWriterLevel(dst, DefaultCompression)
  29. }
  30. // NewWriterLevel is like NewWriter but specifies the compression level instead
  31. // of assuming DefaultCompression.
  32. // The compression level can be DefaultCompression or any integer value between
  33. // BestSpeed and BestCompression inclusive.
  34. func NewWriterLevel(dst io.Writer, level int) *Writer {
  35. return NewWriterOptions(dst, WriterOptions{
  36. Quality: level,
  37. })
  38. }
  39. // NewWriterOptions is like NewWriter but specifies WriterOptions
  40. func NewWriterOptions(dst io.Writer, options WriterOptions) *Writer {
  41. w := new(Writer)
  42. w.options = options
  43. w.Reset(dst)
  44. return w
  45. }
  46. // Reset discards the Writer's state and makes it equivalent to the result of
  47. // its original state from NewWriter or NewWriterLevel, but writing to dst
  48. // instead. This permits reusing a Writer rather than allocating a new one.
  49. func (w *Writer) Reset(dst io.Writer) {
  50. encoderInitState(w)
  51. w.params.quality = w.options.Quality
  52. if w.options.LGWin > 0 {
  53. w.params.lgwin = uint(w.options.LGWin)
  54. }
  55. w.dst = dst
  56. w.err = nil
  57. }
  58. func (w *Writer) writeChunk(p []byte, op int) (n int, err error) {
  59. if w.dst == nil {
  60. return 0, errWriterClosed
  61. }
  62. if w.err != nil {
  63. return 0, w.err
  64. }
  65. for {
  66. availableIn := uint(len(p))
  67. nextIn := p
  68. success := encoderCompressStream(w, op, &availableIn, &nextIn)
  69. bytesConsumed := len(p) - int(availableIn)
  70. p = p[bytesConsumed:]
  71. n += bytesConsumed
  72. if !success {
  73. return n, errEncode
  74. }
  75. if len(p) == 0 || w.err != nil {
  76. return n, w.err
  77. }
  78. }
  79. }
  80. // Flush outputs encoded data for all input provided to Write. The resulting
  81. // output can be decoded to match all input before Flush, but the stream is
  82. // not yet complete until after Close.
  83. // Flush has a negative impact on compression.
  84. func (w *Writer) Flush() error {
  85. _, err := w.writeChunk(nil, operationFlush)
  86. return err
  87. }
  88. // Close flushes remaining data to the decorated writer.
  89. func (w *Writer) Close() error {
  90. // If stream is already closed, it is reported by `writeChunk`.
  91. _, err := w.writeChunk(nil, operationFinish)
  92. w.dst = nil
  93. return err
  94. }
  95. // Write implements io.Writer. Flush or Close must be called to ensure that the
  96. // encoded bytes are actually flushed to the underlying Writer.
  97. func (w *Writer) Write(p []byte) (n int, err error) {
  98. return w.writeChunk(p, operationProcess)
  99. }
  100. type nopCloser struct {
  101. io.Writer
  102. }
  103. func (nopCloser) Close() error { return nil }