]> Cypherpunks repositories - gostls13.git/commitdiff
archive/zip: use encoding/binary again, add readBuf helper
authorAndrew Gerrand <adg@golang.org>
Mon, 27 Feb 2012 22:41:30 +0000 (09:41 +1100)
committerAndrew Gerrand <adg@golang.org>
Mon, 27 Feb 2012 22:41:30 +0000 (09:41 +1100)
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5699097

src/pkg/archive/zip/reader.go
src/pkg/archive/zip/writer.go

index 1c2a2189cc26bb0488eb68002ad538ec124860ae..6a58c49f9acc124145962cc950620e0647400873 100644 (file)
@@ -7,6 +7,7 @@ package zip
 import (
        "bufio"
        "compress/flate"
+       "encoding/binary"
        "errors"
        "hash"
        "hash/crc32"
@@ -169,23 +170,24 @@ func (r *checksumReader) Read(b []byte) (n int, err error) {
 func (r *checksumReader) Close() error { return r.rc.Close() }
 
 func readFileHeader(f *File, r io.Reader) error {
-       var b [fileHeaderLen]byte
-       if _, err := io.ReadFull(r, b[:]); err != nil {
+       var buf [fileHeaderLen]byte
+       if _, err := io.ReadFull(r, buf[:]); err != nil {
                return err
        }
-       if sig := toUint32(b[:]); sig != fileHeaderSignature {
+       b := readBuf(buf[:])
+       if sig := b.uint32(); sig != fileHeaderSignature {
                return ErrFormat
        }
-       f.ReaderVersion = toUint16(b[4:])
-       f.Flags = toUint16(b[6:])
-       f.Method = toUint16(b[8:])
-       f.ModifiedTime = toUint16(b[10:])
-       f.ModifiedDate = toUint16(b[12:])
-       f.CRC32 = toUint32(b[14:])
-       f.CompressedSize = toUint32(b[18:])
-       f.UncompressedSize = toUint32(b[22:])
-       filenameLen := int(toUint16(b[26:]))
-       extraLen := int(toUint16(b[28:]))
+       f.ReaderVersion = b.uint16()
+       f.Flags = b.uint16()
+       f.Method = b.uint16()
+       f.ModifiedTime = b.uint16()
+       f.ModifiedDate = b.uint16()
+       f.CRC32 = b.uint32()
+       f.CompressedSize = b.uint32()
+       f.UncompressedSize = b.uint32()
+       filenameLen := int(b.uint16())
+       extraLen := int(b.uint16())
        d := make([]byte, filenameLen+extraLen)
        if _, err := io.ReadFull(r, d); err != nil {
                return err
@@ -199,15 +201,17 @@ func readFileHeader(f *File, r io.Reader) error {
 // and returns the file body offset.
 func (f *File) findBodyOffset() (int64, error) {
        r := io.NewSectionReader(f.zipr, f.headerOffset, f.zipsize-f.headerOffset)
-       var b [fileHeaderLen]byte
-       if _, err := io.ReadFull(r, b[:]); err != nil {
+       var buf [fileHeaderLen]byte
+       if _, err := io.ReadFull(r, buf[:]); err != nil {
                return 0, err
        }
-       if sig := toUint32(b[:4]); sig != fileHeaderSignature {
+       b := readBuf(buf[:])
+       if sig := b.uint32(); sig != fileHeaderSignature {
                return 0, ErrFormat
        }
-       filenameLen := int(toUint16(b[26:28]))
-       extraLen := int(toUint16(b[28:30]))
+       b = b[22:] // skip over most of the header
+       filenameLen := int(b.uint16())
+       extraLen := int(b.uint16())
        return int64(fileHeaderLen + filenameLen + extraLen), nil
 }
 
@@ -215,28 +219,29 @@ func (f *File) findBodyOffset() (int64, error) {
 // It returns io.ErrUnexpectedEOF if it cannot read a complete header,
 // and ErrFormat if it doesn't find a valid header signature.
 func readDirectoryHeader(f *File, r io.Reader) error {
-       var b [directoryHeaderLen]byte
-       if _, err := io.ReadFull(r, b[:]); err != nil {
+       var buf [directoryHeaderLen]byte
+       if _, err := io.ReadFull(r, buf[:]); err != nil {
                return err
        }
-       if sig := toUint32(b[:]); sig != directoryHeaderSignature {
+       b := readBuf(buf[:])
+       if sig := b.uint32(); sig != directoryHeaderSignature {
                return ErrFormat
        }
-       f.CreatorVersion = toUint16(b[4:])
-       f.ReaderVersion = toUint16(b[6:])
-       f.Flags = toUint16(b[8:])
-       f.Method = toUint16(b[10:])
-       f.ModifiedTime = toUint16(b[12:])
-       f.ModifiedDate = toUint16(b[14:])
-       f.CRC32 = toUint32(b[16:])
-       f.CompressedSize = toUint32(b[20:])
-       f.UncompressedSize = toUint32(b[24:])
-       filenameLen := int(toUint16(b[28:]))
-       extraLen := int(toUint16(b[30:32]))
-       commentLen := int(toUint16(b[32:]))
-       // skipped start disk number and internal attributes (2x uint16)
-       f.ExternalAttrs = toUint32(b[38:])
-       f.headerOffset = int64(toUint32(b[42:]))
+       f.CreatorVersion = b.uint16()
+       f.ReaderVersion = b.uint16()
+       f.Flags = b.uint16()
+       f.Method = b.uint16()
+       f.ModifiedTime = b.uint16()
+       f.ModifiedDate = b.uint16()
+       f.CRC32 = b.uint32()
+       f.CompressedSize = b.uint32()
+       f.UncompressedSize = b.uint32()
+       filenameLen := int(b.uint16())
+       extraLen := int(b.uint16())
+       commentLen := int(b.uint16())
+       b = b[4:] // skipped start disk number and internal attributes (2x uint16)
+       f.ExternalAttrs = b.uint32()
+       f.headerOffset = int64(b.uint32())
        d := make([]byte, filenameLen+extraLen+commentLen)
        if _, err := io.ReadFull(r, d); err != nil {
                return err
@@ -248,29 +253,30 @@ func readDirectoryHeader(f *File, r io.Reader) error {
 }
 
 func readDataDescriptor(r io.Reader, f *File) error {
-       var b [dataDescriptorLen]byte
-       if _, err := io.ReadFull(r, b[:]); err != nil {
+       var buf [dataDescriptorLen]byte
+       if _, err := io.ReadFull(r, buf[:]); err != nil {
                return err
        }
-       f.CRC32 = toUint32(b[:4])
-       f.CompressedSize = toUint32(b[4:8])
-       f.UncompressedSize = toUint32(b[8:12])
+       b := readBuf(buf[:])
+       f.CRC32 = b.uint32()
+       f.CompressedSize = b.uint32()
+       f.UncompressedSize = b.uint32()
        return nil
 }
 
 func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error) {
        // look for directoryEndSignature in the last 1k, then in the last 65k
-       var b []byte
+       var buf []byte
        for i, bLen := range []int64{1024, 65 * 1024} {
                if bLen > size {
                        bLen = size
                }
-               b = make([]byte, int(bLen))
-               if _, err := r.ReadAt(b, size-bLen); err != nil && err != io.EOF {
+               buf = make([]byte, int(bLen))
+               if _, err := r.ReadAt(buf, size-bLen); err != nil && err != io.EOF {
                        return nil, err
                }
-               if p := findSignatureInBlock(b); p >= 0 {
-                       b = b[p:]
+               if p := findSignatureInBlock(buf); p >= 0 {
+                       buf = buf[p:]
                        break
                }
                if i == 1 || bLen == size {
@@ -279,15 +285,21 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
        }
 
        // read header into struct
-       d := new(directoryEnd)
-       d.diskNbr = toUint16(b[4:])
-       d.dirDiskNbr = toUint16(b[6:])
-       d.dirRecordsThisDisk = toUint16(b[8:])
-       d.directoryRecords = toUint16(b[10:])
-       d.directorySize = toUint32(b[12:])
-       d.directoryOffset = toUint32(b[16:])
-       d.commentLen = toUint16(b[20:])
-       d.comment = string(b[22 : 22+int(d.commentLen)])
+       b := readBuf(buf[4:]) // skip signature
+       d := &directoryEnd{
+               diskNbr:            b.uint16(),
+               dirDiskNbr:         b.uint16(),
+               dirRecordsThisDisk: b.uint16(),
+               directoryRecords:   b.uint16(),
+               directorySize:      b.uint32(),
+               directoryOffset:    b.uint32(),
+               commentLen:         b.uint16(),
+       }
+       l := int(d.commentLen)
+       if l > len(b) {
+               return nil, errors.New("zip: invalid comment length")
+       }
+       d.comment = string(b[:l])
        return d, nil
 }
 
@@ -305,8 +317,16 @@ func findSignatureInBlock(b []byte) int {
        return -1
 }
 
-func toUint16(b []byte) uint16 { return uint16(b[0]) | uint16(b[1])<<8 }
+type readBuf []byte
+
+func (b *readBuf) uint16() uint16 {
+       v := binary.LittleEndian.Uint16(*b)
+       *b = (*b)[2:]
+       return v
+}
 
-func toUint32(b []byte) uint32 {
-       return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+func (b *readBuf) uint32() uint32 {
+       v := binary.LittleEndian.Uint32(*b)
+       *b = (*b)[4:]
+       return v
 }
index 476407dfd279ec03a06cd5ca982b226db87d5c6b..b2cc55bc93b2ddd1f4faabb54b9136adbb3fbcfd 100644 (file)
@@ -7,6 +7,7 @@ package zip
 import (
        "bufio"
        "compress/flate"
+       "encoding/binary"
        "errors"
        "hash"
        "hash/crc32"
@@ -249,21 +250,14 @@ func (w nopCloser) Close() error {
        return nil
 }
 
-// We use this helper instead of encoding/binary's Write to avoid reflection.
-// It's easy enough, anyway.
-
 type writeBuf []byte
 
 func (b *writeBuf) uint16(v uint16) {
-       (*b)[0] = byte(v)
-       (*b)[1] = byte(v >> 8)
+       binary.LittleEndian.PutUint16(*b, v)
        *b = (*b)[2:]
 }
 
 func (b *writeBuf) uint32(v uint32) {
-       (*b)[0] = byte(v)
-       (*b)[1] = byte(v >> 8)
-       (*b)[2] = byte(v >> 16)
-       (*b)[3] = byte(v >> 24)
+       binary.LittleEndian.PutUint32(*b, v)
        *b = (*b)[4:]
 }