- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / zlib / google / zip_internal.cc
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.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "base/strings/utf_string_conversions.h"
11
12 #if defined(USE_SYSTEM_MINIZIP)
13 #include <minizip/ioapi.h>
14 #include <minizip/unzip.h>
15 #include <minizip/zip.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   base::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