mirror of
https://github.com/golang/go
synced 2024-11-13 16:00:21 -07:00
archive/zip: stop using encoding/binary
R=golang-dev, r, bradfitz CC=golang-dev https://golang.org/cl/5694085
This commit is contained in:
parent
28668c3a28
commit
228f44a1f5
@ -7,7 +7,6 @@ package zip
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"compress/flate"
|
"compress/flate"
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
"errors"
|
||||||
"hash"
|
"hash"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
@ -174,20 +173,19 @@ func readFileHeader(f *File, r io.Reader) error {
|
|||||||
if _, err := io.ReadFull(r, b[:]); err != nil {
|
if _, err := io.ReadFull(r, b[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c := binary.LittleEndian
|
if sig := toUint32(b[:]); sig != fileHeaderSignature {
|
||||||
if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
|
|
||||||
return ErrFormat
|
return ErrFormat
|
||||||
}
|
}
|
||||||
f.ReaderVersion = c.Uint16(b[4:6])
|
f.ReaderVersion = toUint16(b[4:])
|
||||||
f.Flags = c.Uint16(b[6:8])
|
f.Flags = toUint16(b[6:])
|
||||||
f.Method = c.Uint16(b[8:10])
|
f.Method = toUint16(b[8:])
|
||||||
f.ModifiedTime = c.Uint16(b[10:12])
|
f.ModifiedTime = toUint16(b[10:])
|
||||||
f.ModifiedDate = c.Uint16(b[12:14])
|
f.ModifiedDate = toUint16(b[12:])
|
||||||
f.CRC32 = c.Uint32(b[14:18])
|
f.CRC32 = toUint32(b[14:])
|
||||||
f.CompressedSize = c.Uint32(b[18:22])
|
f.CompressedSize = toUint32(b[18:])
|
||||||
f.UncompressedSize = c.Uint32(b[22:26])
|
f.UncompressedSize = toUint32(b[22:])
|
||||||
filenameLen := int(c.Uint16(b[26:28]))
|
filenameLen := int(toUint16(b[26:]))
|
||||||
extraLen := int(c.Uint16(b[28:30]))
|
extraLen := int(toUint16(b[28:]))
|
||||||
d := make([]byte, filenameLen+extraLen)
|
d := make([]byte, filenameLen+extraLen)
|
||||||
if _, err := io.ReadFull(r, d); err != nil {
|
if _, err := io.ReadFull(r, d); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -205,12 +203,11 @@ func (f *File) findBodyOffset() (int64, error) {
|
|||||||
if _, err := io.ReadFull(r, b[:]); err != nil {
|
if _, err := io.ReadFull(r, b[:]); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
c := binary.LittleEndian
|
if sig := toUint32(b[:4]); sig != fileHeaderSignature {
|
||||||
if sig := c.Uint32(b[:4]); sig != fileHeaderSignature {
|
|
||||||
return 0, ErrFormat
|
return 0, ErrFormat
|
||||||
}
|
}
|
||||||
filenameLen := int(c.Uint16(b[26:28]))
|
filenameLen := int(toUint16(b[26:28]))
|
||||||
extraLen := int(c.Uint16(b[28:30]))
|
extraLen := int(toUint16(b[28:30]))
|
||||||
return int64(fileHeaderLen + filenameLen + extraLen), nil
|
return int64(fileHeaderLen + filenameLen + extraLen), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,26 +219,24 @@ func readDirectoryHeader(f *File, r io.Reader) error {
|
|||||||
if _, err := io.ReadFull(r, b[:]); err != nil {
|
if _, err := io.ReadFull(r, b[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c := binary.LittleEndian
|
if sig := toUint32(b[:]); sig != directoryHeaderSignature {
|
||||||
if sig := c.Uint32(b[:4]); sig != directoryHeaderSignature {
|
|
||||||
return ErrFormat
|
return ErrFormat
|
||||||
}
|
}
|
||||||
f.CreatorVersion = c.Uint16(b[4:6])
|
f.CreatorVersion = toUint16(b[4:])
|
||||||
f.ReaderVersion = c.Uint16(b[6:8])
|
f.ReaderVersion = toUint16(b[6:])
|
||||||
f.Flags = c.Uint16(b[8:10])
|
f.Flags = toUint16(b[8:])
|
||||||
f.Method = c.Uint16(b[10:12])
|
f.Method = toUint16(b[10:])
|
||||||
f.ModifiedTime = c.Uint16(b[12:14])
|
f.ModifiedTime = toUint16(b[12:])
|
||||||
f.ModifiedDate = c.Uint16(b[14:16])
|
f.ModifiedDate = toUint16(b[14:])
|
||||||
f.CRC32 = c.Uint32(b[16:20])
|
f.CRC32 = toUint32(b[16:])
|
||||||
f.CompressedSize = c.Uint32(b[20:24])
|
f.CompressedSize = toUint32(b[20:])
|
||||||
f.UncompressedSize = c.Uint32(b[24:28])
|
f.UncompressedSize = toUint32(b[24:])
|
||||||
filenameLen := int(c.Uint16(b[28:30]))
|
filenameLen := int(toUint16(b[28:]))
|
||||||
extraLen := int(c.Uint16(b[30:32]))
|
extraLen := int(toUint16(b[30:32]))
|
||||||
commentLen := int(c.Uint16(b[32:34]))
|
commentLen := int(toUint16(b[32:]))
|
||||||
// startDiskNumber := c.Uint16(b[34:36]) // Unused
|
// skipped start disk number and internal attributes (2x uint16)
|
||||||
// internalAttributes := c.Uint16(b[36:38]) // Unused
|
f.ExternalAttrs = toUint32(b[38:])
|
||||||
f.ExternalAttrs = c.Uint32(b[38:42])
|
f.headerOffset = int64(toUint32(b[42:]))
|
||||||
f.headerOffset = int64(c.Uint32(b[42:46]))
|
|
||||||
d := make([]byte, filenameLen+extraLen+commentLen)
|
d := make([]byte, filenameLen+extraLen+commentLen)
|
||||||
if _, err := io.ReadFull(r, d); err != nil {
|
if _, err := io.ReadFull(r, d); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -257,10 +252,9 @@ func readDataDescriptor(r io.Reader, f *File) error {
|
|||||||
if _, err := io.ReadFull(r, b[:]); err != nil {
|
if _, err := io.ReadFull(r, b[:]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c := binary.LittleEndian
|
f.CRC32 = toUint32(b[:4])
|
||||||
f.CRC32 = c.Uint32(b[:4])
|
f.CompressedSize = toUint32(b[4:8])
|
||||||
f.CompressedSize = c.Uint32(b[4:8])
|
f.UncompressedSize = toUint32(b[8:12])
|
||||||
f.UncompressedSize = c.Uint32(b[8:12])
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,15 +279,14 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read header into struct
|
// read header into struct
|
||||||
c := binary.LittleEndian
|
|
||||||
d := new(directoryEnd)
|
d := new(directoryEnd)
|
||||||
d.diskNbr = c.Uint16(b[4:6])
|
d.diskNbr = toUint16(b[4:])
|
||||||
d.dirDiskNbr = c.Uint16(b[6:8])
|
d.dirDiskNbr = toUint16(b[6:])
|
||||||
d.dirRecordsThisDisk = c.Uint16(b[8:10])
|
d.dirRecordsThisDisk = toUint16(b[8:])
|
||||||
d.directoryRecords = c.Uint16(b[10:12])
|
d.directoryRecords = toUint16(b[10:])
|
||||||
d.directorySize = c.Uint32(b[12:16])
|
d.directorySize = toUint32(b[12:])
|
||||||
d.directoryOffset = c.Uint32(b[16:20])
|
d.directoryOffset = toUint32(b[16:])
|
||||||
d.commentLen = c.Uint16(b[20:22])
|
d.commentLen = toUint16(b[20:])
|
||||||
d.comment = string(b[22 : 22+int(d.commentLen)])
|
d.comment = string(b[22 : 22+int(d.commentLen)])
|
||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
@ -311,3 +304,9 @@ func findSignatureInBlock(b []byte) int {
|
|||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toUint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
|
||||||
|
|
||||||
|
func toUint32(b []byte) uint32 {
|
||||||
|
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||||
|
}
|
||||||
|
@ -100,16 +100,6 @@ type directoryEnd struct {
|
|||||||
comment string
|
comment string
|
||||||
}
|
}
|
||||||
|
|
||||||
func recoverError(errp *error) {
|
|
||||||
if e := recover(); e != nil {
|
|
||||||
if err, ok := e.(error); ok {
|
|
||||||
*errp = err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
panic(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// msDosTimeToTime converts an MS-DOS date and time into a time.Time.
|
// msDosTimeToTime converts an MS-DOS date and time into a time.Time.
|
||||||
// The resolution is 2s.
|
// The resolution is 2s.
|
||||||
// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
|
// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
|
||||||
|
@ -7,7 +7,6 @@ package zip
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"compress/flate"
|
"compress/flate"
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
"errors"
|
||||||
"hash"
|
"hash"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
@ -37,10 +36,10 @@ func NewWriter(w io.Writer) *Writer {
|
|||||||
|
|
||||||
// Close finishes writing the zip file by writing the central directory.
|
// Close finishes writing the zip file by writing the central directory.
|
||||||
// It does not (and can not) close the underlying writer.
|
// It does not (and can not) close the underlying writer.
|
||||||
func (w *Writer) Close() (err error) {
|
func (w *Writer) Close() error {
|
||||||
if w.last != nil && !w.last.closed {
|
if w.last != nil && !w.last.closed {
|
||||||
if err = w.last.close(); err != nil {
|
if err := w.last.close(); err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
w.last = nil
|
w.last = nil
|
||||||
}
|
}
|
||||||
@ -49,43 +48,54 @@ func (w *Writer) Close() (err error) {
|
|||||||
}
|
}
|
||||||
w.closed = true
|
w.closed = true
|
||||||
|
|
||||||
defer recoverError(&err)
|
|
||||||
|
|
||||||
// write central directory
|
// write central directory
|
||||||
start := w.cw.count
|
start := w.cw.count
|
||||||
for _, h := range w.dir {
|
for _, h := range w.dir {
|
||||||
write(w.cw, uint32(directoryHeaderSignature))
|
var b [directoryHeaderLen]byte
|
||||||
write(w.cw, h.CreatorVersion)
|
putUint32(b[:], uint32(directoryHeaderSignature))
|
||||||
write(w.cw, h.ReaderVersion)
|
putUint16(b[4:], h.CreatorVersion)
|
||||||
write(w.cw, h.Flags)
|
putUint16(b[6:], h.ReaderVersion)
|
||||||
write(w.cw, h.Method)
|
putUint16(b[8:], h.Flags)
|
||||||
write(w.cw, h.ModifiedTime)
|
putUint16(b[10:], h.Method)
|
||||||
write(w.cw, h.ModifiedDate)
|
putUint16(b[12:], h.ModifiedTime)
|
||||||
write(w.cw, h.CRC32)
|
putUint16(b[14:], h.ModifiedDate)
|
||||||
write(w.cw, h.CompressedSize)
|
putUint32(b[16:], h.CRC32)
|
||||||
write(w.cw, h.UncompressedSize)
|
putUint32(b[20:], h.CompressedSize)
|
||||||
write(w.cw, uint16(len(h.Name)))
|
putUint32(b[24:], h.UncompressedSize)
|
||||||
write(w.cw, uint16(len(h.Extra)))
|
putUint16(b[28:], uint16(len(h.Name)))
|
||||||
write(w.cw, uint16(len(h.Comment)))
|
putUint16(b[30:], uint16(len(h.Extra)))
|
||||||
write(w.cw, uint16(0)) // disk number start
|
putUint16(b[32:], uint16(len(h.Comment)))
|
||||||
write(w.cw, uint16(0)) // internal file attributes
|
// skip two uint16's, disk number start and internal file attributes
|
||||||
write(w.cw, h.ExternalAttrs)
|
putUint32(b[38:], h.ExternalAttrs)
|
||||||
write(w.cw, h.offset)
|
putUint32(b[42:], h.offset)
|
||||||
writeBytes(w.cw, []byte(h.Name))
|
if _, err := w.cw.Write(b[:]); err != nil {
|
||||||
writeBytes(w.cw, h.Extra)
|
return err
|
||||||
writeBytes(w.cw, []byte(h.Comment))
|
}
|
||||||
|
if _, err := io.WriteString(w.cw, h.Name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := w.cw.Write(h.Extra); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := io.WriteString(w.cw, h.Comment); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
end := w.cw.count
|
end := w.cw.count
|
||||||
|
|
||||||
// write end record
|
// write end record
|
||||||
write(w.cw, uint32(directoryEndSignature))
|
var b [directoryEndLen]byte
|
||||||
write(w.cw, uint16(0)) // disk number
|
putUint32(b[:], uint32(directoryEndSignature))
|
||||||
write(w.cw, uint16(0)) // disk number where directory starts
|
putUint16(b[4:], uint16(0)) // disk number
|
||||||
write(w.cw, uint16(len(w.dir))) // number of entries this disk
|
putUint16(b[6:], uint16(0)) // disk number where directory starts
|
||||||
write(w.cw, uint16(len(w.dir))) // number of entries total
|
putUint16(b[8:], uint16(len(w.dir))) // number of entries this disk
|
||||||
write(w.cw, uint32(end-start)) // size of directory
|
putUint16(b[10:], uint16(len(w.dir))) // number of entries total
|
||||||
write(w.cw, uint32(start)) // start of directory
|
putUint32(b[12:], uint32(end-start)) // size of directory
|
||||||
write(w.cw, uint16(0)) // size of comment
|
putUint32(b[16:], uint32(start)) // start of directory
|
||||||
|
// skipped size of comment (always zero)
|
||||||
|
if _, err := w.cw.Write(b[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return w.cw.w.(*bufio.Writer).Flush()
|
return w.cw.w.(*bufio.Writer).Flush()
|
||||||
}
|
}
|
||||||
@ -152,22 +162,27 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
|
|||||||
return fw, nil
|
return fw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeHeader(w io.Writer, h *FileHeader) (err error) {
|
func writeHeader(w io.Writer, h *FileHeader) error {
|
||||||
defer recoverError(&err)
|
var b [fileHeaderLen]byte
|
||||||
write(w, uint32(fileHeaderSignature))
|
putUint32(b[:], uint32(fileHeaderSignature))
|
||||||
write(w, h.ReaderVersion)
|
putUint16(b[4:], h.ReaderVersion)
|
||||||
write(w, h.Flags)
|
putUint16(b[6:], h.Flags)
|
||||||
write(w, h.Method)
|
putUint16(b[8:], h.Method)
|
||||||
write(w, h.ModifiedTime)
|
putUint16(b[10:], h.ModifiedTime)
|
||||||
write(w, h.ModifiedDate)
|
putUint16(b[12:], h.ModifiedDate)
|
||||||
write(w, h.CRC32)
|
putUint32(b[14:], h.CRC32)
|
||||||
write(w, h.CompressedSize)
|
putUint32(b[18:], h.CompressedSize)
|
||||||
write(w, h.UncompressedSize)
|
putUint32(b[22:], h.UncompressedSize)
|
||||||
write(w, uint16(len(h.Name)))
|
putUint16(b[26:], uint16(len(h.Name)))
|
||||||
write(w, uint16(len(h.Extra)))
|
putUint16(b[28:], uint16(len(h.Extra)))
|
||||||
writeBytes(w, []byte(h.Name))
|
if _, err := w.Write(b[:]); err != nil {
|
||||||
writeBytes(w, h.Extra)
|
return err
|
||||||
return nil
|
}
|
||||||
|
if _, err := io.WriteString(w, h.Name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err := w.Write(h.Extra)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
type fileWriter struct {
|
type fileWriter struct {
|
||||||
@ -188,13 +203,13 @@ func (w *fileWriter) Write(p []byte) (int, error) {
|
|||||||
return w.rawCount.Write(p)
|
return w.rawCount.Write(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *fileWriter) close() (err error) {
|
func (w *fileWriter) close() error {
|
||||||
if w.closed {
|
if w.closed {
|
||||||
return errors.New("zip: file closed twice")
|
return errors.New("zip: file closed twice")
|
||||||
}
|
}
|
||||||
w.closed = true
|
w.closed = true
|
||||||
if err = w.comp.Close(); err != nil {
|
if err := w.comp.Close(); err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// update FileHeader
|
// update FileHeader
|
||||||
@ -204,12 +219,12 @@ func (w *fileWriter) close() (err error) {
|
|||||||
fh.UncompressedSize = uint32(w.rawCount.count)
|
fh.UncompressedSize = uint32(w.rawCount.count)
|
||||||
|
|
||||||
// write data descriptor
|
// write data descriptor
|
||||||
defer recoverError(&err)
|
var b [dataDescriptorLen]byte
|
||||||
write(w.zipw, fh.CRC32)
|
putUint32(b[:], fh.CRC32)
|
||||||
write(w.zipw, fh.CompressedSize)
|
putUint32(b[4:], fh.CompressedSize)
|
||||||
write(w.zipw, fh.UncompressedSize)
|
putUint32(b[8:], fh.UncompressedSize)
|
||||||
|
_, err := w.zipw.Write(b[:])
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
type countWriter struct {
|
type countWriter struct {
|
||||||
@ -231,18 +246,17 @@ func (w nopCloser) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func write(w io.Writer, data interface{}) {
|
// We use these putUintXX functions instead of encoding/binary's Write to avoid
|
||||||
if err := binary.Write(w, binary.LittleEndian, data); err != nil {
|
// reflection. It's easy enough, anyway.
|
||||||
panic(err)
|
|
||||||
}
|
func putUint16(b []byte, v uint16) {
|
||||||
|
b[0] = byte(v)
|
||||||
|
b[1] = byte(v >> 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeBytes(w io.Writer, b []byte) {
|
func putUint32(b []byte, v uint32) {
|
||||||
n, err := w.Write(b)
|
b[0] = byte(v)
|
||||||
if err != nil {
|
b[1] = byte(v >> 8)
|
||||||
panic(err)
|
b[2] = byte(v >> 16)
|
||||||
}
|
b[3] = byte(v >> 24)
|
||||||
if n != len(b) {
|
|
||||||
panic(io.ErrShortWrite)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user