1*333d2b36SAndroid Build Coastguard Worker// Copyright 2011 The Go Authors. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style 3*333d2b36SAndroid Build Coastguard Worker// license that can be found in the LICENSE file. 4*333d2b36SAndroid Build Coastguard Worker 5*333d2b36SAndroid Build Coastguard Workerpackage zip 6*333d2b36SAndroid Build Coastguard Worker 7*333d2b36SAndroid Build Coastguard Workerimport ( 8*333d2b36SAndroid Build Coastguard Worker "bufio" 9*333d2b36SAndroid Build Coastguard Worker "encoding/binary" 10*333d2b36SAndroid Build Coastguard Worker "errors" 11*333d2b36SAndroid Build Coastguard Worker "hash" 12*333d2b36SAndroid Build Coastguard Worker "hash/crc32" 13*333d2b36SAndroid Build Coastguard Worker "io" 14*333d2b36SAndroid Build Coastguard Worker) 15*333d2b36SAndroid Build Coastguard Worker 16*333d2b36SAndroid Build Coastguard Worker// TODO(adg): support zip file comments 17*333d2b36SAndroid Build Coastguard Worker 18*333d2b36SAndroid Build Coastguard Worker// Writer implements a zip file writer. 19*333d2b36SAndroid Build Coastguard Workertype Writer struct { 20*333d2b36SAndroid Build Coastguard Worker cw *countWriter 21*333d2b36SAndroid Build Coastguard Worker dir []*header 22*333d2b36SAndroid Build Coastguard Worker last *fileWriter 23*333d2b36SAndroid Build Coastguard Worker closed bool 24*333d2b36SAndroid Build Coastguard Worker compressors map[uint16]Compressor 25*333d2b36SAndroid Build Coastguard Worker} 26*333d2b36SAndroid Build Coastguard Worker 27*333d2b36SAndroid Build Coastguard Workertype header struct { 28*333d2b36SAndroid Build Coastguard Worker *FileHeader 29*333d2b36SAndroid Build Coastguard Worker offset uint64 30*333d2b36SAndroid Build Coastguard Worker} 31*333d2b36SAndroid Build Coastguard Worker 32*333d2b36SAndroid Build Coastguard Worker// NewWriter returns a new Writer writing a zip file to w. 33*333d2b36SAndroid Build Coastguard Workerfunc NewWriter(w io.Writer) *Writer { 34*333d2b36SAndroid Build Coastguard Worker return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}} 35*333d2b36SAndroid Build Coastguard Worker} 36*333d2b36SAndroid Build Coastguard Worker 37*333d2b36SAndroid Build Coastguard Worker// SetOffset sets the offset of the beginning of the zip data within the 38*333d2b36SAndroid Build Coastguard Worker// underlying writer. It should be used when the zip data is appended to an 39*333d2b36SAndroid Build Coastguard Worker// existing file, such as a binary executable. 40*333d2b36SAndroid Build Coastguard Worker// It must be called before any data is written. 41*333d2b36SAndroid Build Coastguard Workerfunc (w *Writer) SetOffset(n int64) { 42*333d2b36SAndroid Build Coastguard Worker if w.cw.count != 0 { 43*333d2b36SAndroid Build Coastguard Worker panic("zip: SetOffset called after data was written") 44*333d2b36SAndroid Build Coastguard Worker } 45*333d2b36SAndroid Build Coastguard Worker w.cw.count = n 46*333d2b36SAndroid Build Coastguard Worker} 47*333d2b36SAndroid Build Coastguard Worker 48*333d2b36SAndroid Build Coastguard Worker// Flush flushes any buffered data to the underlying writer. 49*333d2b36SAndroid Build Coastguard Worker// Calling Flush is not normally necessary; calling Close is sufficient. 50*333d2b36SAndroid Build Coastguard Workerfunc (w *Writer) Flush() error { 51*333d2b36SAndroid Build Coastguard Worker return w.cw.w.(*bufio.Writer).Flush() 52*333d2b36SAndroid Build Coastguard Worker} 53*333d2b36SAndroid Build Coastguard Worker 54*333d2b36SAndroid Build Coastguard Worker// Close finishes writing the zip file by writing the central directory. 55*333d2b36SAndroid Build Coastguard Worker// It does not (and cannot) close the underlying writer. 56*333d2b36SAndroid Build Coastguard Workerfunc (w *Writer) Close() error { 57*333d2b36SAndroid Build Coastguard Worker if w.last != nil && !w.last.closed { 58*333d2b36SAndroid Build Coastguard Worker if err := w.last.close(); err != nil { 59*333d2b36SAndroid Build Coastguard Worker return err 60*333d2b36SAndroid Build Coastguard Worker } 61*333d2b36SAndroid Build Coastguard Worker w.last = nil 62*333d2b36SAndroid Build Coastguard Worker } 63*333d2b36SAndroid Build Coastguard Worker if w.closed { 64*333d2b36SAndroid Build Coastguard Worker return errors.New("zip: writer closed twice") 65*333d2b36SAndroid Build Coastguard Worker } 66*333d2b36SAndroid Build Coastguard Worker w.closed = true 67*333d2b36SAndroid Build Coastguard Worker 68*333d2b36SAndroid Build Coastguard Worker // write central directory 69*333d2b36SAndroid Build Coastguard Worker start := w.cw.count 70*333d2b36SAndroid Build Coastguard Worker for _, h := range w.dir { 71*333d2b36SAndroid Build Coastguard Worker var buf [directoryHeaderLen]byte 72*333d2b36SAndroid Build Coastguard Worker b := writeBuf(buf[:]) 73*333d2b36SAndroid Build Coastguard Worker b.uint32(uint32(directoryHeaderSignature)) 74*333d2b36SAndroid Build Coastguard Worker b.uint16(h.CreatorVersion) 75*333d2b36SAndroid Build Coastguard Worker b.uint16(h.ReaderVersion) 76*333d2b36SAndroid Build Coastguard Worker b.uint16(h.Flags) 77*333d2b36SAndroid Build Coastguard Worker b.uint16(h.Method) 78*333d2b36SAndroid Build Coastguard Worker b.uint16(h.ModifiedTime) 79*333d2b36SAndroid Build Coastguard Worker b.uint16(h.ModifiedDate) 80*333d2b36SAndroid Build Coastguard Worker b.uint32(h.CRC32) 81*333d2b36SAndroid Build Coastguard Worker if h.isZip64() || h.offset >= uint32max { 82*333d2b36SAndroid Build Coastguard Worker // the file needs a zip64 header. store maxint in both 83*333d2b36SAndroid Build Coastguard Worker // 32 bit size fields (and offset later) to signal that the 84*333d2b36SAndroid Build Coastguard Worker // zip64 extra header should be used. 85*333d2b36SAndroid Build Coastguard Worker b.uint32(uint32max) // compressed size 86*333d2b36SAndroid Build Coastguard Worker b.uint32(uint32max) // uncompressed size 87*333d2b36SAndroid Build Coastguard Worker 88*333d2b36SAndroid Build Coastguard Worker // append a zip64 extra block to Extra 89*333d2b36SAndroid Build Coastguard Worker var buf [28]byte // 2x uint16 + 3x uint64 90*333d2b36SAndroid Build Coastguard Worker eb := writeBuf(buf[:]) 91*333d2b36SAndroid Build Coastguard Worker eb.uint16(zip64ExtraId) 92*333d2b36SAndroid Build Coastguard Worker eb.uint16(24) // size = 3x uint64 93*333d2b36SAndroid Build Coastguard Worker eb.uint64(h.UncompressedSize64) 94*333d2b36SAndroid Build Coastguard Worker eb.uint64(h.CompressedSize64) 95*333d2b36SAndroid Build Coastguard Worker eb.uint64(h.offset) 96*333d2b36SAndroid Build Coastguard Worker h.Extra = append(h.Extra, buf[:]...) 97*333d2b36SAndroid Build Coastguard Worker } else { 98*333d2b36SAndroid Build Coastguard Worker b.uint32(h.CompressedSize) 99*333d2b36SAndroid Build Coastguard Worker b.uint32(h.UncompressedSize) 100*333d2b36SAndroid Build Coastguard Worker } 101*333d2b36SAndroid Build Coastguard Worker b.uint16(uint16(len(h.Name))) 102*333d2b36SAndroid Build Coastguard Worker b.uint16(uint16(len(h.Extra))) 103*333d2b36SAndroid Build Coastguard Worker b.uint16(uint16(len(h.Comment))) 104*333d2b36SAndroid Build Coastguard Worker b = b[4:] // skip disk number start and internal file attr (2x uint16) 105*333d2b36SAndroid Build Coastguard Worker b.uint32(h.ExternalAttrs) 106*333d2b36SAndroid Build Coastguard Worker if h.offset > uint32max { 107*333d2b36SAndroid Build Coastguard Worker b.uint32(uint32max) 108*333d2b36SAndroid Build Coastguard Worker } else { 109*333d2b36SAndroid Build Coastguard Worker b.uint32(uint32(h.offset)) 110*333d2b36SAndroid Build Coastguard Worker } 111*333d2b36SAndroid Build Coastguard Worker if _, err := w.cw.Write(buf[:]); err != nil { 112*333d2b36SAndroid Build Coastguard Worker return err 113*333d2b36SAndroid Build Coastguard Worker } 114*333d2b36SAndroid Build Coastguard Worker if _, err := io.WriteString(w.cw, h.Name); err != nil { 115*333d2b36SAndroid Build Coastguard Worker return err 116*333d2b36SAndroid Build Coastguard Worker } 117*333d2b36SAndroid Build Coastguard Worker if _, err := w.cw.Write(h.Extra); err != nil { 118*333d2b36SAndroid Build Coastguard Worker return err 119*333d2b36SAndroid Build Coastguard Worker } 120*333d2b36SAndroid Build Coastguard Worker if _, err := io.WriteString(w.cw, h.Comment); err != nil { 121*333d2b36SAndroid Build Coastguard Worker return err 122*333d2b36SAndroid Build Coastguard Worker } 123*333d2b36SAndroid Build Coastguard Worker } 124*333d2b36SAndroid Build Coastguard Worker end := w.cw.count 125*333d2b36SAndroid Build Coastguard Worker 126*333d2b36SAndroid Build Coastguard Worker records := uint64(len(w.dir)) 127*333d2b36SAndroid Build Coastguard Worker size := uint64(end - start) 128*333d2b36SAndroid Build Coastguard Worker offset := uint64(start) 129*333d2b36SAndroid Build Coastguard Worker 130*333d2b36SAndroid Build Coastguard Worker if records > uint16max || size > uint32max || offset > uint32max { 131*333d2b36SAndroid Build Coastguard Worker var buf [directory64EndLen + directory64LocLen]byte 132*333d2b36SAndroid Build Coastguard Worker b := writeBuf(buf[:]) 133*333d2b36SAndroid Build Coastguard Worker 134*333d2b36SAndroid Build Coastguard Worker // zip64 end of central directory record 135*333d2b36SAndroid Build Coastguard Worker b.uint32(directory64EndSignature) 136*333d2b36SAndroid Build Coastguard Worker b.uint64(directory64EndLen - 12) // length minus signature (uint32) and length fields (uint64) 137*333d2b36SAndroid Build Coastguard Worker b.uint16(zipVersion45) // version made by 138*333d2b36SAndroid Build Coastguard Worker b.uint16(zipVersion45) // version needed to extract 139*333d2b36SAndroid Build Coastguard Worker b.uint32(0) // number of this disk 140*333d2b36SAndroid Build Coastguard Worker b.uint32(0) // number of the disk with the start of the central directory 141*333d2b36SAndroid Build Coastguard Worker b.uint64(records) // total number of entries in the central directory on this disk 142*333d2b36SAndroid Build Coastguard Worker b.uint64(records) // total number of entries in the central directory 143*333d2b36SAndroid Build Coastguard Worker b.uint64(size) // size of the central directory 144*333d2b36SAndroid Build Coastguard Worker b.uint64(offset) // offset of start of central directory with respect to the starting disk number 145*333d2b36SAndroid Build Coastguard Worker 146*333d2b36SAndroid Build Coastguard Worker // zip64 end of central directory locator 147*333d2b36SAndroid Build Coastguard Worker b.uint32(directory64LocSignature) 148*333d2b36SAndroid Build Coastguard Worker b.uint32(0) // number of the disk with the start of the zip64 end of central directory 149*333d2b36SAndroid Build Coastguard Worker b.uint64(uint64(end)) // relative offset of the zip64 end of central directory record 150*333d2b36SAndroid Build Coastguard Worker b.uint32(1) // total number of disks 151*333d2b36SAndroid Build Coastguard Worker 152*333d2b36SAndroid Build Coastguard Worker if _, err := w.cw.Write(buf[:]); err != nil { 153*333d2b36SAndroid Build Coastguard Worker return err 154*333d2b36SAndroid Build Coastguard Worker } 155*333d2b36SAndroid Build Coastguard Worker 156*333d2b36SAndroid Build Coastguard Worker // store max values in the regular end record to signal that 157*333d2b36SAndroid Build Coastguard Worker // that the zip64 values should be used instead 158*333d2b36SAndroid Build Coastguard Worker // BEGIN ANDROID CHANGE: only store uintmax for the number of entries in the regular 159*333d2b36SAndroid Build Coastguard Worker // end record if it doesn't fit. p7zip 16.02 rejects zip files where the number of 160*333d2b36SAndroid Build Coastguard Worker // entries in the regular end record is larger than the number of entries counted 161*333d2b36SAndroid Build Coastguard Worker // in the central directory. 162*333d2b36SAndroid Build Coastguard Worker if records > uint16max { 163*333d2b36SAndroid Build Coastguard Worker records = uint16max 164*333d2b36SAndroid Build Coastguard Worker } 165*333d2b36SAndroid Build Coastguard Worker // Only store uint32max for the size and the offset if they don't fit. 166*333d2b36SAndroid Build Coastguard Worker // Robolectric currently doesn't support zip64 and fails to find the 167*333d2b36SAndroid Build Coastguard Worker // offset to the central directory when the number of files in the zip 168*333d2b36SAndroid Build Coastguard Worker // is larger than 2^16. 169*333d2b36SAndroid Build Coastguard Worker if size > uint32max { 170*333d2b36SAndroid Build Coastguard Worker size = uint32max 171*333d2b36SAndroid Build Coastguard Worker } 172*333d2b36SAndroid Build Coastguard Worker if offset > uint32max { 173*333d2b36SAndroid Build Coastguard Worker offset = uint32max 174*333d2b36SAndroid Build Coastguard Worker } 175*333d2b36SAndroid Build Coastguard Worker // END ANDROID CHANGE 176*333d2b36SAndroid Build Coastguard Worker } 177*333d2b36SAndroid Build Coastguard Worker 178*333d2b36SAndroid Build Coastguard Worker // write end record 179*333d2b36SAndroid Build Coastguard Worker var buf [directoryEndLen]byte 180*333d2b36SAndroid Build Coastguard Worker b := writeBuf(buf[:]) 181*333d2b36SAndroid Build Coastguard Worker b.uint32(uint32(directoryEndSignature)) 182*333d2b36SAndroid Build Coastguard Worker b = b[4:] // skip over disk number and first disk number (2x uint16) 183*333d2b36SAndroid Build Coastguard Worker b.uint16(uint16(records)) // number of entries this disk 184*333d2b36SAndroid Build Coastguard Worker b.uint16(uint16(records)) // number of entries total 185*333d2b36SAndroid Build Coastguard Worker b.uint32(uint32(size)) // size of directory 186*333d2b36SAndroid Build Coastguard Worker b.uint32(uint32(offset)) // start of directory 187*333d2b36SAndroid Build Coastguard Worker // skipped size of comment (always zero) 188*333d2b36SAndroid Build Coastguard Worker if _, err := w.cw.Write(buf[:]); err != nil { 189*333d2b36SAndroid Build Coastguard Worker return err 190*333d2b36SAndroid Build Coastguard Worker } 191*333d2b36SAndroid Build Coastguard Worker 192*333d2b36SAndroid Build Coastguard Worker return w.cw.w.(*bufio.Writer).Flush() 193*333d2b36SAndroid Build Coastguard Worker} 194*333d2b36SAndroid Build Coastguard Worker 195*333d2b36SAndroid Build Coastguard Worker// Create adds a file to the zip file using the provided name. 196*333d2b36SAndroid Build Coastguard Worker// It returns a Writer to which the file contents should be written. 197*333d2b36SAndroid Build Coastguard Worker// The name must be a relative path: it must not start with a drive 198*333d2b36SAndroid Build Coastguard Worker// letter (e.g. C:) or leading slash, and only forward slashes are 199*333d2b36SAndroid Build Coastguard Worker// allowed. 200*333d2b36SAndroid Build Coastguard Worker// The file's contents must be written to the io.Writer before the next 201*333d2b36SAndroid Build Coastguard Worker// call to Create, CreateHeader, or Close. 202*333d2b36SAndroid Build Coastguard Workerfunc (w *Writer) Create(name string) (io.Writer, error) { 203*333d2b36SAndroid Build Coastguard Worker header := &FileHeader{ 204*333d2b36SAndroid Build Coastguard Worker Name: name, 205*333d2b36SAndroid Build Coastguard Worker Method: Deflate, 206*333d2b36SAndroid Build Coastguard Worker } 207*333d2b36SAndroid Build Coastguard Worker return w.CreateHeader(header) 208*333d2b36SAndroid Build Coastguard Worker} 209*333d2b36SAndroid Build Coastguard Worker 210*333d2b36SAndroid Build Coastguard Worker// BEGIN ANDROID CHANGE separate createHeaderImpl from CreateHeader 211*333d2b36SAndroid Build Coastguard Worker// Legacy version of CreateHeader 212*333d2b36SAndroid Build Coastguard Workerfunc (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) { 213*333d2b36SAndroid Build Coastguard Worker fh.Flags |= DataDescriptorFlag // writing a data descriptor 214*333d2b36SAndroid Build Coastguard Worker return w.createHeaderImpl(fh) 215*333d2b36SAndroid Build Coastguard Worker} 216*333d2b36SAndroid Build Coastguard Worker 217*333d2b36SAndroid Build Coastguard Worker// END ANDROID CHANGE 218*333d2b36SAndroid Build Coastguard Worker 219*333d2b36SAndroid Build Coastguard Worker// CreateHeader adds a file to the zip file using the provided FileHeader 220*333d2b36SAndroid Build Coastguard Worker// for the file metadata. 221*333d2b36SAndroid Build Coastguard Worker// It returns a Writer to which the file contents should be written. 222*333d2b36SAndroid Build Coastguard Worker// 223*333d2b36SAndroid Build Coastguard Worker// The file's contents must be written to the io.Writer before the next 224*333d2b36SAndroid Build Coastguard Worker// call to Create, CreateHeader, or Close. The provided FileHeader fh 225*333d2b36SAndroid Build Coastguard Worker// must not be modified after a call to CreateHeader. 226*333d2b36SAndroid Build Coastguard Worker 227*333d2b36SAndroid Build Coastguard Worker// BEGIN ANDROID CHANGE separate createHeaderImpl from CreateHeader 228*333d2b36SAndroid Build Coastguard Workerfunc (w *Writer) createHeaderImpl(fh *FileHeader) (io.Writer, error) { 229*333d2b36SAndroid Build Coastguard Worker // END ANDROID CHANGE 230*333d2b36SAndroid Build Coastguard Worker if w.last != nil && !w.last.closed { 231*333d2b36SAndroid Build Coastguard Worker if err := w.last.close(); err != nil { 232*333d2b36SAndroid Build Coastguard Worker return nil, err 233*333d2b36SAndroid Build Coastguard Worker } 234*333d2b36SAndroid Build Coastguard Worker } 235*333d2b36SAndroid Build Coastguard Worker if len(w.dir) > 0 && w.dir[len(w.dir)-1].FileHeader == fh { 236*333d2b36SAndroid Build Coastguard Worker // See https://golang.org/issue/11144 confusion. 237*333d2b36SAndroid Build Coastguard Worker return nil, errors.New("archive/zip: invalid duplicate FileHeader") 238*333d2b36SAndroid Build Coastguard Worker } 239*333d2b36SAndroid Build Coastguard Worker // BEGIN ANDROID CHANGE move the setting of DataDescriptorFlag into CreateHeader 240*333d2b36SAndroid Build Coastguard Worker // fh.Flags |= 0x8 // we will write a data descriptor 241*333d2b36SAndroid Build Coastguard Worker // END ANDROID CHANGE 242*333d2b36SAndroid Build Coastguard Worker fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte 243*333d2b36SAndroid Build Coastguard Worker fh.ReaderVersion = zipVersion20 244*333d2b36SAndroid Build Coastguard Worker 245*333d2b36SAndroid Build Coastguard Worker fw := &fileWriter{ 246*333d2b36SAndroid Build Coastguard Worker zipw: w.cw, 247*333d2b36SAndroid Build Coastguard Worker compCount: &countWriter{w: w.cw}, 248*333d2b36SAndroid Build Coastguard Worker crc32: crc32.NewIEEE(), 249*333d2b36SAndroid Build Coastguard Worker } 250*333d2b36SAndroid Build Coastguard Worker comp := w.compressor(fh.Method) 251*333d2b36SAndroid Build Coastguard Worker if comp == nil { 252*333d2b36SAndroid Build Coastguard Worker return nil, ErrAlgorithm 253*333d2b36SAndroid Build Coastguard Worker } 254*333d2b36SAndroid Build Coastguard Worker var err error 255*333d2b36SAndroid Build Coastguard Worker fw.comp, err = comp(fw.compCount) 256*333d2b36SAndroid Build Coastguard Worker if err != nil { 257*333d2b36SAndroid Build Coastguard Worker return nil, err 258*333d2b36SAndroid Build Coastguard Worker } 259*333d2b36SAndroid Build Coastguard Worker fw.rawCount = &countWriter{w: fw.comp} 260*333d2b36SAndroid Build Coastguard Worker 261*333d2b36SAndroid Build Coastguard Worker h := &header{ 262*333d2b36SAndroid Build Coastguard Worker FileHeader: fh, 263*333d2b36SAndroid Build Coastguard Worker offset: uint64(w.cw.count), 264*333d2b36SAndroid Build Coastguard Worker } 265*333d2b36SAndroid Build Coastguard Worker w.dir = append(w.dir, h) 266*333d2b36SAndroid Build Coastguard Worker fw.header = h 267*333d2b36SAndroid Build Coastguard Worker 268*333d2b36SAndroid Build Coastguard Worker if err := writeHeader(w.cw, fh); err != nil { 269*333d2b36SAndroid Build Coastguard Worker return nil, err 270*333d2b36SAndroid Build Coastguard Worker } 271*333d2b36SAndroid Build Coastguard Worker 272*333d2b36SAndroid Build Coastguard Worker w.last = fw 273*333d2b36SAndroid Build Coastguard Worker return fw, nil 274*333d2b36SAndroid Build Coastguard Worker} 275*333d2b36SAndroid Build Coastguard Worker 276*333d2b36SAndroid Build Coastguard Workerfunc writeHeader(w io.Writer, h *FileHeader) error { 277*333d2b36SAndroid Build Coastguard Worker var buf [fileHeaderLen]byte 278*333d2b36SAndroid Build Coastguard Worker b := writeBuf(buf[:]) 279*333d2b36SAndroid Build Coastguard Worker b.uint32(uint32(fileHeaderSignature)) 280*333d2b36SAndroid Build Coastguard Worker b.uint16(h.ReaderVersion) 281*333d2b36SAndroid Build Coastguard Worker b.uint16(h.Flags) 282*333d2b36SAndroid Build Coastguard Worker b.uint16(h.Method) 283*333d2b36SAndroid Build Coastguard Worker b.uint16(h.ModifiedTime) 284*333d2b36SAndroid Build Coastguard Worker b.uint16(h.ModifiedDate) 285*333d2b36SAndroid Build Coastguard Worker // BEGIN ANDROID CHANGE populate header size fields and crc field if not writing a data descriptor 286*333d2b36SAndroid Build Coastguard Worker if h.Flags&DataDescriptorFlag != 0 { 287*333d2b36SAndroid Build Coastguard Worker // since we are writing a data descriptor, these fields should be 0 288*333d2b36SAndroid Build Coastguard Worker b.uint32(0) // crc32, 289*333d2b36SAndroid Build Coastguard Worker b.uint32(0) // compressed size, 290*333d2b36SAndroid Build Coastguard Worker b.uint32(0) // uncompressed size 291*333d2b36SAndroid Build Coastguard Worker } else { 292*333d2b36SAndroid Build Coastguard Worker b.uint32(h.CRC32) 293*333d2b36SAndroid Build Coastguard Worker 294*333d2b36SAndroid Build Coastguard Worker compressedSize := uint32(h.CompressedSize64) 295*333d2b36SAndroid Build Coastguard Worker if compressedSize == 0 { 296*333d2b36SAndroid Build Coastguard Worker compressedSize = h.CompressedSize 297*333d2b36SAndroid Build Coastguard Worker } 298*333d2b36SAndroid Build Coastguard Worker 299*333d2b36SAndroid Build Coastguard Worker uncompressedSize := uint32(h.UncompressedSize64) 300*333d2b36SAndroid Build Coastguard Worker if uncompressedSize == 0 { 301*333d2b36SAndroid Build Coastguard Worker uncompressedSize = h.UncompressedSize 302*333d2b36SAndroid Build Coastguard Worker } 303*333d2b36SAndroid Build Coastguard Worker 304*333d2b36SAndroid Build Coastguard Worker if h.CompressedSize64 > uint32max || h.UncompressedSize64 > uint32max { 305*333d2b36SAndroid Build Coastguard Worker // Sizes don't fit in a 32-bit field, put them in a zip64 extra instead. 306*333d2b36SAndroid Build Coastguard Worker compressedSize = uint32max 307*333d2b36SAndroid Build Coastguard Worker uncompressedSize = uint32max 308*333d2b36SAndroid Build Coastguard Worker 309*333d2b36SAndroid Build Coastguard Worker // append a zip64 extra block to Extra 310*333d2b36SAndroid Build Coastguard Worker var buf [20]byte // 2x uint16 + 2x uint64 311*333d2b36SAndroid Build Coastguard Worker eb := writeBuf(buf[:]) 312*333d2b36SAndroid Build Coastguard Worker eb.uint16(zip64ExtraId) 313*333d2b36SAndroid Build Coastguard Worker eb.uint16(16) // size = 2x uint64 314*333d2b36SAndroid Build Coastguard Worker eb.uint64(h.UncompressedSize64) 315*333d2b36SAndroid Build Coastguard Worker eb.uint64(h.CompressedSize64) 316*333d2b36SAndroid Build Coastguard Worker h.Extra = append(h.Extra, buf[:]...) 317*333d2b36SAndroid Build Coastguard Worker } 318*333d2b36SAndroid Build Coastguard Worker 319*333d2b36SAndroid Build Coastguard Worker b.uint32(compressedSize) 320*333d2b36SAndroid Build Coastguard Worker b.uint32(uncompressedSize) 321*333d2b36SAndroid Build Coastguard Worker } 322*333d2b36SAndroid Build Coastguard Worker // END ANDROID CHANGE 323*333d2b36SAndroid Build Coastguard Worker b.uint16(uint16(len(h.Name))) 324*333d2b36SAndroid Build Coastguard Worker b.uint16(uint16(len(h.Extra))) 325*333d2b36SAndroid Build Coastguard Worker if _, err := w.Write(buf[:]); err != nil { 326*333d2b36SAndroid Build Coastguard Worker return err 327*333d2b36SAndroid Build Coastguard Worker } 328*333d2b36SAndroid Build Coastguard Worker if _, err := io.WriteString(w, h.Name); err != nil { 329*333d2b36SAndroid Build Coastguard Worker return err 330*333d2b36SAndroid Build Coastguard Worker } 331*333d2b36SAndroid Build Coastguard Worker _, err := w.Write(h.Extra) 332*333d2b36SAndroid Build Coastguard Worker return err 333*333d2b36SAndroid Build Coastguard Worker} 334*333d2b36SAndroid Build Coastguard Worker 335*333d2b36SAndroid Build Coastguard Worker// RegisterCompressor registers or overrides a custom compressor for a specific 336*333d2b36SAndroid Build Coastguard Worker// method ID. If a compressor for a given method is not found, Writer will 337*333d2b36SAndroid Build Coastguard Worker// default to looking up the compressor at the package level. 338*333d2b36SAndroid Build Coastguard Workerfunc (w *Writer) RegisterCompressor(method uint16, comp Compressor) { 339*333d2b36SAndroid Build Coastguard Worker if w.compressors == nil { 340*333d2b36SAndroid Build Coastguard Worker w.compressors = make(map[uint16]Compressor) 341*333d2b36SAndroid Build Coastguard Worker } 342*333d2b36SAndroid Build Coastguard Worker w.compressors[method] = comp 343*333d2b36SAndroid Build Coastguard Worker} 344*333d2b36SAndroid Build Coastguard Worker 345*333d2b36SAndroid Build Coastguard Workerfunc (w *Writer) compressor(method uint16) Compressor { 346*333d2b36SAndroid Build Coastguard Worker comp := w.compressors[method] 347*333d2b36SAndroid Build Coastguard Worker if comp == nil { 348*333d2b36SAndroid Build Coastguard Worker comp = compressor(method) 349*333d2b36SAndroid Build Coastguard Worker } 350*333d2b36SAndroid Build Coastguard Worker return comp 351*333d2b36SAndroid Build Coastguard Worker} 352*333d2b36SAndroid Build Coastguard Worker 353*333d2b36SAndroid Build Coastguard Workertype fileWriter struct { 354*333d2b36SAndroid Build Coastguard Worker *header 355*333d2b36SAndroid Build Coastguard Worker zipw io.Writer 356*333d2b36SAndroid Build Coastguard Worker rawCount *countWriter 357*333d2b36SAndroid Build Coastguard Worker comp io.WriteCloser 358*333d2b36SAndroid Build Coastguard Worker compCount *countWriter 359*333d2b36SAndroid Build Coastguard Worker crc32 hash.Hash32 360*333d2b36SAndroid Build Coastguard Worker closed bool 361*333d2b36SAndroid Build Coastguard Worker} 362*333d2b36SAndroid Build Coastguard Worker 363*333d2b36SAndroid Build Coastguard Workerfunc (w *fileWriter) Write(p []byte) (int, error) { 364*333d2b36SAndroid Build Coastguard Worker if w.closed { 365*333d2b36SAndroid Build Coastguard Worker return 0, errors.New("zip: write to closed file") 366*333d2b36SAndroid Build Coastguard Worker } 367*333d2b36SAndroid Build Coastguard Worker w.crc32.Write(p) 368*333d2b36SAndroid Build Coastguard Worker return w.rawCount.Write(p) 369*333d2b36SAndroid Build Coastguard Worker} 370*333d2b36SAndroid Build Coastguard Worker 371*333d2b36SAndroid Build Coastguard Worker// BEGIN ANDROID CHANGE give the return value a name 372*333d2b36SAndroid Build Coastguard Workerfunc (w *fileWriter) close() (err error) { 373*333d2b36SAndroid Build Coastguard Worker // END ANDROID CHANGE 374*333d2b36SAndroid Build Coastguard Worker if w.closed { 375*333d2b36SAndroid Build Coastguard Worker return errors.New("zip: file closed twice") 376*333d2b36SAndroid Build Coastguard Worker } 377*333d2b36SAndroid Build Coastguard Worker w.closed = true 378*333d2b36SAndroid Build Coastguard Worker if err := w.comp.Close(); err != nil { 379*333d2b36SAndroid Build Coastguard Worker return err 380*333d2b36SAndroid Build Coastguard Worker } 381*333d2b36SAndroid Build Coastguard Worker 382*333d2b36SAndroid Build Coastguard Worker // update FileHeader 383*333d2b36SAndroid Build Coastguard Worker fh := w.header.FileHeader 384*333d2b36SAndroid Build Coastguard Worker fh.CRC32 = w.crc32.Sum32() 385*333d2b36SAndroid Build Coastguard Worker fh.CompressedSize64 = uint64(w.compCount.count) 386*333d2b36SAndroid Build Coastguard Worker fh.UncompressedSize64 = uint64(w.rawCount.count) 387*333d2b36SAndroid Build Coastguard Worker 388*333d2b36SAndroid Build Coastguard Worker if fh.isZip64() { 389*333d2b36SAndroid Build Coastguard Worker fh.CompressedSize = uint32max 390*333d2b36SAndroid Build Coastguard Worker fh.UncompressedSize = uint32max 391*333d2b36SAndroid Build Coastguard Worker fh.ReaderVersion = zipVersion45 // requires 4.5 - File uses ZIP64 format extensions 392*333d2b36SAndroid Build Coastguard Worker } else { 393*333d2b36SAndroid Build Coastguard Worker fh.CompressedSize = uint32(fh.CompressedSize64) 394*333d2b36SAndroid Build Coastguard Worker fh.UncompressedSize = uint32(fh.UncompressedSize64) 395*333d2b36SAndroid Build Coastguard Worker } 396*333d2b36SAndroid Build Coastguard Worker 397*333d2b36SAndroid Build Coastguard Worker // BEGIN ANDROID CHANGE only write data descriptor if the flag is set 398*333d2b36SAndroid Build Coastguard Worker if fh.Flags&DataDescriptorFlag != 0 { 399*333d2b36SAndroid Build Coastguard Worker // Write data descriptor. This is more complicated than one would 400*333d2b36SAndroid Build Coastguard Worker // think, see e.g. comments in zipfile.c:putextended() and 401*333d2b36SAndroid Build Coastguard Worker // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7073588. 402*333d2b36SAndroid Build Coastguard Worker // The approach here is to write 8 byte sizes if needed without 403*333d2b36SAndroid Build Coastguard Worker // adding a zip64 extra in the local header (too late anyway). 404*333d2b36SAndroid Build Coastguard Worker var buf []byte 405*333d2b36SAndroid Build Coastguard Worker if fh.isZip64() { 406*333d2b36SAndroid Build Coastguard Worker buf = make([]byte, dataDescriptor64Len) 407*333d2b36SAndroid Build Coastguard Worker } else { 408*333d2b36SAndroid Build Coastguard Worker buf = make([]byte, dataDescriptorLen) 409*333d2b36SAndroid Build Coastguard Worker } 410*333d2b36SAndroid Build Coastguard Worker b := writeBuf(buf) 411*333d2b36SAndroid Build Coastguard Worker b.uint32(dataDescriptorSignature) // de-facto standard, required by OS X 412*333d2b36SAndroid Build Coastguard Worker b.uint32(fh.CRC32) 413*333d2b36SAndroid Build Coastguard Worker if fh.isZip64() { 414*333d2b36SAndroid Build Coastguard Worker b.uint64(fh.CompressedSize64) 415*333d2b36SAndroid Build Coastguard Worker b.uint64(fh.UncompressedSize64) 416*333d2b36SAndroid Build Coastguard Worker } else { 417*333d2b36SAndroid Build Coastguard Worker b.uint32(fh.CompressedSize) 418*333d2b36SAndroid Build Coastguard Worker b.uint32(fh.UncompressedSize) 419*333d2b36SAndroid Build Coastguard Worker } 420*333d2b36SAndroid Build Coastguard Worker _, err = w.zipw.Write(buf) 421*333d2b36SAndroid Build Coastguard Worker } 422*333d2b36SAndroid Build Coastguard Worker // END ANDROID CHANGE 423*333d2b36SAndroid Build Coastguard Worker return err 424*333d2b36SAndroid Build Coastguard Worker} 425*333d2b36SAndroid Build Coastguard Worker 426*333d2b36SAndroid Build Coastguard Workertype countWriter struct { 427*333d2b36SAndroid Build Coastguard Worker w io.Writer 428*333d2b36SAndroid Build Coastguard Worker count int64 429*333d2b36SAndroid Build Coastguard Worker} 430*333d2b36SAndroid Build Coastguard Worker 431*333d2b36SAndroid Build Coastguard Workerfunc (w *countWriter) Write(p []byte) (int, error) { 432*333d2b36SAndroid Build Coastguard Worker n, err := w.w.Write(p) 433*333d2b36SAndroid Build Coastguard Worker w.count += int64(n) 434*333d2b36SAndroid Build Coastguard Worker return n, err 435*333d2b36SAndroid Build Coastguard Worker} 436*333d2b36SAndroid Build Coastguard Worker 437*333d2b36SAndroid Build Coastguard Workertype nopCloser struct { 438*333d2b36SAndroid Build Coastguard Worker io.Writer 439*333d2b36SAndroid Build Coastguard Worker} 440*333d2b36SAndroid Build Coastguard Worker 441*333d2b36SAndroid Build Coastguard Workerfunc (w nopCloser) Close() error { 442*333d2b36SAndroid Build Coastguard Worker return nil 443*333d2b36SAndroid Build Coastguard Worker} 444*333d2b36SAndroid Build Coastguard Worker 445*333d2b36SAndroid Build Coastguard Workertype writeBuf []byte 446*333d2b36SAndroid Build Coastguard Worker 447*333d2b36SAndroid Build Coastguard Workerfunc (b *writeBuf) uint16(v uint16) { 448*333d2b36SAndroid Build Coastguard Worker binary.LittleEndian.PutUint16(*b, v) 449*333d2b36SAndroid Build Coastguard Worker *b = (*b)[2:] 450*333d2b36SAndroid Build Coastguard Worker} 451*333d2b36SAndroid Build Coastguard Worker 452*333d2b36SAndroid Build Coastguard Workerfunc (b *writeBuf) uint32(v uint32) { 453*333d2b36SAndroid Build Coastguard Worker binary.LittleEndian.PutUint32(*b, v) 454*333d2b36SAndroid Build Coastguard Worker *b = (*b)[4:] 455*333d2b36SAndroid Build Coastguard Worker} 456*333d2b36SAndroid Build Coastguard Worker 457*333d2b36SAndroid Build Coastguard Workerfunc (b *writeBuf) uint64(v uint64) { 458*333d2b36SAndroid Build Coastguard Worker binary.LittleEndian.PutUint64(*b, v) 459*333d2b36SAndroid Build Coastguard Worker *b = (*b)[8:] 460*333d2b36SAndroid Build Coastguard Worker} 461