Index: third_party/zlib/google/zip_reader.cc |
diff --git a/third_party/zlib/google/zip_reader.cc b/third_party/zlib/google/zip_reader.cc |
index a1dddfb85388a429ffc2e1308a4c39be57f87b5d..59d96da14263cbfb88d2230e8250396152e8b85c 100644 |
--- a/third_party/zlib/google/zip_reader.cc |
+++ b/third_party/zlib/google/zip_reader.cc |
@@ -23,6 +23,103 @@ |
namespace zip { |
+namespace { |
+ |
+// FilePathWriterDelegate ------------------------------------------------------ |
+ |
+// A writer delegate that writes a file at a given path. |
+class FilePathWriterDelegate : public WriterDelegate { |
+ public: |
+ explicit FilePathWriterDelegate(const base::FilePath& output_file_path); |
+ ~FilePathWriterDelegate() override; |
+ |
+ // WriterDelegate methods: |
+ |
+ // Creates the output file and any necessary intermediate directories. |
+ bool PrepareOutput() override; |
+ |
+ // Writes |num_bytes| bytes of |data| to the file, returning false if not all |
+ // bytes could be written. |
+ bool WriteBytes(const char* data, int num_bytes) override; |
+ |
+ private: |
+ base::FilePath output_file_path_; |
+ base::File file_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(FilePathWriterDelegate); |
+}; |
+ |
+FilePathWriterDelegate::FilePathWriterDelegate( |
+ const base::FilePath& output_file_path) |
+ : output_file_path_(output_file_path) { |
+} |
+ |
+FilePathWriterDelegate::~FilePathWriterDelegate() { |
+} |
+ |
+bool FilePathWriterDelegate::PrepareOutput() { |
+ // We can't rely on parent directory entries being specified in the |
+ // zip, so we make sure they are created. |
+ if (!base::CreateDirectory(output_file_path_.DirName())) |
+ return false; |
+ |
+ file_.Initialize(output_file_path_, |
+ base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); |
+ return file_.IsValid(); |
+} |
+ |
+bool FilePathWriterDelegate::WriteBytes(const char* data, int num_bytes) { |
+ return num_bytes == file_.WriteAtCurrentPos(data, num_bytes); |
+} |
+ |
+ |
+// StringWriterDelegate -------------------------------------------------------- |
+ |
+// A writer delegate that writes no more than |max_read_bytes| to a given |
+// std::string. |
+class StringWriterDelegate : public WriterDelegate { |
+ public: |
+ StringWriterDelegate(size_t max_read_bytes, std::string* output); |
+ ~StringWriterDelegate() override; |
+ |
+ // WriterDelegate methods: |
+ |
+ // Returns true. |
+ bool PrepareOutput() override; |
+ |
+ // Appends |num_bytes| bytes from |data| to the output string. Returns false |
+ // if |num_bytes| will cause the string to exceed |max_read_bytes|. |
+ bool WriteBytes(const char* data, int num_bytes) override; |
+ |
+ private: |
+ size_t max_read_bytes_; |
+ std::string* output_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(StringWriterDelegate); |
+}; |
+ |
+StringWriterDelegate::StringWriterDelegate(size_t max_read_bytes, |
+ std::string* output) |
+ : max_read_bytes_(max_read_bytes), |
+ output_(output) { |
+} |
+ |
+StringWriterDelegate::~StringWriterDelegate() { |
+} |
+ |
+bool StringWriterDelegate::PrepareOutput() { |
+ return true; |
+} |
+ |
+bool StringWriterDelegate::WriteBytes(const char* data, int num_bytes) { |
+ if (output_->size() + num_bytes > max_read_bytes_) |
+ return false; |
+ output_->append(data, num_bytes); |
+ return true; |
+} |
+ |
+} // namespace |
+ |
// 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. |
@@ -187,33 +284,20 @@ bool ZipReader::LocateAndOpenEntry(const base::FilePath& path_in_zip) { |
return OpenCurrentEntryInZip(); |
} |
-bool ZipReader::ExtractCurrentEntryToFilePath( |
- const base::FilePath& output_file_path) { |
+bool ZipReader::ExtractCurrentEntry(WriterDelegate* delegate) const { |
DCHECK(zip_file_); |
- // If this is a directory, just create it and return. |
- if (current_entry_info()->is_directory()) |
- return base::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 (!base::CreateDirectory(output_dir_path)) |
- return false; |
- |
- base::File file(output_file_path, |
- base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); |
- if (!file.IsValid()) |
+ if (!delegate->PrepareOutput()) |
return false; |
bool success = true; // This becomes false when something bad happens. |
+ scoped_ptr<char[]> buf(new char[internal::kZipBufSize]); |
while (true) { |
- char buf[internal::kZipBufSize]; |
- const int num_bytes_read = unzReadCurrentFile(zip_file_, buf, |
+ const int num_bytes_read = unzReadCurrentFile(zip_file_, buf.get(), |
internal::kZipBufSize); |
if (num_bytes_read == 0) { |
// Reached the end of the file. |
@@ -223,21 +307,39 @@ bool ZipReader::ExtractCurrentEntryToFilePath( |
success = false; |
break; |
} else if (num_bytes_read > 0) { |
- // Some data is read. Write it to the output file. |
- if (num_bytes_read != file.WriteAtCurrentPos(buf, num_bytes_read)) { |
+ // Some data is read. |
+ if (!delegate->WriteBytes(buf.get(), num_bytes_read)) { |
success = false; |
break; |
} |
} |
} |
- file.Close(); |
unzCloseCurrentFile(zip_file_); |
- if (current_entry_info()->last_modified() != base::Time::UnixEpoch()) |
+ return success; |
+} |
+ |
+bool ZipReader::ExtractCurrentEntryToFilePath( |
+ const base::FilePath& output_file_path) const { |
+ DCHECK(zip_file_); |
+ |
+ // If this is a directory, just create it and return. |
+ if (current_entry_info()->is_directory()) |
+ return base::CreateDirectory(output_file_path); |
+ |
+ bool success = false; |
+ { |
+ FilePathWriterDelegate writer(output_file_path); |
+ success = ExtractCurrentEntry(&writer); |
+ } |
+ |
+ if (success && |
+ current_entry_info()->last_modified() != base::Time::UnixEpoch()) { |
base::TouchFile(output_file_path, |
base::Time::Now(), |
current_entry_info()->last_modified()); |
+ } |
return success; |
} |
@@ -296,7 +398,7 @@ void ZipReader::ExtractCurrentEntryToFilePathAsync( |
} |
bool ZipReader::ExtractCurrentEntryIntoDirectory( |
- const base::FilePath& output_directory_path) { |
+ const base::FilePath& output_directory_path) const { |
DCHECK(current_entry_info_.get()); |
base::FilePath output_file_path = output_directory_path.Append( |
@@ -304,61 +406,29 @@ bool ZipReader::ExtractCurrentEntryIntoDirectory( |
return ExtractCurrentEntryToFilePath(output_file_path); |
} |
-#if defined(OS_POSIX) |
-bool ZipReader::ExtractCurrentEntryToFd(const int fd) { |
+bool ZipReader::ExtractCurrentEntryToFile(base::File* file) const { |
DCHECK(zip_file_); |
- // If this is a directory, there's nothing to extract to the file descriptor, |
- // so return false. |
+ // If this is a directory, there's nothing to extract to the file, 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 (!base::WriteFileDescriptor(fd, buf, num_bytes_read)) { |
- success = false; |
- break; |
- } |
- } |
- } |
- |
- unzCloseCurrentFile(zip_file_); |
- return success; |
+ FileWriterDelegate writer(file); |
+ return ExtractCurrentEntry(&writer); |
} |
-#endif // defined(OS_POSIX) |
-bool ZipReader::ExtractCurrentEntryToString( |
- size_t max_read_bytes, |
- std::string* output) const { |
+bool ZipReader::ExtractCurrentEntryToString(size_t max_read_bytes, |
+ std::string* output) const { |
DCHECK(output); |
DCHECK(zip_file_); |
- DCHECK(max_read_bytes != 0); |
+ DCHECK_NE(0U, max_read_bytes); |
if (current_entry_info()->is_directory()) { |
output->clear(); |
return true; |
} |
- const int open_result = unzOpenCurrentFile(zip_file_); |
- if (open_result != UNZ_OK) |
- return false; |
- |
// The original_size() is the best hint for the real size, so it saves |
// doing reallocations for the common case when the uncompressed size is |
// correct. However, we need to assume that the uncompressed size could be |
@@ -368,32 +438,11 @@ bool ZipReader::ExtractCurrentEntryToString( |
static_cast<int64>(max_read_bytes), |
current_entry_info()->original_size()))); |
- bool success = true; // This becomes false when something bad happens. |
- char buf[internal::kZipBufSize]; |
- while (true) { |
- 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) { |
- if (contents.size() + num_bytes_read > max_read_bytes) { |
- success = false; |
- break; |
- } |
- contents.append(buf, num_bytes_read); |
- } |
- } |
- |
- unzCloseCurrentFile(zip_file_); |
- if (success) |
- output->swap(contents); |
- |
- return success; |
+ StringWriterDelegate writer(max_read_bytes, &contents); |
+ if (!ExtractCurrentEntry(&writer)) |
+ return false; |
+ output->swap(contents); |
+ return true; |
} |
bool ZipReader::OpenInternal() { |
@@ -461,5 +510,30 @@ void ZipReader::ExtractChunk(base::File output_file, |
} |
} |
+// FileWriterDelegate ---------------------------------------------------------- |
+ |
+FileWriterDelegate::FileWriterDelegate(base::File* file) |
+ : file_(file), |
+ file_length_(0) { |
+} |
+ |
+FileWriterDelegate::~FileWriterDelegate() { |
+#if !defined(NDEBUG) |
+ const bool success = |
+#endif |
+ file_->SetLength(file_length_); |
+ DPLOG_IF(ERROR, !success) << "Failed updating length of written file"; |
+} |
+ |
+bool FileWriterDelegate::PrepareOutput() { |
+ return file_->Seek(base::File::FROM_BEGIN, 0) >= 0; |
+} |
+ |
+bool FileWriterDelegate::WriteBytes(const char* data, int num_bytes) { |
+ int bytes_written = file_->WriteAtCurrentPos(data, num_bytes); |
+ if (bytes_written > 0) |
+ file_length_ += bytes_written; |
+ return bytes_written == num_bytes; |
+} |
} // namespace zip |