123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- // Copyright 2019+ Klaus Post. All rights reserved.
- // License information can be found in the LICENSE file.
- package zstd
- import (
- "errors"
- "io"
- "sync"
- )
- // ZipMethodWinZip is the method for Zstandard compressed data inside Zip files for WinZip.
- // See https://www.winzip.com/win/en/comp_info.html
- const ZipMethodWinZip = 93
- // ZipMethodPKWare is the original method number used by PKWARE to indicate Zstandard compression.
- // Deprecated: This has been deprecated by PKWARE, use ZipMethodWinZip instead for compression.
- // See https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.9.TXT
- const ZipMethodPKWare = 20
- // zipReaderPool is the default reader pool.
- var zipReaderPool = sync.Pool{New: func() interface{} {
- z, err := NewReader(nil, WithDecoderLowmem(true), WithDecoderMaxWindow(128<<20), WithDecoderConcurrency(1))
- if err != nil {
- panic(err)
- }
- return z
- }}
- // newZipReader creates a pooled zip decompressor.
- func newZipReader(opts ...DOption) func(r io.Reader) io.ReadCloser {
- pool := &zipReaderPool
- if len(opts) > 0 {
- opts = append([]DOption{WithDecoderLowmem(true), WithDecoderMaxWindow(128 << 20)}, opts...)
- // Force concurrency 1
- opts = append(opts, WithDecoderConcurrency(1))
- // Create our own pool
- pool = &sync.Pool{}
- }
- return func(r io.Reader) io.ReadCloser {
- dec, ok := pool.Get().(*Decoder)
- if ok {
- dec.Reset(r)
- } else {
- d, err := NewReader(r, opts...)
- if err != nil {
- panic(err)
- }
- dec = d
- }
- return &pooledZipReader{dec: dec, pool: pool}
- }
- }
- type pooledZipReader struct {
- mu sync.Mutex // guards Close and Read
- pool *sync.Pool
- dec *Decoder
- }
- func (r *pooledZipReader) Read(p []byte) (n int, err error) {
- r.mu.Lock()
- defer r.mu.Unlock()
- if r.dec == nil {
- return 0, errors.New("read after close or EOF")
- }
- dec, err := r.dec.Read(p)
- if err == io.EOF {
- r.dec.Reset(nil)
- r.pool.Put(r.dec)
- r.dec = nil
- }
- return dec, err
- }
- func (r *pooledZipReader) Close() error {
- r.mu.Lock()
- defer r.mu.Unlock()
- var err error
- if r.dec != nil {
- err = r.dec.Reset(nil)
- r.pool.Put(r.dec)
- r.dec = nil
- }
- return err
- }
- type pooledZipWriter struct {
- mu sync.Mutex // guards Close and Read
- enc *Encoder
- pool *sync.Pool
- }
- func (w *pooledZipWriter) Write(p []byte) (n int, err error) {
- w.mu.Lock()
- defer w.mu.Unlock()
- if w.enc == nil {
- return 0, errors.New("Write after Close")
- }
- return w.enc.Write(p)
- }
- func (w *pooledZipWriter) Close() error {
- w.mu.Lock()
- defer w.mu.Unlock()
- var err error
- if w.enc != nil {
- err = w.enc.Close()
- w.pool.Put(w.enc)
- w.enc = nil
- }
- return err
- }
- // ZipCompressor returns a compressor that can be registered with zip libraries.
- // The provided encoder options will be used on all encodes.
- func ZipCompressor(opts ...EOption) func(w io.Writer) (io.WriteCloser, error) {
- var pool sync.Pool
- return func(w io.Writer) (io.WriteCloser, error) {
- enc, ok := pool.Get().(*Encoder)
- if ok {
- enc.Reset(w)
- } else {
- var err error
- enc, err = NewWriter(w, opts...)
- if err != nil {
- return nil, err
- }
- }
- return &pooledZipWriter{enc: enc, pool: &pool}, nil
- }
- }
- // ZipDecompressor returns a decompressor that can be registered with zip libraries.
- // See ZipCompressor for example.
- // Options can be specified. WithDecoderConcurrency(1) is forced,
- // and by default a 128MB maximum decompression window is specified.
- // The window size can be overridden if required.
- func ZipDecompressor(opts ...DOption) func(r io.Reader) io.ReadCloser {
- return newZipReader(opts...)
- }
|