1
2
3
4
5 package zlib
6
7 import (
8 "compress/flate"
9 "hash"
10 "hash/adler32"
11 "io"
12 "os"
13 )
14
15
16
17 const (
18 NoCompression = flate.NoCompression
19 BestSpeed = flate.BestSpeed
20 BestCompression = flate.BestCompression
21 DefaultCompression = flate.DefaultCompression
22 )
23
24
25
26 type Writer struct {
27 w io.Writer
28 compressor *flate.Writer
29 digest hash.Hash32
30 err os.Error
31 scratch [4]byte
32 }
33
34
35 func NewWriter(w io.Writer) (*Writer, os.Error) {
36 return NewWriterLevel(w, DefaultCompression)
37 }
38
39
40 func NewWriterLevel(w io.Writer, level int) (*Writer, os.Error) {
41 return NewWriterDict(w, level, nil)
42 }
43
44
45
46
47
48
49 func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, os.Error) {
50 z := new(Writer)
51
52
53
54 z.scratch[0] = 0x78
55
56
57
58
59 switch level {
60 case 0, 1:
61 z.scratch[1] = 0 << 6
62 case 2, 3, 4, 5:
63 z.scratch[1] = 1 << 6
64 case 6, -1:
65 z.scratch[1] = 2 << 6
66 case 7, 8, 9:
67 z.scratch[1] = 3 << 6
68 default:
69 return nil, os.NewError("level out of range")
70 }
71 if dict != nil {
72 z.scratch[1] |= 1 << 5
73 }
74 z.scratch[1] += uint8(31 - (uint16(z.scratch[0])<<8+uint16(z.scratch[1]))%31)
75 _, err := w.Write(z.scratch[0:2])
76 if err != nil {
77 return nil, err
78 }
79 if dict != nil {
80
81 checksum := adler32.Checksum(dict)
82 z.scratch[0] = uint8(checksum >> 24)
83 z.scratch[1] = uint8(checksum >> 16)
84 z.scratch[2] = uint8(checksum >> 8)
85 z.scratch[3] = uint8(checksum >> 0)
86 _, err = w.Write(z.scratch[0:4])
87 if err != nil {
88 return nil, err
89 }
90 }
91 z.w = w
92 z.compressor = flate.NewWriterDict(w, level, dict)
93 z.digest = adler32.New()
94 return z, nil
95 }
96
97 func (z *Writer) Write(p []byte) (n int, err os.Error) {
98 if z.err != nil {
99 return 0, z.err
100 }
101 if len(p) == 0 {
102 return 0, nil
103 }
104 n, err = z.compressor.Write(p)
105 if err != nil {
106 z.err = err
107 return
108 }
109 z.digest.Write(p)
110 return
111 }
112
113
114 func (z *Writer) Flush() os.Error {
115 if z.err != nil {
116 return z.err
117 }
118 z.err = z.compressor.Flush()
119 return z.err
120 }
121
122
123 func (z *Writer) Close() os.Error {
124 if z.err != nil {
125 return z.err
126 }
127 z.err = z.compressor.Close()
128 if z.err != nil {
129 return z.err
130 }
131 checksum := z.digest.Sum32()
132
133 z.scratch[0] = uint8(checksum >> 24)
134 z.scratch[1] = uint8(checksum >> 16)
135 z.scratch[2] = uint8(checksum >> 8)
136 z.scratch[3] = uint8(checksum >> 0)
137 _, z.err = z.w.Write(z.scratch[0:4])
138 return z.err
139 }