mirror of
https://github.com/krolaw/zipstream.git
synced 2025-04-01 19:39:12 +00:00
93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
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
|
|
}
|