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