...

Source file src/github.com/ProtonMail/go-crypto/openpgp/packet/compressed.go

Documentation: github.com/ProtonMail/go-crypto/openpgp/packet

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package packet
     6  
     7  import (
     8  	"compress/bzip2"
     9  	"compress/flate"
    10  	"compress/zlib"
    11  	"github.com/ProtonMail/go-crypto/openpgp/errors"
    12  	"io"
    13  	"strconv"
    14  )
    15  
    16  // Compressed represents a compressed OpenPGP packet. The decompressed contents
    17  // will contain more OpenPGP packets. See RFC 4880, section 5.6.
    18  type Compressed struct {
    19  	Body io.Reader
    20  }
    21  
    22  const (
    23  	NoCompression      = flate.NoCompression
    24  	BestSpeed          = flate.BestSpeed
    25  	BestCompression    = flate.BestCompression
    26  	DefaultCompression = flate.DefaultCompression
    27  )
    28  
    29  // CompressionConfig contains compressor configuration settings.
    30  type CompressionConfig struct {
    31  	// Level is the compression level to use. It must be set to
    32  	// between -1 and 9, with -1 causing the compressor to use the
    33  	// default compression level, 0 causing the compressor to use
    34  	// no compression and 1 to 9 representing increasing (better,
    35  	// slower) compression levels. If Level is less than -1 or
    36  	// more then 9, a non-nil error will be returned during
    37  	// encryption. See the constants above for convenient common
    38  	// settings for Level.
    39  	Level int
    40  }
    41  
    42  func (c *Compressed) parse(r io.Reader) error {
    43  	var buf [1]byte
    44  	_, err := readFull(r, buf[:])
    45  	if err != nil {
    46  		return err
    47  	}
    48  
    49  	switch buf[0] {
    50  	case 0:
    51  		c.Body = r
    52  	case 1:
    53  		c.Body = flate.NewReader(r)
    54  	case 2:
    55  		c.Body, err = zlib.NewReader(r)
    56  	case 3:
    57  		c.Body = bzip2.NewReader(r)
    58  	default:
    59  		err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
    60  	}
    61  
    62  	return err
    63  }
    64  
    65  // compressedWriterCloser represents the serialized compression stream
    66  // header and the compressor. Its Close() method ensures that both the
    67  // compressor and serialized stream header are closed. Its Write()
    68  // method writes to the compressor.
    69  type compressedWriteCloser struct {
    70  	sh io.Closer      // Stream Header
    71  	c  io.WriteCloser // Compressor
    72  }
    73  
    74  func (cwc compressedWriteCloser) Write(p []byte) (int, error) {
    75  	return cwc.c.Write(p)
    76  }
    77  
    78  func (cwc compressedWriteCloser) Close() (err error) {
    79  	err = cwc.c.Close()
    80  	if err != nil {
    81  		return err
    82  	}
    83  
    84  	return cwc.sh.Close()
    85  }
    86  
    87  // SerializeCompressed serializes a compressed data packet to w and
    88  // returns a WriteCloser to which the literal data packets themselves
    89  // can be written and which MUST be closed on completion. If cc is
    90  // nil, sensible defaults will be used to configure the compression
    91  // algorithm.
    92  func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *CompressionConfig) (literaldata io.WriteCloser, err error) {
    93  	compressed, err := serializeStreamHeader(w, packetTypeCompressed)
    94  	if err != nil {
    95  		return
    96  	}
    97  
    98  	_, err = compressed.Write([]byte{uint8(algo)})
    99  	if err != nil {
   100  		return
   101  	}
   102  
   103  	level := DefaultCompression
   104  	if cc != nil {
   105  		level = cc.Level
   106  	}
   107  
   108  	var compressor io.WriteCloser
   109  	switch algo {
   110  	case CompressionZIP:
   111  		compressor, err = flate.NewWriter(compressed, level)
   112  	case CompressionZLIB:
   113  		compressor, err = zlib.NewWriterLevel(compressed, level)
   114  	default:
   115  		s := strconv.Itoa(int(algo))
   116  		err = errors.UnsupportedError("Unsupported compression algorithm: " + s)
   117  	}
   118  	if err != nil {
   119  		return
   120  	}
   121  
   122  	literaldata = compressedWriteCloser{compressed, compressor}
   123  
   124  	return
   125  }
   126  

View as plain text