writer.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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. package zlib
  5. import (
  6. "encoding/binary"
  7. "fmt"
  8. "hash"
  9. "hash/adler32"
  10. "io"
  11. "github.com/klauspost/compress/flate"
  12. )
  13. // These constants are copied from the flate package, so that code that imports
  14. // "compress/zlib" does not also have to import "compress/flate".
  15. const (
  16. NoCompression = flate.NoCompression
  17. BestSpeed = flate.BestSpeed
  18. BestCompression = flate.BestCompression
  19. DefaultCompression = flate.DefaultCompression
  20. ConstantCompression = flate.ConstantCompression // Deprecated: Use HuffmanOnly.
  21. HuffmanOnly = flate.HuffmanOnly
  22. )
  23. // A Writer takes data written to it and writes the compressed
  24. // form of that data to an underlying writer (see NewWriter).
  25. type Writer struct {
  26. w io.Writer
  27. level int
  28. dict []byte
  29. compressor *flate.Writer
  30. digest hash.Hash32
  31. err error
  32. scratch [4]byte
  33. wroteHeader bool
  34. }
  35. // NewWriter creates a new Writer.
  36. // Writes to the returned Writer are compressed and written to w.
  37. //
  38. // It is the caller's responsibility to call Close on the Writer when done.
  39. // Writes may be buffered and not flushed until Close.
  40. func NewWriter(w io.Writer) *Writer {
  41. z, _ := NewWriterLevelDict(w, DefaultCompression, nil)
  42. return z
  43. }
  44. // NewWriterLevel is like NewWriter but specifies the compression level instead
  45. // of assuming DefaultCompression.
  46. //
  47. // The compression level can be DefaultCompression, NoCompression, HuffmanOnly
  48. // or any integer value between BestSpeed and BestCompression inclusive.
  49. // The error returned will be nil if the level is valid.
  50. func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
  51. return NewWriterLevelDict(w, level, nil)
  52. }
  53. // NewWriterLevelDict is like NewWriterLevel but specifies a dictionary to
  54. // compress with.
  55. //
  56. // The dictionary may be nil. If not, its contents should not be modified until
  57. // the Writer is closed.
  58. func NewWriterLevelDict(w io.Writer, level int, dict []byte) (*Writer, error) {
  59. if level < HuffmanOnly || level > BestCompression {
  60. return nil, fmt.Errorf("zlib: invalid compression level: %d", level)
  61. }
  62. return &Writer{
  63. w: w,
  64. level: level,
  65. dict: dict,
  66. }, nil
  67. }
  68. // Reset clears the state of the Writer z such that it is equivalent to its
  69. // initial state from NewWriterLevel or NewWriterLevelDict, but instead writing
  70. // to w.
  71. func (z *Writer) Reset(w io.Writer) {
  72. z.w = w
  73. // z.level and z.dict left unchanged.
  74. if z.compressor != nil {
  75. z.compressor.Reset(w)
  76. }
  77. if z.digest != nil {
  78. z.digest.Reset()
  79. }
  80. z.err = nil
  81. z.scratch = [4]byte{}
  82. z.wroteHeader = false
  83. }
  84. // writeHeader writes the ZLIB header.
  85. func (z *Writer) writeHeader() (err error) {
  86. z.wroteHeader = true
  87. // ZLIB has a two-byte header (as documented in RFC 1950).
  88. // The first four bits is the CINFO (compression info), which is 7 for the default deflate window size.
  89. // The next four bits is the CM (compression method), which is 8 for deflate.
  90. z.scratch[0] = 0x78
  91. // The next two bits is the FLEVEL (compression level). The four values are:
  92. // 0=fastest, 1=fast, 2=default, 3=best.
  93. // The next bit, FDICT, is set if a dictionary is given.
  94. // The final five FCHECK bits form a mod-31 checksum.
  95. switch z.level {
  96. case -2, 0, 1:
  97. z.scratch[1] = 0 << 6
  98. case 2, 3, 4, 5:
  99. z.scratch[1] = 1 << 6
  100. case 6, -1:
  101. z.scratch[1] = 2 << 6
  102. case 7, 8, 9:
  103. z.scratch[1] = 3 << 6
  104. default:
  105. panic("unreachable")
  106. }
  107. if z.dict != nil {
  108. z.scratch[1] |= 1 << 5
  109. }
  110. z.scratch[1] += uint8(31 - binary.BigEndian.Uint16(z.scratch[:2])%31)
  111. if _, err = z.w.Write(z.scratch[0:2]); err != nil {
  112. return err
  113. }
  114. if z.dict != nil {
  115. // The next four bytes are the Adler-32 checksum of the dictionary.
  116. binary.BigEndian.PutUint32(z.scratch[:], adler32.Checksum(z.dict))
  117. if _, err = z.w.Write(z.scratch[0:4]); err != nil {
  118. return err
  119. }
  120. }
  121. if z.compressor == nil {
  122. // Initialize deflater unless the Writer is being reused
  123. // after a Reset call.
  124. z.compressor, err = flate.NewWriterDict(z.w, z.level, z.dict)
  125. if err != nil {
  126. return err
  127. }
  128. z.digest = adler32.New()
  129. }
  130. return nil
  131. }
  132. // Write writes a compressed form of p to the underlying io.Writer. The
  133. // compressed bytes are not necessarily flushed until the Writer is closed or
  134. // explicitly flushed.
  135. func (z *Writer) Write(p []byte) (n int, err error) {
  136. if !z.wroteHeader {
  137. z.err = z.writeHeader()
  138. }
  139. if z.err != nil {
  140. return 0, z.err
  141. }
  142. if len(p) == 0 {
  143. return 0, nil
  144. }
  145. n, err = z.compressor.Write(p)
  146. if err != nil {
  147. z.err = err
  148. return
  149. }
  150. z.digest.Write(p)
  151. return
  152. }
  153. // Flush flushes the Writer to its underlying io.Writer.
  154. func (z *Writer) Flush() error {
  155. if !z.wroteHeader {
  156. z.err = z.writeHeader()
  157. }
  158. if z.err != nil {
  159. return z.err
  160. }
  161. z.err = z.compressor.Flush()
  162. return z.err
  163. }
  164. // Close closes the Writer, flushing any unwritten data to the underlying
  165. // io.Writer, but does not close the underlying io.Writer.
  166. func (z *Writer) Close() error {
  167. if !z.wroteHeader {
  168. z.err = z.writeHeader()
  169. }
  170. if z.err != nil {
  171. return z.err
  172. }
  173. z.err = z.compressor.Close()
  174. if z.err != nil {
  175. return z.err
  176. }
  177. checksum := z.digest.Sum32()
  178. // ZLIB (RFC 1950) is big-endian, unlike GZIP (RFC 1952).
  179. binary.BigEndian.PutUint32(z.scratch[:], checksum)
  180. _, z.err = z.w.Write(z.scratch[0:4])
  181. return z.err
  182. }