1*333d2b36SAndroid Build Coastguard Worker// Copyright 2010 The Go Authors. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style 3*333d2b36SAndroid Build Coastguard Worker// license that can be found in the LICENSE file. 4*333d2b36SAndroid Build Coastguard Worker 5*333d2b36SAndroid Build Coastguard Workerpackage zip 6*333d2b36SAndroid Build Coastguard Worker 7*333d2b36SAndroid Build Coastguard Workerimport ( 8*333d2b36SAndroid Build Coastguard Worker "compress/flate" 9*333d2b36SAndroid Build Coastguard Worker "errors" 10*333d2b36SAndroid Build Coastguard Worker "io" 11*333d2b36SAndroid Build Coastguard Worker "io/ioutil" 12*333d2b36SAndroid Build Coastguard Worker "sync" 13*333d2b36SAndroid Build Coastguard Worker) 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Worker// A Compressor returns a new compressing writer, writing to w. 16*333d2b36SAndroid Build Coastguard Worker// The WriteCloser's Close method must be used to flush pending data to w. 17*333d2b36SAndroid Build Coastguard Worker// The Compressor itself must be safe to invoke from multiple goroutines 18*333d2b36SAndroid Build Coastguard Worker// simultaneously, but each returned writer will be used only by 19*333d2b36SAndroid Build Coastguard Worker// one goroutine at a time. 20*333d2b36SAndroid Build Coastguard Workertype Compressor func(w io.Writer) (io.WriteCloser, error) 21*333d2b36SAndroid Build Coastguard Worker 22*333d2b36SAndroid Build Coastguard Worker// A Decompressor returns a new decompressing reader, reading from r. 23*333d2b36SAndroid Build Coastguard Worker// The ReadCloser's Close method must be used to release associated resources. 24*333d2b36SAndroid Build Coastguard Worker// The Decompressor itself must be safe to invoke from multiple goroutines 25*333d2b36SAndroid Build Coastguard Worker// simultaneously, but each returned reader will be used only by 26*333d2b36SAndroid Build Coastguard Worker// one goroutine at a time. 27*333d2b36SAndroid Build Coastguard Workertype Decompressor func(r io.Reader) io.ReadCloser 28*333d2b36SAndroid Build Coastguard Worker 29*333d2b36SAndroid Build Coastguard Workervar flateWriterPool sync.Pool 30*333d2b36SAndroid Build Coastguard Worker 31*333d2b36SAndroid Build Coastguard Workerfunc newFlateWriter(w io.Writer) io.WriteCloser { 32*333d2b36SAndroid Build Coastguard Worker fw, ok := flateWriterPool.Get().(*flate.Writer) 33*333d2b36SAndroid Build Coastguard Worker if ok { 34*333d2b36SAndroid Build Coastguard Worker fw.Reset(w) 35*333d2b36SAndroid Build Coastguard Worker } else { 36*333d2b36SAndroid Build Coastguard Worker fw, _ = flate.NewWriter(w, 5) 37*333d2b36SAndroid Build Coastguard Worker } 38*333d2b36SAndroid Build Coastguard Worker return &pooledFlateWriter{fw: fw} 39*333d2b36SAndroid Build Coastguard Worker} 40*333d2b36SAndroid Build Coastguard Worker 41*333d2b36SAndroid Build Coastguard Workertype pooledFlateWriter struct { 42*333d2b36SAndroid Build Coastguard Worker mu sync.Mutex // guards Close and Write 43*333d2b36SAndroid Build Coastguard Worker fw *flate.Writer 44*333d2b36SAndroid Build Coastguard Worker} 45*333d2b36SAndroid Build Coastguard Worker 46*333d2b36SAndroid Build Coastguard Workerfunc (w *pooledFlateWriter) Write(p []byte) (n int, err error) { 47*333d2b36SAndroid Build Coastguard Worker w.mu.Lock() 48*333d2b36SAndroid Build Coastguard Worker defer w.mu.Unlock() 49*333d2b36SAndroid Build Coastguard Worker if w.fw == nil { 50*333d2b36SAndroid Build Coastguard Worker return 0, errors.New("Write after Close") 51*333d2b36SAndroid Build Coastguard Worker } 52*333d2b36SAndroid Build Coastguard Worker return w.fw.Write(p) 53*333d2b36SAndroid Build Coastguard Worker} 54*333d2b36SAndroid Build Coastguard Worker 55*333d2b36SAndroid Build Coastguard Workerfunc (w *pooledFlateWriter) Close() error { 56*333d2b36SAndroid Build Coastguard Worker w.mu.Lock() 57*333d2b36SAndroid Build Coastguard Worker defer w.mu.Unlock() 58*333d2b36SAndroid Build Coastguard Worker var err error 59*333d2b36SAndroid Build Coastguard Worker if w.fw != nil { 60*333d2b36SAndroid Build Coastguard Worker err = w.fw.Close() 61*333d2b36SAndroid Build Coastguard Worker flateWriterPool.Put(w.fw) 62*333d2b36SAndroid Build Coastguard Worker w.fw = nil 63*333d2b36SAndroid Build Coastguard Worker } 64*333d2b36SAndroid Build Coastguard Worker return err 65*333d2b36SAndroid Build Coastguard Worker} 66*333d2b36SAndroid Build Coastguard Worker 67*333d2b36SAndroid Build Coastguard Workervar flateReaderPool sync.Pool 68*333d2b36SAndroid Build Coastguard Worker 69*333d2b36SAndroid Build Coastguard Workerfunc newFlateReader(r io.Reader) io.ReadCloser { 70*333d2b36SAndroid Build Coastguard Worker fr, ok := flateReaderPool.Get().(io.ReadCloser) 71*333d2b36SAndroid Build Coastguard Worker if ok { 72*333d2b36SAndroid Build Coastguard Worker fr.(flate.Resetter).Reset(r, nil) 73*333d2b36SAndroid Build Coastguard Worker } else { 74*333d2b36SAndroid Build Coastguard Worker fr = flate.NewReader(r) 75*333d2b36SAndroid Build Coastguard Worker } 76*333d2b36SAndroid Build Coastguard Worker return &pooledFlateReader{fr: fr} 77*333d2b36SAndroid Build Coastguard Worker} 78*333d2b36SAndroid Build Coastguard Worker 79*333d2b36SAndroid Build Coastguard Workertype pooledFlateReader struct { 80*333d2b36SAndroid Build Coastguard Worker mu sync.Mutex // guards Close and Read 81*333d2b36SAndroid Build Coastguard Worker fr io.ReadCloser 82*333d2b36SAndroid Build Coastguard Worker} 83*333d2b36SAndroid Build Coastguard Worker 84*333d2b36SAndroid Build Coastguard Workerfunc (r *pooledFlateReader) Read(p []byte) (n int, err error) { 85*333d2b36SAndroid Build Coastguard Worker r.mu.Lock() 86*333d2b36SAndroid Build Coastguard Worker defer r.mu.Unlock() 87*333d2b36SAndroid Build Coastguard Worker if r.fr == nil { 88*333d2b36SAndroid Build Coastguard Worker return 0, errors.New("Read after Close") 89*333d2b36SAndroid Build Coastguard Worker } 90*333d2b36SAndroid Build Coastguard Worker return r.fr.Read(p) 91*333d2b36SAndroid Build Coastguard Worker} 92*333d2b36SAndroid Build Coastguard Worker 93*333d2b36SAndroid Build Coastguard Workerfunc (r *pooledFlateReader) Close() error { 94*333d2b36SAndroid Build Coastguard Worker r.mu.Lock() 95*333d2b36SAndroid Build Coastguard Worker defer r.mu.Unlock() 96*333d2b36SAndroid Build Coastguard Worker var err error 97*333d2b36SAndroid Build Coastguard Worker if r.fr != nil { 98*333d2b36SAndroid Build Coastguard Worker err = r.fr.Close() 99*333d2b36SAndroid Build Coastguard Worker flateReaderPool.Put(r.fr) 100*333d2b36SAndroid Build Coastguard Worker r.fr = nil 101*333d2b36SAndroid Build Coastguard Worker } 102*333d2b36SAndroid Build Coastguard Worker return err 103*333d2b36SAndroid Build Coastguard Worker} 104*333d2b36SAndroid Build Coastguard Worker 105*333d2b36SAndroid Build Coastguard Workervar ( 106*333d2b36SAndroid Build Coastguard Worker mu sync.RWMutex // guards compressor and decompressor maps 107*333d2b36SAndroid Build Coastguard Worker 108*333d2b36SAndroid Build Coastguard Worker compressors = map[uint16]Compressor{ 109*333d2b36SAndroid Build Coastguard Worker Store: func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }, 110*333d2b36SAndroid Build Coastguard Worker Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }, 111*333d2b36SAndroid Build Coastguard Worker } 112*333d2b36SAndroid Build Coastguard Worker 113*333d2b36SAndroid Build Coastguard Worker decompressors = map[uint16]Decompressor{ 114*333d2b36SAndroid Build Coastguard Worker Store: ioutil.NopCloser, 115*333d2b36SAndroid Build Coastguard Worker Deflate: newFlateReader, 116*333d2b36SAndroid Build Coastguard Worker } 117*333d2b36SAndroid Build Coastguard Worker) 118*333d2b36SAndroid Build Coastguard Worker 119*333d2b36SAndroid Build Coastguard Worker// RegisterDecompressor allows custom decompressors for a specified method ID. 120*333d2b36SAndroid Build Coastguard Worker// The common methods Store and Deflate are built in. 121*333d2b36SAndroid Build Coastguard Workerfunc RegisterDecompressor(method uint16, dcomp Decompressor) { 122*333d2b36SAndroid Build Coastguard Worker mu.Lock() 123*333d2b36SAndroid Build Coastguard Worker defer mu.Unlock() 124*333d2b36SAndroid Build Coastguard Worker 125*333d2b36SAndroid Build Coastguard Worker if _, ok := decompressors[method]; ok { 126*333d2b36SAndroid Build Coastguard Worker panic("decompressor already registered") 127*333d2b36SAndroid Build Coastguard Worker } 128*333d2b36SAndroid Build Coastguard Worker decompressors[method] = dcomp 129*333d2b36SAndroid Build Coastguard Worker} 130*333d2b36SAndroid Build Coastguard Worker 131*333d2b36SAndroid Build Coastguard Worker// RegisterCompressor registers custom compressors for a specified method ID. 132*333d2b36SAndroid Build Coastguard Worker// The common methods Store and Deflate are built in. 133*333d2b36SAndroid Build Coastguard Workerfunc RegisterCompressor(method uint16, comp Compressor) { 134*333d2b36SAndroid Build Coastguard Worker mu.Lock() 135*333d2b36SAndroid Build Coastguard Worker defer mu.Unlock() 136*333d2b36SAndroid Build Coastguard Worker 137*333d2b36SAndroid Build Coastguard Worker if _, ok := compressors[method]; ok { 138*333d2b36SAndroid Build Coastguard Worker panic("compressor already registered") 139*333d2b36SAndroid Build Coastguard Worker } 140*333d2b36SAndroid Build Coastguard Worker compressors[method] = comp 141*333d2b36SAndroid Build Coastguard Worker} 142*333d2b36SAndroid Build Coastguard Worker 143*333d2b36SAndroid Build Coastguard Workerfunc compressor(method uint16) Compressor { 144*333d2b36SAndroid Build Coastguard Worker mu.RLock() 145*333d2b36SAndroid Build Coastguard Worker defer mu.RUnlock() 146*333d2b36SAndroid Build Coastguard Worker return compressors[method] 147*333d2b36SAndroid Build Coastguard Worker} 148*333d2b36SAndroid Build Coastguard Worker 149*333d2b36SAndroid Build Coastguard Workerfunc decompressor(method uint16) Decompressor { 150*333d2b36SAndroid Build Coastguard Worker mu.RLock() 151*333d2b36SAndroid Build Coastguard Worker defer mu.RUnlock() 152*333d2b36SAndroid Build Coastguard Worker return decompressors[method] 153*333d2b36SAndroid Build Coastguard Worker} 154