| // Copyright 2010 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| /* |
| Package zip provides support for reading and writing ZIP archives. |
| |
| See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT |
| |
| This package does not support ZIP64 or disk spanning. |
| */ |
| package zip |
| |
| import ( |
| "errors" |
| "time" |
| ) |
| |
| // Compression methods. |
| const ( |
| Store uint16 = 0 |
| Deflate uint16 = 8 |
| ) |
| |
| const ( |
| fileHeaderSignature = 0x04034b50 |
| directoryHeaderSignature = 0x02014b50 |
| directoryEndSignature = 0x06054b50 |
| fileHeaderLen = 30 // + filename + extra |
| directoryHeaderLen = 46 // + filename + extra + comment |
| directoryEndLen = 22 // + comment |
| dataDescriptorLen = 12 |
| |
| // Constants for the first byte in CreatorVersion |
| creatorUnix = 3 |
| ) |
| |
| type FileHeader struct { |
| Name string |
| CreatorVersion uint16 |
| ReaderVersion uint16 |
| Flags uint16 |
| Method uint16 |
| ModifiedTime uint16 // MS-DOS time |
| ModifiedDate uint16 // MS-DOS date |
| CRC32 uint32 |
| CompressedSize uint32 |
| UncompressedSize uint32 |
| Extra []byte |
| ExternalAttrs uint32 // Meaning depends on CreatorVersion |
| Comment string |
| } |
| |
| type directoryEnd struct { |
| diskNbr uint16 // unused |
| dirDiskNbr uint16 // unused |
| dirRecordsThisDisk uint16 // unused |
| directoryRecords uint16 |
| directorySize uint32 |
| directoryOffset uint32 // relative to file |
| commentLen uint16 |
| 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. |
| // The resolution is 2s. |
| // See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx |
| func msDosTimeToTime(dosDate, dosTime uint16) time.Time { |
| return time.Date( |
| // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980 |
| int(dosDate>>9+1980), |
| time.Month(dosDate>>5&0xf), |
| int(dosDate&0x1f), |
| |
| // time bits 0-4: second/2; 5-10: minute; 11-15: hour |
| int(dosTime>>11), |
| int(dosTime>>5&0x3f), |
| int(dosTime&0x1f*2), |
| 0, // nanoseconds |
| |
| time.UTC, |
| ) |
| } |
| |
| // ModTime returns the modification time. |
| // The resolution is 2s. |
| func (h *FileHeader) ModTime() time.Time { |
| return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime) |
| } |
| |
| // Mode returns the permission and mode bits for the FileHeader. |
| // An error is returned in case the information is not available. |
| func (h *FileHeader) Mode() (mode uint32, err error) { |
| if h.CreatorVersion>>8 == creatorUnix { |
| return h.ExternalAttrs >> 16, nil |
| } |
| return 0, errors.New("file mode not available") |
| } |
| |
| // SetMode changes the permission and mode bits for the FileHeader. |
| func (h *FileHeader) SetMode(mode uint32) { |
| h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8 |
| h.ExternalAttrs = mode << 16 |
| } |