github.com/letsencrypt/go@v0.0.0-20160714163537-4054769a31f6/src/compress/flate/deflate.go (about)

     1  // Copyright 2009 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 flate
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"math"
    11  )
    12  
    13  const (
    14  	NoCompression      = 0
    15  	BestSpeed          = 1
    16  	BestCompression    = 9
    17  	DefaultCompression = -1
    18  	HuffmanOnly        = -2 // Disables match search and only does Huffman entropy reduction.
    19  )
    20  
    21  const (
    22  	logWindowSize = 15
    23  	windowSize    = 1 << logWindowSize
    24  	windowMask    = windowSize - 1
    25  
    26  	// The LZ77 step produces a sequence of literal tokens and <length, offset>
    27  	// pair tokens. The offset is also known as distance. The underlying wire
    28  	// format limits the range of lengths and offsets. For example, there are
    29  	// 256 legitimate lengths: those in the range [3, 258]. This package's
    30  	// compressor uses a higher minimum match length, enabling optimizations
    31  	// such as finding matches via 32-bit loads and compares.
    32  	baseMatchLength = 3       // The smallest match length per the RFC section 3.2.5
    33  	minMatchLength  = 4       // The smallest match length that the compressor actually emits
    34  	maxMatchLength  = 258     // The largest match length
    35  	baseMatchOffset = 1       // The smallest match offset
    36  	maxMatchOffset  = 1 << 15 // The largest match offset
    37  
    38  	// The maximum number of tokens we put into a single flate block, just to
    39  	// stop things from getting too large.
    40  	maxFlateBlockTokens = 1 << 14
    41  	maxStoreBlockSize   = 65535
    42  	hashBits            = 17 // After 17 performance degrades
    43  	hashSize            = 1 << hashBits
    44  	hashMask            = (1 << hashBits) - 1
    45  	maxHashOffset       = 1 << 24
    46  
    47  	skipNever = math.MaxInt32
    48  )
    49  
    50  type compressionLevel struct {
    51  	level, good, lazy, nice, chain, fastSkipHashing int
    52  }
    53  
    54  var levels = []compressionLevel{
    55  	{0, 0, 0, 0, 0, 0}, // NoCompression.
    56  	{1, 0, 0, 0, 0, 0}, // BestSpeed uses a custom algorithm; see deflatefast.go.
    57  	// For levels 2-3 we don't bother trying with lazy matches.
    58  	{2, 4, 0, 16, 8, 5},
    59  	{3, 4, 0, 32, 32, 6},
    60  	// Levels 4-9 use increasingly more lazy matching
    61  	// and increasingly stringent conditions for "good enough".
    62  	{4, 4, 4, 16, 16, skipNever},
    63  	{5, 8, 16, 32, 32, skipNever},
    64  	{6, 8, 16, 128, 128, skipNever},
    65  	{7, 8, 32, 128, 256, skipNever},
    66  	{8, 32, 128, 258, 1024, skipNever},
    67  	{9, 32, 258, 258, 4096, skipNever},
    68  }
    69  
    70  type compressor struct {
    71  	compressionLevel
    72  
    73  	w          *huffmanBitWriter
    74  	bulkHasher func([]byte, []uint32)
    75  
    76  	// compression algorithm
    77  	fill func(*compressor, []byte) int // copy data to window
    78  	step func(*compressor)             // process window
    79  	sync bool                          // requesting flush
    80  
    81  	// Input hash chains
    82  	// hashHead[hashValue] contains the largest inputIndex with the specified hash value
    83  	// If hashHead[hashValue] is within the current window, then
    84  	// hashPrev[hashHead[hashValue] & windowMask] contains the previous index
    85  	// with the same hash value.
    86  	chainHead  int
    87  	hashHead   [hashSize]uint32
    88  	hashPrev   [windowSize]uint32
    89  	hashOffset int
    90  
    91  	// input window: unprocessed data is window[index:windowEnd]
    92  	index         int
    93  	window        []byte
    94  	windowEnd     int
    95  	blockStart    int  // window index where current tokens start
    96  	byteAvailable bool // if true, still need to process window[index-1].
    97  
    98  	// queued output tokens
    99  	tokens []token
   100  
   101  	// deflate state
   102  	length         int
   103  	offset         int
   104  	hash           uint32
   105  	maxInsertIndex int
   106  	err            error
   107  
   108  	// hashMatch must be able to contain hashes for the maximum match length.
   109  	hashMatch [maxMatchLength - 1]uint32
   110  }
   111  
   112  func (d *compressor) fillDeflate(b []byte) int {
   113  	if d.index >= 2*windowSize-(minMatchLength+maxMatchLength) {
   114  		// shift the window by windowSize
   115  		copy(d.window, d.window[windowSize:2*windowSize])
   116  		d.index -= windowSize
   117  		d.windowEnd -= windowSize
   118  		if d.blockStart >= windowSize {
   119  			d.blockStart -= windowSize
   120  		} else {
   121  			d.blockStart = math.MaxInt32
   122  		}
   123  		d.hashOffset += windowSize
   124  		if d.hashOffset > maxHashOffset {
   125  			delta := d.hashOffset - 1
   126  			d.hashOffset -= delta
   127  			d.chainHead -= delta
   128  			for i, v := range d.hashPrev {
   129  				if int(v) > delta {
   130  					d.hashPrev[i] = uint32(int(v) - delta)
   131  				} else {
   132  					d.hashPrev[i] = 0
   133  				}
   134  			}
   135  			for i, v := range d.hashHead {
   136  				if int(v) > delta {
   137  					d.hashHead[i] = uint32(int(v) - delta)
   138  				} else {
   139  					d.hashHead[i] = 0
   140  				}
   141  			}
   142  		}
   143  	}
   144  	n := copy(d.window[d.windowEnd:], b)
   145  	d.windowEnd += n
   146  	return n
   147  }
   148  
   149  func (d *compressor) writeBlock(tokens []token, index int) error {
   150  	if index > 0 {
   151  		var window []byte
   152  		if d.blockStart <= index {
   153  			window = d.window[d.blockStart:index]
   154  		}
   155  		d.blockStart = index
   156  		d.w.writeBlock(tokens, false, window)
   157  		return d.w.err
   158  	}
   159  	return nil
   160  }
   161  
   162  // fillWindow will fill the current window with the supplied
   163  // dictionary and calculate all hashes.
   164  // This is much faster than doing a full encode.
   165  // Should only be used after a reset.
   166  func (d *compressor) fillWindow(b []byte) {
   167  	// Do not fill window if we are in store-only mode.
   168  	if d.compressionLevel.level < 2 {
   169  		return
   170  	}
   171  	if d.index != 0 || d.windowEnd != 0 {
   172  		panic("internal error: fillWindow called with stale data")
   173  	}
   174  
   175  	// If we are given too much, cut it.
   176  	if len(b) > windowSize {
   177  		b = b[len(b)-windowSize:]
   178  	}
   179  	// Add all to window.
   180  	n := copy(d.window, b)
   181  
   182  	// Calculate 256 hashes at the time (more L1 cache hits)
   183  	loops := (n + 256 - minMatchLength) / 256
   184  	for j := 0; j < loops; j++ {
   185  		index := j * 256
   186  		end := index + 256 + minMatchLength - 1
   187  		if end > n {
   188  			end = n
   189  		}
   190  		toCheck := d.window[index:end]
   191  		dstSize := len(toCheck) - minMatchLength + 1
   192  
   193  		if dstSize <= 0 {
   194  			continue
   195  		}
   196  
   197  		dst := d.hashMatch[:dstSize]
   198  		d.bulkHasher(toCheck, dst)
   199  		var newH uint32
   200  		for i, val := range dst {
   201  			di := i + index
   202  			newH = val
   203  			hh := &d.hashHead[newH&hashMask]
   204  			// Get previous value with the same hash.
   205  			// Our chain should point to the previous value.
   206  			d.hashPrev[di&windowMask] = *hh
   207  			// Set the head of the hash chain to us.
   208  			*hh = uint32(di + d.hashOffset)
   209  		}
   210  		d.hash = newH
   211  	}
   212  	// Update window information.
   213  	d.windowEnd = n
   214  	d.index = n
   215  }
   216  
   217  // Try to find a match starting at index whose length is greater than prevSize.
   218  // We only look at chainCount possibilities before giving up.
   219  func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) {
   220  	minMatchLook := maxMatchLength
   221  	if lookahead < minMatchLook {
   222  		minMatchLook = lookahead
   223  	}
   224  
   225  	win := d.window[0 : pos+minMatchLook]
   226  
   227  	// We quit when we get a match that's at least nice long
   228  	nice := len(win) - pos
   229  	if d.nice < nice {
   230  		nice = d.nice
   231  	}
   232  
   233  	// If we've got a match that's good enough, only look in 1/4 the chain.
   234  	tries := d.chain
   235  	length = prevLength
   236  	if length >= d.good {
   237  		tries >>= 2
   238  	}
   239  
   240  	wEnd := win[pos+length]
   241  	wPos := win[pos:]
   242  	minIndex := pos - windowSize
   243  
   244  	for i := prevHead; tries > 0; tries-- {
   245  		if wEnd == win[i+length] {
   246  			n := matchLen(win[i:], wPos, minMatchLook)
   247  
   248  			if n > length && (n > minMatchLength || pos-i <= 4096) {
   249  				length = n
   250  				offset = pos - i
   251  				ok = true
   252  				if n >= nice {
   253  					// The match is good enough that we don't try to find a better one.
   254  					break
   255  				}
   256  				wEnd = win[pos+n]
   257  			}
   258  		}
   259  		if i == minIndex {
   260  			// hashPrev[i & windowMask] has already been overwritten, so stop now.
   261  			break
   262  		}
   263  		i = int(d.hashPrev[i&windowMask]) - d.hashOffset
   264  		if i < minIndex || i < 0 {
   265  			break
   266  		}
   267  	}
   268  	return
   269  }
   270  
   271  func (d *compressor) writeStoredBlock(buf []byte) error {
   272  	if d.w.writeStoredHeader(len(buf), false); d.w.err != nil {
   273  		return d.w.err
   274  	}
   275  	d.w.writeBytes(buf)
   276  	return d.w.err
   277  }
   278  
   279  const hashmul = 0x1e35a7bd
   280  
   281  // hash4 returns a hash representation of the first 4 bytes
   282  // of the supplied slice.
   283  // The caller must ensure that len(b) >= 4.
   284  func hash4(b []byte) uint32 {
   285  	return ((uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24) * hashmul) >> (32 - hashBits)
   286  }
   287  
   288  // bulkHash4 will compute hashes using the same
   289  // algorithm as hash4
   290  func bulkHash4(b []byte, dst []uint32) {
   291  	if len(b) < minMatchLength {
   292  		return
   293  	}
   294  	hb := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
   295  	dst[0] = (hb * hashmul) >> (32 - hashBits)
   296  	end := len(b) - minMatchLength + 1
   297  	for i := 1; i < end; i++ {
   298  		hb = (hb << 8) | uint32(b[i+3])
   299  		dst[i] = (hb * hashmul) >> (32 - hashBits)
   300  	}
   301  }
   302  
   303  // matchLen returns the number of matching bytes in a and b
   304  // up to length 'max'. Both slices must be at least 'max'
   305  // bytes in size.
   306  func matchLen(a, b []byte, max int) int {
   307  	a = a[:max]
   308  	b = b[:len(a)]
   309  	for i, av := range a {
   310  		if b[i] != av {
   311  			return i
   312  		}
   313  	}
   314  	return max
   315  }
   316  
   317  // encSpeed will compress and store the currently added data,
   318  // if enough has been accumulated or we at the end of the stream.
   319  // Any error that occurred will be in d.err
   320  func (d *compressor) encSpeed() {
   321  	// We only compress if we have maxStoreBlockSize.
   322  	if d.windowEnd < maxStoreBlockSize {
   323  		if !d.sync {
   324  			return
   325  		}
   326  
   327  		// Handle small sizes.
   328  		if d.windowEnd < 128 {
   329  			switch {
   330  			case d.windowEnd == 0:
   331  				return
   332  			case d.windowEnd <= 16:
   333  				d.err = d.writeStoredBlock(d.window[:d.windowEnd])
   334  			default:
   335  				d.w.writeBlockHuff(false, d.window[:d.windowEnd])
   336  				d.err = d.w.err
   337  			}
   338  			d.windowEnd = 0
   339  			return
   340  		}
   341  
   342  	}
   343  	// Encode the block.
   344  	d.tokens = encodeBestSpeed(d.tokens[:0], d.window[:d.windowEnd])
   345  
   346  	// If we removed less than 1/16th, Huffman compress the block.
   347  	if len(d.tokens) > d.windowEnd-(d.windowEnd>>4) {
   348  		d.w.writeBlockHuff(false, d.window[:d.windowEnd])
   349  	} else {
   350  		d.w.writeBlockDynamic(d.tokens, false, d.window[:d.windowEnd])
   351  	}
   352  	d.err = d.w.err
   353  	d.windowEnd = 0
   354  }
   355  
   356  func (d *compressor) initDeflate() {
   357  	d.window = make([]byte, 2*windowSize)
   358  	d.hashOffset = 1
   359  	d.tokens = make([]token, 0, maxFlateBlockTokens+1)
   360  	d.length = minMatchLength - 1
   361  	d.offset = 0
   362  	d.byteAvailable = false
   363  	d.index = 0
   364  	d.hash = 0
   365  	d.chainHead = -1
   366  	d.bulkHasher = bulkHash4
   367  }
   368  
   369  func (d *compressor) deflate() {
   370  	if d.windowEnd-d.index < minMatchLength+maxMatchLength && !d.sync {
   371  		return
   372  	}
   373  
   374  	d.maxInsertIndex = d.windowEnd - (minMatchLength - 1)
   375  	if d.index < d.maxInsertIndex {
   376  		d.hash = hash4(d.window[d.index : d.index+minMatchLength])
   377  	}
   378  
   379  Loop:
   380  	for {
   381  		if d.index > d.windowEnd {
   382  			panic("index > windowEnd")
   383  		}
   384  		lookahead := d.windowEnd - d.index
   385  		if lookahead < minMatchLength+maxMatchLength {
   386  			if !d.sync {
   387  				break Loop
   388  			}
   389  			if d.index > d.windowEnd {
   390  				panic("index > windowEnd")
   391  			}
   392  			if lookahead == 0 {
   393  				// Flush current output block if any.
   394  				if d.byteAvailable {
   395  					// There is still one pending token that needs to be flushed
   396  					d.tokens = append(d.tokens, literalToken(uint32(d.window[d.index-1])))
   397  					d.byteAvailable = false
   398  				}
   399  				if len(d.tokens) > 0 {
   400  					if d.err = d.writeBlock(d.tokens, d.index); d.err != nil {
   401  						return
   402  					}
   403  					d.tokens = d.tokens[:0]
   404  				}
   405  				break Loop
   406  			}
   407  		}
   408  		if d.index < d.maxInsertIndex {
   409  			// Update the hash
   410  			d.hash = hash4(d.window[d.index : d.index+minMatchLength])
   411  			hh := &d.hashHead[d.hash&hashMask]
   412  			d.chainHead = int(*hh)
   413  			d.hashPrev[d.index&windowMask] = uint32(d.chainHead)
   414  			*hh = uint32(d.index + d.hashOffset)
   415  		}
   416  		prevLength := d.length
   417  		prevOffset := d.offset
   418  		d.length = minMatchLength - 1
   419  		d.offset = 0
   420  		minIndex := d.index - windowSize
   421  		if minIndex < 0 {
   422  			minIndex = 0
   423  		}
   424  
   425  		if d.chainHead-d.hashOffset >= minIndex &&
   426  			(d.fastSkipHashing != skipNever && lookahead > minMatchLength-1 ||
   427  				d.fastSkipHashing == skipNever && lookahead > prevLength && prevLength < d.lazy) {
   428  			if newLength, newOffset, ok := d.findMatch(d.index, d.chainHead-d.hashOffset, minMatchLength-1, lookahead); ok {
   429  				d.length = newLength
   430  				d.offset = newOffset
   431  			}
   432  		}
   433  		if d.fastSkipHashing != skipNever && d.length >= minMatchLength ||
   434  			d.fastSkipHashing == skipNever && prevLength >= minMatchLength && d.length <= prevLength {
   435  			// There was a match at the previous step, and the current match is
   436  			// not better. Output the previous match.
   437  			if d.fastSkipHashing != skipNever {
   438  				d.tokens = append(d.tokens, matchToken(uint32(d.length-baseMatchLength), uint32(d.offset-baseMatchOffset)))
   439  			} else {
   440  				d.tokens = append(d.tokens, matchToken(uint32(prevLength-baseMatchLength), uint32(prevOffset-baseMatchOffset)))
   441  			}
   442  			// Insert in the hash table all strings up to the end of the match.
   443  			// index and index-1 are already inserted. If there is not enough
   444  			// lookahead, the last two strings are not inserted into the hash
   445  			// table.
   446  			if d.length <= d.fastSkipHashing {
   447  				var newIndex int
   448  				if d.fastSkipHashing != skipNever {
   449  					newIndex = d.index + d.length
   450  				} else {
   451  					newIndex = d.index + prevLength - 1
   452  				}
   453  				for d.index++; d.index < newIndex; d.index++ {
   454  					if d.index < d.maxInsertIndex {
   455  						d.hash = hash4(d.window[d.index : d.index+minMatchLength])
   456  						// Get previous value with the same hash.
   457  						// Our chain should point to the previous value.
   458  						hh := &d.hashHead[d.hash&hashMask]
   459  						d.hashPrev[d.index&windowMask] = *hh
   460  						// Set the head of the hash chain to us.
   461  						*hh = uint32(d.index + d.hashOffset)
   462  					}
   463  				}
   464  				if d.fastSkipHashing == skipNever {
   465  					d.byteAvailable = false
   466  					d.length = minMatchLength - 1
   467  				}
   468  			} else {
   469  				// For matches this long, we don't bother inserting each individual
   470  				// item into the table.
   471  				d.index += d.length
   472  				if d.index < d.maxInsertIndex {
   473  					d.hash = hash4(d.window[d.index : d.index+minMatchLength])
   474  				}
   475  			}
   476  			if len(d.tokens) == maxFlateBlockTokens {
   477  				// The block includes the current character
   478  				if d.err = d.writeBlock(d.tokens, d.index); d.err != nil {
   479  					return
   480  				}
   481  				d.tokens = d.tokens[:0]
   482  			}
   483  		} else {
   484  			if d.fastSkipHashing != skipNever || d.byteAvailable {
   485  				i := d.index - 1
   486  				if d.fastSkipHashing != skipNever {
   487  					i = d.index
   488  				}
   489  				d.tokens = append(d.tokens, literalToken(uint32(d.window[i])))
   490  				if len(d.tokens) == maxFlateBlockTokens {
   491  					if d.err = d.writeBlock(d.tokens, i+1); d.err != nil {
   492  						return
   493  					}
   494  					d.tokens = d.tokens[:0]
   495  				}
   496  			}
   497  			d.index++
   498  			if d.fastSkipHashing == skipNever {
   499  				d.byteAvailable = true
   500  			}
   501  		}
   502  	}
   503  }
   504  
   505  func (d *compressor) fillStore(b []byte) int {
   506  	n := copy(d.window[d.windowEnd:], b)
   507  	d.windowEnd += n
   508  	return n
   509  }
   510  
   511  func (d *compressor) store() {
   512  	if d.windowEnd > 0 {
   513  		d.err = d.writeStoredBlock(d.window[:d.windowEnd])
   514  	}
   515  	d.windowEnd = 0
   516  }
   517  
   518  // storeHuff compresses and stores the currently added data
   519  // when the d.window is full or we are at the end of the stream.
   520  // Any error that occurred will be in d.err
   521  func (d *compressor) storeHuff() {
   522  	if d.windowEnd < len(d.window) && !d.sync || d.windowEnd == 0 {
   523  		return
   524  	}
   525  	d.w.writeBlockHuff(false, d.window[:d.windowEnd])
   526  	d.err = d.w.err
   527  	d.windowEnd = 0
   528  }
   529  
   530  func (d *compressor) write(b []byte) (n int, err error) {
   531  	if d.err != nil {
   532  		return 0, d.err
   533  	}
   534  	n = len(b)
   535  	for len(b) > 0 {
   536  		d.step(d)
   537  		b = b[d.fill(d, b):]
   538  		if d.err != nil {
   539  			return 0, d.err
   540  		}
   541  	}
   542  	return n, nil
   543  }
   544  
   545  func (d *compressor) syncFlush() error {
   546  	if d.err != nil {
   547  		return d.err
   548  	}
   549  	d.sync = true
   550  	d.step(d)
   551  	if d.err == nil {
   552  		d.w.writeStoredHeader(0, false)
   553  		d.w.flush()
   554  		d.err = d.w.err
   555  	}
   556  	d.sync = false
   557  	return d.err
   558  }
   559  
   560  func (d *compressor) init(w io.Writer, level int) (err error) {
   561  	d.w = newHuffmanBitWriter(w)
   562  
   563  	switch {
   564  	case level == NoCompression:
   565  		d.window = make([]byte, maxStoreBlockSize)
   566  		d.fill = (*compressor).fillStore
   567  		d.step = (*compressor).store
   568  	case level == HuffmanOnly:
   569  		d.window = make([]byte, maxStoreBlockSize)
   570  		d.fill = (*compressor).fillStore
   571  		d.step = (*compressor).storeHuff
   572  	case level == BestSpeed:
   573  		d.compressionLevel = levels[level]
   574  		d.window = make([]byte, maxStoreBlockSize)
   575  		d.fill = (*compressor).fillStore
   576  		d.step = (*compressor).encSpeed
   577  		d.tokens = make([]token, maxStoreBlockSize)
   578  	case level == DefaultCompression:
   579  		level = 6
   580  		fallthrough
   581  	case 2 <= level && level <= 9:
   582  		d.compressionLevel = levels[level]
   583  		d.initDeflate()
   584  		d.fill = (*compressor).fillDeflate
   585  		d.step = (*compressor).deflate
   586  	default:
   587  		return fmt.Errorf("flate: invalid compression level %d: want value in range [-2, 9]", level)
   588  	}
   589  	return nil
   590  }
   591  
   592  func (d *compressor) reset(w io.Writer) {
   593  	d.w.reset(w)
   594  	d.sync = false
   595  	d.err = nil
   596  	switch d.compressionLevel.level {
   597  	case NoCompression:
   598  		d.windowEnd = 0
   599  	case BestSpeed:
   600  		d.windowEnd = 0
   601  		d.tokens = d.tokens[:0]
   602  	default:
   603  		d.chainHead = -1
   604  		for i := range d.hashHead {
   605  			d.hashHead[i] = 0
   606  		}
   607  		for i := range d.hashPrev {
   608  			d.hashPrev[i] = 0
   609  		}
   610  		d.hashOffset = 1
   611  		d.index, d.windowEnd = 0, 0
   612  		d.blockStart, d.byteAvailable = 0, false
   613  		d.tokens = d.tokens[:0]
   614  		d.length = minMatchLength - 1
   615  		d.offset = 0
   616  		d.hash = 0
   617  		d.maxInsertIndex = 0
   618  	}
   619  }
   620  
   621  func (d *compressor) close() error {
   622  	if d.err != nil {
   623  		return d.err
   624  	}
   625  	d.sync = true
   626  	d.step(d)
   627  	if d.err != nil {
   628  		return d.err
   629  	}
   630  	if d.w.writeStoredHeader(0, true); d.w.err != nil {
   631  		return d.w.err
   632  	}
   633  	d.w.flush()
   634  	return d.w.err
   635  }
   636  
   637  // NewWriter returns a new Writer compressing data at the given level.
   638  // Following zlib, levels range from 1 (BestSpeed) to 9 (BestCompression);
   639  // higher levels typically run slower but compress more. Level 0
   640  // (NoCompression) does not attempt any compression; it only adds the
   641  // necessary DEFLATE framing.
   642  // Level -1 (DefaultCompression) uses the default compression level.
   643  // Level -2 (HuffmanOnly) will use Huffman compression only, giving
   644  // a very fast compression for all types of input, but sacrificing considerable
   645  // compression efficiency.
   646  //
   647  //
   648  // If level is in the range [-2, 9] then the error returned will be nil.
   649  // Otherwise the error returned will be non-nil.
   650  func NewWriter(w io.Writer, level int) (*Writer, error) {
   651  	var dw Writer
   652  	if err := dw.d.init(w, level); err != nil {
   653  		return nil, err
   654  	}
   655  	return &dw, nil
   656  }
   657  
   658  // NewWriterDict is like NewWriter but initializes the new
   659  // Writer with a preset dictionary. The returned Writer behaves
   660  // as if the dictionary had been written to it without producing
   661  // any compressed output. The compressed data written to w
   662  // can only be decompressed by a Reader initialized with the
   663  // same dictionary.
   664  func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) {
   665  	dw := &dictWriter{w}
   666  	zw, err := NewWriter(dw, level)
   667  	if err != nil {
   668  		return nil, err
   669  	}
   670  	zw.d.fillWindow(dict)
   671  	zw.dict = append(zw.dict, dict...) // duplicate dictionary for Reset method.
   672  	return zw, err
   673  }
   674  
   675  type dictWriter struct {
   676  	w io.Writer
   677  }
   678  
   679  func (w *dictWriter) Write(b []byte) (n int, err error) {
   680  	return w.w.Write(b)
   681  }
   682  
   683  // A Writer takes data written to it and writes the compressed
   684  // form of that data to an underlying writer (see NewWriter).
   685  type Writer struct {
   686  	d    compressor
   687  	dict []byte
   688  }
   689  
   690  // Write writes data to w, which will eventually write the
   691  // compressed form of data to its underlying writer.
   692  func (w *Writer) Write(data []byte) (n int, err error) {
   693  	return w.d.write(data)
   694  }
   695  
   696  // Flush flushes any pending compressed data to the underlying writer.
   697  // It is useful mainly in compressed network protocols, to ensure that
   698  // a remote reader has enough data to reconstruct a packet.
   699  // Flush does not return until the data has been written.
   700  // If the underlying writer returns an error, Flush returns that error.
   701  //
   702  // In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
   703  func (w *Writer) Flush() error {
   704  	// For more about flushing:
   705  	// http://www.bolet.org/~pornin/deflate-flush.html
   706  	return w.d.syncFlush()
   707  }
   708  
   709  // Close flushes and closes the writer.
   710  func (w *Writer) Close() error {
   711  	return w.d.close()
   712  }
   713  
   714  // Reset discards the writer's state and makes it equivalent to
   715  // the result of NewWriter or NewWriterDict called with dst
   716  // and w's level and dictionary.
   717  func (w *Writer) Reset(dst io.Writer) {
   718  	if dw, ok := w.d.w.w.(*dictWriter); ok {
   719  		// w was created with NewWriterDict
   720  		dw.w = dst
   721  		w.d.reset(dw)
   722  		w.d.fillWindow(w.dict)
   723  	} else {
   724  		// w was created with NewWriter
   725  		w.d.reset(dst)
   726  	}
   727  }