| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013 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 "chrome/test/chromedriver/zip.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "base/utf_string_conversions.h" | |
| 11 | |
| 12 #if defined(USE_SYSTEM_MINIZIP) | |
| 13 #include <minizip/unzip.h> | |
| 14 #include <minizip/zip.h> | |
| 15 #include <minizip/ioapi.h> | |
| 16 #else | |
| 17 #include "third_party/zlib/contrib/minizip/unzip.h" | |
| 18 #include "third_party/zlib/contrib/minizip/zip.h" | |
| 19 #if defined(OS_WIN) | |
| 20 #include "third_party/zlib/contrib/minizip/iowin32.h" | |
| 21 #elif defined(OS_POSIX) | |
| 22 #include "third_party/zlib/contrib/minizip/ioapi.h" | |
| 23 #endif // defined(OS_POSIX) | |
| 24 #endif // defined(USE_SYSTEM_MINIZIP) | |
| 25 | |
| 26 namespace { | |
| 27 | |
| 28 #if defined(OS_WIN) | |
| 29 typedef struct { | |
| 30 HANDLE hf; | |
| 31 int error; | |
| 32 } WIN32FILE_IOWIN; | |
| 33 | |
| 34 // This function is derived from third_party/minizip/iowin32.c. | |
| 35 // Its only difference is that it treats the char* as UTF8 and | |
| 36 // uses the Unicode version of CreateFile. | |
| 37 void* ZipOpenFunc(void *opaque, const char* filename, int mode) { | |
| 38 DWORD desired_access, creation_disposition; | |
| 39 DWORD share_mode, flags_and_attributes; | |
| 40 HANDLE file = 0; | |
| 41 void* ret = NULL; | |
| 42 | |
| 43 desired_access = share_mode = flags_and_attributes = 0; | |
| 44 | |
| 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; | |
| 55 } | |
| 56 | |
| 57 string16 filename16 = 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); | |
| 61 } | |
| 62 | |
| 63 if (file == INVALID_HANDLE_VALUE) | |
| 64 file = NULL; | |
| 65 | |
| 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; | |
| 75 } | |
| 76 return ret; | |
| 77 } | |
| 78 #endif | |
| 79 | |
| 80 #if defined(OS_POSIX) | |
| 81 // Callback function for zlib that opens a file stream from a file descriptor. | |
| 82 void* FdOpenFileFunc(void* opaque, const char* filename, int mode) { | |
| 83 FILE* file = NULL; | |
| 84 const char* mode_fopen = NULL; | |
| 85 | |
| 86 if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) | |
| 87 mode_fopen = "rb"; | |
| 88 else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) | |
| 89 mode_fopen = "r+b"; | |
| 90 else if (mode & ZLIB_FILEFUNC_MODE_CREATE) | |
| 91 mode_fopen = "wb"; | |
| 92 | |
| 93 if ((filename != NULL) && (mode_fopen != NULL)) | |
| 94 file = fdopen(*static_cast<int*>(opaque), mode_fopen); | |
| 95 | |
| 96 return file; | |
| 97 } | |
| 98 | |
| 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)); | |
| 104 free(opaque); | |
| 105 return 0; | |
| 106 } | |
| 107 | |
| 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))); | |
| 115 *ptr_fd = fd; | |
| 116 pzlib_filefunc_def->opaque = ptr_fd; | |
| 117 } | |
| 118 #endif // defined(OS_POSIX) | |
| 119 | |
| 120 #if defined(OS_WIN) | |
| 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); | |
| 125 file_ret.error = 0; | |
| 126 if (file_ret.hf == INVALID_HANDLE_VALUE) | |
| 127 return NULL; | |
| 128 | |
| 129 void* ret = malloc(sizeof(WIN32FILE_IOWIN)); | |
| 130 if (ret != NULL) | |
| 131 *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret; | |
| 132 return ret; | |
| 133 } | |
| 134 #endif | |
| 135 | |
| 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. | |
| 139 struct ZipBuffer { | |
| 140 const char* data; // weak | |
| 141 size_t length; | |
| 142 size_t offset; | |
| 143 }; | |
| 144 | |
| 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) { | |
| 153 NOTREACHED(); | |
| 154 return NULL; | |
| 155 } | |
| 156 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque); | |
| 157 if (!buffer || !buffer->data || !buffer->length) | |
| 158 return NULL; | |
| 159 buffer->offset = 0; | |
| 160 return opaque; | |
| 161 } | |
| 162 | |
| 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) | |
| 170 return 0; | |
| 171 size = std::min(size, static_cast<uLong>(remaining_bytes)); | |
| 172 memcpy(buf, &buffer->data[buffer->offset], size); | |
| 173 buffer->offset += size; | |
| 174 return size; | |
| 175 } | |
| 176 | |
| 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*/, | |
| 180 void* /*stream*/, | |
| 181 const void* /*buf*/, | |
| 182 uLong /*size*/) { | |
| 183 NOTREACHED(); | |
| 184 return 0; | |
| 185 } | |
| 186 | |
| 187 // Returns the offset from the beginning of the data. | |
| 188 long GetOffsetOfZipBuffer(void* opaque, void* /*stream*/) { | |
| 189 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque); | |
| 190 if (!buffer) | |
| 191 return -1; | |
| 192 return static_cast<long>(buffer->offset); | |
| 193 } | |
| 194 | |
| 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); | |
| 198 if (!buffer) | |
| 199 return -1; | |
| 200 if (origin == ZLIB_FILEFUNC_SEEK_CUR) { | |
| 201 buffer->offset = std::min(buffer->offset + static_cast<size_t>(offset), | |
| 202 buffer->length); | |
| 203 return 0; | |
| 204 } | |
| 205 if (origin == ZLIB_FILEFUNC_SEEK_END) { | |
| 206 buffer->offset = (buffer->length > offset) ? buffer->length - offset : 0; | |
| 207 return 0; | |
| 208 } | |
| 209 if (origin == ZLIB_FILEFUNC_SEEK_SET) { | |
| 210 buffer->offset = std::min(buffer->length, static_cast<size_t>(offset)); | |
| 211 return 0; | |
| 212 } | |
| 213 NOTREACHED(); | |
| 214 return -1; | |
| 215 } | |
| 216 | |
| 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*/) { | |
| 222 if (opaque) | |
| 223 free(opaque); | |
| 224 return 0; | |
| 225 } | |
| 226 | |
| 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*/) { | |
| 230 return 0; | |
| 231 } | |
| 232 | |
| 233 } // namespace | |
| 234 | |
| 235 namespace zip { | |
| 236 namespace internal { | |
| 237 | |
| 238 unzFile OpenForUnzipping(const std::string& file_name_utf8) { | |
| 239 zlib_filefunc_def* zip_func_ptrs = NULL; | |
| 240 #if defined(OS_WIN) | |
| 241 zlib_filefunc_def zip_funcs; | |
| 242 fill_win32_filefunc(&zip_funcs); | |
| 243 zip_funcs.zopen_file = ZipOpenFunc; | |
| 244 zip_func_ptrs = &zip_funcs; | |
| 245 #endif | |
| 246 return unzOpen2(file_name_utf8.c_str(), zip_func_ptrs); | |
| 247 } | |
| 248 | |
| 249 #if defined(OS_POSIX) | |
| 250 unzFile OpenFdForUnzipping(int zip_fd) { | |
| 251 zlib_filefunc_def zip_funcs; | |
| 252 FillFdOpenFileFunc(&zip_funcs, zip_fd); | |
| 253 // Passing dummy "fd" filename to zlib. | |
| 254 return unzOpen2("fd", &zip_funcs); | |
| 255 } | |
| 256 #endif | |
| 257 | |
| 258 #if defined(OS_WIN) | |
| 259 unzFile OpenHandleForUnzipping(HANDLE zip_handle) { | |
| 260 zlib_filefunc_def zip_funcs; | |
| 261 fill_win32_filefunc(&zip_funcs); | |
| 262 zip_funcs.zopen_file = HandleOpenFileFunc; | |
| 263 zip_funcs.opaque = zip_handle; | |
| 264 return unzOpen2("fd", &zip_funcs); | |
| 265 } | |
| 266 #endif | |
| 267 | |
| 268 // static | |
| 269 unzFile PreprareMemoryForUnzipping(const std::string& data) { | |
| 270 if (data.empty()) | |
| 271 return NULL; | |
| 272 | |
| 273 ZipBuffer* buffer = static_cast<ZipBuffer*>(malloc(sizeof(ZipBuffer))); | |
| 274 if (!buffer) | |
| 275 return NULL; | |
| 276 buffer->data = data.data(); | |
| 277 buffer->length = data.length(); | |
| 278 buffer->offset = 0; | |
| 279 | |
| 280 zlib_filefunc_def zip_functions; | |
| 281 zip_functions.zopen_file = OpenZipBuffer; | |
| 282 zip_functions.zread_file = ReadZipBuffer; | |
| 283 zip_functions.zwrite_file = WriteZipBuffer; | |
| 284 zip_functions.ztell_file = GetOffsetOfZipBuffer; | |
| 285 zip_functions.zseek_file = SeekZipBuffer; | |
| 286 zip_functions.zclose_file = CloseZipBuffer; | |
| 287 zip_functions.zerror_file = GetErrorOfZipBuffer; | |
| 288 zip_functions.opaque = static_cast<void*>(buffer); | |
| 289 return unzOpen2(NULL, &zip_functions); | |
| 290 } | |
| 291 | |
| 292 zipFile OpenForZipping(const std::string& file_name_utf8, int append_flag) { | |
| 293 zlib_filefunc_def* zip_func_ptrs = NULL; | |
| 294 #if defined(OS_WIN) | |
| 295 zlib_filefunc_def zip_funcs; | |
| 296 fill_win32_filefunc(&zip_funcs); | |
| 297 zip_funcs.zopen_file = ZipOpenFunc; | |
| 298 zip_func_ptrs = &zip_funcs; | |
| 299 #endif | |
| 300 return zipOpen2(file_name_utf8.c_str(), | |
| 301 append_flag, | |
| 302 NULL, // global comment | |
| 303 zip_func_ptrs); | |
| 304 } | |
| 305 | |
| 306 #if defined(OS_POSIX) | |
| 307 zipFile OpenFdForZipping(int zip_fd, int append_flag) { | |
| 308 zlib_filefunc_def zip_funcs; | |
| 309 FillFdOpenFileFunc(&zip_funcs, zip_fd); | |
| 310 // Passing dummy "fd" filename to zlib. | |
| 311 return zipOpen2("fd", append_flag, NULL, &zip_funcs); | |
| 312 } | |
| 313 #endif | |
| 314 | |
| 315 } // namespace internal | |
| 316 } // namespace zip | |
| OLD | NEW |