// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package zip import ( "compress/flate" "errors" "io" "io/ioutil" "sync" ) // A Compressor returns a new compressing writer, writing to w. // The WriteCloser's Close method must be used to flush pending data to w. // The Compressor itself must be safe to invoke from multiple goroutines // simultaneously, but each returned writer will be used only by // one goroutine at a time. type Compressor func(w io.Writer) (io.WriteCloser, error) // A Decompressor returns a new decompressing reader, reading from r. // The ReadCloser's Close method must be used to release associated resources. // The Decompressor itself must be safe to invoke from multiple goroutines // simultaneously, but each returned reader will be used only by // one goroutine at a time. type Decompressor func(r io.Reader) io.ReadCloser var flateWriterPool sync.Pool func newFlateWriter(w io.Writer) io.WriteCloser { fw, ok := flateWriterPool.Get().(*flate.Writer) if ok { fw.Reset(w) } else { fw, _ = flate.NewWriter(w, 5) } return &pooledFlateWriter{fw: fw} } type pooledFlateWriter struct { mu sync.Mutex // guards Close and Write fw *flate.Writer } func (w *pooledFlateWriter) Write(p []byte) (n int, err error) { w.mu.Lock() defer w.mu.Unlock() if w.fw == nil { return 0, errors.New("Write after Close") } return w.fw.Write(p) } func (w *pooledFlateWriter) Close() error { w.mu.Lock() defer w.mu.Unlock() var err error if w.fw != nil { err = w.fw.Close() flateWriterPool.Put(w.fw) w.fw = nil } return err } var ( mu sync.RWMutex // guards compressor and decompressor maps compressors = map[uint16]Compressor{ Store: func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }, Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }, } decompressors = map[uint16]Decompressor{ Store: ioutil.NopCloser, Deflate: flate.NewReader, } ) // RegisterDecompressor allows custom decompressors for a specified method ID. // The common methods Store and Deflate are built in. func RegisterDecompressor(method uint16, dcomp Decompressor) { mu.Lock() defer mu.Unlock() if _, ok := decompressors[method]; ok { panic("decompressor already registered") } decompressors[method] = dcomp } // RegisterCompressor registers custom compressors for a specified method ID. // The common methods Store and Deflate are built in. func RegisterCompressor(method uint16, comp Compressor) { mu.Lock() defer mu.Unlock() if _, ok := compressors[method]; ok { panic("compressor already registered") } compressors[method] = comp } func compressor(method uint16) Compressor { mu.RLock() defer mu.RUnlock() return compressors[method] } func decompressor(method uint16) Decompressor { mu.RLock() defer mu.RUnlock() return decompressors[method] }