1*86ee64e7SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*86ee64e7SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*86ee64e7SAndroid Build Coastguard Worker // found in the LICENSE file.
4*86ee64e7SAndroid Build Coastguard Worker
5*86ee64e7SAndroid Build Coastguard Worker #include "third_party/zlib/google/zip_internal.h"
6*86ee64e7SAndroid Build Coastguard Worker
7*86ee64e7SAndroid Build Coastguard Worker #include <stddef.h>
8*86ee64e7SAndroid Build Coastguard Worker #include <string.h>
9*86ee64e7SAndroid Build Coastguard Worker
10*86ee64e7SAndroid Build Coastguard Worker #include <algorithm>
11*86ee64e7SAndroid Build Coastguard Worker
12*86ee64e7SAndroid Build Coastguard Worker #include "base/containers/fixed_flat_set.h"
13*86ee64e7SAndroid Build Coastguard Worker #include "base/files/file_path.h"
14*86ee64e7SAndroid Build Coastguard Worker #include "base/logging.h"
15*86ee64e7SAndroid Build Coastguard Worker #include "base/notreached.h"
16*86ee64e7SAndroid Build Coastguard Worker #include "base/strings/string_piece.h"
17*86ee64e7SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
18*86ee64e7SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
19*86ee64e7SAndroid Build Coastguard Worker
20*86ee64e7SAndroid Build Coastguard Worker #if defined(USE_SYSTEM_MINIZIP)
21*86ee64e7SAndroid Build Coastguard Worker #include <minizip/ioapi.h>
22*86ee64e7SAndroid Build Coastguard Worker #include <minizip/unzip.h>
23*86ee64e7SAndroid Build Coastguard Worker #include <minizip/zip.h>
24*86ee64e7SAndroid Build Coastguard Worker #else
25*86ee64e7SAndroid Build Coastguard Worker #include "third_party/zlib/contrib/minizip/unzip.h"
26*86ee64e7SAndroid Build Coastguard Worker #include "third_party/zlib/contrib/minizip/zip.h"
27*86ee64e7SAndroid Build Coastguard Worker #if defined(OS_WIN)
28*86ee64e7SAndroid Build Coastguard Worker #include "third_party/zlib/contrib/minizip/iowin32.h"
29*86ee64e7SAndroid Build Coastguard Worker #elif defined(OS_POSIX)
30*86ee64e7SAndroid Build Coastguard Worker #include "third_party/zlib/contrib/minizip/ioapi.h"
31*86ee64e7SAndroid Build Coastguard Worker #endif // defined(OS_POSIX)
32*86ee64e7SAndroid Build Coastguard Worker #endif // defined(USE_SYSTEM_MINIZIP)
33*86ee64e7SAndroid Build Coastguard Worker
34*86ee64e7SAndroid Build Coastguard Worker namespace {
35*86ee64e7SAndroid Build Coastguard Worker
36*86ee64e7SAndroid Build Coastguard Worker #if defined(OS_WIN)
37*86ee64e7SAndroid Build Coastguard Worker typedef struct {
38*86ee64e7SAndroid Build Coastguard Worker HANDLE hf;
39*86ee64e7SAndroid Build Coastguard Worker int error;
40*86ee64e7SAndroid Build Coastguard Worker } WIN32FILE_IOWIN;
41*86ee64e7SAndroid Build Coastguard Worker
42*86ee64e7SAndroid Build Coastguard Worker // This function is derived from third_party/minizip/iowin32.c.
43*86ee64e7SAndroid Build Coastguard Worker // Its only difference is that it treats the filename as UTF-8 and
44*86ee64e7SAndroid Build Coastguard Worker // uses the Unicode version of CreateFile.
ZipOpenFunc(void * opaque,const void * filename,int mode)45*86ee64e7SAndroid Build Coastguard Worker void* ZipOpenFunc(void* opaque, const void* filename, int mode) {
46*86ee64e7SAndroid Build Coastguard Worker DWORD desired_access = 0, creation_disposition = 0;
47*86ee64e7SAndroid Build Coastguard Worker DWORD share_mode = 0, flags_and_attributes = 0;
48*86ee64e7SAndroid Build Coastguard Worker HANDLE file = 0;
49*86ee64e7SAndroid Build Coastguard Worker void* ret = NULL;
50*86ee64e7SAndroid Build Coastguard Worker
51*86ee64e7SAndroid Build Coastguard Worker if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
52*86ee64e7SAndroid Build Coastguard Worker desired_access = GENERIC_READ;
53*86ee64e7SAndroid Build Coastguard Worker creation_disposition = OPEN_EXISTING;
54*86ee64e7SAndroid Build Coastguard Worker share_mode = FILE_SHARE_READ;
55*86ee64e7SAndroid Build Coastguard Worker } else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) {
56*86ee64e7SAndroid Build Coastguard Worker desired_access = GENERIC_WRITE | GENERIC_READ;
57*86ee64e7SAndroid Build Coastguard Worker creation_disposition = OPEN_EXISTING;
58*86ee64e7SAndroid Build Coastguard Worker } else if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
59*86ee64e7SAndroid Build Coastguard Worker desired_access = GENERIC_WRITE | GENERIC_READ;
60*86ee64e7SAndroid Build Coastguard Worker creation_disposition = CREATE_ALWAYS;
61*86ee64e7SAndroid Build Coastguard Worker }
62*86ee64e7SAndroid Build Coastguard Worker
63*86ee64e7SAndroid Build Coastguard Worker if (filename != nullptr && desired_access != 0) {
64*86ee64e7SAndroid Build Coastguard Worker file = CreateFileW(
65*86ee64e7SAndroid Build Coastguard Worker base::UTF8ToWide(static_cast<const char*>(filename)).c_str(),
66*86ee64e7SAndroid Build Coastguard Worker desired_access, share_mode, nullptr, creation_disposition,
67*86ee64e7SAndroid Build Coastguard Worker flags_and_attributes, nullptr);
68*86ee64e7SAndroid Build Coastguard Worker }
69*86ee64e7SAndroid Build Coastguard Worker
70*86ee64e7SAndroid Build Coastguard Worker if (file == INVALID_HANDLE_VALUE)
71*86ee64e7SAndroid Build Coastguard Worker file = NULL;
72*86ee64e7SAndroid Build Coastguard Worker
73*86ee64e7SAndroid Build Coastguard Worker if (file != NULL) {
74*86ee64e7SAndroid Build Coastguard Worker WIN32FILE_IOWIN file_ret;
75*86ee64e7SAndroid Build Coastguard Worker file_ret.hf = file;
76*86ee64e7SAndroid Build Coastguard Worker file_ret.error = 0;
77*86ee64e7SAndroid Build Coastguard Worker ret = malloc(sizeof(WIN32FILE_IOWIN));
78*86ee64e7SAndroid Build Coastguard Worker if (ret == NULL)
79*86ee64e7SAndroid Build Coastguard Worker CloseHandle(file);
80*86ee64e7SAndroid Build Coastguard Worker else
81*86ee64e7SAndroid Build Coastguard Worker *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret;
82*86ee64e7SAndroid Build Coastguard Worker }
83*86ee64e7SAndroid Build Coastguard Worker return ret;
84*86ee64e7SAndroid Build Coastguard Worker }
85*86ee64e7SAndroid Build Coastguard Worker #endif
86*86ee64e7SAndroid Build Coastguard Worker
87*86ee64e7SAndroid Build Coastguard Worker #if defined(OS_POSIX) || defined(OS_FUCHSIA)
88*86ee64e7SAndroid Build Coastguard Worker // Callback function for zlib that opens a file stream from a file descriptor.
89*86ee64e7SAndroid Build Coastguard Worker // Since we do not own the file descriptor, dup it so that we can fdopen/fclose
90*86ee64e7SAndroid Build Coastguard Worker // a file stream.
FdOpenFileFunc(void * opaque,const void * filename,int mode)91*86ee64e7SAndroid Build Coastguard Worker void* FdOpenFileFunc(void* opaque, const void* filename, int mode) {
92*86ee64e7SAndroid Build Coastguard Worker FILE* file = NULL;
93*86ee64e7SAndroid Build Coastguard Worker const char* mode_fopen = NULL;
94*86ee64e7SAndroid Build Coastguard Worker
95*86ee64e7SAndroid Build Coastguard Worker if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
96*86ee64e7SAndroid Build Coastguard Worker mode_fopen = "rb";
97*86ee64e7SAndroid Build Coastguard Worker else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
98*86ee64e7SAndroid Build Coastguard Worker mode_fopen = "r+b";
99*86ee64e7SAndroid Build Coastguard Worker else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
100*86ee64e7SAndroid Build Coastguard Worker mode_fopen = "wb";
101*86ee64e7SAndroid Build Coastguard Worker
102*86ee64e7SAndroid Build Coastguard Worker if ((filename != NULL) && (mode_fopen != NULL)) {
103*86ee64e7SAndroid Build Coastguard Worker int fd = dup(*static_cast<int*>(opaque));
104*86ee64e7SAndroid Build Coastguard Worker if (fd != -1)
105*86ee64e7SAndroid Build Coastguard Worker file = fdopen(fd, mode_fopen);
106*86ee64e7SAndroid Build Coastguard Worker }
107*86ee64e7SAndroid Build Coastguard Worker
108*86ee64e7SAndroid Build Coastguard Worker return file;
109*86ee64e7SAndroid Build Coastguard Worker }
110*86ee64e7SAndroid Build Coastguard Worker
FdCloseFileFunc(void * opaque,void * stream)111*86ee64e7SAndroid Build Coastguard Worker int FdCloseFileFunc(void* opaque, void* stream) {
112*86ee64e7SAndroid Build Coastguard Worker fclose(static_cast<FILE*>(stream));
113*86ee64e7SAndroid Build Coastguard Worker free(opaque); // malloc'ed in FillFdOpenFileFunc()
114*86ee64e7SAndroid Build Coastguard Worker return 0;
115*86ee64e7SAndroid Build Coastguard Worker }
116*86ee64e7SAndroid Build Coastguard Worker
117*86ee64e7SAndroid Build Coastguard Worker // Fills |pzlib_filecunc_def| appropriately to handle the zip file
118*86ee64e7SAndroid Build Coastguard Worker // referred to by |fd|.
FillFdOpenFileFunc(zlib_filefunc64_def * pzlib_filefunc_def,int fd)119*86ee64e7SAndroid Build Coastguard Worker void FillFdOpenFileFunc(zlib_filefunc64_def* pzlib_filefunc_def, int fd) {
120*86ee64e7SAndroid Build Coastguard Worker fill_fopen64_filefunc(pzlib_filefunc_def);
121*86ee64e7SAndroid Build Coastguard Worker pzlib_filefunc_def->zopen64_file = FdOpenFileFunc;
122*86ee64e7SAndroid Build Coastguard Worker pzlib_filefunc_def->zclose_file = FdCloseFileFunc;
123*86ee64e7SAndroid Build Coastguard Worker int* ptr_fd = static_cast<int*>(malloc(sizeof(fd)));
124*86ee64e7SAndroid Build Coastguard Worker *ptr_fd = fd;
125*86ee64e7SAndroid Build Coastguard Worker pzlib_filefunc_def->opaque = ptr_fd;
126*86ee64e7SAndroid Build Coastguard Worker }
127*86ee64e7SAndroid Build Coastguard Worker #endif // defined(OS_POSIX)
128*86ee64e7SAndroid Build Coastguard Worker
129*86ee64e7SAndroid Build Coastguard Worker #if defined(OS_WIN)
130*86ee64e7SAndroid Build Coastguard Worker // Callback function for zlib that opens a file stream from a Windows handle.
131*86ee64e7SAndroid Build Coastguard Worker // Does not take ownership of the handle.
HandleOpenFileFunc(void * opaque,const void *,int mode)132*86ee64e7SAndroid Build Coastguard Worker void* HandleOpenFileFunc(void* opaque, const void* /*filename*/, int mode) {
133*86ee64e7SAndroid Build Coastguard Worker WIN32FILE_IOWIN file_ret;
134*86ee64e7SAndroid Build Coastguard Worker file_ret.hf = static_cast<HANDLE>(opaque);
135*86ee64e7SAndroid Build Coastguard Worker file_ret.error = 0;
136*86ee64e7SAndroid Build Coastguard Worker if (file_ret.hf == INVALID_HANDLE_VALUE)
137*86ee64e7SAndroid Build Coastguard Worker return NULL;
138*86ee64e7SAndroid Build Coastguard Worker
139*86ee64e7SAndroid Build Coastguard Worker void* ret = malloc(sizeof(WIN32FILE_IOWIN));
140*86ee64e7SAndroid Build Coastguard Worker if (ret != NULL)
141*86ee64e7SAndroid Build Coastguard Worker *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret;
142*86ee64e7SAndroid Build Coastguard Worker return ret;
143*86ee64e7SAndroid Build Coastguard Worker }
144*86ee64e7SAndroid Build Coastguard Worker
HandleCloseFileFunc(void * opaque,void * stream)145*86ee64e7SAndroid Build Coastguard Worker int HandleCloseFileFunc(void* opaque, void* stream) {
146*86ee64e7SAndroid Build Coastguard Worker free(stream); // malloc'ed in HandleOpenFileFunc()
147*86ee64e7SAndroid Build Coastguard Worker return 0;
148*86ee64e7SAndroid Build Coastguard Worker }
149*86ee64e7SAndroid Build Coastguard Worker #endif
150*86ee64e7SAndroid Build Coastguard Worker
151*86ee64e7SAndroid Build Coastguard Worker // A struct that contains data required for zlib functions to extract files from
152*86ee64e7SAndroid Build Coastguard Worker // a zip archive stored in memory directly. The following I/O API functions
153*86ee64e7SAndroid Build Coastguard Worker // expect their opaque parameters refer to this struct.
154*86ee64e7SAndroid Build Coastguard Worker struct ZipBuffer {
155*86ee64e7SAndroid Build Coastguard Worker const char* data; // weak
156*86ee64e7SAndroid Build Coastguard Worker ZPOS64_T length;
157*86ee64e7SAndroid Build Coastguard Worker ZPOS64_T offset;
158*86ee64e7SAndroid Build Coastguard Worker };
159*86ee64e7SAndroid Build Coastguard Worker
160*86ee64e7SAndroid Build Coastguard Worker // Opens the specified file. When this function returns a non-NULL pointer, zlib
161*86ee64e7SAndroid Build Coastguard Worker // uses this pointer as a stream parameter while compressing or uncompressing
162*86ee64e7SAndroid Build Coastguard Worker // data. (Returning NULL represents an error.) This function initializes the
163*86ee64e7SAndroid Build Coastguard Worker // given opaque parameter and returns it because this parameter stores all
164*86ee64e7SAndroid Build Coastguard Worker // information needed for uncompressing data. (This function does not support
165*86ee64e7SAndroid Build Coastguard Worker // writing compressed data and it returns NULL for this case.)
OpenZipBuffer(void * opaque,const void *,int mode)166*86ee64e7SAndroid Build Coastguard Worker void* OpenZipBuffer(void* opaque, const void* /*filename*/, int mode) {
167*86ee64e7SAndroid Build Coastguard Worker if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) {
168*86ee64e7SAndroid Build Coastguard Worker NOTREACHED();
169*86ee64e7SAndroid Build Coastguard Worker return NULL;
170*86ee64e7SAndroid Build Coastguard Worker }
171*86ee64e7SAndroid Build Coastguard Worker ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
172*86ee64e7SAndroid Build Coastguard Worker if (!buffer || !buffer->data || !buffer->length)
173*86ee64e7SAndroid Build Coastguard Worker return NULL;
174*86ee64e7SAndroid Build Coastguard Worker buffer->offset = 0;
175*86ee64e7SAndroid Build Coastguard Worker return opaque;
176*86ee64e7SAndroid Build Coastguard Worker }
177*86ee64e7SAndroid Build Coastguard Worker
178*86ee64e7SAndroid Build Coastguard Worker // Reads compressed data from the specified stream. This function copies data
179*86ee64e7SAndroid Build Coastguard Worker // refered by the opaque parameter and returns the size actually copied.
ReadZipBuffer(void * opaque,void *,void * buf,uLong size)180*86ee64e7SAndroid Build Coastguard Worker uLong ReadZipBuffer(void* opaque, void* /*stream*/, void* buf, uLong size) {
181*86ee64e7SAndroid Build Coastguard Worker ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
182*86ee64e7SAndroid Build Coastguard Worker DCHECK_LE(buffer->offset, buffer->length);
183*86ee64e7SAndroid Build Coastguard Worker ZPOS64_T remaining_bytes = buffer->length - buffer->offset;
184*86ee64e7SAndroid Build Coastguard Worker if (!buffer || !buffer->data || !remaining_bytes)
185*86ee64e7SAndroid Build Coastguard Worker return 0;
186*86ee64e7SAndroid Build Coastguard Worker if (size > remaining_bytes)
187*86ee64e7SAndroid Build Coastguard Worker size = remaining_bytes;
188*86ee64e7SAndroid Build Coastguard Worker memcpy(buf, &buffer->data[buffer->offset], size);
189*86ee64e7SAndroid Build Coastguard Worker buffer->offset += size;
190*86ee64e7SAndroid Build Coastguard Worker return size;
191*86ee64e7SAndroid Build Coastguard Worker }
192*86ee64e7SAndroid Build Coastguard Worker
193*86ee64e7SAndroid Build Coastguard Worker // Writes compressed data to the stream. This function always returns zero
194*86ee64e7SAndroid Build Coastguard Worker // because this implementation is only for reading compressed data.
WriteZipBuffer(void *,void *,const void *,uLong)195*86ee64e7SAndroid Build Coastguard Worker uLong WriteZipBuffer(void* /*opaque*/,
196*86ee64e7SAndroid Build Coastguard Worker void* /*stream*/,
197*86ee64e7SAndroid Build Coastguard Worker const void* /*buf*/,
198*86ee64e7SAndroid Build Coastguard Worker uLong /*size*/) {
199*86ee64e7SAndroid Build Coastguard Worker NOTREACHED();
200*86ee64e7SAndroid Build Coastguard Worker return 0;
201*86ee64e7SAndroid Build Coastguard Worker }
202*86ee64e7SAndroid Build Coastguard Worker
203*86ee64e7SAndroid Build Coastguard Worker // Returns the offset from the beginning of the data.
GetOffsetOfZipBuffer(void * opaque,void *)204*86ee64e7SAndroid Build Coastguard Worker ZPOS64_T GetOffsetOfZipBuffer(void* opaque, void* /*stream*/) {
205*86ee64e7SAndroid Build Coastguard Worker ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
206*86ee64e7SAndroid Build Coastguard Worker if (!buffer)
207*86ee64e7SAndroid Build Coastguard Worker return -1;
208*86ee64e7SAndroid Build Coastguard Worker return buffer->offset;
209*86ee64e7SAndroid Build Coastguard Worker }
210*86ee64e7SAndroid Build Coastguard Worker
211*86ee64e7SAndroid Build Coastguard Worker // Moves the current offset to the specified position.
SeekZipBuffer(void * opaque,void *,ZPOS64_T offset,int origin)212*86ee64e7SAndroid Build Coastguard Worker long SeekZipBuffer(void* opaque,
213*86ee64e7SAndroid Build Coastguard Worker void* /*stream*/,
214*86ee64e7SAndroid Build Coastguard Worker ZPOS64_T offset,
215*86ee64e7SAndroid Build Coastguard Worker int origin) {
216*86ee64e7SAndroid Build Coastguard Worker ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
217*86ee64e7SAndroid Build Coastguard Worker if (!buffer)
218*86ee64e7SAndroid Build Coastguard Worker return -1;
219*86ee64e7SAndroid Build Coastguard Worker if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
220*86ee64e7SAndroid Build Coastguard Worker buffer->offset = std::min(buffer->offset + offset, buffer->length);
221*86ee64e7SAndroid Build Coastguard Worker return 0;
222*86ee64e7SAndroid Build Coastguard Worker }
223*86ee64e7SAndroid Build Coastguard Worker if (origin == ZLIB_FILEFUNC_SEEK_END) {
224*86ee64e7SAndroid Build Coastguard Worker buffer->offset = (buffer->length > offset) ? buffer->length - offset : 0;
225*86ee64e7SAndroid Build Coastguard Worker return 0;
226*86ee64e7SAndroid Build Coastguard Worker }
227*86ee64e7SAndroid Build Coastguard Worker if (origin == ZLIB_FILEFUNC_SEEK_SET) {
228*86ee64e7SAndroid Build Coastguard Worker buffer->offset = std::min(buffer->length, offset);
229*86ee64e7SAndroid Build Coastguard Worker return 0;
230*86ee64e7SAndroid Build Coastguard Worker }
231*86ee64e7SAndroid Build Coastguard Worker NOTREACHED();
232*86ee64e7SAndroid Build Coastguard Worker return -1;
233*86ee64e7SAndroid Build Coastguard Worker }
234*86ee64e7SAndroid Build Coastguard Worker
235*86ee64e7SAndroid Build Coastguard Worker // Closes the input offset and deletes all resources used for compressing or
236*86ee64e7SAndroid Build Coastguard Worker // uncompressing data. This function deletes the ZipBuffer object referred by
237*86ee64e7SAndroid Build Coastguard Worker // the opaque parameter since zlib deletes the unzFile object and it does not
238*86ee64e7SAndroid Build Coastguard Worker // use this object any longer.
CloseZipBuffer(void * opaque,void *)239*86ee64e7SAndroid Build Coastguard Worker int CloseZipBuffer(void* opaque, void* /*stream*/) {
240*86ee64e7SAndroid Build Coastguard Worker if (opaque)
241*86ee64e7SAndroid Build Coastguard Worker free(opaque);
242*86ee64e7SAndroid Build Coastguard Worker return 0;
243*86ee64e7SAndroid Build Coastguard Worker }
244*86ee64e7SAndroid Build Coastguard Worker
245*86ee64e7SAndroid Build Coastguard Worker // Returns the last error happened when reading or writing data. This function
246*86ee64e7SAndroid Build Coastguard Worker // always returns zero, which means there are not any errors.
GetErrorOfZipBuffer(void *,void *)247*86ee64e7SAndroid Build Coastguard Worker int GetErrorOfZipBuffer(void* /*opaque*/, void* /*stream*/) {
248*86ee64e7SAndroid Build Coastguard Worker return 0;
249*86ee64e7SAndroid Build Coastguard Worker }
250*86ee64e7SAndroid Build Coastguard Worker
251*86ee64e7SAndroid Build Coastguard Worker // Returns a zip_fileinfo struct with the time represented by |file_time|.
TimeToZipFileInfo(const base::Time & file_time)252*86ee64e7SAndroid Build Coastguard Worker zip_fileinfo TimeToZipFileInfo(const base::Time& file_time) {
253*86ee64e7SAndroid Build Coastguard Worker base::Time::Exploded file_time_parts;
254*86ee64e7SAndroid Build Coastguard Worker file_time.UTCExplode(&file_time_parts);
255*86ee64e7SAndroid Build Coastguard Worker
256*86ee64e7SAndroid Build Coastguard Worker zip_fileinfo zip_info = {};
257*86ee64e7SAndroid Build Coastguard Worker if (file_time_parts.year >= 1980) {
258*86ee64e7SAndroid Build Coastguard Worker // This if check works around the handling of the year value in
259*86ee64e7SAndroid Build Coastguard Worker // contrib/minizip/zip.c in function zip64local_TmzDateToDosDate
260*86ee64e7SAndroid Build Coastguard Worker // It assumes that dates below 1980 are in the double digit format.
261*86ee64e7SAndroid Build Coastguard Worker // Hence the fail safe option is to leave the date unset. Some programs
262*86ee64e7SAndroid Build Coastguard Worker // might show the unset date as 1980-0-0 which is invalid.
263*86ee64e7SAndroid Build Coastguard Worker zip_info.tmz_date.tm_year = file_time_parts.year;
264*86ee64e7SAndroid Build Coastguard Worker zip_info.tmz_date.tm_mon = file_time_parts.month - 1;
265*86ee64e7SAndroid Build Coastguard Worker zip_info.tmz_date.tm_mday = file_time_parts.day_of_month;
266*86ee64e7SAndroid Build Coastguard Worker zip_info.tmz_date.tm_hour = file_time_parts.hour;
267*86ee64e7SAndroid Build Coastguard Worker zip_info.tmz_date.tm_min = file_time_parts.minute;
268*86ee64e7SAndroid Build Coastguard Worker zip_info.tmz_date.tm_sec = file_time_parts.second;
269*86ee64e7SAndroid Build Coastguard Worker }
270*86ee64e7SAndroid Build Coastguard Worker
271*86ee64e7SAndroid Build Coastguard Worker return zip_info;
272*86ee64e7SAndroid Build Coastguard Worker }
273*86ee64e7SAndroid Build Coastguard Worker } // namespace
274*86ee64e7SAndroid Build Coastguard Worker
275*86ee64e7SAndroid Build Coastguard Worker namespace zip {
276*86ee64e7SAndroid Build Coastguard Worker namespace internal {
277*86ee64e7SAndroid Build Coastguard Worker
OpenForUnzipping(const std::string & file_name_utf8)278*86ee64e7SAndroid Build Coastguard Worker unzFile OpenForUnzipping(const std::string& file_name_utf8) {
279*86ee64e7SAndroid Build Coastguard Worker zlib_filefunc64_def* zip_func_ptrs = nullptr;
280*86ee64e7SAndroid Build Coastguard Worker #if defined(OS_WIN)
281*86ee64e7SAndroid Build Coastguard Worker zlib_filefunc64_def zip_funcs;
282*86ee64e7SAndroid Build Coastguard Worker fill_win32_filefunc64(&zip_funcs);
283*86ee64e7SAndroid Build Coastguard Worker zip_funcs.zopen64_file = ZipOpenFunc;
284*86ee64e7SAndroid Build Coastguard Worker zip_func_ptrs = &zip_funcs;
285*86ee64e7SAndroid Build Coastguard Worker #endif
286*86ee64e7SAndroid Build Coastguard Worker return unzOpen2_64(file_name_utf8.c_str(), zip_func_ptrs);
287*86ee64e7SAndroid Build Coastguard Worker }
288*86ee64e7SAndroid Build Coastguard Worker
289*86ee64e7SAndroid Build Coastguard Worker #if defined(OS_POSIX) || defined(OS_FUCHSIA)
OpenFdForUnzipping(int zip_fd)290*86ee64e7SAndroid Build Coastguard Worker unzFile OpenFdForUnzipping(int zip_fd) {
291*86ee64e7SAndroid Build Coastguard Worker zlib_filefunc64_def zip_funcs;
292*86ee64e7SAndroid Build Coastguard Worker FillFdOpenFileFunc(&zip_funcs, zip_fd);
293*86ee64e7SAndroid Build Coastguard Worker // Passing dummy "fd" filename to zlib.
294*86ee64e7SAndroid Build Coastguard Worker return unzOpen2_64("fd", &zip_funcs);
295*86ee64e7SAndroid Build Coastguard Worker }
296*86ee64e7SAndroid Build Coastguard Worker #endif
297*86ee64e7SAndroid Build Coastguard Worker
298*86ee64e7SAndroid Build Coastguard Worker #if defined(OS_WIN)
OpenHandleForUnzipping(HANDLE zip_handle)299*86ee64e7SAndroid Build Coastguard Worker unzFile OpenHandleForUnzipping(HANDLE zip_handle) {
300*86ee64e7SAndroid Build Coastguard Worker zlib_filefunc64_def zip_funcs;
301*86ee64e7SAndroid Build Coastguard Worker fill_win32_filefunc64(&zip_funcs);
302*86ee64e7SAndroid Build Coastguard Worker zip_funcs.zopen64_file = HandleOpenFileFunc;
303*86ee64e7SAndroid Build Coastguard Worker zip_funcs.zclose_file = HandleCloseFileFunc;
304*86ee64e7SAndroid Build Coastguard Worker zip_funcs.opaque = zip_handle;
305*86ee64e7SAndroid Build Coastguard Worker return unzOpen2_64("fd", &zip_funcs);
306*86ee64e7SAndroid Build Coastguard Worker }
307*86ee64e7SAndroid Build Coastguard Worker #endif
308*86ee64e7SAndroid Build Coastguard Worker
309*86ee64e7SAndroid Build Coastguard Worker // static
PrepareMemoryForUnzipping(const std::string & data)310*86ee64e7SAndroid Build Coastguard Worker unzFile PrepareMemoryForUnzipping(const std::string& data) {
311*86ee64e7SAndroid Build Coastguard Worker if (data.empty())
312*86ee64e7SAndroid Build Coastguard Worker return NULL;
313*86ee64e7SAndroid Build Coastguard Worker
314*86ee64e7SAndroid Build Coastguard Worker ZipBuffer* buffer = static_cast<ZipBuffer*>(malloc(sizeof(ZipBuffer)));
315*86ee64e7SAndroid Build Coastguard Worker if (!buffer)
316*86ee64e7SAndroid Build Coastguard Worker return NULL;
317*86ee64e7SAndroid Build Coastguard Worker buffer->data = data.data();
318*86ee64e7SAndroid Build Coastguard Worker buffer->length = data.length();
319*86ee64e7SAndroid Build Coastguard Worker buffer->offset = 0;
320*86ee64e7SAndroid Build Coastguard Worker
321*86ee64e7SAndroid Build Coastguard Worker zlib_filefunc64_def zip_functions;
322*86ee64e7SAndroid Build Coastguard Worker zip_functions.zopen64_file = OpenZipBuffer;
323*86ee64e7SAndroid Build Coastguard Worker zip_functions.zread_file = ReadZipBuffer;
324*86ee64e7SAndroid Build Coastguard Worker zip_functions.zwrite_file = WriteZipBuffer;
325*86ee64e7SAndroid Build Coastguard Worker zip_functions.ztell64_file = GetOffsetOfZipBuffer;
326*86ee64e7SAndroid Build Coastguard Worker zip_functions.zseek64_file = SeekZipBuffer;
327*86ee64e7SAndroid Build Coastguard Worker zip_functions.zclose_file = CloseZipBuffer;
328*86ee64e7SAndroid Build Coastguard Worker zip_functions.zerror_file = GetErrorOfZipBuffer;
329*86ee64e7SAndroid Build Coastguard Worker zip_functions.opaque = buffer;
330*86ee64e7SAndroid Build Coastguard Worker return unzOpen2_64(nullptr, &zip_functions);
331*86ee64e7SAndroid Build Coastguard Worker }
332*86ee64e7SAndroid Build Coastguard Worker
OpenForZipping(const std::string & file_name_utf8,int append_flag)333*86ee64e7SAndroid Build Coastguard Worker zipFile OpenForZipping(const std::string& file_name_utf8, int append_flag) {
334*86ee64e7SAndroid Build Coastguard Worker zlib_filefunc64_def* zip_func_ptrs = nullptr;
335*86ee64e7SAndroid Build Coastguard Worker #if defined(OS_WIN)
336*86ee64e7SAndroid Build Coastguard Worker zlib_filefunc64_def zip_funcs;
337*86ee64e7SAndroid Build Coastguard Worker fill_win32_filefunc64(&zip_funcs);
338*86ee64e7SAndroid Build Coastguard Worker zip_funcs.zopen64_file = ZipOpenFunc;
339*86ee64e7SAndroid Build Coastguard Worker zip_func_ptrs = &zip_funcs;
340*86ee64e7SAndroid Build Coastguard Worker #endif
341*86ee64e7SAndroid Build Coastguard Worker return zipOpen2_64(file_name_utf8.c_str(), append_flag, nullptr,
342*86ee64e7SAndroid Build Coastguard Worker zip_func_ptrs);
343*86ee64e7SAndroid Build Coastguard Worker }
344*86ee64e7SAndroid Build Coastguard Worker
345*86ee64e7SAndroid Build Coastguard Worker #if defined(OS_POSIX) || defined(OS_FUCHSIA)
OpenFdForZipping(int zip_fd,int append_flag)346*86ee64e7SAndroid Build Coastguard Worker zipFile OpenFdForZipping(int zip_fd, int append_flag) {
347*86ee64e7SAndroid Build Coastguard Worker zlib_filefunc64_def zip_funcs;
348*86ee64e7SAndroid Build Coastguard Worker FillFdOpenFileFunc(&zip_funcs, zip_fd);
349*86ee64e7SAndroid Build Coastguard Worker // Passing dummy "fd" filename to zlib.
350*86ee64e7SAndroid Build Coastguard Worker return zipOpen2_64("fd", append_flag, nullptr, &zip_funcs);
351*86ee64e7SAndroid Build Coastguard Worker }
352*86ee64e7SAndroid Build Coastguard Worker #endif
353*86ee64e7SAndroid Build Coastguard Worker
ZipOpenNewFileInZip(zipFile zip_file,const std::string & str_path,base::Time last_modified_time,Compression compression)354*86ee64e7SAndroid Build Coastguard Worker bool ZipOpenNewFileInZip(zipFile zip_file,
355*86ee64e7SAndroid Build Coastguard Worker const std::string& str_path,
356*86ee64e7SAndroid Build Coastguard Worker base::Time last_modified_time,
357*86ee64e7SAndroid Build Coastguard Worker Compression compression) {
358*86ee64e7SAndroid Build Coastguard Worker // Section 4.4.4 http://www.pkware.com/documents/casestudies/APPNOTE.TXT
359*86ee64e7SAndroid Build Coastguard Worker // Setting the Language encoding flag so the file is told to be in utf-8.
360*86ee64e7SAndroid Build Coastguard Worker const uLong LANGUAGE_ENCODING_FLAG = 0x1 << 11;
361*86ee64e7SAndroid Build Coastguard Worker
362*86ee64e7SAndroid Build Coastguard Worker const zip_fileinfo file_info = TimeToZipFileInfo(last_modified_time);
363*86ee64e7SAndroid Build Coastguard Worker const int err = zipOpenNewFileInZip4_64(
364*86ee64e7SAndroid Build Coastguard Worker /*file=*/zip_file,
365*86ee64e7SAndroid Build Coastguard Worker /*filename=*/str_path.c_str(),
366*86ee64e7SAndroid Build Coastguard Worker /*zip_fileinfo=*/&file_info,
367*86ee64e7SAndroid Build Coastguard Worker /*extrafield_local=*/nullptr,
368*86ee64e7SAndroid Build Coastguard Worker /*size_extrafield_local=*/0u,
369*86ee64e7SAndroid Build Coastguard Worker /*extrafield_global=*/nullptr,
370*86ee64e7SAndroid Build Coastguard Worker /*size_extrafield_global=*/0u,
371*86ee64e7SAndroid Build Coastguard Worker /*comment=*/nullptr,
372*86ee64e7SAndroid Build Coastguard Worker /*method=*/compression,
373*86ee64e7SAndroid Build Coastguard Worker /*level=*/Z_DEFAULT_COMPRESSION,
374*86ee64e7SAndroid Build Coastguard Worker /*raw=*/0,
375*86ee64e7SAndroid Build Coastguard Worker /*windowBits=*/-MAX_WBITS,
376*86ee64e7SAndroid Build Coastguard Worker /*memLevel=*/DEF_MEM_LEVEL,
377*86ee64e7SAndroid Build Coastguard Worker /*strategy=*/Z_DEFAULT_STRATEGY,
378*86ee64e7SAndroid Build Coastguard Worker /*password=*/nullptr,
379*86ee64e7SAndroid Build Coastguard Worker /*crcForCrypting=*/0,
380*86ee64e7SAndroid Build Coastguard Worker /*versionMadeBy=*/0,
381*86ee64e7SAndroid Build Coastguard Worker /*flagBase=*/LANGUAGE_ENCODING_FLAG,
382*86ee64e7SAndroid Build Coastguard Worker /*zip64=*/1);
383*86ee64e7SAndroid Build Coastguard Worker
384*86ee64e7SAndroid Build Coastguard Worker if (err != ZIP_OK) {
385*86ee64e7SAndroid Build Coastguard Worker DLOG(ERROR) << "Cannot open ZIP file entry '" << str_path
386*86ee64e7SAndroid Build Coastguard Worker << "': zipOpenNewFileInZip4_64 returned " << err;
387*86ee64e7SAndroid Build Coastguard Worker return false;
388*86ee64e7SAndroid Build Coastguard Worker }
389*86ee64e7SAndroid Build Coastguard Worker
390*86ee64e7SAndroid Build Coastguard Worker return true;
391*86ee64e7SAndroid Build Coastguard Worker }
392*86ee64e7SAndroid Build Coastguard Worker
GetCompressionMethod(const base::FilePath & path)393*86ee64e7SAndroid Build Coastguard Worker Compression GetCompressionMethod(const base::FilePath& path) {
394*86ee64e7SAndroid Build Coastguard Worker // Get the filename extension in lower case.
395*86ee64e7SAndroid Build Coastguard Worker const base::FilePath::StringType ext =
396*86ee64e7SAndroid Build Coastguard Worker base::ToLowerASCII(path.FinalExtension());
397*86ee64e7SAndroid Build Coastguard Worker
398*86ee64e7SAndroid Build Coastguard Worker if (ext.empty())
399*86ee64e7SAndroid Build Coastguard Worker return kDeflated;
400*86ee64e7SAndroid Build Coastguard Worker
401*86ee64e7SAndroid Build Coastguard Worker using StringPiece = base::FilePath::StringPieceType;
402*86ee64e7SAndroid Build Coastguard Worker
403*86ee64e7SAndroid Build Coastguard Worker // Skip the leading dot.
404*86ee64e7SAndroid Build Coastguard Worker StringPiece ext_without_dot = ext;
405*86ee64e7SAndroid Build Coastguard Worker DCHECK_EQ(ext_without_dot.front(), FILE_PATH_LITERAL('.'));
406*86ee64e7SAndroid Build Coastguard Worker ext_without_dot.remove_prefix(1);
407*86ee64e7SAndroid Build Coastguard Worker
408*86ee64e7SAndroid Build Coastguard Worker // Well known filename extensions of files that a likely to be already
409*86ee64e7SAndroid Build Coastguard Worker // compressed. The extensions are in lower case without the leading dot.
410*86ee64e7SAndroid Build Coastguard Worker static constexpr auto kExts = base::MakeFixedFlatSet<StringPiece>({
411*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("3g2"), //
412*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("3gp"), //
413*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("7z"), //
414*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("7zip"), //
415*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("aac"), //
416*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("avi"), //
417*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("bz"), //
418*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("bz2"), //
419*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("crx"), //
420*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("gif"), //
421*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("gz"), //
422*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("jar"), //
423*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("jpeg"), //
424*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("jpg"), //
425*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("lz"), //
426*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("m2v"), //
427*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("m4p"), //
428*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("m4v"), //
429*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("mng"), //
430*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("mov"), //
431*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("mp2"), //
432*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("mp3"), //
433*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("mp4"), //
434*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("mpe"), //
435*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("mpeg"), //
436*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("mpg"), //
437*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("mpv"), //
438*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("ogg"), //
439*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("ogv"), //
440*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("png"), //
441*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("qt"), //
442*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("rar"), //
443*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("taz"), //
444*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("tb2"), //
445*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("tbz"), //
446*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("tbz2"), //
447*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("tgz"), //
448*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("tlz"), //
449*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("tz"), //
450*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("tz2"), //
451*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("vob"), //
452*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("webm"), //
453*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("wma"), //
454*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("wmv"), //
455*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("xz"), //
456*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("z"), //
457*86ee64e7SAndroid Build Coastguard Worker FILE_PATH_LITERAL("zip"), //
458*86ee64e7SAndroid Build Coastguard Worker });
459*86ee64e7SAndroid Build Coastguard Worker
460*86ee64e7SAndroid Build Coastguard Worker if (kExts.count(ext_without_dot)) {
461*86ee64e7SAndroid Build Coastguard Worker return kStored;
462*86ee64e7SAndroid Build Coastguard Worker }
463*86ee64e7SAndroid Build Coastguard Worker
464*86ee64e7SAndroid Build Coastguard Worker return kDeflated;
465*86ee64e7SAndroid Build Coastguard Worker }
466*86ee64e7SAndroid Build Coastguard Worker
467*86ee64e7SAndroid Build Coastguard Worker } // namespace internal
468*86ee64e7SAndroid Build Coastguard Worker } // namespace zip
469