github.com/bir3/gocompiler@v0.9.2202/extra/compress/zstd/zip.go (about) 1 // Copyright 2019+ Klaus Post. All rights reserved. 2 // License information can be found in the LICENSE file. 3 4 package zstd 5 6 import ( 7 "errors" 8 "io" 9 "sync" 10 ) 11 12 // ZipMethodWinZip is the method for Zstandard compressed data inside Zip files for WinZip. 13 // See https://www.winzip.com/win/en/comp_info.html 14 const ZipMethodWinZip = 93 15 16 // ZipMethodPKWare is the original method number used by PKWARE to indicate Zstandard compression. 17 // Deprecated: This has been deprecated by PKWARE, use ZipMethodWinZip instead for compression. 18 // See https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.9.TXT 19 const ZipMethodPKWare = 20 20 21 // zipReaderPool is the default reader pool. 22 var zipReaderPool = sync.Pool{New: func() interface{} { 23 z, err := NewReader(nil, WithDecoderLowmem(true), WithDecoderMaxWindow(128<<20), WithDecoderConcurrency(1)) 24 if err != nil { 25 panic(err) 26 } 27 return z 28 }} 29 30 // newZipReader creates a pooled zip decompressor. 31 func newZipReader(opts ...DOption) func(r io.Reader) io.ReadCloser { 32 pool := &zipReaderPool 33 if len(opts) > 0 { 34 opts = append([]DOption{WithDecoderLowmem(true), WithDecoderMaxWindow(128 << 20)}, opts...) 35 // Force concurrency 1 36 opts = append(opts, WithDecoderConcurrency(1)) 37 // Create our own pool 38 pool = &sync.Pool{} 39 } 40 return func(r io.Reader) io.ReadCloser { 41 dec, ok := pool.Get().(*Decoder) 42 if ok { 43 dec.Reset(r) 44 } else { 45 d, err := NewReader(r, opts...) 46 if err != nil { 47 panic(err) 48 } 49 dec = d 50 } 51 return &pooledZipReader{dec: dec, pool: pool} 52 } 53 } 54 55 type pooledZipReader struct { 56 mu sync.Mutex // guards Close and Read 57 pool *sync.Pool 58 dec *Decoder 59 } 60 61 func (r *pooledZipReader) Read(p []byte) (n int, err error) { 62 r.mu.Lock() 63 defer r.mu.Unlock() 64 if r.dec == nil { 65 return 0, errors.New("read after close or EOF") 66 } 67 dec, err := r.dec.Read(p) 68 if err == io.EOF { 69 r.dec.Reset(nil) 70 r.pool.Put(r.dec) 71 r.dec = nil 72 } 73 return dec, err 74 } 75 76 func (r *pooledZipReader) Close() error { 77 r.mu.Lock() 78 defer r.mu.Unlock() 79 var err error 80 if r.dec != nil { 81 err = r.dec.Reset(nil) 82 r.pool.Put(r.dec) 83 r.dec = nil 84 } 85 return err 86 } 87 88 type pooledZipWriter struct { 89 mu sync.Mutex // guards Close and Read 90 enc *Encoder 91 pool *sync.Pool 92 } 93 94 func (w *pooledZipWriter) Write(p []byte) (n int, err error) { 95 w.mu.Lock() 96 defer w.mu.Unlock() 97 if w.enc == nil { 98 return 0, errors.New("Write after Close") 99 } 100 return w.enc.Write(p) 101 } 102 103 func (w *pooledZipWriter) Close() error { 104 w.mu.Lock() 105 defer w.mu.Unlock() 106 var err error 107 if w.enc != nil { 108 err = w.enc.Close() 109 w.pool.Put(w.enc) 110 w.enc = nil 111 } 112 return err 113 } 114 115 // ZipCompressor returns a compressor that can be registered with zip libraries. 116 // The provided encoder options will be used on all encodes. 117 func ZipCompressor(opts ...EOption) func(w io.Writer) (io.WriteCloser, error) { 118 var pool sync.Pool 119 return func(w io.Writer) (io.WriteCloser, error) { 120 enc, ok := pool.Get().(*Encoder) 121 if ok { 122 enc.Reset(w) 123 } else { 124 var err error 125 enc, err = NewWriter(w, opts...) 126 if err != nil { 127 return nil, err 128 } 129 } 130 return &pooledZipWriter{enc: enc, pool: &pool}, nil 131 } 132 } 133 134 // ZipDecompressor returns a decompressor that can be registered with zip libraries. 135 // See ZipCompressor for example. 136 // Options can be specified. WithDecoderConcurrency(1) is forced, 137 // and by default a 128MB maximum decompression window is specified. 138 // The window size can be overridden if required. 139 func ZipDecompressor(opts ...DOption) func(r io.Reader) io.ReadCloser { 140 return newZipReader(opts...) 141 }