Source file src/pkg/archive/zip/writer.go
1
2
3
4
5 package zip
6
7 import (
8 "bufio"
9 "compress/flate"
10 "encoding/binary"
11 "errors"
12 "hash"
13 "hash/crc32"
14 "io"
15 )
16
17
18
19
20
21 type Writer struct {
22 cw *countWriter
23 dir []*header
24 last *fileWriter
25 closed bool
26 }
27
28 type header struct {
29 *FileHeader
30 offset uint64
31 }
32
33
34 func NewWriter(w io.Writer) *Writer {
35 return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}}
36 }
37
38
39
40 func (w *Writer) Close() error {
41 if w.last != nil && !w.last.closed {
42 if err := w.last.close(); err != nil {
43 return err
44 }
45 w.last = nil
46 }
47 if w.closed {
48 return errors.New("zip: writer closed twice")
49 }
50 w.closed = true
51
52
53 start := w.cw.count
54 for _, h := range w.dir {
55 var buf [directoryHeaderLen]byte
56 b := writeBuf(buf[:])
57 b.uint32(uint32(directoryHeaderSignature))
58 b.uint16(h.CreatorVersion)
59 b.uint16(h.ReaderVersion)
60 b.uint16(h.Flags)
61 b.uint16(h.Method)
62 b.uint16(h.ModifiedTime)
63 b.uint16(h.ModifiedDate)
64 b.uint32(h.CRC32)
65 if h.isZip64() || h.offset > uint32max {
66
67
68
69 b.uint32(uint32max)
70 b.uint32(uint32max)
71
72
73 var buf [28]byte
74 eb := writeBuf(buf[:])
75 eb.uint16(zip64ExtraId)
76 eb.uint16(24)
77 eb.uint64(h.UncompressedSize64)
78 eb.uint64(h.CompressedSize64)
79 eb.uint64(h.offset)
80 h.Extra = append(h.Extra, buf[:]...)
81 } else {
82 b.uint32(h.CompressedSize)
83 b.uint32(h.UncompressedSize)
84 }
85 b.uint16(uint16(len(h.Name)))
86 b.uint16(uint16(len(h.Extra)))
87 b.uint16(uint16(len(h.Comment)))
88 b = b[4:]
89 b.uint32(h.ExternalAttrs)
90 if h.offset > uint32max {
91 b.uint32(uint32max)
92 } else {
93 b.uint32(uint32(h.offset))
94 }
95 if _, err := w.cw.Write(buf[:]); err != nil {
96 return err
97 }
98 if _, err := io.WriteString(w.cw, h.Name); err != nil {
99 return err
100 }
101 if _, err := w.cw.Write(h.Extra); err != nil {
102 return err
103 }
104 if _, err := io.WriteString(w.cw, h.Comment); err != nil {
105 return err
106 }
107 }
108 end := w.cw.count
109
110 records := uint64(len(w.dir))
111 size := uint64(end - start)
112 offset := uint64(start)
113
114 if records > uint16max || size > uint32max || offset > uint32max {
115 var buf [directory64EndLen + directory64LocLen]byte
116 b := writeBuf(buf[:])
117
118
119 b.uint32(directory64EndSignature)
120 b.uint64(directory64EndLen)
121 b.uint16(zipVersion45)
122 b.uint16(zipVersion45)
123 b.uint32(0)
124 b.uint32(0)
125 b.uint64(records)
126 b.uint64(records)
127 b.uint64(size)
128 b.uint64(offset)
129
130
131 b.uint32(directory64LocSignature)
132 b.uint32(0)
133 b.uint64(uint64(end))
134 b.uint32(1)
135
136 if _, err := w.cw.Write(buf[:]); err != nil {
137 return err
138 }
139
140
141
142 records = uint16max
143 size = uint32max
144 offset = uint32max
145 }
146
147
148 var buf [directoryEndLen]byte
149 b := writeBuf(buf[:])
150 b.uint32(uint32(directoryEndSignature))
151 b = b[4:]
152 b.uint16(uint16(records))
153 b.uint16(uint16(records))
154 b.uint32(uint32(size))
155 b.uint32(uint32(offset))
156
157 if _, err := w.cw.Write(buf[:]); err != nil {
158 return err
159 }
160
161 return w.cw.w.(*bufio.Writer).Flush()
162 }
163
164
165
166
167
168
169
170
171 func (w *Writer) Create(name string) (io.Writer, error) {
172 header := &FileHeader{
173 Name: name,
174 Method: Deflate,
175 }
176 return w.CreateHeader(header)
177 }
178
179
180
181
182
183
184 func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
185 if w.last != nil && !w.last.closed {
186 if err := w.last.close(); err != nil {
187 return nil, err
188 }
189 }
190
191 fh.Flags |= 0x8
192
193 fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20
194 fh.ReaderVersion = zipVersion20
195
196 fw := &fileWriter{
197 zipw: w.cw,
198 compCount: &countWriter{w: w.cw},
199 crc32: crc32.NewIEEE(),
200 }
201 switch fh.Method {
202 case Store:
203 fw.comp = nopCloser{fw.compCount}
204 case Deflate:
205 var err error
206 fw.comp, err = flate.NewWriter(fw.compCount, 5)
207 if err != nil {
208 return nil, err
209 }
210 default:
211 return nil, ErrAlgorithm
212 }
213 fw.rawCount = &countWriter{w: fw.comp}
214
215 h := &header{
216 FileHeader: fh,
217 offset: uint64(w.cw.count),
218 }
219 w.dir = append(w.dir, h)
220 fw.header = h
221
222 if err := writeHeader(w.cw, fh); err != nil {
223 return nil, err
224 }
225
226 w.last = fw
227 return fw, nil
228 }
229
230 func writeHeader(w io.Writer, h *FileHeader) error {
231 var buf [fileHeaderLen]byte
232 b := writeBuf(buf[:])
233 b.uint32(uint32(fileHeaderSignature))
234 b.uint16(h.ReaderVersion)
235 b.uint16(h.Flags)
236 b.uint16(h.Method)
237 b.uint16(h.ModifiedTime)
238 b.uint16(h.ModifiedDate)
239 b.uint32(0)
240 b.uint32(0)
241 b.uint32(0)
242 b.uint16(uint16(len(h.Name)))
243 b.uint16(uint16(len(h.Extra)))
244 if _, err := w.Write(buf[:]); err != nil {
245 return err
246 }
247 if _, err := io.WriteString(w, h.Name); err != nil {
248 return err
249 }
250 _, err := w.Write(h.Extra)
251 return err
252 }
253
254 type fileWriter struct {
255 *header
256 zipw io.Writer
257 rawCount *countWriter
258 comp io.WriteCloser
259 compCount *countWriter
260 crc32 hash.Hash32
261 closed bool
262 }
263
264 func (w *fileWriter) Write(p []byte) (int, error) {
265 if w.closed {
266 return 0, errors.New("zip: write to closed file")
267 }
268 w.crc32.Write(p)
269 return w.rawCount.Write(p)
270 }
271
272 func (w *fileWriter) close() error {
273 if w.closed {
274 return errors.New("zip: file closed twice")
275 }
276 w.closed = true
277 if err := w.comp.Close(); err != nil {
278 return err
279 }
280
281
282 fh := w.header.FileHeader
283 fh.CRC32 = w.crc32.Sum32()
284 fh.CompressedSize64 = uint64(w.compCount.count)
285 fh.UncompressedSize64 = uint64(w.rawCount.count)
286
287 if fh.isZip64() {
288 fh.CompressedSize = uint32max
289 fh.UncompressedSize = uint32max
290 fh.ReaderVersion = zipVersion45
291 } else {
292 fh.CompressedSize = uint32(fh.CompressedSize64)
293 fh.UncompressedSize = uint32(fh.UncompressedSize64)
294 }
295
296
297
298
299
300
301 var buf []byte
302 if fh.isZip64() {
303 buf = make([]byte, dataDescriptor64Len)
304 } else {
305 buf = make([]byte, dataDescriptorLen)
306 }
307 b := writeBuf(buf)
308 b.uint32(dataDescriptorSignature)
309 b.uint32(fh.CRC32)
310 if fh.isZip64() {
311 b.uint64(fh.CompressedSize64)
312 b.uint64(fh.UncompressedSize64)
313 } else {
314 b.uint32(fh.CompressedSize)
315 b.uint32(fh.UncompressedSize)
316 }
317 _, err := w.zipw.Write(buf)
318 return err
319 }
320
321 type countWriter struct {
322 w io.Writer
323 count int64
324 }
325
326 func (w *countWriter) Write(p []byte) (int, error) {
327 n, err := w.w.Write(p)
328 w.count += int64(n)
329 return n, err
330 }
331
332 type nopCloser struct {
333 io.Writer
334 }
335
336 func (w nopCloser) Close() error {
337 return nil
338 }
339
340 type writeBuf []byte
341
342 func (b *writeBuf) uint16(v uint16) {
343 binary.LittleEndian.PutUint16(*b, v)
344 *b = (*b)[2:]
345 }
346
347 func (b *writeBuf) uint32(v uint32) {
348 binary.LittleEndian.PutUint32(*b, v)
349 *b = (*b)[4:]
350 }
351
352 func (b *writeBuf) uint64(v uint64) {
353 binary.LittleEndian.PutUint64(*b, v)
354 *b = (*b)[8:]
355 }
View as plain text