...

Source file src/compress/gzip/gzip.go

Documentation: compress/gzip

		 1  // Copyright 2010 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 gzip
		 6  
		 7  import (
		 8  	"compress/flate"
		 9  	"errors"
		10  	"fmt"
		11  	"hash/crc32"
		12  	"io"
		13  	"time"
		14  )
		15  
		16  // These constants are copied from the flate package, so that code that imports
		17  // "compress/gzip" does not also have to import "compress/flate".
		18  const (
		19  	NoCompression			= flate.NoCompression
		20  	BestSpeed					= flate.BestSpeed
		21  	BestCompression		= flate.BestCompression
		22  	DefaultCompression = flate.DefaultCompression
		23  	HuffmanOnly				= flate.HuffmanOnly
		24  )
		25  
		26  // A Writer is an io.WriteCloser.
		27  // Writes to a Writer are compressed and written to w.
		28  type Writer struct {
		29  	Header			// written at first call to Write, Flush, or Close
		30  	w					 io.Writer
		31  	level			 int
		32  	wroteHeader bool
		33  	compressor	*flate.Writer
		34  	digest			uint32 // CRC-32, IEEE polynomial (section 8)
		35  	size				uint32 // Uncompressed size (section 2.3.1)
		36  	closed			bool
		37  	buf				 [10]byte
		38  	err				 error
		39  }
		40  
		41  // NewWriter returns a new Writer.
		42  // Writes to the returned writer are compressed and written to w.
		43  //
		44  // It is the caller's responsibility to call Close on the Writer when done.
		45  // Writes may be buffered and not flushed until Close.
		46  //
		47  // Callers that wish to set the fields in Writer.Header must do so before
		48  // the first call to Write, Flush, or Close.
		49  func NewWriter(w io.Writer) *Writer {
		50  	z, _ := NewWriterLevel(w, DefaultCompression)
		51  	return z
		52  }
		53  
		54  // NewWriterLevel is like NewWriter but specifies the compression level instead
		55  // of assuming DefaultCompression.
		56  //
		57  // The compression level can be DefaultCompression, NoCompression, HuffmanOnly
		58  // or any integer value between BestSpeed and BestCompression inclusive.
		59  // The error returned will be nil if the level is valid.
		60  func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
		61  	if level < HuffmanOnly || level > BestCompression {
		62  		return nil, fmt.Errorf("gzip: invalid compression level: %d", level)
		63  	}
		64  	z := new(Writer)
		65  	z.init(w, level)
		66  	return z, nil
		67  }
		68  
		69  func (z *Writer) init(w io.Writer, level int) {
		70  	compressor := z.compressor
		71  	if compressor != nil {
		72  		compressor.Reset(w)
		73  	}
		74  	*z = Writer{
		75  		Header: Header{
		76  			OS: 255, // unknown
		77  		},
		78  		w:					w,
		79  		level:			level,
		80  		compressor: compressor,
		81  	}
		82  }
		83  
		84  // Reset discards the Writer z's state and makes it equivalent to the
		85  // result of its original state from NewWriter or NewWriterLevel, but
		86  // writing to w instead. This permits reusing a Writer rather than
		87  // allocating a new one.
		88  func (z *Writer) Reset(w io.Writer) {
		89  	z.init(w, z.level)
		90  }
		91  
		92  // writeBytes writes a length-prefixed byte slice to z.w.
		93  func (z *Writer) writeBytes(b []byte) error {
		94  	if len(b) > 0xffff {
		95  		return errors.New("gzip.Write: Extra data is too large")
		96  	}
		97  	le.PutUint16(z.buf[:2], uint16(len(b)))
		98  	_, err := z.w.Write(z.buf[:2])
		99  	if err != nil {
	 100  		return err
	 101  	}
	 102  	_, err = z.w.Write(b)
	 103  	return err
	 104  }
	 105  
	 106  // writeString writes a UTF-8 string s in GZIP's format to z.w.
	 107  // GZIP (RFC 1952) specifies that strings are NUL-terminated ISO 8859-1 (Latin-1).
	 108  func (z *Writer) writeString(s string) (err error) {
	 109  	// GZIP stores Latin-1 strings; error if non-Latin-1; convert if non-ASCII.
	 110  	needconv := false
	 111  	for _, v := range s {
	 112  		if v == 0 || v > 0xff {
	 113  			return errors.New("gzip.Write: non-Latin-1 header string")
	 114  		}
	 115  		if v > 0x7f {
	 116  			needconv = true
	 117  		}
	 118  	}
	 119  	if needconv {
	 120  		b := make([]byte, 0, len(s))
	 121  		for _, v := range s {
	 122  			b = append(b, byte(v))
	 123  		}
	 124  		_, err = z.w.Write(b)
	 125  	} else {
	 126  		_, err = io.WriteString(z.w, s)
	 127  	}
	 128  	if err != nil {
	 129  		return err
	 130  	}
	 131  	// GZIP strings are NUL-terminated.
	 132  	z.buf[0] = 0
	 133  	_, err = z.w.Write(z.buf[:1])
	 134  	return err
	 135  }
	 136  
	 137  // Write writes a compressed form of p to the underlying io.Writer. The
	 138  // compressed bytes are not necessarily flushed until the Writer is closed.
	 139  func (z *Writer) Write(p []byte) (int, error) {
	 140  	if z.err != nil {
	 141  		return 0, z.err
	 142  	}
	 143  	var n int
	 144  	// Write the GZIP header lazily.
	 145  	if !z.wroteHeader {
	 146  		z.wroteHeader = true
	 147  		z.buf = [10]byte{0: gzipID1, 1: gzipID2, 2: gzipDeflate}
	 148  		if z.Extra != nil {
	 149  			z.buf[3] |= 0x04
	 150  		}
	 151  		if z.Name != "" {
	 152  			z.buf[3] |= 0x08
	 153  		}
	 154  		if z.Comment != "" {
	 155  			z.buf[3] |= 0x10
	 156  		}
	 157  		if z.ModTime.After(time.Unix(0, 0)) {
	 158  			// Section 2.3.1, the zero value for MTIME means that the
	 159  			// modified time is not set.
	 160  			le.PutUint32(z.buf[4:8], uint32(z.ModTime.Unix()))
	 161  		}
	 162  		if z.level == BestCompression {
	 163  			z.buf[8] = 2
	 164  		} else if z.level == BestSpeed {
	 165  			z.buf[8] = 4
	 166  		}
	 167  		z.buf[9] = z.OS
	 168  		_, z.err = z.w.Write(z.buf[:10])
	 169  		if z.err != nil {
	 170  			return 0, z.err
	 171  		}
	 172  		if z.Extra != nil {
	 173  			z.err = z.writeBytes(z.Extra)
	 174  			if z.err != nil {
	 175  				return 0, z.err
	 176  			}
	 177  		}
	 178  		if z.Name != "" {
	 179  			z.err = z.writeString(z.Name)
	 180  			if z.err != nil {
	 181  				return 0, z.err
	 182  			}
	 183  		}
	 184  		if z.Comment != "" {
	 185  			z.err = z.writeString(z.Comment)
	 186  			if z.err != nil {
	 187  				return 0, z.err
	 188  			}
	 189  		}
	 190  		if z.compressor == nil {
	 191  			z.compressor, _ = flate.NewWriter(z.w, z.level)
	 192  		}
	 193  	}
	 194  	z.size += uint32(len(p))
	 195  	z.digest = crc32.Update(z.digest, crc32.IEEETable, p)
	 196  	n, z.err = z.compressor.Write(p)
	 197  	return n, z.err
	 198  }
	 199  
	 200  // Flush flushes any pending compressed data to the underlying writer.
	 201  //
	 202  // It is useful mainly in compressed network protocols, to ensure that
	 203  // a remote reader has enough data to reconstruct a packet. Flush does
	 204  // not return until the data has been written. If the underlying
	 205  // writer returns an error, Flush returns that error.
	 206  //
	 207  // In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
	 208  func (z *Writer) Flush() error {
	 209  	if z.err != nil {
	 210  		return z.err
	 211  	}
	 212  	if z.closed {
	 213  		return nil
	 214  	}
	 215  	if !z.wroteHeader {
	 216  		z.Write(nil)
	 217  		if z.err != nil {
	 218  			return z.err
	 219  		}
	 220  	}
	 221  	z.err = z.compressor.Flush()
	 222  	return z.err
	 223  }
	 224  
	 225  // Close closes the Writer by flushing any unwritten data to the underlying
	 226  // io.Writer and writing the GZIP footer.
	 227  // It does not close the underlying io.Writer.
	 228  func (z *Writer) Close() error {
	 229  	if z.err != nil {
	 230  		return z.err
	 231  	}
	 232  	if z.closed {
	 233  		return nil
	 234  	}
	 235  	z.closed = true
	 236  	if !z.wroteHeader {
	 237  		z.Write(nil)
	 238  		if z.err != nil {
	 239  			return z.err
	 240  		}
	 241  	}
	 242  	z.err = z.compressor.Close()
	 243  	if z.err != nil {
	 244  		return z.err
	 245  	}
	 246  	le.PutUint32(z.buf[:4], z.digest)
	 247  	le.PutUint32(z.buf[4:8], z.size)
	 248  	_, z.err = z.w.Write(z.buf[:8])
	 249  	return z.err
	 250  }
	 251  

View as plain text