Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / zlib / google / zip_internal.cc
blob1f026c987bf4800cc036c094993713d41c916bda
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"
7 #include <algorithm>
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>
18 #else
19 #include "third_party/zlib/contrib/minizip/unzip.h"
20 #include "third_party/zlib/contrib/minizip/zip.h"
21 #if defined(OS_WIN)
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)
28 namespace {
30 #if defined(OS_WIN)
31 typedef struct {
32 HANDLE hf;
33 int error;
34 } WIN32FILE_IOWIN;
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;
42 HANDLE file = 0;
43 void* ret = NULL;
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)
64 file = NULL;
66 if (file != NULL) {
67 WIN32FILE_IOWIN file_ret;
68 file_ret.hf = file;
69 file_ret.error = 0;
70 ret = malloc(sizeof(WIN32FILE_IOWIN));
71 if (ret == NULL)
72 CloseHandle(file);
73 else
74 *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret;
76 return ret;
78 #endif
80 #if defined(OS_POSIX)
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
83 // a file stream.
84 void* FdOpenFileFunc(void* opaque, const char* filename, int mode) {
85 FILE* file = NULL;
86 const char* mode_fopen = NULL;
88 if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
89 mode_fopen = "rb";
90 else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
91 mode_fopen = "r+b";
92 else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
93 mode_fopen = "wb";
95 if ((filename != NULL) && (mode_fopen != NULL)) {
96 int fd = dup(*static_cast<int*>(opaque));
97 if (fd != -1)
98 file = fdopen(fd, mode_fopen);
101 return file;
104 int FdCloseFileFunc(void* opaque, void* stream) {
105 fclose(static_cast<FILE*>(stream));
106 free(opaque); // malloc'ed in FillFdOpenFileFunc()
107 return 0;
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)));
117 *ptr_fd = fd;
118 pzlib_filefunc_def->opaque = ptr_fd;
120 #endif // defined(OS_POSIX)
122 #if defined(OS_WIN)
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);
128 file_ret.error = 0;
129 if (file_ret.hf == INVALID_HANDLE_VALUE)
130 return NULL;
132 void* ret = malloc(sizeof(WIN32FILE_IOWIN));
133 if (ret != NULL)
134 *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret;
135 return ret;
138 int HandleCloseFileFunc(void* opaque, void* stream) {
139 free(stream); // malloc'ed in HandleOpenFileFunc()
140 return 0;
142 #endif
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.
147 struct ZipBuffer {
148 const char* data; // weak
149 size_t length;
150 size_t offset;
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) {
161 NOTREACHED();
162 return NULL;
164 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
165 if (!buffer || !buffer->data || !buffer->length)
166 return NULL;
167 buffer->offset = 0;
168 return opaque;
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)
178 return 0;
179 size = std::min(size, static_cast<uLong>(remaining_bytes));
180 memcpy(buf, &buffer->data[buffer->offset], size);
181 buffer->offset += size;
182 return 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*/,
188 void* /*stream*/,
189 const void* /*buf*/,
190 uLong /*size*/) {
191 NOTREACHED();
192 return 0;
195 // Returns the offset from the beginning of the data.
196 long GetOffsetOfZipBuffer(void* opaque, void* /*stream*/) {
197 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
198 if (!buffer)
199 return -1;
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);
206 if (!buffer)
207 return -1;
208 if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
209 buffer->offset = std::min(buffer->offset + static_cast<size_t>(offset),
210 buffer->length);
211 return 0;
213 if (origin == ZLIB_FILEFUNC_SEEK_END) {
214 buffer->offset = (buffer->length > offset) ? buffer->length - offset : 0;
215 return 0;
217 if (origin == ZLIB_FILEFUNC_SEEK_SET) {
218 buffer->offset = std::min(buffer->length, static_cast<size_t>(offset));
219 return 0;
221 NOTREACHED();
222 return -1;
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*/) {
230 if (opaque)
231 free(opaque);
232 return 0;
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*/) {
238 return 0;
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;
261 return zip_info;
263 } // namespace
265 namespace zip {
266 namespace internal {
268 unzFile OpenForUnzipping(const std::string& file_name_utf8) {
269 zlib_filefunc_def* zip_func_ptrs = NULL;
270 #if defined(OS_WIN)
271 zlib_filefunc_def zip_funcs;
272 fill_win32_filefunc(&zip_funcs);
273 zip_funcs.zopen_file = ZipOpenFunc;
274 zip_func_ptrs = &zip_funcs;
275 #endif
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);
286 #endif
288 #if defined(OS_WIN)
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);
297 #endif
299 // static
300 unzFile PrepareMemoryForUnzipping(const std::string& data) {
301 if (data.empty())
302 return NULL;
304 ZipBuffer* buffer = static_cast<ZipBuffer*>(malloc(sizeof(ZipBuffer)));
305 if (!buffer)
306 return NULL;
307 buffer->data = data.data();
308 buffer->length = data.length();
309 buffer->offset = 0;
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;
325 #if defined(OS_WIN)
326 zlib_filefunc_def zip_funcs;
327 fill_win32_filefunc(&zip_funcs);
328 zip_funcs.zopen_file = ZipOpenFunc;
329 zip_func_ptrs = &zip_funcs;
330 #endif
331 return zipOpen2(file_name_utf8.c_str(),
332 append_flag,
333 NULL, // global comment
334 zip_func_ptrs);
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);
344 #endif
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(
362 zip_file, // file
363 str_path.c_str(), // filename
364 file_info, // zipfi
365 NULL, // extrafield_local,
366 0u, // size_extrafield_local
367 NULL, // extrafield_global
368 0u, // size_extrafield_global
369 NULL, // comment
370 Z_DEFLATED, // method
371 Z_DEFAULT_COMPRESSION, // level
372 0, // raw
373 -MAX_WBITS, // windowBits
374 DEF_MEM_LEVEL, // memLevel
375 Z_DEFAULT_STRATEGY, // strategy
376 NULL, // password
377 0, // crcForCrypting
378 0, // versionMadeBy
379 LANGUAGE_ENCODING_FLAG)) { // flagBase
380 DLOG(ERROR) << "Could not open zip file entry " << str_path;
381 return false;
383 return true;
386 } // namespace internal
387 } // namespace zip