Extract SIGPIPE ignoring code to a common place.
[chromium-blink-merge.git] / chrome / common / zip_internal.cc
blobfe84696fd13fc1b2013269a0e8ededf931ee4d9b
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 "chrome/common/zip.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #include "base/utf_string_conversions.h"
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)
26 namespace {
28 #if defined(OS_WIN)
29 typedef struct {
30 HANDLE hf;
31 int error;
32 } WIN32FILE_IOWIN;
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;
43 desired_access = share_mode = 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 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);
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 void* FdOpenFileFunc(void* opaque, const char* filename, int mode) {
83 FILE* file = NULL;
84 const char* mode_fopen = NULL;
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";
93 if ((filename != NULL) && (mode_fopen != NULL))
94 file = fdopen(*static_cast<int*>(opaque), mode_fopen);
96 return file;
99 // We don't actually close the file stream since that would close
100 // the underlying file descriptor, and we don't own it. We do free
101 // |opaque| since we malloc'ed it in FillFdOpenFileFunc.
102 int CloseFileFunc(void* opaque, void* stream) {
103 free(opaque);
104 return 0;
107 // Fills |pzlib_filecunc_def| appropriately to handle the zip file
108 // referred to by |fd|.
109 void FillFdOpenFileFunc(zlib_filefunc_def* pzlib_filefunc_def, int fd) {
110 fill_fopen_filefunc(pzlib_filefunc_def);
111 pzlib_filefunc_def->zopen_file = FdOpenFileFunc;
112 pzlib_filefunc_def->zclose_file = CloseFileFunc;
113 int* ptr_fd = static_cast<int*>(malloc(sizeof(fd)));
114 *ptr_fd = fd;
115 pzlib_filefunc_def->opaque = ptr_fd;
117 #endif // defined(OS_POSIX)
119 // A struct that contains data required for zlib functions to extract files from
120 // a zip archive stored in memory directly. The following I/O API functions
121 // expect their opaque parameters refer to this struct.
122 struct ZipBuffer {
123 const char* data; // weak
124 size_t length;
125 size_t offset;
128 // Opens the specified file. When this function returns a non-NULL pointer, zlib
129 // uses this pointer as a stream parameter while compressing or uncompressing
130 // data. (Returning NULL represents an error.) This function initializes the
131 // given opaque parameter and returns it because this parameter stores all
132 // information needed for uncompressing data. (This function does not support
133 // writing compressed data and it returns NULL for this case.)
134 void* OpenZipBuffer(void* opaque, const char* /*filename*/, int mode) {
135 if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) {
136 NOTREACHED();
137 return NULL;
139 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
140 if (!buffer || !buffer->data || !buffer->length)
141 return NULL;
142 buffer->offset = 0;
143 return opaque;
146 // Reads compressed data from the specified stream. This function copies data
147 // refered by the opaque parameter and returns the size actually copied.
148 uLong ReadZipBuffer(void* opaque, void* /*stream*/, void* buf, uLong size) {
149 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
150 DCHECK_LE(buffer->offset, buffer->length);
151 size_t remaining_bytes = buffer->length - buffer->offset;
152 if (!buffer || !buffer->data || !remaining_bytes)
153 return 0;
154 size = std::min(size, static_cast<uLong>(remaining_bytes));
155 memcpy(buf, &buffer->data[buffer->offset], size);
156 buffer->offset += size;
157 return size;
160 // Writes compressed data to the stream. This function always returns zero
161 // because this implementation is only for reading compressed data.
162 uLong WriteZipBuffer(void* /*opaque*/,
163 void* /*stream*/,
164 const void* /*buf*/,
165 uLong /*size*/) {
166 NOTREACHED();
167 return 0;
170 // Returns the offset from the beginning of the data.
171 long GetOffsetOfZipBuffer(void* opaque, void* /*stream*/) {
172 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
173 if (!buffer)
174 return -1;
175 return static_cast<long>(buffer->offset);
178 // Moves the current offset to the specified position.
179 long SeekZipBuffer(void* opaque, void* /*stream*/, uLong offset, int origin) {
180 ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
181 if (!buffer)
182 return -1;
183 if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
184 buffer->offset = std::min(buffer->offset + static_cast<size_t>(offset),
185 buffer->length);
186 return 0;
188 if (origin == ZLIB_FILEFUNC_SEEK_END) {
189 buffer->offset = (buffer->length > offset) ? buffer->length - offset : 0;
190 return 0;
192 if (origin == ZLIB_FILEFUNC_SEEK_SET) {
193 buffer->offset = std::min(buffer->length, static_cast<size_t>(offset));
194 return 0;
196 NOTREACHED();
197 return -1;
200 // Closes the input offset and deletes all resources used for compressing or
201 // uncompressing data. This function deletes the ZipBuffer object referred by
202 // the opaque parameter since zlib deletes the unzFile object and it does not
203 // use this object any longer.
204 int CloseZipBuffer(void* opaque, void* /*stream*/) {
205 if (opaque)
206 free(opaque);
207 return 0;
210 // Returns the last error happened when reading or writing data. This function
211 // always returns zero, which means there are not any errors.
212 int GetErrorOfZipBuffer(void* /*opaque*/, void* /*stream*/) {
213 return 0;
216 } // namespace
218 namespace zip {
219 namespace internal {
221 unzFile OpenForUnzipping(const std::string& file_name_utf8) {
222 zlib_filefunc_def* zip_func_ptrs = NULL;
223 #if defined(OS_WIN)
224 zlib_filefunc_def zip_funcs;
225 fill_win32_filefunc(&zip_funcs);
226 zip_funcs.zopen_file = ZipOpenFunc;
227 zip_func_ptrs = &zip_funcs;
228 #endif
229 return unzOpen2(file_name_utf8.c_str(), zip_func_ptrs);
232 #if defined(OS_POSIX)
233 unzFile OpenFdForUnzipping(int zip_fd) {
234 zlib_filefunc_def zip_funcs;
235 FillFdOpenFileFunc(&zip_funcs, zip_fd);
236 // Passing dummy "fd" filename to zlib.
237 return unzOpen2("fd", &zip_funcs);
239 #endif
241 // static
242 unzFile PreprareMemoryForUnzipping(const std::string& data) {
243 if (data.empty())
244 return NULL;
246 ZipBuffer* buffer = static_cast<ZipBuffer*>(malloc(sizeof(ZipBuffer)));
247 if (!buffer)
248 return NULL;
249 buffer->data = data.data();
250 buffer->length = data.length();
251 buffer->offset = 0;
253 zlib_filefunc_def zip_functions;
254 zip_functions.zopen_file = OpenZipBuffer;
255 zip_functions.zread_file = ReadZipBuffer;
256 zip_functions.zwrite_file = WriteZipBuffer;
257 zip_functions.ztell_file = GetOffsetOfZipBuffer;
258 zip_functions.zseek_file = SeekZipBuffer;
259 zip_functions.zclose_file = CloseZipBuffer;
260 zip_functions.zerror_file = GetErrorOfZipBuffer;
261 zip_functions.opaque = static_cast<void*>(buffer);
262 return unzOpen2(NULL, &zip_functions);
265 zipFile OpenForZipping(const std::string& file_name_utf8, int append_flag) {
266 zlib_filefunc_def* zip_func_ptrs = NULL;
267 #if defined(OS_WIN)
268 zlib_filefunc_def zip_funcs;
269 fill_win32_filefunc(&zip_funcs);
270 zip_funcs.zopen_file = ZipOpenFunc;
271 zip_func_ptrs = &zip_funcs;
272 #endif
273 return zipOpen2(file_name_utf8.c_str(),
274 append_flag,
275 NULL, // global comment
276 zip_func_ptrs);
279 } // namespace internal
280 } // namespace zip