Chromium Code Reviews
[email protected] (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(974)

Side by Side Diff: chrome/common/zip.cc

Issue 118028: Implements a Zip() utility function. Refactor existing (Closed)
Patch Set: Attempt to get rietveld to recognize copies Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2009 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/common/zip.h"
6
7 #include "base/file_util.h"
8 #include "base/string_util.h"
9 #include "net/base/file_stream.h"
10 #include "third_party/zlib/contrib/minizip/unzip.h"
11 #include "third_party/zlib/contrib/minizip/zip.h"
12 #if defined(OS_WIN)
13 #include "third_party/zlib/contrib/minizip/iowin32.h"
14 #endif
15
16 static const int kZipMaxPath = 256;
17 static const int kZipBufSize = 8192;
18
19 // Extract the 'current' selected file from the zip into dest_dir.
20 // Output filename is stored in out_file. Returns true on success.
21 static bool ExtractCurrentFile(unzFile zip_file,
22 const FilePath& dest_dir,
23 FilePath* out_file) {
24 char filename_inzip[kZipMaxPath] = {0};
25 unz_file_info file_info;
26 int err = unzGetCurrentFileInfo(zip_file, &file_info, filename_inzip,
27 sizeof(filename_inzip), NULL, 0, NULL, 0);
28 if (err != UNZ_OK)
29 return false;
30 if (filename_inzip[0] == '\0')
31 return false;
32
33 err = unzOpenCurrentFile(zip_file);
34 if (err != UNZ_OK)
35 return false;
36
37 FilePath::StringType filename;
38 std::vector<FilePath::StringType> filename_parts;
39 #if defined(OS_WIN)
40 filename = UTF8ToWide(filename_inzip);
41 #elif defined(OS_POSIX)
42 filename = filename_inzip;
43 #endif
44 SplitString(filename, '/', &filename_parts);
45
46 FilePath dest_file(dest_dir);
47 std::vector<FilePath::StringType>::iterator iter;
48 for (iter = filename_parts.begin(); iter != filename_parts.end(); ++iter)
49 dest_file = dest_file.Append(*iter);
50 if (out_file)
51 *out_file = dest_file;
52 // If this is a directory, just create it and return.
53 if (filename_inzip[strlen(filename_inzip) - 1] == '/') {
54 if (!file_util::CreateDirectory(dest_file))
55 return false;
56 return true;
57 }
58 // TODO(erikkay): Can we always count on the directory entry coming before a
59 // file in that directory? If so, then these three lines can be removed.
60 FilePath dir = dest_file.DirName();
61 if (!file_util::CreateDirectory(dir))
62 return false;
63
64 net::FileStream stream;
65 int flags = base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE;
66 if (stream.Open(dest_file, flags) != 0)
67 return false;
68
69 bool ret = true;
70 int num_bytes = 0;
71 char buf[kZipBufSize];
72 do {
73 num_bytes = unzReadCurrentFile(zip_file, buf, kZipBufSize);
74 if (num_bytes < 0) {
75 // If num_bytes < 0, then it's a specific UNZ_* error code.
76 // While we're not currently handling these codes specifically, save
77 // it away in case we want to in the future.
78 err = num_bytes;
79 break;
80 }
81 if (num_bytes > 0) {
82 if (num_bytes != stream.Write(buf, num_bytes, NULL)) {
83 ret = false;
84 break;
85 }
86 }
87 } while (num_bytes > 0);
88
89 stream.Close();
90 if (err == UNZ_OK)
91 err = unzCloseCurrentFile(zip_file);
92 else
93 unzCloseCurrentFile(zip_file); // Don't lose the original error code.
94 if (err != UNZ_OK)
95 ret = false;
96 return ret;
97 }
98
99 #if defined(OS_WIN)
100 typedef struct {
101 HANDLE hf;
102 int error;
103 } WIN32FILE_IOWIN;
104
105 // This function is derived from third_party/minizip/iowin32.c.
106 // Its only difference is that it treats the char* as UTF8 and
107 // uses the Unicode version of CreateFile.
108 static void* ZipOpenFunc(void *opaque, const char* filename, int mode) {
109 DWORD desired_access, creation_disposition;
110 DWORD share_mode, flags_and_attributes;
111 HANDLE file = 0;
112 void* ret = NULL;
113
114 desired_access = share_mode = flags_and_attributes = 0;
115
116 if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
117 desired_access = GENERIC_READ;
118 creation_disposition = OPEN_EXISTING;
119 share_mode = FILE_SHARE_READ;
120 } else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) {
121 desired_access = GENERIC_WRITE | GENERIC_READ;
122 creation_disposition = OPEN_EXISTING;
123 } else if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
124 desired_access = GENERIC_WRITE | GENERIC_READ;
125 creation_disposition = CREATE_ALWAYS;
126 }
127
128 std::wstring filename_wstr = UTF8ToWide(filename);
129 if ((filename != NULL) && (desired_access != 0)) {
130 file = CreateFile(filename_wstr.c_str(), desired_access, share_mode,
131 NULL, creation_disposition, flags_and_attributes, NULL);
132 }
133
134 if (file == INVALID_HANDLE_VALUE)
135 file = NULL;
136
137 if (file != NULL) {
138 WIN32FILE_IOWIN file_ret;
139 file_ret.hf = file;
140 file_ret.error = 0;
141 ret = malloc(sizeof(WIN32FILE_IOWIN));
142 if (ret == NULL)
143 CloseHandle(file);
144 else
145 *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret;
146 }
147 return ret;
148 }
149 #endif
150
151 bool Unzip(const FilePath& src_file, const FilePath& dest_dir,
152 std::vector<FilePath>* files) {
153 #if defined(OS_WIN)
154 zlib_filefunc_def zip_funcs;
155 fill_win32_filefunc(&zip_funcs);
156 zip_funcs.zopen_file = ZipOpenFunc;
157 #endif
158
159 #if defined(OS_POSIX)
160 std::string src_file_str = src_file.value();
161 unzFile zip_file = unzOpen(src_file_str.c_str());
162 #elif defined(OS_WIN)
163 std::string src_file_str = WideToUTF8(src_file.value());
164 unzFile zip_file = unzOpen2(src_file_str.c_str(), &zip_funcs);
165 #endif
166 if (!zip_file) {
167 LOG(WARNING) << "couldn't open extension file " << src_file_str;
168 return false;
169 }
170 unz_global_info zip_info;
171 int err;
172 err = unzGetGlobalInfo(zip_file, &zip_info);
173 if (err != UNZ_OK) {
174 LOG(WARNING) << "couldn't open extension file " << src_file_str;
175 return false;
176 }
177 bool ret = true;
178 for (unsigned int i = 0; i < zip_info.number_entry; ++i) {
179 FilePath dest_file;
180 if (!ExtractCurrentFile(zip_file, dest_dir, &dest_file)) {
181 ret = false;
182 break;
183 }
184 if (files)
185 files->push_back(dest_file);
186
187 if (i + 1 < zip_info.number_entry) {
188 err = unzGoToNextFile(zip_file);
189 if (err != UNZ_OK) {
190 LOG(WARNING) << "error %d in unzGoToNextFile";
191 ret = false;
192 break;
193 }
194 }
195 }
196 unzClose(zip_file);
197 return ret;
198 }
199
200 static bool AddFileToZip(zipFile zip_file, const FilePath& src_path) {
201 net::FileStream stream;
202 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
203 if (stream.Open(src_path, flags) != 0) {
204 LOG(ERROR) << "Could not open stream for path "
205 << WideToASCII(src_path.ToWStringHack());
206 return false;
207 }
208
209 int num_bytes;
210 char buf[kZipBufSize];
211 do {
212 num_bytes = stream.Read(buf, kZipBufSize, NULL);
213 if (num_bytes > 0) {
214 if (ZIP_OK != zipWriteInFileInZip(zip_file, buf, num_bytes)) {
215 LOG(ERROR) << "Could not write data to zip for path "
216 << WideToASCII(src_path.ToWStringHack());
217 return false;
218 }
219 }
220 } while (num_bytes > 0);
221
222 return true;
223 }
224
225 bool Zip(const FilePath& src_path, const FilePath& dest_file) {
226 #if defined(OS_WIN)
227 zlib_filefunc_def zip_funcs;
228 fill_win32_filefunc(&zip_funcs);
229 zip_funcs.zopen_file = ZipOpenFunc;
230 #endif
231
232 #if defined(OS_POSIX)
233 std::string src_path_str = src_path.value();
234 zipFile zip_file = zipOpen(src_path_str.c_str(), APPEND_STATUS_CREATE);
235 #elif defined(OS_WIN)
236 std::string dest_file_str = WideToUTF8(dest_file.value());
237 zipFile zip_file = zipOpen2(dest_file_str.c_str(), APPEND_STATUS_CREATE,
238 NULL, // global comment
239 &zip_funcs);
240 #endif
241
242 if (!zip_file) {
243 LOG(WARNING) << "couldn't open extension file " << dest_file_str;
244 return false;
245 }
246
247 file_util::FileEnumerator file_enumerator(
248 src_path, true, // recursive
249 file_util::FileEnumerator::FILES_AND_DIRECTORIES);
250 for (FilePath path = file_enumerator.Next(); !path.value().empty();
251 path = file_enumerator.Next()) {
252 #if defined(OS_WIN)
253 std::string str_path =
254 WideToUTF8(path.value().substr(src_path.value().length() + 1));
255 ReplaceSubstringsAfterOffset(&str_path, 0u, "\\", "/");
256 #else
257 std::string str_path = path.value().substring(src_path.length() + 1);
258 #endif
259
260 bool is_directory = file_util::DirectoryExists(path);
261 if (is_directory)
262 str_path += "/";
263
264 if (ZIP_OK != zipOpenNewFileInZip(
265 zip_file, str_path.c_str(),
266 NULL, NULL, 0u, NULL, 0u, NULL, // file info, extrafield local, length,
267 // extrafield global, length, comment
268 Z_DEFLATED, Z_DEFAULT_COMPRESSION)) {
269 LOG(ERROR) << "Could not open zip file entry " << str_path;
270 return false;
271 }
272
273 bool success = true;
274 if (!is_directory) {
275 success = AddFileToZip(zip_file, path);
276 }
277
278 if (ZIP_OK != zipCloseFileInZip(zip_file)) {
279 LOG(ERROR) << "Could not close zip file entry " << str_path;
280 return false;
281 }
282
283 if (!success)
284 return false;
285 }
286
287 if (ZIP_OK != zipClose(zip_file, NULL)) { // global comment
288 LOG(ERROR) << "Error closing zip file " << dest_file_str;
289 return false;
290 }
291
292 return true;
293 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698