-
Notifications
You must be signed in to change notification settings - Fork 16
/
descriptor.go
92 lines (78 loc) · 1.92 KB
/
descriptor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package zipstream
import (
"archive/zip"
"bufio"
"bytes"
"encoding/binary"
"io"
)
type descriptorReader struct {
br *bufio.Reader
size uint64
eof bool
fileHeader *zip.FileHeader
}
var (
sigBytes = []byte{0x50, 0x4b}
)
func (r *descriptorReader) Read(p []byte) (n int, err error) {
if r.eof {
return 0, io.EOF
}
if n = len(p); n > maxRead {
n = maxRead
}
z, err := r.br.Peek(n + readAhead)
if err != nil {
if err == io.EOF && len(z) < 46+22 { // Min length of Central directory + End of central directory
return 0, err
}
n = len(z)
}
// Look for header of next file or central directory
discard := n
s := 16
for !r.eof && s < n {
i := bytes.Index(z[s:len(z)-4], sigBytes) + s
if i == -1 {
break
}
// If directoryHeaderSignature or fileHeaderSignature file could be finished
if sig := binary.LittleEndian.Uint32(z[i : i+4]); sig == fileHeaderSignature ||
sig == directoryHeaderSignature {
// Now check for compressed file sizes to ensure not false positive and if zip64.
if i < len(z)-8 { // Zip32
// Zip32 optional dataDescriptorSignature
offset := 0
if binary.LittleEndian.Uint32(z[i-16:i-12]) == dataDescriptorSignature {
offset = 4
}
// Zip32 compressed file size
if binary.LittleEndian.Uint32(z[i-8:i-4]) == uint32(r.size)+uint32(i-12-offset) {
n, discard = i-12-offset, i
r.eof = true
r.fileHeader.CRC32 = binary.LittleEndian.Uint32(z[i-12 : i-8])
break
}
}
if i > 24 {
// Zip64 optional dataDescriptorSignature
offset := 0
if binary.LittleEndian.Uint32(z[i-24:i-20]) == dataDescriptorSignature {
offset = 4
}
// Zip64 compressed file size
if i >= 8 && binary.LittleEndian.Uint64(z[i-16:i-8]) == r.size+uint64(i-20-offset) {
n, discard = i-20-offset, i
r.eof = true
break
}
}
}
s = i + 2
}
copy(p, z[:n])
r.br.Discard(discard)
r.size += uint64(n)
return
}