gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

gzip.go (6940B)


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