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

Side by Side Diff: chrome/common/unzip.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) 2006-2008 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/unzip.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 #if defined(OS_WIN)
12 #include "third_party/zlib/contrib/minizip/iowin32.h"
13 #endif
14
15 static const int kZipMaxPath = 256;
16 static const int kUnzipBufSize = 8192;
17
18 // Extract the 'current' selected file from the zip into dest_dir.
19 // Output filename is stored in out_file. Returns true on success.
20 static bool ExtractCurrentFile(unzFile zip_file,
21 const FilePath& dest_dir,
22 FilePath* out_file) {
23 char filename_inzip[kZipMaxPath] = {0};
24 unz_file_info file_info;
25 int err = unzGetCurrentFileInfo(zip_file, &file_info, filename_inzip,
26 sizeof(filename_inzip), NULL, 0, NULL, 0);
27 if (err != UNZ_OK)
28 return false;
29 if (filename_inzip[0] == '\0')
30 return false;
31
32 err = unzOpenCurrentFile(zip_file);
33 if (err != UNZ_OK)
34 return false;
35
36 FilePath::StringType filename;
37 std::vector<FilePath::StringType> filename_parts;
38 #if defined(OS_WIN)
39 filename = UTF8ToWide(filename_inzip);
40 #elif defined(OS_POSIX)
41 filename = filename_inzip;
42 #endif
43 SplitString(filename, '/', &filename_parts);
44
45 FilePath dest_file(dest_dir);
46 std::vector<FilePath::StringType>::iterator iter;
47 for (iter = filename_parts.begin(); iter != filename_parts.end(); ++iter)
48 dest_file = dest_file.Append(*iter);
49 if (out_file)
50 *out_file = dest_file;
51 // If this is a directory, just create it and return.
52 if (filename_inzip[strlen(filename_inzip) - 1] == '/') {
53 if (!file_util::CreateDirectory(dest_file))
54 return false;
55 return true;
56 }
57 // TODO(erikkay): Can we always count on the directory entry coming before a
58 // file in that directory? If so, then these three lines can be removed.
59 FilePath dir = dest_file.DirName();
60 if (!file_util::CreateDirectory(dir))
61 return false;
62
63 net::FileStream stream;
64 int flags = base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE;
65 if (stream.Open(dest_file, flags) != 0)
66 return false;
67
68 bool ret = true;
69 int num_bytes = 0;
70 char buf[kUnzipBufSize];
71 do {
72 num_bytes = unzReadCurrentFile(zip_file, buf, kUnzipBufSize);
73 if (num_bytes < 0) {
74 // If num_bytes < 0, then it's a specific UNZ_* error code.
75 // While we're not currently handling these codes specifically, save
76 // it away in case we want to in the future.
77 err = num_bytes;
78 break;
79 }
80 if (num_bytes > 0) {
81 if (num_bytes != stream.Write(buf, num_bytes, NULL)) {
82 ret = false;
83 break;
84 }
85 }
86 } while (num_bytes > 0);
87
88 stream.Close();
89 if (err == UNZ_OK)
90 err = unzCloseCurrentFile(zip_file);
91 else
92 unzCloseCurrentFile(zip_file); // Don't lose the original error code.
93 if (err != UNZ_OK)
94 ret = false;
95 return ret;
96 }
97
98 #if defined(OS_WIN)
99 typedef struct {
100 HANDLE hf;
101 int error;
102 } WIN32FILE_IOWIN;
103
104 // This function is derived from third_party/minizip/iowin32.c.
105 // Its only difference is that it treats the char* as UTF8 and
106 // uses the Unicode version of CreateFile.
107 static void* UnzipOpenFunc(void *opaque, const char* filename, int mode) {
108 DWORD desired_access, creation_disposition;
109 DWORD share_mode, flags_and_attributes;
110 HANDLE file = 0;
111 void* ret = NULL;
112
113 desired_access = share_mode = flags_and_attributes = 0;
114
115 if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
116 desired_access = GENERIC_READ;
117 creation_disposition = OPEN_EXISTING;
118 share_mode = FILE_SHARE_READ;
119 } else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) {
120 desired_access = GENERIC_WRITE | GENERIC_READ;
121 creation_disposition = OPEN_EXISTING;
122 } else if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
123 desired_access = GENERIC_WRITE | GENERIC_READ;
124 creation_disposition = CREATE_ALWAYS;
125 }
126
127 std::wstring filename_wstr = UTF8ToWide(filename);
128 if ((filename != NULL) && (desired_access != 0)) {
129 file = CreateFile(filename_wstr.c_str(), desired_access, share_mode,
130 NULL, creation_disposition, flags_and_attributes, NULL);
131 }
132
133 if (file == INVALID_HANDLE_VALUE)
134 file = NULL;
135
136 if (file != NULL) {
137 WIN32FILE_IOWIN file_ret;
138 file_ret.hf = file;
139 file_ret.error = 0;
140 ret = malloc(sizeof(WIN32FILE_IOWIN));
141 if (ret == NULL)
142 CloseHandle(file);
143 else
144 *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret;
145 }
146 return ret;
147 }
148 #endif
149
150 // TODO(erikkay): Make this function asynchronous so that a large zip file
151 // won't starve the thread it's running on. This won't be entirely possible
152 // since reads need to be synchronous, but we can at least make writes async.
153 bool Unzip(const FilePath& zip_path, const FilePath& dest_dir,
154 std::vector<FilePath>* files) {
155 #if defined(OS_WIN)
156 zlib_filefunc_def unzip_funcs;
157 fill_win32_filefunc(&unzip_funcs);
158 unzip_funcs.zopen_file = UnzipOpenFunc;
159 #endif
160
161 #if defined(OS_POSIX)
162 std::string zip_file_str = zip_path.value();
163 unzFile zip_file = unzOpen(zip_file_str.c_str());
164 #elif defined(OS_WIN)
165 std::string zip_file_str = WideToUTF8(zip_path.value());
166 unzFile zip_file = unzOpen2(zip_file_str.c_str(), &unzip_funcs);
167 #endif
168 if (!zip_file) {
169 LOG(WARNING) << "couldn't open extension file " << zip_file_str;
170 return false;
171 }
172 unz_global_info zip_info;
173 int err;
174 err = unzGetGlobalInfo(zip_file, &zip_info);
175 if (err != UNZ_OK) {
176 LOG(WARNING) << "couldn't open extension file " << zip_file_str;
177 return false;
178 }
179 bool ret = true;
180 for (unsigned int i = 0; i < zip_info.number_entry; ++i) {
181 FilePath dest_file;
182 if (!ExtractCurrentFile(zip_file, dest_dir, &dest_file)) {
183 ret = false;
184 break;
185 }
186 if (files)
187 files->push_back(dest_file);
188
189 if (i + 1 < zip_info.number_entry) {
190 err = unzGoToNextFile(zip_file);
191 if (err != UNZ_OK) {
192 LOG(WARNING) << "error %d in unzGoToNextFile";
193 ret = false;
194 break;
195 }
196 }
197 }
198 unzClose(zip_file);
199 return ret;
200 }
OLDNEW
« no previous file with comments | « chrome/common/unzip.h ('k') | chrome/common/unzip_unittest.cc » ('j') | chrome/common/zip.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698