| 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 | 
|  |