Chromium Code Reviews| 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 d29082cebbf07e0c24c470951d93ed36141ef486..707c2f514a2c08ed73f03212d4be8bf6226e453a 100644 |
| --- a/third_party/zlib/google/zip_reader.cc |
| +++ b/third_party/zlib/google/zip_reader.cc |
| @@ -5,6 +5,7 @@ |
| #include "third_party/zlib/google/zip_reader.h" |
| #include "base/file_util.h" |
| +#include "base/location.h" |
| #include "base/logging.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| @@ -22,6 +23,40 @@ |
| namespace zip { |
| +namespace { |
| + |
| +// A listener that will close a PlatformFile when the operation is complete, |
| +// with a delegate to pass events to. This is used by some asynchronous |
| +// functions to ensure a PlatformFile is closed when done. |
| +class FileClosingListener : public ZipReader::Listener { |
| + public: |
| + FileClosingListener(scoped_refptr<ZipReader::Listener> delegate, |
| + base::PlatformFile platform_file) |
| + : delegate_(delegate), |
| + platform_file_(platform_file) { |
| + } |
| + |
| + virtual void OnUnzipProgress(int progress) OVERRIDE { |
| + delegate_->OnUnzipProgress(progress); |
| + } |
| + |
| + virtual void OnUnzipSuccess() OVERRIDE { |
| + base::ClosePlatformFile(platform_file_); |
| + delegate_->OnUnzipSuccess(); |
| + } |
| + |
| + virtual void OnUnzipFailed() OVERRIDE { |
| + base::ClosePlatformFile(platform_file_); |
| + delegate_->OnUnzipFailed(); |
| + } |
| + |
| + private: |
| + scoped_refptr<ZipReader::Listener> delegate_; |
| + base::PlatformFile platform_file_; |
| +}; |
| + |
| +} // 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. |
| @@ -69,7 +104,8 @@ ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip, |
| } |
| } |
| -ZipReader::ZipReader() { |
| +ZipReader::ZipReader() |
| + : weak_factory_(this) { |
| Reset(); |
| } |
| @@ -235,6 +271,53 @@ bool ZipReader::ExtractCurrentEntryToFilePath( |
| return success; |
| } |
| +void ZipReader::ExtractCurrentEntryToFilePathAsync( |
| + const base::FilePath& output_file_path, |
| + scoped_refptr<base::MessageLoopProxy> message_loop_proxy, |
| + scoped_refptr<Listener> listener) { |
| + DCHECK(zip_file_); |
| + DCHECK(current_entry_info_.get()); |
| + |
| + // If this is a directory, just create it and return. |
| + if (current_entry_info()->is_directory()) { |
| + if (file_util::CreateDirectory(output_file_path)) { |
| + listener->OnUnzipSuccess(); |
| + } else { |
| + DVLOG(1) << "Unzip failed: unable to create directory."; |
| + listener->OnUnzipFailed(); |
| + } |
| + return; |
| + } |
| + |
| + base::FilePath output_dir_path = output_file_path.DirName(); |
| + if (!file_util::CreateDirectory(output_dir_path)) { |
| + DVLOG(1) << "Unzip failed: unable to create containing directory."; |
| + listener->OnUnzipFailed(); |
| + return; |
| + } |
| + |
| + const int flags = (base::PLATFORM_FILE_CREATE_ALWAYS | |
| + base::PLATFORM_FILE_WRITE); |
| + bool created = false; |
| + base::PlatformFileError platform_file_error; |
| + base::PlatformFile output_file = CreatePlatformFile(output_file_path, |
| + flags, |
| + &created, |
| + &platform_file_error); |
| + |
| + if (platform_file_error != base::PLATFORM_FILE_OK) { |
| + DVLOG(1) << "Unzip failed: unable to create platform file at " |
| + << output_file_path.value(); |
| + listener->OnUnzipFailed(); |
| + return; |
| + } |
| + |
| + ExtractCurrentEntryToPlatformFileAsync(output_file, |
| + message_loop_proxy, |
| + new FileClosingListener(listener, |
| + output_file)); |
| +} |
| + |
| bool ZipReader::ExtractCurrentEntryIntoDirectory( |
| const base::FilePath& output_directory_path) { |
| DCHECK(current_entry_info_.get()); |
| @@ -244,6 +327,49 @@ bool ZipReader::ExtractCurrentEntryIntoDirectory( |
| return ExtractCurrentEntryToFilePath(output_file_path); |
| } |
| +void ZipReader::ExtractCurrentEntryIntoDirectoryAsync( |
| + const base::FilePath& output_directory_path, |
| + scoped_refptr<base::MessageLoopProxy> message_loop_proxy, |
| + scoped_refptr<Listener> listener) { |
| + DCHECK(current_entry_info_.get()); |
| + |
| + base::FilePath output_file_path = output_directory_path.Append( |
| + current_entry_info()->file_path()); |
| + ExtractCurrentEntryToFilePathAsync(output_file_path, |
| + message_loop_proxy, |
| + listener); |
| +} |
| + |
| +void ZipReader::ExtractCurrentEntryToPlatformFileAsync( |
| + base::PlatformFile output_file, |
| + scoped_refptr<base::MessageLoopProxy> message_loop_proxy, |
| + scoped_refptr<Listener> listener) { |
| + DCHECK(zip_file_); |
| + DCHECK(current_entry_info_.get()); |
| + |
| + if (current_entry_info()->is_directory()) { |
| + DVLOG(1) << "Unzip failed: Cannot unzip a directory to an open file."; |
| + listener->OnUnzipFailed(); |
| + } |
| + |
| + if (unzOpenCurrentFile(zip_file_) != UNZ_OK) { |
| + DVLOG(1) << "Unzip failed: unable to open current zip entry."; |
| + listener->OnUnzipFailed(); |
| + return; |
| + } |
| + |
| + message_loop_proxy->PostTask( |
| + FROM_HERE, |
| + base::Bind(&ZipReader::ExtractChunk, |
| + weak_factory_.GetWeakPtr(), |
|
satorux1
2013/12/05 04:39:37
this is worrisome. WeakPtr only works if you are p
Drew Haven
2013/12/09 23:33:12
I left the weakptr in, but I'm using the current m
|
| + output_file, |
| + message_loop_proxy, |
| + listener, |
| + 0, |
| + current_entry_info()->original_size())); |
| +} |
| + |
| + |
| #if defined(OS_POSIX) |
| bool ZipReader::ExtractCurrentEntryToFd(const int fd) { |
| DCHECK(zip_file_); |
| @@ -282,6 +408,15 @@ bool ZipReader::ExtractCurrentEntryToFd(const int fd) { |
| unzCloseCurrentFile(zip_file_); |
| return success; |
| } |
| + |
| +void ZipReader::ExtractCurrentEntryToFdAsync( |
| + int fd, |
| + scoped_refptr<base::MessageLoopProxy> message_loop_proxy, |
| + scoped_refptr<Listener> listener) { |
| + // A POSIX PlatformFile is just an int, so we can use the same internal |
| + // functions. |
| + ExtractCurrentEntryToPlatformFileAsync(fd, message_loop_proxy, listener); |
| +} |
| #endif // defined(OS_POSIX) |
| bool ZipReader::OpenInternal() { |
| @@ -307,4 +442,52 @@ void ZipReader::Reset() { |
| current_entry_info_.reset(); |
| } |
| +void ZipReader::ExtractChunk(base::PlatformFile output_file, |
| + scoped_refptr<base::MessageLoopProxy> message_loop_proxy, |
|
satorux1
2013/12/05 04:39:37
> 80+ chars.
Drew Haven
2013/12/09 23:33:12
Done.
|
| + scoped_refptr<Listener> listener, |
| + int offset, |
| + int size) { |
| + char buffer[internal::kZipBufSize]; |
| + |
| + const int num_bytes_read = unzReadCurrentFile(zip_file_, |
| + buffer, |
| + internal::kZipBufSize); |
| + |
| + if (num_bytes_read == 0) { |
| + unzCloseCurrentFile(zip_file_); |
| + listener->OnUnzipSuccess(); |
| + } else if (num_bytes_read < 0) { |
| + DVLOG(1) << "Unzip failed: error while reading zipfile " |
| + << "(" << num_bytes_read << ")"; |
| + listener->OnUnzipFailed(); |
| + } else { |
| + if (num_bytes_read != base::WritePlatformFileAtCurrentPos(output_file, |
| + buffer, |
| + num_bytes_read)) { |
| + DVLOG(1) << "Unzip failed: unable to write all bytes to target."; |
| + listener->OnUnzipFailed(); |
| + return; |
| + } |
| + |
| + const int prev_progress = offset / size; |
| + const int curr_progress = (offset + num_bytes_read) / size; |
| + |
| + if (curr_progress > prev_progress) { |
| + listener->OnUnzipProgress(curr_progress); |
| + } |
| + |
| + message_loop_proxy->PostTask( |
| + FROM_HERE, |
| + base::Bind(&ZipReader::ExtractChunk, |
| + weak_factory_.GetWeakPtr(), |
| + output_file, |
| + message_loop_proxy, |
| + listener, |
| + offset + num_bytes_read, |
| + size)); |
| + |
| + } |
| +} |
| + |
| + |
| } // namespace zip |