github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/third_party/zip/android.go (about)

     1  // Copyright 2016 Google Inc. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package zip
    16  
    17  import (
    18  	"errors"
    19  	"io"
    20  )
    21  
    22  const DataDescriptorFlag = 0x8
    23  const ExtendedTimeStampTag = 0x5455
    24  
    25  func (w *Writer) CopyFrom(orig *File, newName string) error {
    26  	if w.last != nil && !w.last.closed {
    27  		if err := w.last.close(); err != nil {
    28  			return err
    29  		}
    30  		w.last = nil
    31  	}
    32  
    33  	fileHeader := orig.FileHeader
    34  	fileHeader.Name = newName
    35  	fh := &fileHeader
    36  
    37  	// In some cases, we need strip the extras if it change between Central Directory
    38  	// and Local File Header.
    39  	fh.Extra = stripExtras(fh.Extra)
    40  
    41  	h := &header{
    42  		FileHeader: fh,
    43  		offset:     uint64(w.cw.count),
    44  	}
    45  	w.dir = append(w.dir, h)
    46  
    47  	if err := writeHeader(w.cw, fh); err != nil {
    48  		return err
    49  	}
    50  	dataOffset, err := orig.DataOffset()
    51  	if err != nil {
    52  		return err
    53  	}
    54  	io.Copy(w.cw, io.NewSectionReader(orig.zipr, dataOffset, int64(orig.CompressedSize64)))
    55  
    56  	if orig.hasDataDescriptor() {
    57  		// Write data descriptor.
    58  		var buf []byte
    59  		if fh.isZip64() {
    60  			buf = make([]byte, dataDescriptor64Len)
    61  		} else {
    62  			buf = make([]byte, dataDescriptorLen)
    63  		}
    64  		b := writeBuf(buf)
    65  		b.uint32(dataDescriptorSignature)
    66  		b.uint32(fh.CRC32)
    67  		if fh.isZip64() {
    68  			b.uint64(fh.CompressedSize64)
    69  			b.uint64(fh.UncompressedSize64)
    70  		} else {
    71  			b.uint32(fh.CompressedSize)
    72  			b.uint32(fh.UncompressedSize)
    73  		}
    74  		_, err = w.cw.Write(buf)
    75  	}
    76  	return err
    77  }
    78  
    79  // The zip64 extras change between the Central Directory and Local File Header, while we use
    80  // the same structure for both. The Local File Haeder is taken care of by us writing a data
    81  // descriptor with the zip64 values. The Central Directory Entry is written by Close(), where
    82  // the zip64 extra is automatically created and appended when necessary.
    83  //
    84  // The extended-timestamp extra block changes between the Central Directory Header and Local
    85  // File Header.
    86  // Extended-Timestamp extra(LFH): <tag-size-flag-modtime-actime-changetime>
    87  // Extended-Timestamp extra(CDH): <tag-size-flag-modtime>
    88  func stripExtras(input []byte) []byte {
    89  	ret := []byte{}
    90  
    91  	for len(input) >= 4 {
    92  		r := readBuf(input)
    93  		tag := r.uint16()
    94  		size := r.uint16()
    95  		if int(size) > len(r) {
    96  			break
    97  		}
    98  		if tag != zip64ExtraId && tag != ExtendedTimeStampTag {
    99  			ret = append(ret, input[:4+size]...)
   100  		}
   101  		input = input[4+size:]
   102  	}
   103  
   104  	// Keep any trailing data
   105  	ret = append(ret, input...)
   106  
   107  	return ret
   108  }
   109  
   110  // CreateCompressedHeader adds a file to the zip file using the provied
   111  // FileHeader for the file metadata.
   112  // It returns a Writer to which the already compressed file contents
   113  // should be written.
   114  //
   115  // The UncompressedSize64 and CRC32 entries in the FileHeader must be filled
   116  // out already.
   117  //
   118  // The file's contents must be written to the io.Writer before the next
   119  // call to Create, CreateHeader, CreateCompressedHeader, or Close. The
   120  // provided FileHeader fh must not be modified after a call to
   121  // CreateCompressedHeader
   122  func (w *Writer) CreateCompressedHeader(fh *FileHeader) (io.WriteCloser, error) {
   123  	if w.last != nil && !w.last.closed {
   124  		if err := w.last.close(); err != nil {
   125  			return nil, err
   126  		}
   127  	}
   128  	if len(w.dir) > 0 && w.dir[len(w.dir)-1].FileHeader == fh {
   129  		// See https://golang.org/issue/11144 confusion.
   130  		return nil, errors.New("archive/zip: invalid duplicate FileHeader")
   131  	}
   132  
   133  	fh.Flags |= DataDescriptorFlag // we will write a data descriptor
   134  
   135  	fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte
   136  	fh.ReaderVersion = zipVersion20
   137  
   138  	fw := &compressedFileWriter{
   139  		fileWriter{
   140  			zipw:      w.cw,
   141  			compCount: &countWriter{w: w.cw},
   142  		},
   143  	}
   144  
   145  	h := &header{
   146  		FileHeader: fh,
   147  		offset:     uint64(w.cw.count),
   148  	}
   149  	w.dir = append(w.dir, h)
   150  	fw.header = h
   151  
   152  	if err := writeHeader(w.cw, fh); err != nil {
   153  		return nil, err
   154  	}
   155  
   156  	w.last = &fw.fileWriter
   157  	return fw, nil
   158  }
   159  
   160  // Updated version of CreateHeader that doesn't enforce writing a data descriptor
   161  func (w *Writer) CreateHeaderAndroid(fh *FileHeader) (io.Writer, error) {
   162  	writeDataDescriptor := fh.Method != Store
   163  	if writeDataDescriptor {
   164  		fh.Flags &= DataDescriptorFlag
   165  	} else {
   166  		fh.Flags &= ^uint16(DataDescriptorFlag)
   167  	}
   168  	return w.createHeaderImpl(fh)
   169  }
   170  
   171  type compressedFileWriter struct {
   172  	fileWriter
   173  }
   174  
   175  func (w *compressedFileWriter) Write(p []byte) (int, error) {
   176  	if w.closed {
   177  		return 0, errors.New("zip: write to closed file")
   178  	}
   179  	return w.compCount.Write(p)
   180  }
   181  
   182  func (w *compressedFileWriter) Close() error {
   183  	if w.closed {
   184  		return errors.New("zip: file closed twice")
   185  	}
   186  	w.closed = true
   187  
   188  	// update FileHeader
   189  	fh := w.header.FileHeader
   190  	fh.CompressedSize64 = uint64(w.compCount.count)
   191  
   192  	if fh.isZip64() {
   193  		fh.CompressedSize = uint32max
   194  		fh.UncompressedSize = uint32max
   195  		fh.ReaderVersion = zipVersion45 // requires 4.5 - File uses ZIP64 format extensions
   196  	} else {
   197  		fh.CompressedSize = uint32(fh.CompressedSize64)
   198  		fh.UncompressedSize = uint32(fh.UncompressedSize64)
   199  	}
   200  
   201  	// Write data descriptor. This is more complicated than one would
   202  	// think, see e.g. comments in zipfile.c:putextended() and
   203  	// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7073588.
   204  	// The approach here is to write 8 byte sizes if needed without
   205  	// adding a zip64 extra in the local header (too late anyway).
   206  	var buf []byte
   207  	if fh.isZip64() {
   208  		buf = make([]byte, dataDescriptor64Len)
   209  	} else {
   210  		buf = make([]byte, dataDescriptorLen)
   211  	}
   212  	b := writeBuf(buf)
   213  	b.uint32(dataDescriptorSignature) // de-facto standard, required by OS X
   214  	b.uint32(fh.CRC32)
   215  	if fh.isZip64() {
   216  		b.uint64(fh.CompressedSize64)
   217  		b.uint64(fh.UncompressedSize64)
   218  	} else {
   219  		b.uint32(fh.CompressedSize)
   220  		b.uint32(fh.UncompressedSize)
   221  	}
   222  	_, err := w.zipw.Write(buf)
   223  	return err
   224  }