github.com/grailbio/base@v0.0.11/compress/libdeflate/libdeflate_nocgo.go (about) 1 // Copyright 2018 GRAIL, Inc. All rights reserved. 2 // Use of this source code is governed by the Apache-2.0 3 // license that can be found in the LICENSE file. 4 5 //go:build !cgo || arm64 6 // +build !cgo arm64 7 8 package libdeflate 9 10 // Fall back on the pure-go compress/flate package if cgo support is 11 // unavailable, to make it safe to include this package unconditionally. 12 13 import ( 14 "bytes" 15 "compress/flate" 16 "compress/gzip" 17 "io" 18 ) 19 20 type Decompressor struct{} 21 22 func (dd *Decompressor) Init() error { 23 return nil 24 } 25 26 // Decompress performs raw DEFLATE decompression on a byte slice. outData[] 27 // must be large enough to fit the decompressed data. Byte count of the 28 // decompressed data is returned on success (it may be smaller than 29 // len(outData)). 30 func (dd *Decompressor) Decompress(outData, inData []byte) (int, error) { 31 dataReader := bytes.NewReader(inData) 32 actualDecompressor := flate.NewReader(dataReader) 33 // Copy of readToEOF() in github.com/biogo/hts/bgzf/cache.go. 34 n := 0 35 outDataMax := len(outData) 36 var err error 37 for err == nil && n < outDataMax { 38 var nn int 39 nn, err = actualDecompressor.Read(outData[n:]) 40 n += nn 41 } 42 switch { 43 case err == io.EOF: 44 return n, nil 45 case n == outDataMax && err == nil: 46 var dummy [1]byte 47 _, err = actualDecompressor.Read(dummy[:]) 48 if err == nil { 49 return 0, io.ErrShortBuffer 50 } 51 if err == io.EOF { 52 err = nil 53 } 54 } 55 return n, err 56 } 57 58 // GzipDecompress performs gzip decompression on a byte slice. outData[] must 59 // be large enough to fit the decompressed data. Byte count of the 60 // decompressed data is returned on success (it may be smaller than 61 // len(outData)). 62 func (dd *Decompressor) GzipDecompress(outData, inData []byte) (int, error) { 63 dataReader := bytes.NewReader(inData) 64 actualDecompressor, err := gzip.NewReader(dataReader) 65 if err != nil { 66 return 0, err 67 } 68 // Copy of readToEOF() in github.com/biogo/hts/bgzf/cache.go. 69 n := 0 70 outDataMax := len(outData) 71 for err == nil && n < outDataMax { 72 var nn int 73 nn, err = actualDecompressor.Read(outData[n:]) 74 n += nn 75 } 76 switch { 77 case err == io.EOF: 78 return n, nil 79 case n == outDataMax && err == nil: 80 var dummy [1]byte 81 _, err = actualDecompressor.Read(dummy[:]) 82 if err == nil { 83 return 0, io.ErrShortBuffer 84 } 85 if err == io.EOF { 86 err = nil 87 } 88 } 89 return n, err 90 } 91 92 func (dd *Decompressor) Cleanup() { 93 } 94 95 type Compressor struct { 96 clvl int 97 } 98 99 func (cc *Compressor) Init(compressionLevel int) error { 100 cc.clvl = compressionLevel 101 return nil 102 } 103 104 // Compress performs raw DEFLATE compression on a byte slice. outData[] must 105 // be large enough to fit the compressed data. Byte count of the compressed 106 // data is returned on success. 107 // Zero is currently returned on failure. A side effect is that inData cannot 108 // be length zero; this function will panic or crash if it is. 109 func (cc *Compressor) Compress(outData, inData []byte) int { 110 // I suspect this currently makes a few unnecessary allocations and copies; 111 // can optimize later. 112 if len(inData) == 0 { 113 panic("libdeflate.Compress: zero-length inData") 114 } 115 var buf bytes.Buffer 116 actualCompressor, err := flate.NewWriter(&buf, cc.clvl) 117 if err != nil { 118 return 0 119 } 120 _, err = actualCompressor.Write(inData) 121 if err != nil { 122 return 0 123 } 124 err = actualCompressor.Close() 125 if err != nil { 126 return 0 127 } 128 outLen := buf.Len() 129 if outLen > len(outData) { 130 return 0 131 } 132 copy(outData, buf.Bytes()) 133 return outLen 134 } 135 136 func (cc *Compressor) Cleanup() { 137 }