summaryrefslogtreecommitdiffstats
path: root/third_party/zlib
diff options
context:
space:
mode:
authoralecflett@chromium.org <alecflett@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-03 23:02:57 +0000
committeralecflett@chromium.org <alecflett@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-05-03 23:02:57 +0000
commit4170d3a06feb349153149c05493756bfd3700cd3 (patch)
treec3b3b20ddd3689b1c177b44635fe3c2d27750f35 /third_party/zlib
parentc1c416186e47a3caab464ffe8851e8ce5ff92b5b (diff)
downloadchromium_src-4170d3a06feb349153149c05493756bfd3700cd3.zip
chromium_src-4170d3a06feb349153149c05493756bfd3700cd3.tar.gz
chromium_src-4170d3a06feb349153149c05493756bfd3700cd3.tar.bz2
Move components/zip to third_party/zip
Move components to zip as per the discussion here: https://groups.google.com/a/chromium.org/d/topic/chromium-dev/MgbMTQCNzR0/discussion BUG= R=agl@chromium.org, gavinp@chromium.org, jam@chromium.org, joi@chromium.org Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=197964 Review URL: https://codereview.chromium.org/14021015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@198222 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/zlib')
-rw-r--r--third_party/zlib/google/DEPS3
-rw-r--r--third_party/zlib/google/OWNERS2
-rw-r--r--third_party/zlib/google/zip.cc207
-rw-r--r--third_party/zlib/google/zip.h44
-rw-r--r--third_party/zlib/google/zip_internal.cc316
-rw-r--r--third_party/zlib/google/zip_internal.h62
-rw-r--r--third_party/zlib/google/zip_reader.cc310
-rw-r--r--third_party/zlib/google/zip_reader.h177
-rw-r--r--third_party/zlib/google/zip_reader_unittest.cc431
-rw-r--r--third_party/zlib/google/zip_unittest.cc207
-rw-r--r--third_party/zlib/zlib.gyp21
11 files changed, 1779 insertions, 1 deletions
diff --git a/third_party/zlib/google/DEPS b/third_party/zlib/google/DEPS
new file mode 100644
index 0000000..6a2f02e
--- /dev/null
+++ b/third_party/zlib/google/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+net/base",
+]
diff --git a/third_party/zlib/google/OWNERS b/third_party/zlib/google/OWNERS
new file mode 100644
index 0000000..ff93254
--- /dev/null
+++ b/third_party/zlib/google/OWNERS
@@ -0,0 +1,2 @@
+hshi@chromium.org
+satorux@chromium.org
diff --git a/third_party/zlib/google/zip.cc b/third_party/zlib/google/zip.cc
new file mode 100644
index 0000000..e24449b
--- /dev/null
+++ b/third_party/zlib/google/zip.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/zlib/google/zip.h"
+
+#include "base/bind.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string16.h"
+#include "base/string_util.h"
+#include "net/base/file_stream.h"
+#include "third_party/zlib/google/zip_internal.h"
+#include "third_party/zlib/google/zip_reader.h"
+
+#if defined(USE_SYSTEM_MINIZIP)
+#include <minizip/unzip.h>
+#include <minizip/zip.h>
+#else
+#include "third_party/zlib/contrib/minizip/unzip.h"
+#include "third_party/zlib/contrib/minizip/zip.h"
+#endif
+
+namespace {
+
+bool AddFileToZip(zipFile zip_file, const base::FilePath& src_dir) {
+ net::FileStream stream(NULL);
+ int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
+ if (stream.OpenSync(src_dir, flags) != 0) {
+ DLOG(ERROR) << "Could not open stream for path "
+ << src_dir.value();
+ return false;
+ }
+
+ int num_bytes;
+ char buf[zip::internal::kZipBufSize];
+ do {
+ num_bytes = stream.ReadSync(buf, zip::internal::kZipBufSize);
+ if (num_bytes > 0) {
+ if (ZIP_OK != zipWriteInFileInZip(zip_file, buf, num_bytes)) {
+ DLOG(ERROR) << "Could not write data to zip for path "
+ << src_dir.value();
+ return false;
+ }
+ }
+ } while (num_bytes > 0);
+
+ return true;
+}
+
+bool AddEntryToZip(zipFile zip_file, const base::FilePath& path,
+ const base::FilePath& root_path) {
+ std::string str_path =
+ path.AsUTF8Unsafe().substr(root_path.value().length() + 1);
+#if defined(OS_WIN)
+ ReplaceSubstringsAfterOffset(&str_path, 0u, "\\", "/");
+#endif
+
+ bool is_directory = file_util::DirectoryExists(path);
+ if (is_directory)
+ str_path += "/";
+
+ if (ZIP_OK != zipOpenNewFileInZip(
+ zip_file, str_path.c_str(),
+ NULL, NULL, 0u, NULL, 0u, NULL, // file info, extrafield local, length,
+ // extrafield global, length, comment
+ Z_DEFLATED, Z_DEFAULT_COMPRESSION)) {
+ DLOG(ERROR) << "Could not open zip file entry " << str_path;
+ return false;
+ }
+
+ bool success = true;
+ if (!is_directory) {
+ success = AddFileToZip(zip_file, path);
+ }
+
+ if (ZIP_OK != zipCloseFileInZip(zip_file)) {
+ DLOG(ERROR) << "Could not close zip file entry " << str_path;
+ return false;
+ }
+
+ return success;
+}
+
+bool ExcludeNoFilesFilter(const base::FilePath& file_path) {
+ return true;
+}
+
+bool ExcludeHiddenFilesFilter(const base::FilePath& file_path) {
+ return file_path.BaseName().value()[0] != '.';
+}
+
+} // namespace
+
+namespace zip {
+
+bool Unzip(const base::FilePath& src_file, const base::FilePath& dest_dir) {
+ ZipReader reader;
+ if (!reader.Open(src_file)) {
+ DLOG(WARNING) << "Failed to open " << src_file.value();
+ return false;
+ }
+ while (reader.HasMore()) {
+ if (!reader.OpenCurrentEntryInZip()) {
+ DLOG(WARNING) << "Failed to open the current file in zip";
+ return false;
+ }
+ if (reader.current_entry_info()->is_unsafe()) {
+ DLOG(WARNING) << "Found an unsafe file in zip "
+ << reader.current_entry_info()->file_path().value();
+ return false;
+ }
+ if (!reader.ExtractCurrentEntryIntoDirectory(dest_dir)) {
+ DLOG(WARNING) << "Failed to extract "
+ << reader.current_entry_info()->file_path().value();
+ return false;
+ }
+ if (!reader.AdvanceToNextEntry()) {
+ DLOG(WARNING) << "Failed to advance to the next file";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ZipWithFilterCallback(const base::FilePath& src_dir,
+ const base::FilePath& dest_file,
+ const FilterCallback& filter_cb) {
+ DCHECK(file_util::DirectoryExists(src_dir));
+
+ zipFile zip_file = internal::OpenForZipping(dest_file.AsUTF8Unsafe(),
+ APPEND_STATUS_CREATE);
+
+ if (!zip_file) {
+ DLOG(WARNING) << "couldn't create file " << dest_file.value();
+ return false;
+ }
+
+ bool success = true;
+ file_util::FileEnumerator file_enumerator(src_dir, true /* recursive */,
+ file_util::FileEnumerator::FILES |
+ file_util::FileEnumerator::DIRECTORIES);
+ for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
+ path = file_enumerator.Next()) {
+ if (!filter_cb.Run(path)) {
+ continue;
+ }
+
+ if (!AddEntryToZip(zip_file, path, src_dir)) {
+ success = false;
+ return false;
+ }
+ }
+
+ if (ZIP_OK != zipClose(zip_file, NULL)) {
+ DLOG(ERROR) << "Error closing zip file " << dest_file.value();
+ return false;
+ }
+
+ return success;
+}
+
+bool Zip(const base::FilePath& src_dir, const base::FilePath& dest_file,
+ bool include_hidden_files) {
+ if (include_hidden_files) {
+ return ZipWithFilterCallback(
+ src_dir, dest_file, base::Bind(&ExcludeNoFilesFilter));
+ } else {
+ return ZipWithFilterCallback(
+ src_dir, dest_file, base::Bind(&ExcludeHiddenFilesFilter));
+ }
+}
+
+#if defined(OS_POSIX)
+bool ZipFiles(const base::FilePath& src_dir,
+ const std::vector<base::FilePath>& src_relative_paths,
+ int dest_fd) {
+ DCHECK(file_util::DirectoryExists(src_dir));
+ zipFile zip_file = internal::OpenFdForZipping(dest_fd, APPEND_STATUS_CREATE);
+
+ if (!zip_file) {
+ DLOG(ERROR) << "couldn't create file for fd " << dest_fd;
+ return false;
+ }
+
+ bool success = true;
+ for (std::vector<base::FilePath>::const_iterator iter =
+ src_relative_paths.begin();
+ iter != src_relative_paths.end(); ++iter) {
+ const base::FilePath& path = src_dir.Append(*iter);
+ if (!AddEntryToZip(zip_file, path, src_dir)) {
+ // TODO(hshi): clean up the partial zip file when error occurs.
+ success = false;
+ break;
+ }
+ }
+
+ if (ZIP_OK != zipClose(zip_file, NULL)) {
+ DLOG(ERROR) << "Error closing zip file for fd " << dest_fd;
+ success = false;
+ }
+
+ return success;
+}
+#endif // defined(OS_POSIX)
+
+} // namespace zip
diff --git a/third_party/zlib/google/zip.h b/third_party/zlib/google/zip.h
new file mode 100644
index 0000000..9809fce
--- /dev/null
+++ b/third_party/zlib/google/zip.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_ZLIB_GOOGLE_ZIP_H_
+#define THIRD_PARTY_ZLIB_GOOGLE_ZIP_H_
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+
+namespace zip {
+
+// Zip the contents of src_dir into dest_file. src_path must be a directory.
+// An entry will *not* be created in the zip for the root folder -- children
+// of src_dir will be at the root level of the created zip. For each file in
+// src_dir, include it only if the callback |filter_cb| returns true. Otherwise
+// omit it.
+typedef base::Callback<bool(const base::FilePath&)> FilterCallback;
+bool ZipWithFilterCallback(const base::FilePath& src_dir,
+ const base::FilePath& dest_file,
+ const FilterCallback& filter_cb);
+
+// Convenience method for callers who don't need to set up the filter callback.
+// If |include_hidden_files| is true, files starting with "." are included.
+// Otherwise they are omitted.
+bool Zip(const base::FilePath& src_dir, const base::FilePath& dest_file,
+ bool include_hidden_files);
+
+#if defined(OS_POSIX)
+// Zips files listed in |src_relative_paths| to destination specified by file
+// descriptor |dest_fd|. The paths listed in |src_relative_paths| are relative
+// to the |src_dir| and will be used as the file names in the created zip file.
+// All source paths must be under |src_dir| in the file system hierarchy.
+bool ZipFiles(const base::FilePath& src_dir,
+ const std::vector<base::FilePath>& src_relative_paths,
+ int dest_fd);
+#endif // defined(OS_POSIX)
+
+// Unzip the contents of zip_file into dest_dir.
+bool Unzip(const base::FilePath& zip_file, const base::FilePath& dest_dir);
+
+} // namespace zip
+
+#endif // THIRD_PARTY_ZLIB_GOOGLE_ZIP_H_
diff --git a/third_party/zlib/google/zip_internal.cc b/third_party/zlib/google/zip_internal.cc
new file mode 100644
index 0000000..3a3a51a
--- /dev/null
+++ b/third_party/zlib/google/zip_internal.cc
@@ -0,0 +1,316 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/zlib/google/zip.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+
+#if defined(USE_SYSTEM_MINIZIP)
+#include <minizip/ioapi.h>
+#include <minizip/unzip.h>
+#include <minizip/zip.h>
+#else
+#include "third_party/zlib/contrib/minizip/unzip.h"
+#include "third_party/zlib/contrib/minizip/zip.h"
+#if defined(OS_WIN)
+#include "third_party/zlib/contrib/minizip/iowin32.h"
+#elif defined(OS_POSIX)
+#include "third_party/zlib/contrib/minizip/ioapi.h"
+#endif // defined(OS_POSIX)
+#endif // defined(USE_SYSTEM_MINIZIP)
+
+namespace {
+
+#if defined(OS_WIN)
+typedef struct {
+ HANDLE hf;
+ int error;
+} WIN32FILE_IOWIN;
+
+// This function is derived from third_party/minizip/iowin32.c.
+// Its only difference is that it treats the char* as UTF8 and
+// uses the Unicode version of CreateFile.
+void* ZipOpenFunc(void *opaque, const char* filename, int mode) {
+ DWORD desired_access, creation_disposition;
+ DWORD share_mode, flags_and_attributes;
+ HANDLE file = 0;
+ void* ret = NULL;
+
+ desired_access = share_mode = flags_and_attributes = 0;
+
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
+ desired_access = GENERIC_READ;
+ creation_disposition = OPEN_EXISTING;
+ share_mode = FILE_SHARE_READ;
+ } else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) {
+ desired_access = GENERIC_WRITE | GENERIC_READ;
+ creation_disposition = OPEN_EXISTING;
+ } else if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
+ desired_access = GENERIC_WRITE | GENERIC_READ;
+ creation_disposition = CREATE_ALWAYS;
+ }
+
+ base::string16 filename16 = UTF8ToUTF16(filename);
+ if ((filename != NULL) && (desired_access != 0)) {
+ file = CreateFile(filename16.c_str(), desired_access, share_mode,
+ NULL, creation_disposition, flags_and_attributes, NULL);
+ }
+
+ if (file == INVALID_HANDLE_VALUE)
+ file = NULL;
+
+ if (file != NULL) {
+ WIN32FILE_IOWIN file_ret;
+ file_ret.hf = file;
+ file_ret.error = 0;
+ ret = malloc(sizeof(WIN32FILE_IOWIN));
+ if (ret == NULL)
+ CloseHandle(file);
+ else
+ *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret;
+ }
+ return ret;
+}
+#endif
+
+#if defined(OS_POSIX)
+// Callback function for zlib that opens a file stream from a file descriptor.
+void* FdOpenFileFunc(void* opaque, const char* filename, int mode) {
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename != NULL) && (mode_fopen != NULL))
+ file = fdopen(*static_cast<int*>(opaque), mode_fopen);
+
+ return file;
+}
+
+// We don't actually close the file stream since that would close
+// the underlying file descriptor, and we don't own it. However we do need to
+// flush buffers and free |opaque| since we malloc'ed it in FillFdOpenFileFunc.
+int CloseFileFunc(void* opaque, void* stream) {
+ fflush(static_cast<FILE*>(stream));
+ free(opaque);
+ return 0;
+}
+
+// Fills |pzlib_filecunc_def| appropriately to handle the zip file
+// referred to by |fd|.
+void FillFdOpenFileFunc(zlib_filefunc_def* pzlib_filefunc_def, int fd) {
+ fill_fopen_filefunc(pzlib_filefunc_def);
+ pzlib_filefunc_def->zopen_file = FdOpenFileFunc;
+ pzlib_filefunc_def->zclose_file = CloseFileFunc;
+ int* ptr_fd = static_cast<int*>(malloc(sizeof(fd)));
+ *ptr_fd = fd;
+ pzlib_filefunc_def->opaque = ptr_fd;
+}
+#endif // defined(OS_POSIX)
+
+#if defined(OS_WIN)
+// Callback function for zlib that opens a file stream from a Windows handle.
+void* HandleOpenFileFunc(void* opaque, const char* filename, int mode) {
+ WIN32FILE_IOWIN file_ret;
+ file_ret.hf = static_cast<HANDLE>(opaque);
+ file_ret.error = 0;
+ if (file_ret.hf == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ void* ret = malloc(sizeof(WIN32FILE_IOWIN));
+ if (ret != NULL)
+ *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret;
+ return ret;
+}
+#endif
+
+// A struct that contains data required for zlib functions to extract files from
+// a zip archive stored in memory directly. The following I/O API functions
+// expect their opaque parameters refer to this struct.
+struct ZipBuffer {
+ const char* data; // weak
+ size_t length;
+ size_t offset;
+};
+
+// Opens the specified file. When this function returns a non-NULL pointer, zlib
+// uses this pointer as a stream parameter while compressing or uncompressing
+// data. (Returning NULL represents an error.) This function initializes the
+// given opaque parameter and returns it because this parameter stores all
+// information needed for uncompressing data. (This function does not support
+// writing compressed data and it returns NULL for this case.)
+void* OpenZipBuffer(void* opaque, const char* /*filename*/, int mode) {
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) {
+ NOTREACHED();
+ return NULL;
+ }
+ ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
+ if (!buffer || !buffer->data || !buffer->length)
+ return NULL;
+ buffer->offset = 0;
+ return opaque;
+}
+
+// Reads compressed data from the specified stream. This function copies data
+// refered by the opaque parameter and returns the size actually copied.
+uLong ReadZipBuffer(void* opaque, void* /*stream*/, void* buf, uLong size) {
+ ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
+ DCHECK_LE(buffer->offset, buffer->length);
+ size_t remaining_bytes = buffer->length - buffer->offset;
+ if (!buffer || !buffer->data || !remaining_bytes)
+ return 0;
+ size = std::min(size, static_cast<uLong>(remaining_bytes));
+ memcpy(buf, &buffer->data[buffer->offset], size);
+ buffer->offset += size;
+ return size;
+}
+
+// Writes compressed data to the stream. This function always returns zero
+// because this implementation is only for reading compressed data.
+uLong WriteZipBuffer(void* /*opaque*/,
+ void* /*stream*/,
+ const void* /*buf*/,
+ uLong /*size*/) {
+ NOTREACHED();
+ return 0;
+}
+
+// Returns the offset from the beginning of the data.
+long GetOffsetOfZipBuffer(void* opaque, void* /*stream*/) {
+ ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
+ if (!buffer)
+ return -1;
+ return static_cast<long>(buffer->offset);
+}
+
+// Moves the current offset to the specified position.
+long SeekZipBuffer(void* opaque, void* /*stream*/, uLong offset, int origin) {
+ ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
+ if (!buffer)
+ return -1;
+ if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
+ buffer->offset = std::min(buffer->offset + static_cast<size_t>(offset),
+ buffer->length);
+ return 0;
+ }
+ if (origin == ZLIB_FILEFUNC_SEEK_END) {
+ buffer->offset = (buffer->length > offset) ? buffer->length - offset : 0;
+ return 0;
+ }
+ if (origin == ZLIB_FILEFUNC_SEEK_SET) {
+ buffer->offset = std::min(buffer->length, static_cast<size_t>(offset));
+ return 0;
+ }
+ NOTREACHED();
+ return -1;
+}
+
+// Closes the input offset and deletes all resources used for compressing or
+// uncompressing data. This function deletes the ZipBuffer object referred by
+// the opaque parameter since zlib deletes the unzFile object and it does not
+// use this object any longer.
+int CloseZipBuffer(void* opaque, void* /*stream*/) {
+ if (opaque)
+ free(opaque);
+ return 0;
+}
+
+// Returns the last error happened when reading or writing data. This function
+// always returns zero, which means there are not any errors.
+int GetErrorOfZipBuffer(void* /*opaque*/, void* /*stream*/) {
+ return 0;
+}
+
+} // namespace
+
+namespace zip {
+namespace internal {
+
+unzFile OpenForUnzipping(const std::string& file_name_utf8) {
+ zlib_filefunc_def* zip_func_ptrs = NULL;
+#if defined(OS_WIN)
+ zlib_filefunc_def zip_funcs;
+ fill_win32_filefunc(&zip_funcs);
+ zip_funcs.zopen_file = ZipOpenFunc;
+ zip_func_ptrs = &zip_funcs;
+#endif
+ return unzOpen2(file_name_utf8.c_str(), zip_func_ptrs);
+}
+
+#if defined(OS_POSIX)
+unzFile OpenFdForUnzipping(int zip_fd) {
+ zlib_filefunc_def zip_funcs;
+ FillFdOpenFileFunc(&zip_funcs, zip_fd);
+ // Passing dummy "fd" filename to zlib.
+ return unzOpen2("fd", &zip_funcs);
+}
+#endif
+
+#if defined(OS_WIN)
+unzFile OpenHandleForUnzipping(HANDLE zip_handle) {
+ zlib_filefunc_def zip_funcs;
+ fill_win32_filefunc(&zip_funcs);
+ zip_funcs.zopen_file = HandleOpenFileFunc;
+ zip_funcs.opaque = zip_handle;
+ return unzOpen2("fd", &zip_funcs);
+}
+#endif
+
+// static
+unzFile PreprareMemoryForUnzipping(const std::string& data) {
+ if (data.empty())
+ return NULL;
+
+ ZipBuffer* buffer = static_cast<ZipBuffer*>(malloc(sizeof(ZipBuffer)));
+ if (!buffer)
+ return NULL;
+ buffer->data = data.data();
+ buffer->length = data.length();
+ buffer->offset = 0;
+
+ zlib_filefunc_def zip_functions;
+ zip_functions.zopen_file = OpenZipBuffer;
+ zip_functions.zread_file = ReadZipBuffer;
+ zip_functions.zwrite_file = WriteZipBuffer;
+ zip_functions.ztell_file = GetOffsetOfZipBuffer;
+ zip_functions.zseek_file = SeekZipBuffer;
+ zip_functions.zclose_file = CloseZipBuffer;
+ zip_functions.zerror_file = GetErrorOfZipBuffer;
+ zip_functions.opaque = static_cast<void*>(buffer);
+ return unzOpen2(NULL, &zip_functions);
+}
+
+zipFile OpenForZipping(const std::string& file_name_utf8, int append_flag) {
+ zlib_filefunc_def* zip_func_ptrs = NULL;
+#if defined(OS_WIN)
+ zlib_filefunc_def zip_funcs;
+ fill_win32_filefunc(&zip_funcs);
+ zip_funcs.zopen_file = ZipOpenFunc;
+ zip_func_ptrs = &zip_funcs;
+#endif
+ return zipOpen2(file_name_utf8.c_str(),
+ append_flag,
+ NULL, // global comment
+ zip_func_ptrs);
+}
+
+#if defined(OS_POSIX)
+zipFile OpenFdForZipping(int zip_fd, int append_flag) {
+ zlib_filefunc_def zip_funcs;
+ FillFdOpenFileFunc(&zip_funcs, zip_fd);
+ // Passing dummy "fd" filename to zlib.
+ return zipOpen2("fd", append_flag, NULL, &zip_funcs);
+}
+#endif
+
+} // namespace internal
+} // namespace zip
diff --git a/third_party/zlib/google/zip_internal.h b/third_party/zlib/google/zip_internal.h
new file mode 100644
index 0000000..57894be
--- /dev/null
+++ b/third_party/zlib/google/zip_internal.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_ZLIB_GOOGLE_ZIP_INTERNAL_H_
+#define THIRD_PARTY_ZLIB_GOOGLE_ZIP_INTERNAL_H_
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include <string>
+
+#if defined(USE_SYSTEM_MINIZIP)
+#include <minizip/unzip.h>
+#include <minizip/zip.h>
+#else
+#include "third_party/zlib/contrib/minizip/unzip.h"
+#include "third_party/zlib/contrib/minizip/zip.h"
+#endif
+
+// Utility functions and constants used internally for the zip file
+// library in the directory. Don't use them outside of the library.
+namespace zip {
+namespace internal {
+
+// Opens the given file name in UTF-8 for unzipping, with some setup for
+// Windows.
+unzFile OpenForUnzipping(const std::string& file_name_utf8);
+
+#if defined(OS_POSIX)
+// Opens the file referred to by |zip_fd| for unzipping.
+unzFile OpenFdForUnzipping(int zip_fd);
+#endif
+
+#if defined(OS_WIN)
+// Opens the file referred to by |zip_handle| for unzipping.
+unzFile OpenHandleForUnzipping(HANDLE zip_handle);
+#endif
+
+// Creates a custom unzFile object which reads data from the specified string.
+// This custom unzFile object overrides the I/O API functions of zlib so it can
+// read data from the specified string.
+unzFile PreprareMemoryForUnzipping(const std::string& data);
+
+// Opens the given file name in UTF-8 for zipping, with some setup for
+// Windows. |append_flag| will be passed to zipOpen2().
+zipFile OpenForZipping(const std::string& file_name_utf8, int append_flag);
+
+#if defined(OS_POSIX)
+// Opens the file referred to by |zip_fd| for zipping. |append_flag| will be
+// passed to zipOpen2().
+zipFile OpenFdForZipping(int zip_fd, int append_flag);
+#endif
+
+const int kZipMaxPath = 256;
+const int kZipBufSize = 8192;
+
+} // namespace internal
+} // namespace zip
+
+#endif // THIRD_PARTY_ZLIB_GOOGLE_ZIP_INTERNAL_H_
diff --git a/third_party/zlib/google/zip_reader.cc b/third_party/zlib/google/zip_reader.cc
new file mode 100644
index 0000000..5433b04
--- /dev/null
+++ b/third_party/zlib/google/zip_reader.cc
@@ -0,0 +1,310 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/zlib/google/zip_reader.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "net/base/file_stream.h"
+#include "third_party/zlib/google/zip_internal.h"
+
+#if defined(USE_SYSTEM_MINIZIP)
+#include <minizip/unzip.h>
+#else
+#include "third_party/zlib/contrib/minizip/unzip.h"
+#if defined(OS_WIN)
+#include "third_party/zlib/contrib/minizip/iowin32.h"
+#endif // defined(OS_WIN)
+#endif // defined(USE_SYSTEM_MINIZIP)
+
+namespace zip {
+
+// TODO(satorux): The implementation assumes that file names in zip files
+// are encoded in UTF-8. This is true for zip files created by Zip()
+// function in zip.h, but not true for user-supplied random zip files.
+ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip,
+ const unz_file_info& raw_file_info)
+ : file_path_(base::FilePath::FromUTF8Unsafe(file_name_in_zip)),
+ is_directory_(false) {
+ original_size_ = raw_file_info.uncompressed_size;
+
+ // Directory entries in zip files end with "/".
+ is_directory_ = EndsWith(file_name_in_zip, "/", false);
+
+ // Check the file name here for directory traversal issues. In the name of
+ // simplicity and security, we might reject a valid file name such as "a..b".
+ is_unsafe_ = file_name_in_zip.find("..") != std::string::npos;
+
+ // We also consider that the file name is unsafe, if it's invalid UTF-8.
+ string16 file_name_utf16;
+ if (!UTF8ToUTF16(file_name_in_zip.data(), file_name_in_zip.size(),
+ &file_name_utf16)) {
+ is_unsafe_ = true;
+ }
+
+ // We also consider that the file name is unsafe, if it's absolute.
+ // On Windows, IsAbsolute() returns false for paths starting with "/".
+ if (file_path_.IsAbsolute() || StartsWithASCII(file_name_in_zip, "/", false))
+ is_unsafe_ = true;
+
+ // Construct the last modified time. The timezone info is not present in
+ // zip files, so we construct the time as local time.
+ base::Time::Exploded exploded_time = {}; // Zero-clear.
+ exploded_time.year = raw_file_info.tmu_date.tm_year;
+ // The month in zip file is 0-based, whereas ours is 1-based.
+ exploded_time.month = raw_file_info.tmu_date.tm_mon + 1;
+ exploded_time.day_of_month = raw_file_info.tmu_date.tm_mday;
+ exploded_time.hour = raw_file_info.tmu_date.tm_hour;
+ exploded_time.minute = raw_file_info.tmu_date.tm_min;
+ exploded_time.second = raw_file_info.tmu_date.tm_sec;
+ exploded_time.millisecond = 0;
+ if (exploded_time.HasValidValues()) {
+ last_modified_ = base::Time::FromLocalExploded(exploded_time);
+ } else {
+ // Use Unix time epoch if the time stamp data is invalid.
+ last_modified_ = base::Time::UnixEpoch();
+ }
+}
+
+ZipReader::ZipReader() {
+ Reset();
+}
+
+ZipReader::~ZipReader() {
+ Close();
+}
+
+bool ZipReader::Open(const base::FilePath& zip_file_path) {
+ DCHECK(!zip_file_);
+
+ // Use of "Unsafe" function does not look good, but there is no way to do
+ // this safely on Linux. See file_util.h for details.
+ zip_file_ = internal::OpenForUnzipping(zip_file_path.AsUTF8Unsafe());
+ if (!zip_file_) {
+ return false;
+ }
+
+ return OpenInternal();
+}
+
+bool ZipReader::OpenFromPlatformFile(base::PlatformFile zip_fd) {
+ DCHECK(!zip_file_);
+
+#if defined(OS_POSIX)
+ zip_file_ = internal::OpenFdForUnzipping(zip_fd);
+#elif defined(OS_WIN)
+ zip_file_ = internal::OpenHandleForUnzipping(zip_fd);
+#endif
+ if (!zip_file_) {
+ return false;
+ }
+
+ return OpenInternal();
+}
+
+bool ZipReader::OpenFromString(const std::string& data) {
+ zip_file_ = internal::PreprareMemoryForUnzipping(data);
+ if (!zip_file_)
+ return false;
+ return OpenInternal();
+}
+
+void ZipReader::Close() {
+ if (zip_file_) {
+ unzClose(zip_file_);
+ }
+ Reset();
+}
+
+bool ZipReader::HasMore() {
+ return !reached_end_;
+}
+
+bool ZipReader::AdvanceToNextEntry() {
+ DCHECK(zip_file_);
+
+ // Should not go further if we already reached the end.
+ if (reached_end_)
+ return false;
+
+ unz_file_pos position = {};
+ if (unzGetFilePos(zip_file_, &position) != UNZ_OK)
+ return false;
+ const int current_entry_index = position.num_of_file;
+ // If we are currently at the last entry, then the next position is the
+ // end of the zip file, so mark that we reached the end.
+ if (current_entry_index + 1 == num_entries_) {
+ reached_end_ = true;
+ } else {
+ DCHECK_LT(current_entry_index + 1, num_entries_);
+ if (unzGoToNextFile(zip_file_) != UNZ_OK) {
+ return false;
+ }
+ }
+ current_entry_info_.reset();
+ return true;
+}
+
+bool ZipReader::OpenCurrentEntryInZip() {
+ DCHECK(zip_file_);
+
+ unz_file_info raw_file_info = {};
+ char raw_file_name_in_zip[internal::kZipMaxPath] = {};
+ const int result = unzGetCurrentFileInfo(zip_file_,
+ &raw_file_info,
+ raw_file_name_in_zip,
+ sizeof(raw_file_name_in_zip) - 1,
+ NULL, // extraField.
+ 0, // extraFieldBufferSize.
+ NULL, // szComment.
+ 0); // commentBufferSize.
+ if (result != UNZ_OK)
+ return false;
+ if (raw_file_name_in_zip[0] == '\0')
+ return false;
+ current_entry_info_.reset(
+ new EntryInfo(raw_file_name_in_zip, raw_file_info));
+ return true;
+}
+
+bool ZipReader::LocateAndOpenEntry(const base::FilePath& path_in_zip) {
+ DCHECK(zip_file_);
+
+ current_entry_info_.reset();
+ reached_end_ = false;
+ const int kDefaultCaseSensivityOfOS = 0;
+ const int result = unzLocateFile(zip_file_,
+ path_in_zip.AsUTF8Unsafe().c_str(),
+ kDefaultCaseSensivityOfOS);
+ if (result != UNZ_OK)
+ return false;
+
+ // Then Open the entry.
+ return OpenCurrentEntryInZip();
+}
+
+bool ZipReader::ExtractCurrentEntryToFilePath(
+ const base::FilePath& output_file_path) {
+ DCHECK(zip_file_);
+
+ // If this is a directory, just create it and return.
+ if (current_entry_info()->is_directory())
+ return file_util::CreateDirectory(output_file_path);
+
+ const int open_result = unzOpenCurrentFile(zip_file_);
+ if (open_result != UNZ_OK)
+ return false;
+
+ // We can't rely on parent directory entries being specified in the
+ // zip, so we make sure they are created.
+ base::FilePath output_dir_path = output_file_path.DirName();
+ if (!file_util::CreateDirectory(output_dir_path))
+ return false;
+
+ net::FileStream stream(NULL);
+ const int flags = (base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_WRITE);
+ if (stream.OpenSync(output_file_path, flags) != 0)
+ return false;
+
+ bool success = true; // This becomes false when something bad happens.
+ while (true) {
+ char buf[internal::kZipBufSize];
+ const int num_bytes_read = unzReadCurrentFile(zip_file_, buf,
+ internal::kZipBufSize);
+ if (num_bytes_read == 0) {
+ // Reached the end of the file.
+ break;
+ } else if (num_bytes_read < 0) {
+ // If num_bytes_read < 0, then it's a specific UNZ_* error code.
+ success = false;
+ break;
+ } else if (num_bytes_read > 0) {
+ // Some data is read. Write it to the output file.
+ if (num_bytes_read != stream.WriteSync(buf, num_bytes_read)) {
+ success = false;
+ break;
+ }
+ }
+ }
+
+ unzCloseCurrentFile(zip_file_);
+ return success;
+}
+
+bool ZipReader::ExtractCurrentEntryIntoDirectory(
+ const base::FilePath& output_directory_path) {
+ DCHECK(current_entry_info_.get());
+
+ base::FilePath output_file_path = output_directory_path.Append(
+ current_entry_info()->file_path());
+ return ExtractCurrentEntryToFilePath(output_file_path);
+}
+
+#if defined(OS_POSIX)
+bool ZipReader::ExtractCurrentEntryToFd(const int fd) {
+ DCHECK(zip_file_);
+
+ // If this is a directory, there's nothing to extract to the file descriptor,
+ // so return false.
+ if (current_entry_info()->is_directory())
+ return false;
+
+ const int open_result = unzOpenCurrentFile(zip_file_);
+ if (open_result != UNZ_OK)
+ return false;
+
+ bool success = true; // This becomes false when something bad happens.
+ while (true) {
+ char buf[internal::kZipBufSize];
+ const int num_bytes_read = unzReadCurrentFile(zip_file_, buf,
+ internal::kZipBufSize);
+ if (num_bytes_read == 0) {
+ // Reached the end of the file.
+ break;
+ } else if (num_bytes_read < 0) {
+ // If num_bytes_read < 0, then it's a specific UNZ_* error code.
+ success = false;
+ break;
+ } else if (num_bytes_read > 0) {
+ // Some data is read. Write it to the output file descriptor.
+ if (num_bytes_read !=
+ file_util::WriteFileDescriptor(fd, buf, num_bytes_read)) {
+ success = false;
+ break;
+ }
+ }
+ }
+
+ unzCloseCurrentFile(zip_file_);
+ return success;
+}
+#endif // defined(OS_POSIX)
+
+bool ZipReader::OpenInternal() {
+ DCHECK(zip_file_);
+
+ unz_global_info zip_info = {}; // Zero-clear.
+ if (unzGetGlobalInfo(zip_file_, &zip_info) != UNZ_OK) {
+ return false;
+ }
+ num_entries_ = zip_info.number_entry;
+ if (num_entries_ < 0)
+ return false;
+
+ // We are already at the end if the zip file is empty.
+ reached_end_ = (num_entries_ == 0);
+ return true;
+}
+
+void ZipReader::Reset() {
+ zip_file_ = NULL;
+ num_entries_ = 0;
+ reached_end_ = false;
+ current_entry_info_.reset();
+}
+
+} // namespace zip
diff --git a/third_party/zlib/google/zip_reader.h b/third_party/zlib/google/zip_reader.h
new file mode 100644
index 0000000..4064da4
--- /dev/null
+++ b/third_party/zlib/google/zip_reader.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_ZLIB_GOOGLE_ZIP_READER_H_
+#define THIRD_PARTY_ZLIB_GOOGLE_ZIP_READER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/platform_file.h"
+#include "base/time.h"
+
+#if defined(USE_SYSTEM_MINIZIP)
+#include <minizip/unzip.h>
+#else
+#include "third_party/zlib/contrib/minizip/unzip.h"
+#endif
+
+namespace zip {
+
+// This class is used for reading zip files. A typical use case of this
+// class is to scan entries in a zip file and extract them. The code will
+// look like:
+//
+// ZipReader reader;
+// reader.Open(zip_file_path);
+// while (reader.HasMore()) {
+// reader.OpenCurrentEntryInZip();
+// reader.ExtractCurrentEntryToDirectory(output_directory_path);
+// reader.AdvanceToNextEntry();
+// }
+//
+// For simplicty, error checking is omitted in the example code above. The
+// production code should check return values from all of these functions.
+//
+// This calls can also be used for random access of contents in a zip file
+// using LocateAndOpenEntry().
+//
+class ZipReader {
+ public:
+ // This class represents information of an entry (file or directory) in
+ // a zip file.
+ class EntryInfo {
+ public:
+ EntryInfo(const std::string& filename_in_zip,
+ const unz_file_info& raw_file_info);
+
+ // Returns the file path. The path is usually relative like
+ // "foo/bar.txt", but if it's absolute, is_unsafe() returns true.
+ const base::FilePath& file_path() const { return file_path_; }
+
+ // Returns the size of the original file (i.e. after uncompressed).
+ // Returns 0 if the entry is a directory.
+ int64 original_size() const { return original_size_; }
+
+ // Returns the last modified time.
+ base::Time last_modified() const { return last_modified_; }
+
+ // Returns true if the entry is a directory.
+ bool is_directory() const { return is_directory_; }
+
+ // Returns true if the entry is unsafe, like having ".." or invalid
+ // UTF-8 characters in its file name, or the file path is absolute.
+ bool is_unsafe() const { return is_unsafe_; }
+
+ private:
+ const base::FilePath file_path_;
+ int64 original_size_;
+ base::Time last_modified_;
+ bool is_directory_;
+ bool is_unsafe_;
+ DISALLOW_COPY_AND_ASSIGN(EntryInfo);
+ };
+
+ ZipReader();
+ ~ZipReader();
+
+ // Opens the zip file specified by |zip_file_path|. Returns true on
+ // success.
+ bool Open(const base::FilePath& zip_file_path);
+
+ // Opens the zip file referred to by the platform file |zip_fd|.
+ // Returns true on success.
+ bool OpenFromPlatformFile(base::PlatformFile zip_fd);
+
+ // Opens the zip data stored in |data|. This class uses a weak reference to
+ // the given sring while extracting files, i.e. the caller should keep the
+ // string until it finishes extracting files.
+ bool OpenFromString(const std::string& data);
+
+ // Closes the currently opened zip file. This function is called in the
+ // destructor of the class, so you usually don't need to call this.
+ void Close();
+
+ // Returns true if there is at least one entry to read. This function is
+ // used to scan entries with AdvanceToNextEntry(), like:
+ //
+ // while (reader.HasMore()) {
+ // // Do something with the current file here.
+ // reader.AdvanceToNextEntry();
+ // }
+ bool HasMore();
+
+ // Advances the next entry. Returns true on success.
+ bool AdvanceToNextEntry();
+
+ // Opens the current entry in the zip file. On success, returns true and
+ // updates the the current entry state (i.e. current_entry_info() is
+ // updated). This function should be called before operations over the
+ // current entry like ExtractCurrentEntryToFile().
+ //
+ // Note that there is no CloseCurrentEntryInZip(). The the current entry
+ // state is reset automatically as needed.
+ bool OpenCurrentEntryInZip();
+
+ // Locates an entry in the zip file and opens it. Returns true on
+ // success. This function internally calls OpenCurrentEntryInZip() on
+ // success. On failure, current_entry_info() becomes NULL.
+ bool LocateAndOpenEntry(const base::FilePath& path_in_zip);
+
+ // Extracts the current entry to the given output file path. If the
+ // current file is a directory, just creates a directory
+ // instead. Returns true on success. OpenCurrentEntryInZip() must be
+ // called beforehand.
+ //
+ // This function does not preserve the timestamp of the original entry.
+ bool ExtractCurrentEntryToFilePath(const base::FilePath& output_file_path);
+
+ // Extracts the current entry to the given output directory path using
+ // ExtractCurrentEntryToFilePath(). Sub directories are created as needed
+ // based on the file path of the current entry. For example, if the file
+ // path in zip is "foo/bar.txt", and the output directory is "output",
+ // "output/foo/bar.txt" will be created.
+ //
+ // Returns true on success. OpenCurrentEntryInZip() must be called
+ // beforehand.
+ bool ExtractCurrentEntryIntoDirectory(
+ const base::FilePath& output_directory_path);
+
+#if defined(OS_POSIX)
+ // Extracts the current entry by writing directly to a file descriptor.
+ // Does not close the file descriptor. Returns true on success.
+ bool ExtractCurrentEntryToFd(int fd);
+#endif
+
+ // Returns the current entry info. Returns NULL if the current entry is
+ // not yet opened. OpenCurrentEntryInZip() must be called beforehand.
+ EntryInfo* current_entry_info() const {
+ return current_entry_info_.get();
+ }
+
+ // Returns the number of entries in the zip file.
+ // Open() must be called beforehand.
+ int num_entries() const { return num_entries_; }
+
+ private:
+ // Common code used both in Open and OpenFromFd.
+ bool OpenInternal();
+
+ // Resets the internal state.
+ void Reset();
+
+ unzFile zip_file_;
+ int num_entries_;
+ bool reached_end_;
+ scoped_ptr<EntryInfo> current_entry_info_;
+
+ DISALLOW_COPY_AND_ASSIGN(ZipReader);
+};
+
+} // namespace zip
+
+#endif // THIRD_PARTY_ZLIB_GOOGLE_ZIP_READER_H_
diff --git a/third_party/zlib/google/zip_reader_unittest.cc b/third_party/zlib/google/zip_reader_unittest.cc
new file mode 100644
index 0000000..a12b04e
--- /dev/null
+++ b/third_party/zlib/google/zip_reader_unittest.cc
@@ -0,0 +1,431 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/zlib/google/zip_reader.h"
+
+#include <set>
+#include <string>
+
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/md5.h"
+#include "base/path_service.h"
+#include "base/platform_file.h"
+#include "base/time.h"
+#include "base/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "third_party/zlib/google/zip_internal.h"
+
+namespace {
+
+// Wrap PlatformFiles in a class so that we don't leak them in tests.
+class PlatformFileWrapper {
+ public:
+ typedef enum {
+ READ_ONLY,
+ READ_WRITE
+ } AccessMode;
+
+ PlatformFileWrapper(const base::FilePath& file, AccessMode mode)
+ : file_(base::kInvalidPlatformFileValue) {
+ switch (mode) {
+ case READ_ONLY:
+ file_ = base::CreatePlatformFile(file,
+ base::PLATFORM_FILE_OPEN |
+ base::PLATFORM_FILE_READ,
+ NULL, NULL);
+ break;
+ case READ_WRITE:
+ file_ = base::CreatePlatformFile(file,
+ base::PLATFORM_FILE_CREATE_ALWAYS |
+ base::PLATFORM_FILE_READ |
+ base::PLATFORM_FILE_WRITE,
+ NULL, NULL);
+ break;
+ default:
+ NOTREACHED();
+ }
+ return;
+ }
+
+ ~PlatformFileWrapper() {
+ base::ClosePlatformFile(file_);
+ }
+
+ base::PlatformFile platform_file() { return file_; }
+
+ private:
+ base::PlatformFile file_;
+};
+
+} // namespace
+
+namespace zip {
+
+// Make the test a PlatformTest to setup autorelease pools properly on Mac.
+class ZipReaderTest : public PlatformTest {
+ protected:
+ virtual void SetUp() {
+ PlatformTest::SetUp();
+
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ test_dir_ = temp_dir_.path();
+
+ ASSERT_TRUE(GetTestDataDirectory(&test_data_dir_));
+
+ test_zip_file_ = test_data_dir_.AppendASCII("test.zip");
+ evil_zip_file_ = test_data_dir_.AppendASCII("evil.zip");
+ evil_via_invalid_utf8_zip_file_ = test_data_dir_.AppendASCII(
+ "evil_via_invalid_utf8.zip");
+ evil_via_absolute_file_name_zip_file_ = test_data_dir_.AppendASCII(
+ "evil_via_absolute_file_name.zip");
+
+ test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/")));
+ test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/bar/")));
+ test_zip_contents_.insert(
+ base::FilePath(FILE_PATH_LITERAL("foo/bar/baz.txt")));
+ test_zip_contents_.insert(
+ base::FilePath(FILE_PATH_LITERAL("foo/bar/quux.txt")));
+ test_zip_contents_.insert(
+ base::FilePath(FILE_PATH_LITERAL("foo/bar.txt")));
+ test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo.txt")));
+ test_zip_contents_.insert(
+ base::FilePath(FILE_PATH_LITERAL("foo/bar/.hidden")));
+ }
+
+ virtual void TearDown() {
+ PlatformTest::TearDown();
+ }
+
+ bool GetTestDataDirectory(base::FilePath* path) {
+ bool success = PathService::Get(base::DIR_SOURCE_ROOT, path);
+ EXPECT_TRUE(success);
+ if (!success)
+ return false;
+ *path = path->AppendASCII("third_party");
+ *path = path->AppendASCII("zlib");
+ *path = path->AppendASCII("google");
+ *path = path->AppendASCII("test");
+ *path = path->AppendASCII("data");
+ return true;
+ }
+
+ // The path to temporary directory used to contain the test operations.
+ base::FilePath test_dir_;
+ // The path to the test data directory where test.zip etc. are located.
+ base::FilePath test_data_dir_;
+ // The path to test.zip in the test data directory.
+ base::FilePath test_zip_file_;
+ // The path to evil.zip in the test data directory.
+ base::FilePath evil_zip_file_;
+ // The path to evil_via_invalid_utf8.zip in the test data directory.
+ base::FilePath evil_via_invalid_utf8_zip_file_;
+ // The path to evil_via_absolute_file_name.zip in the test data directory.
+ base::FilePath evil_via_absolute_file_name_zip_file_;
+ std::set<base::FilePath> test_zip_contents_;
+
+ base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(ZipReaderTest, Open_ValidZipFile) {
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+}
+
+TEST_F(ZipReaderTest, Open_ValidZipPlatformFile) {
+ ZipReader reader;
+ PlatformFileWrapper zip_fd_wrapper(test_zip_file_,
+ PlatformFileWrapper::READ_ONLY);
+ ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
+}
+
+TEST_F(ZipReaderTest, Open_NonExistentFile) {
+ ZipReader reader;
+ ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("nonexistent.zip")));
+}
+
+TEST_F(ZipReaderTest, Open_ExistentButNonZipFile) {
+ ZipReader reader;
+ ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("create_test_zip.sh")));
+}
+
+// Iterate through the contents in the test zip file, and compare that the
+// contents collected from the zip reader matches the expected contents.
+TEST_F(ZipReaderTest, Iteration) {
+ std::set<base::FilePath> actual_contents;
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+ while (reader.HasMore()) {
+ ASSERT_TRUE(reader.OpenCurrentEntryInZip());
+ actual_contents.insert(reader.current_entry_info()->file_path());
+ ASSERT_TRUE(reader.AdvanceToNextEntry());
+ }
+ EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further.
+ EXPECT_EQ(test_zip_contents_.size(),
+ static_cast<size_t>(reader.num_entries()));
+ EXPECT_EQ(test_zip_contents_.size(), actual_contents.size());
+ EXPECT_EQ(test_zip_contents_, actual_contents);
+}
+
+// Open the test zip file from a file descriptor, iterate through its contents,
+// and compare that they match the expected contents.
+TEST_F(ZipReaderTest, PlatformFileIteration) {
+ std::set<base::FilePath> actual_contents;
+ ZipReader reader;
+ PlatformFileWrapper zip_fd_wrapper(test_zip_file_,
+ PlatformFileWrapper::READ_ONLY);
+ ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
+ while (reader.HasMore()) {
+ ASSERT_TRUE(reader.OpenCurrentEntryInZip());
+ actual_contents.insert(reader.current_entry_info()->file_path());
+ ASSERT_TRUE(reader.AdvanceToNextEntry());
+ }
+ EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further.
+ EXPECT_EQ(test_zip_contents_.size(),
+ static_cast<size_t>(reader.num_entries()));
+ EXPECT_EQ(test_zip_contents_.size(), actual_contents.size());
+ EXPECT_EQ(test_zip_contents_, actual_contents);
+}
+
+TEST_F(ZipReaderTest, LocateAndOpenEntry_ValidFile) {
+ std::set<base::FilePath> actual_contents;
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+ base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ EXPECT_EQ(target_path, reader.current_entry_info()->file_path());
+}
+
+TEST_F(ZipReaderTest, LocateAndOpenEntry_NonExistentFile) {
+ std::set<base::FilePath> actual_contents;
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+ base::FilePath target_path(FILE_PATH_LITERAL("nonexistent.txt"));
+ ASSERT_FALSE(reader.LocateAndOpenEntry(target_path));
+ EXPECT_EQ(NULL, reader.current_entry_info());
+}
+
+TEST_F(ZipReaderTest, ExtractCurrentEntryToFilePath_RegularFile) {
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+ base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
+ test_dir_.AppendASCII("quux.txt")));
+ // Read the output file ans compute the MD5.
+ std::string output;
+ ASSERT_TRUE(file_util::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
+ &output));
+ const std::string md5 = base::MD5String(output);
+ const std::string kExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6";
+ EXPECT_EQ(kExpectedMD5, md5);
+ // quux.txt should be larger than kZipBufSize so that we can exercise
+ // the loop in ExtractCurrentEntry().
+ EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size());
+}
+
+TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFilePath_RegularFile) {
+ ZipReader reader;
+ PlatformFileWrapper zip_fd_wrapper(test_zip_file_,
+ PlatformFileWrapper::READ_ONLY);
+ ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
+ base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
+ test_dir_.AppendASCII("quux.txt")));
+ // Read the output file and compute the MD5.
+ std::string output;
+ ASSERT_TRUE(file_util::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
+ &output));
+ const std::string md5 = base::MD5String(output);
+ const std::string kExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6";
+ EXPECT_EQ(kExpectedMD5, md5);
+ // quux.txt should be larger than kZipBufSize so that we can exercise
+ // the loop in ExtractCurrentEntry().
+ EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size());
+}
+
+#if defined(OS_POSIX)
+TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFd_RegularFile) {
+ ZipReader reader;
+ PlatformFileWrapper zip_fd_wrapper(test_zip_file_,
+ PlatformFileWrapper::READ_ONLY);
+ ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
+ base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
+ base::FilePath out_path = test_dir_.AppendASCII("quux.txt");
+ PlatformFileWrapper out_fd_w(out_path, PlatformFileWrapper::READ_WRITE);
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ASSERT_TRUE(reader.ExtractCurrentEntryToFd(out_fd_w.platform_file()));
+ // Read the output file and compute the MD5.
+ std::string output;
+ ASSERT_TRUE(file_util::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
+ &output));
+ const std::string md5 = base::MD5String(output);
+ const std::string kExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6";
+ EXPECT_EQ(kExpectedMD5, md5);
+ // quux.txt should be larger than kZipBufSize so that we can exercise
+ // the loop in ExtractCurrentEntry().
+ EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size());
+}
+#endif
+
+TEST_F(ZipReaderTest, ExtractCurrentEntryToFilePath_Directory) {
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+ base::FilePath target_path(FILE_PATH_LITERAL("foo/"));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
+ test_dir_.AppendASCII("foo")));
+ // The directory should be created.
+ ASSERT_TRUE(file_util::DirectoryExists(test_dir_.AppendASCII("foo")));
+}
+
+TEST_F(ZipReaderTest, ExtractCurrentEntryIntoDirectory_RegularFile) {
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+ base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ASSERT_TRUE(reader.ExtractCurrentEntryIntoDirectory(test_dir_));
+ // Sub directories should be created.
+ ASSERT_TRUE(file_util::DirectoryExists(test_dir_.AppendASCII("foo/bar")));
+ // And the file should be created.
+ std::string output;
+ ASSERT_TRUE(file_util::ReadFileToString(
+ test_dir_.AppendASCII("foo/bar/quux.txt"), &output));
+ const std::string md5 = base::MD5String(output);
+ const std::string kExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6";
+ EXPECT_EQ(kExpectedMD5, md5);
+}
+
+TEST_F(ZipReaderTest, current_entry_info_RegularFile) {
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+ base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
+
+ EXPECT_EQ(target_path, current_entry_info->file_path());
+ EXPECT_EQ(13527, current_entry_info->original_size());
+
+ // The expected time stamp: 2009-05-29 06:22:20
+ base::Time::Exploded exploded = {}; // Zero-clear.
+ current_entry_info->last_modified().LocalExplode(&exploded);
+ EXPECT_EQ(2009, exploded.year);
+ EXPECT_EQ(5, exploded.month);
+ EXPECT_EQ(29, exploded.day_of_month);
+ EXPECT_EQ(6, exploded.hour);
+ EXPECT_EQ(22, exploded.minute);
+ EXPECT_EQ(20, exploded.second);
+ EXPECT_EQ(0, exploded.millisecond);
+
+ EXPECT_FALSE(current_entry_info->is_unsafe());
+ EXPECT_FALSE(current_entry_info->is_directory());
+}
+
+TEST_F(ZipReaderTest, current_entry_info_DotDotFile) {
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(evil_zip_file_));
+ base::FilePath target_path(FILE_PATH_LITERAL(
+ "../levilevilevilevilevilevilevilevilevilevilevilevil"));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
+ EXPECT_EQ(target_path, current_entry_info->file_path());
+
+ // This file is unsafe because of ".." in the file name.
+ EXPECT_TRUE(current_entry_info->is_unsafe());
+ EXPECT_FALSE(current_entry_info->is_directory());
+}
+
+TEST_F(ZipReaderTest, current_entry_info_InvalidUTF8File) {
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(evil_via_invalid_utf8_zip_file_));
+ // The evil file is the 2nd file in the zip file.
+ // We cannot locate by the file name ".\x80.\\evil.txt",
+ // as FilePath may internally convert the string.
+ ASSERT_TRUE(reader.AdvanceToNextEntry());
+ ASSERT_TRUE(reader.OpenCurrentEntryInZip());
+ ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
+
+ // This file is unsafe because of invalid UTF-8 in the file name.
+ EXPECT_TRUE(current_entry_info->is_unsafe());
+ EXPECT_FALSE(current_entry_info->is_directory());
+}
+
+TEST_F(ZipReaderTest, current_entry_info_AbsoluteFile) {
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(evil_via_absolute_file_name_zip_file_));
+ base::FilePath target_path(FILE_PATH_LITERAL("/evil.txt"));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
+ EXPECT_EQ(target_path, current_entry_info->file_path());
+
+ // This file is unsafe because of the absolute file name.
+ EXPECT_TRUE(current_entry_info->is_unsafe());
+ EXPECT_FALSE(current_entry_info->is_directory());
+}
+
+TEST_F(ZipReaderTest, current_entry_info_Directory) {
+ ZipReader reader;
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+ base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/"));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
+
+ EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("foo/bar/")),
+ current_entry_info->file_path());
+ // The directory size should be zero.
+ EXPECT_EQ(0, current_entry_info->original_size());
+
+ // The expected time stamp: 2009-05-31 15:49:52
+ base::Time::Exploded exploded = {}; // Zero-clear.
+ current_entry_info->last_modified().LocalExplode(&exploded);
+ EXPECT_EQ(2009, exploded.year);
+ EXPECT_EQ(5, exploded.month);
+ EXPECT_EQ(31, exploded.day_of_month);
+ EXPECT_EQ(15, exploded.hour);
+ EXPECT_EQ(49, exploded.minute);
+ EXPECT_EQ(52, exploded.second);
+ EXPECT_EQ(0, exploded.millisecond);
+
+ EXPECT_FALSE(current_entry_info->is_unsafe());
+ EXPECT_TRUE(current_entry_info->is_directory());
+}
+
+// Verifies that the ZipReader class can extract a file from a zip archive
+// stored in memory. This test opens a zip archive in a std::string object,
+// extracts its content, and verifies the content is the same as the expected
+// text.
+TEST_F(ZipReaderTest, OpenFromString) {
+ // A zip archive consisting of one file "test.txt", which is a 16-byte text
+ // file that contains "This is a test.\n".
+ const char kTestData[] =
+ "\x50\x4b\x03\x04\x0a\x00\x00\x00\x00\x00\xa4\x66\x24\x41\x13\xe8"
+ "\xcb\x27\x10\x00\x00\x00\x10\x00\x00\x00\x08\x00\x1c\x00\x74\x65"
+ "\x73\x74\x2e\x74\x78\x74\x55\x54\x09\x00\x03\x34\x89\x45\x50\x34"
+ "\x89\x45\x50\x75\x78\x0b\x00\x01\x04\x8e\xf0\x00\x00\x04\x88\x13"
+ "\x00\x00\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74"
+ "\x2e\x0a\x50\x4b\x01\x02\x1e\x03\x0a\x00\x00\x00\x00\x00\xa4\x66"
+ "\x24\x41\x13\xe8\xcb\x27\x10\x00\x00\x00\x10\x00\x00\x00\x08\x00"
+ "\x18\x00\x00\x00\x00\x00\x01\x00\x00\x00\xa4\x81\x00\x00\x00\x00"
+ "\x74\x65\x73\x74\x2e\x74\x78\x74\x55\x54\x05\x00\x03\x34\x89\x45"
+ "\x50\x75\x78\x0b\x00\x01\x04\x8e\xf0\x00\x00\x04\x88\x13\x00\x00"
+ "\x50\x4b\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00\x4e\x00\x00\x00"
+ "\x52\x00\x00\x00\x00\x00";
+ std::string data(kTestData, arraysize(kTestData));
+ ZipReader reader;
+ ASSERT_TRUE(reader.OpenFromString(data));
+ base::FilePath target_path(FILE_PATH_LITERAL("test.txt"));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ASSERT_TRUE(reader.ExtractCurrentEntryToFilePath(
+ test_dir_.AppendASCII("test.txt")));
+
+ std::string actual;
+ ASSERT_TRUE(file_util::ReadFileToString(
+ test_dir_.AppendASCII("test.txt"), &actual));
+ EXPECT_EQ(std::string("This is a test.\n"), actual);
+}
+
+} // namespace zip
diff --git a/third_party/zlib/google/zip_unittest.cc b/third_party/zlib/google/zip_unittest.cc
new file mode 100644
index 0000000..3f7911e
--- /dev/null
+++ b/third_party/zlib/google/zip_unittest.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <set>
+#include <vector>
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "third_party/zlib/google/zip.h"
+#include "third_party/zlib/google/zip_reader.h"
+
+namespace {
+
+// Make the test a PlatformTest to setup autorelease pools properly on Mac.
+class ZipTest : public PlatformTest {
+ protected:
+ virtual void SetUp() {
+ PlatformTest::SetUp();
+
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ test_dir_ = temp_dir_.path();
+
+ base::FilePath zip_path(test_dir_);
+ zip_contents_.insert(zip_path.AppendASCII("foo.txt"));
+ zip_path = zip_path.AppendASCII("foo");
+ zip_contents_.insert(zip_path);
+ zip_contents_.insert(zip_path.AppendASCII("bar.txt"));
+ zip_path = zip_path.AppendASCII("bar");
+ zip_contents_.insert(zip_path);
+ zip_contents_.insert(zip_path.AppendASCII("baz.txt"));
+ zip_contents_.insert(zip_path.AppendASCII("quux.txt"));
+ zip_contents_.insert(zip_path.AppendASCII(".hidden"));
+
+ // Include a subset of files in |zip_file_list_| to test ZipFiles().
+ zip_file_list_.push_back(base::FilePath(FILE_PATH_LITERAL("foo.txt")));
+ zip_file_list_.push_back(
+ base::FilePath(FILE_PATH_LITERAL("foo/bar/quux.txt")));
+ zip_file_list_.push_back(
+ base::FilePath(FILE_PATH_LITERAL("foo/bar/.hidden")));
+ }
+
+ virtual void TearDown() {
+ PlatformTest::TearDown();
+ }
+
+ bool GetTestDataDirectory(base::FilePath* path) {
+ bool success = PathService::Get(base::DIR_SOURCE_ROOT, path);
+ EXPECT_TRUE(success);
+ if (!success)
+ return false;
+ *path = path->AppendASCII("third_party");
+ *path = path->AppendASCII("zlib");
+ *path = path->AppendASCII("google");
+ *path = path->AppendASCII("test");
+ *path = path->AppendASCII("data");
+ return true;
+ }
+
+ void TestUnzipFile(const base::FilePath::StringType& filename,
+ bool expect_hidden_files) {
+ base::FilePath test_dir;
+ ASSERT_TRUE(GetTestDataDirectory(&test_dir));
+ TestUnzipFile(test_dir.Append(filename), expect_hidden_files);
+ }
+
+ void TestUnzipFile(const base::FilePath& path, bool expect_hidden_files) {
+ ASSERT_TRUE(file_util::PathExists(path)) << "no file " << path.value();
+ ASSERT_TRUE(zip::Unzip(path, test_dir_));
+
+ file_util::FileEnumerator files(test_dir_, true,
+ file_util::FileEnumerator::FILES |
+ file_util::FileEnumerator::DIRECTORIES);
+ base::FilePath next_path = files.Next();
+ size_t count = 0;
+ while (!next_path.value().empty()) {
+ if (next_path.value().find(FILE_PATH_LITERAL(".svn")) ==
+ base::FilePath::StringType::npos) {
+ EXPECT_EQ(zip_contents_.count(next_path), 1U) <<
+ "Couldn't find " << next_path.value();
+ count++;
+ }
+ next_path = files.Next();
+ }
+
+ size_t expected_count = 0;
+ for (std::set<base::FilePath>::iterator iter = zip_contents_.begin();
+ iter != zip_contents_.end(); ++iter) {
+ if (expect_hidden_files || iter->BaseName().value()[0] != '.')
+ ++expected_count;
+ }
+
+ EXPECT_EQ(expected_count, count);
+ }
+
+ // The path to temporary directory used to contain the test operations.
+ base::FilePath test_dir_;
+
+ base::ScopedTempDir temp_dir_;
+
+ // Hard-coded contents of a known zip file.
+ std::set<base::FilePath> zip_contents_;
+
+ // Hard-coded list of relative paths for a zip file created with ZipFiles.
+ std::vector<base::FilePath> zip_file_list_;
+};
+
+TEST_F(ZipTest, Unzip) {
+ TestUnzipFile(FILE_PATH_LITERAL("test.zip"), true);
+}
+
+TEST_F(ZipTest, UnzipUncompressed) {
+ TestUnzipFile(FILE_PATH_LITERAL("test_nocompress.zip"), true);
+}
+
+TEST_F(ZipTest, UnzipEvil) {
+ base::FilePath path;
+ ASSERT_TRUE(GetTestDataDirectory(&path));
+ path = path.AppendASCII("evil.zip");
+ // Unzip the zip file into a sub directory of test_dir_ so evil.zip
+ // won't create a persistent file outside test_dir_ in case of a
+ // failure.
+ base::FilePath output_dir = test_dir_.AppendASCII("out");
+ ASSERT_FALSE(zip::Unzip(path, output_dir));
+ base::FilePath evil_file = output_dir;
+ evil_file = evil_file.AppendASCII(
+ "../levilevilevilevilevilevilevilevilevilevilevilevil");
+ ASSERT_FALSE(file_util::PathExists(evil_file));
+}
+
+TEST_F(ZipTest, UnzipEvil2) {
+ base::FilePath path;
+ ASSERT_TRUE(GetTestDataDirectory(&path));
+ // The zip file contains an evil file with invalid UTF-8 in its file
+ // name.
+ path = path.AppendASCII("evil_via_invalid_utf8.zip");
+ // See the comment at UnzipEvil() for why we do this.
+ base::FilePath output_dir = test_dir_.AppendASCII("out");
+ // This should fail as it contains an evil file.
+ ASSERT_FALSE(zip::Unzip(path, output_dir));
+ base::FilePath evil_file = output_dir;
+ evil_file = evil_file.AppendASCII("../evil.txt");
+ ASSERT_FALSE(file_util::PathExists(evil_file));
+}
+
+TEST_F(ZipTest, Zip) {
+ base::FilePath src_dir;
+ ASSERT_TRUE(GetTestDataDirectory(&src_dir));
+ src_dir = src_dir.AppendASCII("test");
+
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath zip_file = temp_dir.path().AppendASCII("out.zip");
+
+ EXPECT_TRUE(zip::Zip(src_dir, zip_file, true));
+ TestUnzipFile(zip_file, true);
+}
+
+TEST_F(ZipTest, ZipIgnoreHidden) {
+ base::FilePath src_dir;
+ ASSERT_TRUE(GetTestDataDirectory(&src_dir));
+ src_dir = src_dir.AppendASCII("test");
+
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath zip_file = temp_dir.path().AppendASCII("out.zip");
+
+ EXPECT_TRUE(zip::Zip(src_dir, zip_file, false));
+ TestUnzipFile(zip_file, false);
+}
+
+#if defined(OS_POSIX)
+TEST_F(ZipTest, ZipFiles) {
+ base::FilePath src_dir;
+ ASSERT_TRUE(GetTestDataDirectory(&src_dir));
+ src_dir = src_dir.AppendASCII("test");
+
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath zip_file = temp_dir.path().AppendASCII("out.zip");
+
+ const int flags = base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE;
+ const base::PlatformFile zip_fd =
+ base::CreatePlatformFile(zip_file, flags, NULL, NULL);
+ ASSERT_LE(0, zip_fd);
+ EXPECT_TRUE(zip::ZipFiles(src_dir, zip_file_list_, zip_fd));
+ base::ClosePlatformFile(zip_fd);
+
+ zip::ZipReader reader;
+ EXPECT_TRUE(reader.Open(zip_file));
+ EXPECT_EQ(zip_file_list_.size(), static_cast<size_t>(reader.num_entries()));
+ for (size_t i = 0; i < zip_file_list_.size(); ++i) {
+ EXPECT_TRUE(reader.LocateAndOpenEntry(zip_file_list_[i]));
+ // Check the path in the entry just in case.
+ const zip::ZipReader::EntryInfo* entry_info = reader.current_entry_info();
+ EXPECT_EQ(entry_info->file_path(), zip_file_list_[i]);
+ }
+}
+#endif // defined(OS_POSIX)
+
+} // namespace
+
diff --git a/third_party/zlib/zlib.gyp b/third_party/zlib/zlib.gyp
index 069fb63..ebdad42 100644
--- a/third_party/zlib/zlib.gyp
+++ b/third_party/zlib/zlib.gyp
@@ -106,6 +106,25 @@
],
}],
],
- }
+ },
+ {
+ 'target_name': 'zip',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'minizip',
+ '../../base/base.gyp:base',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'google/zip.cc',
+ 'google/zip.h',
+ 'google/zip_internal.cc',
+ 'google/zip_internal.h',
+ 'google/zip_reader.cc',
+ 'google/zip_reader.h',
+ ],
+ },
],
}