...
Run Format

Source file src/archive/zip/register.go

Documentation: archive/zip

  // 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 flateReaderPool sync.Pool
  
  func newFlateReader(r io.Reader) io.ReadCloser {
  	fr, ok := flateReaderPool.Get().(io.ReadCloser)
  	if ok {
  		fr.(flate.Resetter).Reset(r, nil)
  	} else {
  		fr = flate.NewReader(r)
  	}
  	return &pooledFlateReader{fr: fr}
  }
  
  type pooledFlateReader struct {
  	mu sync.Mutex // guards Close and Read
  	fr io.ReadCloser
  }
  
  func (r *pooledFlateReader) Read(p []byte) (n int, err error) {
  	r.mu.Lock()
  	defer r.mu.Unlock()
  	if r.fr == nil {
  		return 0, errors.New("Read after Close")
  	}
  	return r.fr.Read(p)
  }
  
  func (r *pooledFlateReader) Close() error {
  	r.mu.Lock()
  	defer r.mu.Unlock()
  	var err error
  	if r.fr != nil {
  		err = r.fr.Close()
  		flateReaderPool.Put(r.fr)
  		r.fr = nil
  	}
  	return err
  }
  
  var (
  	compressors   sync.Map // map[uint16]Compressor
  	decompressors sync.Map // map[uint16]Decompressor
  )
  
  func init() {
  	compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }))
  	compressors.Store(Deflate, Compressor(func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }))
  
  	decompressors.Store(Store, Decompressor(ioutil.NopCloser))
  	decompressors.Store(Deflate, Decompressor(newFlateReader))
  }
  
  // RegisterDecompressor allows custom decompressors for a specified method ID.
  // The common methods Store and Deflate are built in.
  func RegisterDecompressor(method uint16, dcomp Decompressor) {
  	if _, dup := decompressors.LoadOrStore(method, dcomp); dup {
  		panic("decompressor already registered")
  	}
  }
  
  // RegisterCompressor registers custom compressors for a specified method ID.
  // The common methods Store and Deflate are built in.
  func RegisterCompressor(method uint16, comp Compressor) {
  	if _, dup := compressors.LoadOrStore(method, comp); dup {
  		panic("compressor already registered")
  	}
  }
  
  func compressor(method uint16) Compressor {
  	ci, ok := compressors.Load(method)
  	if !ok {
  		return nil
  	}
  	return ci.(Compressor)
  }
  
  func decompressor(method uint16) Decompressor {
  	di, ok := decompressors.Load(method)
  	if !ok {
  		return nil
  	}
  	return di.(Decompressor)
  }
  

View as plain text