1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "third_party/zlib/google/zip_internal.h"
9 #include "base/file_util.h"
10 #include "base/logging.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/time/time.h"
14 #if defined(USE_SYSTEM_MINIZIP)
15 #include <minizip/ioapi.h>
16 #include <minizip/unzip.h>
17 #include <minizip/zip.h>
19 #include "third_party/zlib/contrib/minizip/unzip.h"
20 #include "third_party/zlib/contrib/minizip/zip.h"
22 #include "third_party/zlib/contrib/minizip/iowin32.h"
23 #elif defined(OS_POSIX)
24 #include "third_party/zlib/contrib/minizip/ioapi.h"
25 #endif // defined(OS_POSIX)
26 #endif // defined(USE_SYSTEM_MINIZIP)
36 // This function is derived from third_party/minizip/iowin32.c.
37 // Its only difference is that it treats the char* as UTF8 and
38 // uses the Unicode version of CreateFile.
39 void* ZipOpenFunc(void *opaque
, const char* filename
, int mode
) {
40 DWORD desired_access
= 0, creation_disposition
= 0;
41 DWORD share_mode
= 0, flags_and_attributes
= 0;
45 if ((mode
& ZLIB_FILEFUNC_MODE_READWRITEFILTER
) == ZLIB_FILEFUNC_MODE_READ
) {
46 desired_access
= GENERIC_READ
;
47 creation_disposition
= OPEN_EXISTING
;
48 share_mode
= FILE_SHARE_READ
;
49 } else if (mode
& ZLIB_FILEFUNC_MODE_EXISTING
) {
50 desired_access
= GENERIC_WRITE
| GENERIC_READ
;
51 creation_disposition
= OPEN_EXISTING
;
52 } else if (mode
& ZLIB_FILEFUNC_MODE_CREATE
) {
53 desired_access
= GENERIC_WRITE
| GENERIC_READ
;
54 creation_disposition
= CREATE_ALWAYS
;
57 base::string16 filename16
= base::UTF8ToUTF16(filename
);
58 if ((filename
!= NULL
) && (desired_access
!= 0)) {
59 file
= CreateFile(filename16
.c_str(), desired_access
, share_mode
,
60 NULL
, creation_disposition
, flags_and_attributes
, NULL
);
63 if (file
== INVALID_HANDLE_VALUE
)
67 WIN32FILE_IOWIN file_ret
;
70 ret
= malloc(sizeof(WIN32FILE_IOWIN
));
74 *(static_cast<WIN32FILE_IOWIN
*>(ret
)) = file_ret
;
81 // Callback function for zlib that opens a file stream from a file descriptor.
82 void* FdOpenFileFunc(void* opaque
, const char* filename
, int mode
) {
84 const char* mode_fopen
= NULL
;
86 if ((mode
& ZLIB_FILEFUNC_MODE_READWRITEFILTER
) == ZLIB_FILEFUNC_MODE_READ
)
88 else if (mode
& ZLIB_FILEFUNC_MODE_EXISTING
)
90 else if (mode
& ZLIB_FILEFUNC_MODE_CREATE
)
93 if ((filename
!= NULL
) && (mode_fopen
!= NULL
))
94 file
= fdopen(*static_cast<int*>(opaque
), mode_fopen
);
99 // We don't actually close the file stream since that would close
100 // the underlying file descriptor, and we don't own it. However we do need to
101 // flush buffers and free |opaque| since we malloc'ed it in FillFdOpenFileFunc.
102 int CloseFileFunc(void* opaque
, void* stream
) {
103 fflush(static_cast<FILE*>(stream
));
108 // Fills |pzlib_filecunc_def| appropriately to handle the zip file
109 // referred to by |fd|.
110 void FillFdOpenFileFunc(zlib_filefunc_def
* pzlib_filefunc_def
, int fd
) {
111 fill_fopen_filefunc(pzlib_filefunc_def
);
112 pzlib_filefunc_def
->zopen_file
= FdOpenFileFunc
;
113 pzlib_filefunc_def
->zclose_file
= CloseFileFunc
;
114 int* ptr_fd
= static_cast<int*>(malloc(sizeof(fd
)));
116 pzlib_filefunc_def
->opaque
= ptr_fd
;
118 #endif // defined(OS_POSIX)
121 // Callback function for zlib that opens a file stream from a Windows handle.
122 void* HandleOpenFileFunc(void* opaque
, const char* filename
, int mode
) {
123 WIN32FILE_IOWIN file_ret
;
124 file_ret
.hf
= static_cast<HANDLE
>(opaque
);
126 if (file_ret
.hf
== INVALID_HANDLE_VALUE
)
129 void* ret
= malloc(sizeof(WIN32FILE_IOWIN
));
131 *(static_cast<WIN32FILE_IOWIN
*>(ret
)) = file_ret
;
136 // A struct that contains data required for zlib functions to extract files from
137 // a zip archive stored in memory directly. The following I/O API functions
138 // expect their opaque parameters refer to this struct.
140 const char* data
; // weak
145 // Opens the specified file. When this function returns a non-NULL pointer, zlib
146 // uses this pointer as a stream parameter while compressing or uncompressing
147 // data. (Returning NULL represents an error.) This function initializes the
148 // given opaque parameter and returns it because this parameter stores all
149 // information needed for uncompressing data. (This function does not support
150 // writing compressed data and it returns NULL for this case.)
151 void* OpenZipBuffer(void* opaque
, const char* /*filename*/, int mode
) {
152 if ((mode
& ZLIB_FILEFUNC_MODE_READWRITEFILTER
) != ZLIB_FILEFUNC_MODE_READ
) {
156 ZipBuffer
* buffer
= static_cast<ZipBuffer
*>(opaque
);
157 if (!buffer
|| !buffer
->data
|| !buffer
->length
)
163 // Reads compressed data from the specified stream. This function copies data
164 // refered by the opaque parameter and returns the size actually copied.
165 uLong
ReadZipBuffer(void* opaque
, void* /*stream*/, void* buf
, uLong size
) {
166 ZipBuffer
* buffer
= static_cast<ZipBuffer
*>(opaque
);
167 DCHECK_LE(buffer
->offset
, buffer
->length
);
168 size_t remaining_bytes
= buffer
->length
- buffer
->offset
;
169 if (!buffer
|| !buffer
->data
|| !remaining_bytes
)
171 size
= std::min(size
, static_cast<uLong
>(remaining_bytes
));
172 memcpy(buf
, &buffer
->data
[buffer
->offset
], size
);
173 buffer
->offset
+= size
;
177 // Writes compressed data to the stream. This function always returns zero
178 // because this implementation is only for reading compressed data.
179 uLong
WriteZipBuffer(void* /*opaque*/,
187 // Returns the offset from the beginning of the data.
188 long GetOffsetOfZipBuffer(void* opaque
, void* /*stream*/) {
189 ZipBuffer
* buffer
= static_cast<ZipBuffer
*>(opaque
);
192 return static_cast<long>(buffer
->offset
);
195 // Moves the current offset to the specified position.
196 long SeekZipBuffer(void* opaque
, void* /*stream*/, uLong offset
, int origin
) {
197 ZipBuffer
* buffer
= static_cast<ZipBuffer
*>(opaque
);
200 if (origin
== ZLIB_FILEFUNC_SEEK_CUR
) {
201 buffer
->offset
= std::min(buffer
->offset
+ static_cast<size_t>(offset
),
205 if (origin
== ZLIB_FILEFUNC_SEEK_END
) {
206 buffer
->offset
= (buffer
->length
> offset
) ? buffer
->length
- offset
: 0;
209 if (origin
== ZLIB_FILEFUNC_SEEK_SET
) {
210 buffer
->offset
= std::min(buffer
->length
, static_cast<size_t>(offset
));
217 // Closes the input offset and deletes all resources used for compressing or
218 // uncompressing data. This function deletes the ZipBuffer object referred by
219 // the opaque parameter since zlib deletes the unzFile object and it does not
220 // use this object any longer.
221 int CloseZipBuffer(void* opaque
, void* /*stream*/) {
227 // Returns the last error happened when reading or writing data. This function
228 // always returns zero, which means there are not any errors.
229 int GetErrorOfZipBuffer(void* /*opaque*/, void* /*stream*/) {
233 // Returns a zip_fileinfo struct with the time represented by |file_time|.
234 zip_fileinfo
TimeToZipFileInfo(const base::Time
& file_time
) {
235 base::Time::Exploded file_time_parts
;
236 file_time
.LocalExplode(&file_time_parts
);
238 zip_fileinfo zip_info
= {};
239 if (file_time_parts
.year
>= 1980) {
240 // This if check works around the handling of the year value in
241 // contrib/minizip/zip.c in function zip64local_TmzDateToDosDate
242 // It assumes that dates below 1980 are in the double digit format.
243 // Hence the fail safe option is to leave the date unset. Some programs
244 // might show the unset date as 1980-0-0 which is invalid.
245 zip_info
.tmz_date
.tm_year
= file_time_parts
.year
;
246 zip_info
.tmz_date
.tm_mon
= file_time_parts
.month
- 1;
247 zip_info
.tmz_date
.tm_mday
= file_time_parts
.day_of_month
;
248 zip_info
.tmz_date
.tm_hour
= file_time_parts
.hour
;
249 zip_info
.tmz_date
.tm_min
= file_time_parts
.minute
;
250 zip_info
.tmz_date
.tm_sec
= file_time_parts
.second
;
260 unzFile
OpenForUnzipping(const std::string
& file_name_utf8
) {
261 zlib_filefunc_def
* zip_func_ptrs
= NULL
;
263 zlib_filefunc_def zip_funcs
;
264 fill_win32_filefunc(&zip_funcs
);
265 zip_funcs
.zopen_file
= ZipOpenFunc
;
266 zip_func_ptrs
= &zip_funcs
;
268 return unzOpen2(file_name_utf8
.c_str(), zip_func_ptrs
);
271 #if defined(OS_POSIX)
272 unzFile
OpenFdForUnzipping(int zip_fd
) {
273 zlib_filefunc_def zip_funcs
;
274 FillFdOpenFileFunc(&zip_funcs
, zip_fd
);
275 // Passing dummy "fd" filename to zlib.
276 return unzOpen2("fd", &zip_funcs
);
281 unzFile
OpenHandleForUnzipping(HANDLE zip_handle
) {
282 zlib_filefunc_def zip_funcs
;
283 fill_win32_filefunc(&zip_funcs
);
284 zip_funcs
.zopen_file
= HandleOpenFileFunc
;
285 zip_funcs
.opaque
= zip_handle
;
286 return unzOpen2("fd", &zip_funcs
);
291 unzFile
PrepareMemoryForUnzipping(const std::string
& data
) {
295 ZipBuffer
* buffer
= static_cast<ZipBuffer
*>(malloc(sizeof(ZipBuffer
)));
298 buffer
->data
= data
.data();
299 buffer
->length
= data
.length();
302 zlib_filefunc_def zip_functions
;
303 zip_functions
.zopen_file
= OpenZipBuffer
;
304 zip_functions
.zread_file
= ReadZipBuffer
;
305 zip_functions
.zwrite_file
= WriteZipBuffer
;
306 zip_functions
.ztell_file
= GetOffsetOfZipBuffer
;
307 zip_functions
.zseek_file
= SeekZipBuffer
;
308 zip_functions
.zclose_file
= CloseZipBuffer
;
309 zip_functions
.zerror_file
= GetErrorOfZipBuffer
;
310 zip_functions
.opaque
= static_cast<void*>(buffer
);
311 return unzOpen2(NULL
, &zip_functions
);
314 zipFile
OpenForZipping(const std::string
& file_name_utf8
, int append_flag
) {
315 zlib_filefunc_def
* zip_func_ptrs
= NULL
;
317 zlib_filefunc_def zip_funcs
;
318 fill_win32_filefunc(&zip_funcs
);
319 zip_funcs
.zopen_file
= ZipOpenFunc
;
320 zip_func_ptrs
= &zip_funcs
;
322 return zipOpen2(file_name_utf8
.c_str(),
324 NULL
, // global comment
328 #if defined(OS_POSIX)
329 zipFile
OpenFdForZipping(int zip_fd
, int append_flag
) {
330 zlib_filefunc_def zip_funcs
;
331 FillFdOpenFileFunc(&zip_funcs
, zip_fd
);
332 // Passing dummy "fd" filename to zlib.
333 return zipOpen2("fd", append_flag
, NULL
, &zip_funcs
);
337 zip_fileinfo
GetFileInfoForZipping(const base::FilePath
& path
) {
338 base::Time file_time
;
339 base::File::Info file_info
;
340 if (base::GetFileInfo(path
, &file_info
))
341 file_time
= file_info
.last_modified
;
342 return TimeToZipFileInfo(file_time
);
345 bool ZipOpenNewFileInZip(zipFile zip_file
,
346 const std::string
& str_path
,
347 const zip_fileinfo
* file_info
) {
348 // Section 4.4.4 http://www.pkware.com/documents/casestudies/APPNOTE.TXT
349 // Setting the Language encoding flag so the file is told to be in utf-8.
350 const uLong LANGUAGE_ENCODING_FLAG
= 0x1 << 11;
352 if (ZIP_OK
!= zipOpenNewFileInZip4(
354 str_path
.c_str(), // filename
356 NULL
, // extrafield_local,
357 0u, // size_extrafield_local
358 NULL
, // extrafield_global
359 0u, // size_extrafield_global
361 Z_DEFLATED
, // method
362 Z_DEFAULT_COMPRESSION
, // level
364 -MAX_WBITS
, // windowBits
365 DEF_MEM_LEVEL
, // memLevel
366 Z_DEFAULT_STRATEGY
, // strategy
370 LANGUAGE_ENCODING_FLAG
)) { // flagBase
371 DLOG(ERROR
) << "Could not open zip file entry " << str_path
;
377 } // namespace internal