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/files/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 // Since we do not own the file descriptor, dup it so that we can fdopen/fclose
84 void* FdOpenFileFunc(void* opaque
, const char* filename
, int mode
) {
86 const char* mode_fopen
= NULL
;
88 if ((mode
& ZLIB_FILEFUNC_MODE_READWRITEFILTER
) == ZLIB_FILEFUNC_MODE_READ
)
90 else if (mode
& ZLIB_FILEFUNC_MODE_EXISTING
)
92 else if (mode
& ZLIB_FILEFUNC_MODE_CREATE
)
95 if ((filename
!= NULL
) && (mode_fopen
!= NULL
)) {
96 int fd
= dup(*static_cast<int*>(opaque
));
98 file
= fdopen(fd
, mode_fopen
);
104 int FdCloseFileFunc(void* opaque
, void* stream
) {
105 fclose(static_cast<FILE*>(stream
));
106 free(opaque
); // malloc'ed in FillFdOpenFileFunc()
110 // Fills |pzlib_filecunc_def| appropriately to handle the zip file
111 // referred to by |fd|.
112 void FillFdOpenFileFunc(zlib_filefunc_def
* pzlib_filefunc_def
, int fd
) {
113 fill_fopen_filefunc(pzlib_filefunc_def
);
114 pzlib_filefunc_def
->zopen_file
= FdOpenFileFunc
;
115 pzlib_filefunc_def
->zclose_file
= FdCloseFileFunc
;
116 int* ptr_fd
= static_cast<int*>(malloc(sizeof(fd
)));
118 pzlib_filefunc_def
->opaque
= ptr_fd
;
120 #endif // defined(OS_POSIX)
123 // Callback function for zlib that opens a file stream from a Windows handle.
124 // Does not take ownership of the handle.
125 void* HandleOpenFileFunc(void* opaque
, const char* filename
, int mode
) {
126 WIN32FILE_IOWIN file_ret
;
127 file_ret
.hf
= static_cast<HANDLE
>(opaque
);
129 if (file_ret
.hf
== INVALID_HANDLE_VALUE
)
132 void* ret
= malloc(sizeof(WIN32FILE_IOWIN
));
134 *(static_cast<WIN32FILE_IOWIN
*>(ret
)) = file_ret
;
138 int HandleCloseFileFunc(void* opaque
, void* stream
) {
139 free(stream
); // malloc'ed in HandleOpenFileFunc()
144 // A struct that contains data required for zlib functions to extract files from
145 // a zip archive stored in memory directly. The following I/O API functions
146 // expect their opaque parameters refer to this struct.
148 const char* data
; // weak
153 // Opens the specified file. When this function returns a non-NULL pointer, zlib
154 // uses this pointer as a stream parameter while compressing or uncompressing
155 // data. (Returning NULL represents an error.) This function initializes the
156 // given opaque parameter and returns it because this parameter stores all
157 // information needed for uncompressing data. (This function does not support
158 // writing compressed data and it returns NULL for this case.)
159 void* OpenZipBuffer(void* opaque
, const char* /*filename*/, int mode
) {
160 if ((mode
& ZLIB_FILEFUNC_MODE_READWRITEFILTER
) != ZLIB_FILEFUNC_MODE_READ
) {
164 ZipBuffer
* buffer
= static_cast<ZipBuffer
*>(opaque
);
165 if (!buffer
|| !buffer
->data
|| !buffer
->length
)
171 // Reads compressed data from the specified stream. This function copies data
172 // refered by the opaque parameter and returns the size actually copied.
173 uLong
ReadZipBuffer(void* opaque
, void* /*stream*/, void* buf
, uLong size
) {
174 ZipBuffer
* buffer
= static_cast<ZipBuffer
*>(opaque
);
175 DCHECK_LE(buffer
->offset
, buffer
->length
);
176 size_t remaining_bytes
= buffer
->length
- buffer
->offset
;
177 if (!buffer
|| !buffer
->data
|| !remaining_bytes
)
179 size
= std::min(size
, static_cast<uLong
>(remaining_bytes
));
180 memcpy(buf
, &buffer
->data
[buffer
->offset
], size
);
181 buffer
->offset
+= size
;
185 // Writes compressed data to the stream. This function always returns zero
186 // because this implementation is only for reading compressed data.
187 uLong
WriteZipBuffer(void* /*opaque*/,
195 // Returns the offset from the beginning of the data.
196 long GetOffsetOfZipBuffer(void* opaque
, void* /*stream*/) {
197 ZipBuffer
* buffer
= static_cast<ZipBuffer
*>(opaque
);
200 return static_cast<long>(buffer
->offset
);
203 // Moves the current offset to the specified position.
204 long SeekZipBuffer(void* opaque
, void* /*stream*/, uLong offset
, int origin
) {
205 ZipBuffer
* buffer
= static_cast<ZipBuffer
*>(opaque
);
208 if (origin
== ZLIB_FILEFUNC_SEEK_CUR
) {
209 buffer
->offset
= std::min(buffer
->offset
+ static_cast<size_t>(offset
),
213 if (origin
== ZLIB_FILEFUNC_SEEK_END
) {
214 buffer
->offset
= (buffer
->length
> offset
) ? buffer
->length
- offset
: 0;
217 if (origin
== ZLIB_FILEFUNC_SEEK_SET
) {
218 buffer
->offset
= std::min(buffer
->length
, static_cast<size_t>(offset
));
225 // Closes the input offset and deletes all resources used for compressing or
226 // uncompressing data. This function deletes the ZipBuffer object referred by
227 // the opaque parameter since zlib deletes the unzFile object and it does not
228 // use this object any longer.
229 int CloseZipBuffer(void* opaque
, void* /*stream*/) {
235 // Returns the last error happened when reading or writing data. This function
236 // always returns zero, which means there are not any errors.
237 int GetErrorOfZipBuffer(void* /*opaque*/, void* /*stream*/) {
241 // Returns a zip_fileinfo struct with the time represented by |file_time|.
242 zip_fileinfo
TimeToZipFileInfo(const base::Time
& file_time
) {
243 base::Time::Exploded file_time_parts
;
244 file_time
.LocalExplode(&file_time_parts
);
246 zip_fileinfo zip_info
= {};
247 if (file_time_parts
.year
>= 1980) {
248 // This if check works around the handling of the year value in
249 // contrib/minizip/zip.c in function zip64local_TmzDateToDosDate
250 // It assumes that dates below 1980 are in the double digit format.
251 // Hence the fail safe option is to leave the date unset. Some programs
252 // might show the unset date as 1980-0-0 which is invalid.
253 zip_info
.tmz_date
.tm_year
= file_time_parts
.year
;
254 zip_info
.tmz_date
.tm_mon
= file_time_parts
.month
- 1;
255 zip_info
.tmz_date
.tm_mday
= file_time_parts
.day_of_month
;
256 zip_info
.tmz_date
.tm_hour
= file_time_parts
.hour
;
257 zip_info
.tmz_date
.tm_min
= file_time_parts
.minute
;
258 zip_info
.tmz_date
.tm_sec
= file_time_parts
.second
;
268 unzFile
OpenForUnzipping(const std::string
& file_name_utf8
) {
269 zlib_filefunc_def
* zip_func_ptrs
= NULL
;
271 zlib_filefunc_def zip_funcs
;
272 fill_win32_filefunc(&zip_funcs
);
273 zip_funcs
.zopen_file
= ZipOpenFunc
;
274 zip_func_ptrs
= &zip_funcs
;
276 return unzOpen2(file_name_utf8
.c_str(), zip_func_ptrs
);
279 #if defined(OS_POSIX)
280 unzFile
OpenFdForUnzipping(int zip_fd
) {
281 zlib_filefunc_def zip_funcs
;
282 FillFdOpenFileFunc(&zip_funcs
, zip_fd
);
283 // Passing dummy "fd" filename to zlib.
284 return unzOpen2("fd", &zip_funcs
);
289 unzFile
OpenHandleForUnzipping(HANDLE zip_handle
) {
290 zlib_filefunc_def zip_funcs
;
291 fill_win32_filefunc(&zip_funcs
);
292 zip_funcs
.zopen_file
= HandleOpenFileFunc
;
293 zip_funcs
.zclose_file
= HandleCloseFileFunc
;
294 zip_funcs
.opaque
= zip_handle
;
295 return unzOpen2("fd", &zip_funcs
);
300 unzFile
PrepareMemoryForUnzipping(const std::string
& data
) {
304 ZipBuffer
* buffer
= static_cast<ZipBuffer
*>(malloc(sizeof(ZipBuffer
)));
307 buffer
->data
= data
.data();
308 buffer
->length
= data
.length();
311 zlib_filefunc_def zip_functions
;
312 zip_functions
.zopen_file
= OpenZipBuffer
;
313 zip_functions
.zread_file
= ReadZipBuffer
;
314 zip_functions
.zwrite_file
= WriteZipBuffer
;
315 zip_functions
.ztell_file
= GetOffsetOfZipBuffer
;
316 zip_functions
.zseek_file
= SeekZipBuffer
;
317 zip_functions
.zclose_file
= CloseZipBuffer
;
318 zip_functions
.zerror_file
= GetErrorOfZipBuffer
;
319 zip_functions
.opaque
= static_cast<void*>(buffer
);
320 return unzOpen2(NULL
, &zip_functions
);
323 zipFile
OpenForZipping(const std::string
& file_name_utf8
, int append_flag
) {
324 zlib_filefunc_def
* zip_func_ptrs
= NULL
;
326 zlib_filefunc_def zip_funcs
;
327 fill_win32_filefunc(&zip_funcs
);
328 zip_funcs
.zopen_file
= ZipOpenFunc
;
329 zip_func_ptrs
= &zip_funcs
;
331 return zipOpen2(file_name_utf8
.c_str(),
333 NULL
, // global comment
337 #if defined(OS_POSIX)
338 zipFile
OpenFdForZipping(int zip_fd
, int append_flag
) {
339 zlib_filefunc_def zip_funcs
;
340 FillFdOpenFileFunc(&zip_funcs
, zip_fd
);
341 // Passing dummy "fd" filename to zlib.
342 return zipOpen2("fd", append_flag
, NULL
, &zip_funcs
);
346 zip_fileinfo
GetFileInfoForZipping(const base::FilePath
& path
) {
347 base::Time file_time
;
348 base::File::Info file_info
;
349 if (base::GetFileInfo(path
, &file_info
))
350 file_time
= file_info
.last_modified
;
351 return TimeToZipFileInfo(file_time
);
354 bool ZipOpenNewFileInZip(zipFile zip_file
,
355 const std::string
& str_path
,
356 const zip_fileinfo
* file_info
) {
357 // Section 4.4.4 http://www.pkware.com/documents/casestudies/APPNOTE.TXT
358 // Setting the Language encoding flag so the file is told to be in utf-8.
359 const uLong LANGUAGE_ENCODING_FLAG
= 0x1 << 11;
361 if (ZIP_OK
!= zipOpenNewFileInZip4(
363 str_path
.c_str(), // filename
365 NULL
, // extrafield_local,
366 0u, // size_extrafield_local
367 NULL
, // extrafield_global
368 0u, // size_extrafield_global
370 Z_DEFLATED
, // method
371 Z_DEFAULT_COMPRESSION
, // level
373 -MAX_WBITS
, // windowBits
374 DEF_MEM_LEVEL
, // memLevel
375 Z_DEFAULT_STRATEGY
, // strategy
379 LANGUAGE_ENCODING_FLAG
)) { // flagBase
380 DLOG(ERROR
) << "Could not open zip file entry " << str_path
;
386 } // namespace internal