Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / zlib / google / zip.cc
blob39e2e534ce4b7b73d7bdbbe839fca7709f333fed
1 // Copyright (c) 2012 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 "third_party/zlib/google/zip.h"
7 #include <string>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/files/file.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/logging.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/string_util.h"
16 #include "third_party/zlib/google/zip_internal.h"
17 #include "third_party/zlib/google/zip_reader.h"
19 #if defined(USE_SYSTEM_MINIZIP)
20 #include <minizip/unzip.h>
21 #include <minizip/zip.h>
22 #else
23 #include "third_party/zlib/contrib/minizip/unzip.h"
24 #include "third_party/zlib/contrib/minizip/zip.h"
25 #endif
27 namespace {
29 bool AddFileToZip(zipFile zip_file, const base::FilePath& src_dir) {
30 base::File file(src_dir, base::File::FLAG_OPEN | base::File::FLAG_READ);
31 if (!file.IsValid()) {
32 DLOG(ERROR) << "Could not open file for path " << src_dir.value();
33 return false;
36 int num_bytes;
37 char buf[zip::internal::kZipBufSize];
38 do {
39 num_bytes = file.ReadAtCurrentPos(buf, zip::internal::kZipBufSize);
40 if (num_bytes > 0) {
41 if (ZIP_OK != zipWriteInFileInZip(zip_file, buf, num_bytes)) {
42 DLOG(ERROR) << "Could not write data to zip for path "
43 << src_dir.value();
44 return false;
47 } while (num_bytes > 0);
49 return true;
52 bool AddEntryToZip(zipFile zip_file, const base::FilePath& path,
53 const base::FilePath& root_path) {
54 base::FilePath relative_path;
55 bool result = root_path.AppendRelativePath(path, &relative_path);
56 DCHECK(result);
57 std::string str_path = relative_path.AsUTF8Unsafe();
58 #if defined(OS_WIN)
59 base::ReplaceSubstringsAfterOffset(&str_path, 0u, "\\", "/");
60 #endif
62 bool is_directory = base::DirectoryExists(path);
63 if (is_directory)
64 str_path += "/";
66 zip_fileinfo file_info = zip::internal::GetFileInfoForZipping(path);
67 if (!zip::internal::ZipOpenNewFileInZip(zip_file, str_path, &file_info))
68 return false;
70 bool success = true;
71 if (!is_directory) {
72 success = AddFileToZip(zip_file, path);
75 if (ZIP_OK != zipCloseFileInZip(zip_file)) {
76 DLOG(ERROR) << "Could not close zip file entry " << str_path;
77 return false;
80 return success;
83 bool ExcludeNoFilesFilter(const base::FilePath& file_path) {
84 return true;
87 bool ExcludeHiddenFilesFilter(const base::FilePath& file_path) {
88 return file_path.BaseName().value()[0] != '.';
91 } // namespace
93 namespace zip {
95 bool Unzip(const base::FilePath& src_file, const base::FilePath& dest_dir) {
96 ZipReader reader;
97 if (!reader.Open(src_file)) {
98 DLOG(WARNING) << "Failed to open " << src_file.value();
99 return false;
101 while (reader.HasMore()) {
102 if (!reader.OpenCurrentEntryInZip()) {
103 DLOG(WARNING) << "Failed to open the current file in zip";
104 return false;
106 if (reader.current_entry_info()->is_unsafe()) {
107 DLOG(WARNING) << "Found an unsafe file in zip "
108 << reader.current_entry_info()->file_path().value();
109 return false;
111 if (!reader.ExtractCurrentEntryIntoDirectory(dest_dir)) {
112 DLOG(WARNING) << "Failed to extract "
113 << reader.current_entry_info()->file_path().value();
114 return false;
116 if (!reader.AdvanceToNextEntry()) {
117 DLOG(WARNING) << "Failed to advance to the next file";
118 return false;
121 return true;
124 bool ZipWithFilterCallback(const base::FilePath& src_dir,
125 const base::FilePath& dest_file,
126 const FilterCallback& filter_cb) {
127 DCHECK(base::DirectoryExists(src_dir));
129 zipFile zip_file = internal::OpenForZipping(dest_file.AsUTF8Unsafe(),
130 APPEND_STATUS_CREATE);
132 if (!zip_file) {
133 DLOG(WARNING) << "couldn't create file " << dest_file.value();
134 return false;
137 bool success = true;
138 base::FileEnumerator file_enumerator(src_dir, true /* recursive */,
139 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
140 for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
141 path = file_enumerator.Next()) {
142 if (!filter_cb.Run(path)) {
143 continue;
146 if (!AddEntryToZip(zip_file, path, src_dir)) {
147 success = false;
148 break;
152 if (ZIP_OK != zipClose(zip_file, NULL)) {
153 DLOG(ERROR) << "Error closing zip file " << dest_file.value();
154 return false;
157 return success;
160 bool Zip(const base::FilePath& src_dir, const base::FilePath& dest_file,
161 bool include_hidden_files) {
162 if (include_hidden_files) {
163 return ZipWithFilterCallback(
164 src_dir, dest_file, base::Bind(&ExcludeNoFilesFilter));
165 } else {
166 return ZipWithFilterCallback(
167 src_dir, dest_file, base::Bind(&ExcludeHiddenFilesFilter));
171 #if defined(OS_POSIX)
172 bool ZipFiles(const base::FilePath& src_dir,
173 const std::vector<base::FilePath>& src_relative_paths,
174 int dest_fd) {
175 DCHECK(base::DirectoryExists(src_dir));
176 zipFile zip_file = internal::OpenFdForZipping(dest_fd, APPEND_STATUS_CREATE);
178 if (!zip_file) {
179 DLOG(ERROR) << "couldn't create file for fd " << dest_fd;
180 return false;
183 bool success = true;
184 for (std::vector<base::FilePath>::const_iterator iter =
185 src_relative_paths.begin();
186 iter != src_relative_paths.end(); ++iter) {
187 const base::FilePath& path = src_dir.Append(*iter);
188 if (!AddEntryToZip(zip_file, path, src_dir)) {
189 // TODO(hshi): clean up the partial zip file when error occurs.
190 success = false;
191 break;
195 if (ZIP_OK != zipClose(zip_file, NULL)) {
196 DLOG(ERROR) << "Error closing zip file for fd " << dest_fd;
197 success = false;
200 return success;
202 #endif // defined(OS_POSIX)
204 } // namespace zip