124 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			124 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|   | // Copyright 2011 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 packet | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"compress/bzip2" | ||
|  | 	"compress/flate" | ||
|  | 	"compress/zlib" | ||
|  | 	"golang.org/x/crypto/openpgp/errors" | ||
|  | 	"io" | ||
|  | 	"strconv" | ||
|  | ) | ||
|  | 
 | ||
|  | // Compressed represents a compressed OpenPGP packet. The decompressed contents | ||
|  | // will contain more OpenPGP packets. See RFC 4880, section 5.6. | ||
|  | type Compressed struct { | ||
|  | 	Body io.Reader | ||
|  | } | ||
|  | 
 | ||
|  | const ( | ||
|  | 	NoCompression      = flate.NoCompression | ||
|  | 	BestSpeed          = flate.BestSpeed | ||
|  | 	BestCompression    = flate.BestCompression | ||
|  | 	DefaultCompression = flate.DefaultCompression | ||
|  | ) | ||
|  | 
 | ||
|  | // CompressionConfig contains compressor configuration settings. | ||
|  | type CompressionConfig struct { | ||
|  | 	// Level is the compression level to use. It must be set to | ||
|  | 	// between -1 and 9, with -1 causing the compressor to use the | ||
|  | 	// default compression level, 0 causing the compressor to use | ||
|  | 	// no compression and 1 to 9 representing increasing (better, | ||
|  | 	// slower) compression levels. If Level is less than -1 or | ||
|  | 	// more then 9, a non-nil error will be returned during | ||
|  | 	// encryption. See the constants above for convenient common | ||
|  | 	// settings for Level. | ||
|  | 	Level int | ||
|  | } | ||
|  | 
 | ||
|  | func (c *Compressed) parse(r io.Reader) error { | ||
|  | 	var buf [1]byte | ||
|  | 	_, err := readFull(r, buf[:]) | ||
|  | 	if err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 
 | ||
|  | 	switch buf[0] { | ||
|  | 	case 1: | ||
|  | 		c.Body = flate.NewReader(r) | ||
|  | 	case 2: | ||
|  | 		c.Body, err = zlib.NewReader(r) | ||
|  | 	case 3: | ||
|  | 		c.Body = bzip2.NewReader(r) | ||
|  | 	default: | ||
|  | 		err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0]))) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return err | ||
|  | } | ||
|  | 
 | ||
|  | // compressedWriterCloser represents the serialized compression stream | ||
|  | // header and the compressor. Its Close() method ensures that both the | ||
|  | // compressor and serialized stream header are closed. Its Write() | ||
|  | // method writes to the compressor. | ||
|  | type compressedWriteCloser struct { | ||
|  | 	sh io.Closer      // Stream Header | ||
|  | 	c  io.WriteCloser // Compressor | ||
|  | } | ||
|  | 
 | ||
|  | func (cwc compressedWriteCloser) Write(p []byte) (int, error) { | ||
|  | 	return cwc.c.Write(p) | ||
|  | } | ||
|  | 
 | ||
|  | func (cwc compressedWriteCloser) Close() (err error) { | ||
|  | 	err = cwc.c.Close() | ||
|  | 	if err != nil { | ||
|  | 		return err | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return cwc.sh.Close() | ||
|  | } | ||
|  | 
 | ||
|  | // SerializeCompressed serializes a compressed data packet to w and | ||
|  | // returns a WriteCloser to which the literal data packets themselves | ||
|  | // can be written and which MUST be closed on completion. If cc is | ||
|  | // nil, sensible defaults will be used to configure the compression | ||
|  | // algorithm. | ||
|  | func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *CompressionConfig) (literaldata io.WriteCloser, err error) { | ||
|  | 	compressed, err := serializeStreamHeader(w, packetTypeCompressed) | ||
|  | 	if err != nil { | ||
|  | 		return | ||
|  | 	} | ||
|  | 
 | ||
|  | 	_, err = compressed.Write([]byte{uint8(algo)}) | ||
|  | 	if err != nil { | ||
|  | 		return | ||
|  | 	} | ||
|  | 
 | ||
|  | 	level := DefaultCompression | ||
|  | 	if cc != nil { | ||
|  | 		level = cc.Level | ||
|  | 	} | ||
|  | 
 | ||
|  | 	var compressor io.WriteCloser | ||
|  | 	switch algo { | ||
|  | 	case CompressionZIP: | ||
|  | 		compressor, err = flate.NewWriter(compressed, level) | ||
|  | 	case CompressionZLIB: | ||
|  | 		compressor, err = zlib.NewWriterLevel(compressed, level) | ||
|  | 	default: | ||
|  | 		s := strconv.Itoa(int(algo)) | ||
|  | 		err = errors.UnsupportedError("Unsupported compression algorithm: " + s) | ||
|  | 	} | ||
|  | 	if err != nil { | ||
|  | 		return | ||
|  | 	} | ||
|  | 
 | ||
|  | 	literaldata = compressedWriteCloser{compressed, compressor} | ||
|  | 
 | ||
|  | 	return | ||
|  | } |