OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "third_party/zlib/google/zip_internal.h" |
| 6 |
| 7 #include <stddef.h> |
| 8 |
| 9 #include <algorithm> |
| 10 |
| 11 #include "base/files/file_util.h" |
| 12 #include "base/logging.h" |
| 13 #include "base/strings/utf_string_conversions.h" |
| 14 #include "base/time/time.h" |
| 15 #include "build/build_config.h" |
| 16 |
| 17 #if defined(USE_SYSTEM_MINIZIP) |
| 18 #include <minizip/ioapi.h> |
| 19 #include <minizip/unzip.h> |
| 20 #include <minizip/zip.h> |
| 21 #else |
| 22 #include "third_party/zlib/contrib/minizip/unzip.h" |
| 23 #include "third_party/zlib/contrib/minizip/zip.h" |
| 24 #if defined(OS_WIN) |
| 25 #include "third_party/zlib/contrib/minizip/iowin32.h" |
| 26 #elif defined(OS_POSIX) |
| 27 #include "third_party/zlib/contrib/minizip/ioapi.h" |
| 28 #endif // defined(OS_POSIX) |
| 29 #endif // defined(USE_SYSTEM_MINIZIP) |
| 30 |
| 31 namespace { |
| 32 |
| 33 #if defined(OS_WIN) |
| 34 typedef struct { |
| 35 HANDLE hf; |
| 36 int error; |
| 37 } WIN32FILE_IOWIN; |
| 38 |
| 39 // This function is derived from third_party/minizip/iowin32.c. |
| 40 // Its only difference is that it treats the char* as UTF8 and |
| 41 // uses the Unicode version of CreateFile. |
| 42 void* ZipOpenFunc(void *opaque, const char* filename, int mode) { |
| 43 DWORD desired_access = 0, creation_disposition = 0; |
| 44 DWORD share_mode = 0, flags_and_attributes = 0; |
| 45 HANDLE file = 0; |
| 46 void* ret = NULL; |
| 47 |
| 48 if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) { |
| 49 desired_access = GENERIC_READ; |
| 50 creation_disposition = OPEN_EXISTING; |
| 51 share_mode = FILE_SHARE_READ; |
| 52 } else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) { |
| 53 desired_access = GENERIC_WRITE | GENERIC_READ; |
| 54 creation_disposition = OPEN_EXISTING; |
| 55 } else if (mode & ZLIB_FILEFUNC_MODE_CREATE) { |
| 56 desired_access = GENERIC_WRITE | GENERIC_READ; |
| 57 creation_disposition = CREATE_ALWAYS; |
| 58 } |
| 59 |
| 60 base::string16 filename16 = base::UTF8ToUTF16(filename); |
| 61 if ((filename != NULL) && (desired_access != 0)) { |
| 62 file = CreateFile(filename16.c_str(), desired_access, share_mode, |
| 63 NULL, creation_disposition, flags_and_attributes, NULL); |
| 64 } |
| 65 |
| 66 if (file == INVALID_HANDLE_VALUE) |
| 67 file = NULL; |
| 68 |
| 69 if (file != NULL) { |
| 70 WIN32FILE_IOWIN file_ret; |
| 71 file_ret.hf = file; |
| 72 file_ret.error = 0; |
| 73 ret = malloc(sizeof(WIN32FILE_IOWIN)); |
| 74 if (ret == NULL) |
| 75 CloseHandle(file); |
| 76 else |
| 77 *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret; |
| 78 } |
| 79 return ret; |
| 80 } |
| 81 #endif |
| 82 |
| 83 #if defined(OS_POSIX) |
| 84 // Callback function for zlib that opens a file stream from a file descriptor. |
| 85 // Since we do not own the file descriptor, dup it so that we can fdopen/fclose |
| 86 // a file stream. |
| 87 void* FdOpenFileFunc(void* opaque, const char* filename, int mode) { |
| 88 FILE* file = NULL; |
| 89 const char* mode_fopen = NULL; |
| 90 |
| 91 if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) |
| 92 mode_fopen = "rb"; |
| 93 else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) |
| 94 mode_fopen = "r+b"; |
| 95 else if (mode & ZLIB_FILEFUNC_MODE_CREATE) |
| 96 mode_fopen = "wb"; |
| 97 |
| 98 if ((filename != NULL) && (mode_fopen != NULL)) { |
| 99 int fd = dup(*static_cast<int*>(opaque)); |
| 100 if (fd != -1) |
| 101 file = fdopen(fd, mode_fopen); |
| 102 } |
| 103 |
| 104 return file; |
| 105 } |
| 106 |
| 107 int FdCloseFileFunc(void* opaque, void* stream) { |
| 108 fclose(static_cast<FILE*>(stream)); |
| 109 free(opaque); // malloc'ed in FillFdOpenFileFunc() |
| 110 return 0; |
| 111 } |
| 112 |
| 113 // Fills |pzlib_filecunc_def| appropriately to handle the zip file |
| 114 // referred to by |fd|. |
| 115 void FillFdOpenFileFunc(zlib_filefunc_def* pzlib_filefunc_def, int fd) { |
| 116 fill_fopen_filefunc(pzlib_filefunc_def); |
| 117 pzlib_filefunc_def->zopen_file = FdOpenFileFunc; |
| 118 pzlib_filefunc_def->zclose_file = FdCloseFileFunc; |
| 119 int* ptr_fd = static_cast<int*>(malloc(sizeof(fd))); |
| 120 *ptr_fd = fd; |
| 121 pzlib_filefunc_def->opaque = ptr_fd; |
| 122 } |
| 123 #endif // defined(OS_POSIX) |
| 124 |
| 125 #if defined(OS_WIN) |
| 126 // Callback function for zlib that opens a file stream from a Windows handle. |
| 127 // Does not take ownership of the handle. |
| 128 void* HandleOpenFileFunc(void* opaque, const char* filename, int mode) { |
| 129 WIN32FILE_IOWIN file_ret; |
| 130 file_ret.hf = static_cast<HANDLE>(opaque); |
| 131 file_ret.error = 0; |
| 132 if (file_ret.hf == INVALID_HANDLE_VALUE) |
| 133 return NULL; |
| 134 |
| 135 void* ret = malloc(sizeof(WIN32FILE_IOWIN)); |
| 136 if (ret != NULL) |
| 137 *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret; |
| 138 return ret; |
| 139 } |
| 140 |
| 141 int HandleCloseFileFunc(void* opaque, void* stream) { |
| 142 free(stream); // malloc'ed in HandleOpenFileFunc() |
| 143 return 0; |
| 144 } |
| 145 #endif |
| 146 |
| 147 // A struct that contains data required for zlib functions to extract files from |
| 148 // a zip archive stored in memory directly. The following I/O API functions |
| 149 // expect their opaque parameters refer to this struct. |
| 150 struct ZipBuffer { |
| 151 const char* data; // weak |
| 152 size_t length; |
| 153 size_t offset; |
| 154 }; |
| 155 |
| 156 // Opens the specified file. When this function returns a non-NULL pointer, zlib |
| 157 // uses this pointer as a stream parameter while compressing or uncompressing |
| 158 // data. (Returning NULL represents an error.) This function initializes the |
| 159 // given opaque parameter and returns it because this parameter stores all |
| 160 // information needed for uncompressing data. (This function does not support |
| 161 // writing compressed data and it returns NULL for this case.) |
| 162 void* OpenZipBuffer(void* opaque, const char* /*filename*/, int mode) { |
| 163 if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) { |
| 164 NOTREACHED(); |
| 165 return NULL; |
| 166 } |
| 167 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque); |
| 168 if (!buffer || !buffer->data || !buffer->length) |
| 169 return NULL; |
| 170 buffer->offset = 0; |
| 171 return opaque; |
| 172 } |
| 173 |
| 174 // Reads compressed data from the specified stream. This function copies data |
| 175 // refered by the opaque parameter and returns the size actually copied. |
| 176 uLong ReadZipBuffer(void* opaque, void* /*stream*/, void* buf, uLong size) { |
| 177 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque); |
| 178 DCHECK_LE(buffer->offset, buffer->length); |
| 179 size_t remaining_bytes = buffer->length - buffer->offset; |
| 180 if (!buffer || !buffer->data || !remaining_bytes) |
| 181 return 0; |
| 182 size = std::min(size, static_cast<uLong>(remaining_bytes)); |
| 183 memcpy(buf, &buffer->data[buffer->offset], size); |
| 184 buffer->offset += size; |
| 185 return size; |
| 186 } |
| 187 |
| 188 // Writes compressed data to the stream. This function always returns zero |
| 189 // because this implementation is only for reading compressed data. |
| 190 uLong WriteZipBuffer(void* /*opaque*/, |
| 191 void* /*stream*/, |
| 192 const void* /*buf*/, |
| 193 uLong /*size*/) { |
| 194 NOTREACHED(); |
| 195 return 0; |
| 196 } |
| 197 |
| 198 // Returns the offset from the beginning of the data. |
| 199 long GetOffsetOfZipBuffer(void* opaque, void* /*stream*/) { |
| 200 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque); |
| 201 if (!buffer) |
| 202 return -1; |
| 203 return static_cast<long>(buffer->offset); |
| 204 } |
| 205 |
| 206 // Moves the current offset to the specified position. |
| 207 long SeekZipBuffer(void* opaque, void* /*stream*/, uLong offset, int origin) { |
| 208 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque); |
| 209 if (!buffer) |
| 210 return -1; |
| 211 if (origin == ZLIB_FILEFUNC_SEEK_CUR) { |
| 212 buffer->offset = std::min(buffer->offset + static_cast<size_t>(offset), |
| 213 buffer->length); |
| 214 return 0; |
| 215 } |
| 216 if (origin == ZLIB_FILEFUNC_SEEK_END) { |
| 217 buffer->offset = (buffer->length > offset) ? buffer->length - offset : 0; |
| 218 return 0; |
| 219 } |
| 220 if (origin == ZLIB_FILEFUNC_SEEK_SET) { |
| 221 buffer->offset = std::min(buffer->length, static_cast<size_t>(offset)); |
| 222 return 0; |
| 223 } |
| 224 NOTREACHED(); |
| 225 return -1; |
| 226 } |
| 227 |
| 228 // Closes the input offset and deletes all resources used for compressing or |
| 229 // uncompressing data. This function deletes the ZipBuffer object referred by |
| 230 // the opaque parameter since zlib deletes the unzFile object and it does not |
| 231 // use this object any longer. |
| 232 int CloseZipBuffer(void* opaque, void* /*stream*/) { |
| 233 if (opaque) |
| 234 free(opaque); |
| 235 return 0; |
| 236 } |
| 237 |
| 238 // Returns the last error happened when reading or writing data. This function |
| 239 // always returns zero, which means there are not any errors. |
| 240 int GetErrorOfZipBuffer(void* /*opaque*/, void* /*stream*/) { |
| 241 return 0; |
| 242 } |
| 243 |
| 244 // Returns a zip_fileinfo struct with the time represented by |file_time|. |
| 245 zip_fileinfo TimeToZipFileInfo(const base::Time& file_time) { |
| 246 base::Time::Exploded file_time_parts; |
| 247 file_time.LocalExplode(&file_time_parts); |
| 248 |
| 249 zip_fileinfo zip_info = {}; |
| 250 if (file_time_parts.year >= 1980) { |
| 251 // This if check works around the handling of the year value in |
| 252 // contrib/minizip/zip.c in function zip64local_TmzDateToDosDate |
| 253 // It assumes that dates below 1980 are in the double digit format. |
| 254 // Hence the fail safe option is to leave the date unset. Some programs |
| 255 // might show the unset date as 1980-0-0 which is invalid. |
| 256 zip_info.tmz_date.tm_year = file_time_parts.year; |
| 257 zip_info.tmz_date.tm_mon = file_time_parts.month - 1; |
| 258 zip_info.tmz_date.tm_mday = file_time_parts.day_of_month; |
| 259 zip_info.tmz_date.tm_hour = file_time_parts.hour; |
| 260 zip_info.tmz_date.tm_min = file_time_parts.minute; |
| 261 zip_info.tmz_date.tm_sec = file_time_parts.second; |
| 262 } |
| 263 |
| 264 return zip_info; |
| 265 } |
| 266 } // namespace |
| 267 |
| 268 namespace zip { |
| 269 namespace internal { |
| 270 |
| 271 unzFile OpenForUnzipping(const std::string& file_name_utf8) { |
| 272 zlib_filefunc_def* zip_func_ptrs = NULL; |
| 273 #if defined(OS_WIN) |
| 274 zlib_filefunc_def zip_funcs; |
| 275 fill_win32_filefunc(&zip_funcs); |
| 276 zip_funcs.zopen_file = ZipOpenFunc; |
| 277 zip_func_ptrs = &zip_funcs; |
| 278 #endif |
| 279 return unzOpen2(file_name_utf8.c_str(), zip_func_ptrs); |
| 280 } |
| 281 |
| 282 #if defined(OS_POSIX) |
| 283 unzFile OpenFdForUnzipping(int zip_fd) { |
| 284 zlib_filefunc_def zip_funcs; |
| 285 FillFdOpenFileFunc(&zip_funcs, zip_fd); |
| 286 // Passing dummy "fd" filename to zlib. |
| 287 return unzOpen2("fd", &zip_funcs); |
| 288 } |
| 289 #endif |
| 290 |
| 291 #if defined(OS_WIN) |
| 292 unzFile OpenHandleForUnzipping(HANDLE zip_handle) { |
| 293 zlib_filefunc_def zip_funcs; |
| 294 fill_win32_filefunc(&zip_funcs); |
| 295 zip_funcs.zopen_file = HandleOpenFileFunc; |
| 296 zip_funcs.zclose_file = HandleCloseFileFunc; |
| 297 zip_funcs.opaque = zip_handle; |
| 298 return unzOpen2("fd", &zip_funcs); |
| 299 } |
| 300 #endif |
| 301 |
| 302 // static |
| 303 unzFile PrepareMemoryForUnzipping(const std::string& data) { |
| 304 if (data.empty()) |
| 305 return NULL; |
| 306 |
| 307 ZipBuffer* buffer = static_cast<ZipBuffer*>(malloc(sizeof(ZipBuffer))); |
| 308 if (!buffer) |
| 309 return NULL; |
| 310 buffer->data = data.data(); |
| 311 buffer->length = data.length(); |
| 312 buffer->offset = 0; |
| 313 |
| 314 zlib_filefunc_def zip_functions; |
| 315 zip_functions.zopen_file = OpenZipBuffer; |
| 316 zip_functions.zread_file = ReadZipBuffer; |
| 317 zip_functions.zwrite_file = WriteZipBuffer; |
| 318 zip_functions.ztell_file = GetOffsetOfZipBuffer; |
| 319 zip_functions.zseek_file = SeekZipBuffer; |
| 320 zip_functions.zclose_file = CloseZipBuffer; |
| 321 zip_functions.zerror_file = GetErrorOfZipBuffer; |
| 322 zip_functions.opaque = static_cast<void*>(buffer); |
| 323 return unzOpen2(NULL, &zip_functions); |
| 324 } |
| 325 |
| 326 zipFile OpenForZipping(const std::string& file_name_utf8, int append_flag) { |
| 327 zlib_filefunc_def* zip_func_ptrs = NULL; |
| 328 #if defined(OS_WIN) |
| 329 zlib_filefunc_def zip_funcs; |
| 330 fill_win32_filefunc(&zip_funcs); |
| 331 zip_funcs.zopen_file = ZipOpenFunc; |
| 332 zip_func_ptrs = &zip_funcs; |
| 333 #endif |
| 334 return zipOpen2(file_name_utf8.c_str(), |
| 335 append_flag, |
| 336 NULL, // global comment |
| 337 zip_func_ptrs); |
| 338 } |
| 339 |
| 340 #if defined(OS_POSIX) |
| 341 zipFile OpenFdForZipping(int zip_fd, int append_flag) { |
| 342 zlib_filefunc_def zip_funcs; |
| 343 FillFdOpenFileFunc(&zip_funcs, zip_fd); |
| 344 // Passing dummy "fd" filename to zlib. |
| 345 return zipOpen2("fd", append_flag, NULL, &zip_funcs); |
| 346 } |
| 347 #endif |
| 348 |
| 349 zip_fileinfo GetFileInfoForZipping(const base::FilePath& path) { |
| 350 base::Time file_time; |
| 351 base::File::Info file_info; |
| 352 if (base::GetFileInfo(path, &file_info)) |
| 353 file_time = file_info.last_modified; |
| 354 return TimeToZipFileInfo(file_time); |
| 355 } |
| 356 |
| 357 bool ZipOpenNewFileInZip(zipFile zip_file, |
| 358 const std::string& str_path, |
| 359 const zip_fileinfo* file_info) { |
| 360 // Section 4.4.4 http://www.pkware.com/documents/casestudies/APPNOTE.TXT |
| 361 // Setting the Language encoding flag so the file is told to be in utf-8. |
| 362 const uLong LANGUAGE_ENCODING_FLAG = 0x1 << 11; |
| 363 |
| 364 if (ZIP_OK != zipOpenNewFileInZip4( |
| 365 zip_file, // file |
| 366 str_path.c_str(), // filename |
| 367 file_info, // zipfi |
| 368 NULL, // extrafield_local, |
| 369 0u, // size_extrafield_local |
| 370 NULL, // extrafield_global |
| 371 0u, // size_extrafield_global |
| 372 NULL, // comment |
| 373 Z_DEFLATED, // method |
| 374 Z_DEFAULT_COMPRESSION, // level |
| 375 0, // raw |
| 376 -MAX_WBITS, // windowBits |
| 377 DEF_MEM_LEVEL, // memLevel |
| 378 Z_DEFAULT_STRATEGY, // strategy |
| 379 NULL, // password |
| 380 0, // crcForCrypting |
| 381 0, // versionMadeBy |
| 382 LANGUAGE_ENCODING_FLAG)) { // flagBase |
| 383 DLOG(ERROR) << "Could not open zip file entry " << str_path; |
| 384 return false; |
| 385 } |
| 386 return true; |
| 387 } |
| 388 |
| 389 } // namespace internal |
| 390 } // namespace zip |
OLD | NEW |