github.com/andybalholm/brotli@v1.0.6/writer.go (about)

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