115 lines
2.9 KiB
Go
115 lines
2.9 KiB
Go
// 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]
|
|
}
|