| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "third_party/zlib/google/zip_reader.h" | 5 #include "third_party/zlib/google/zip_reader.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/files/file.h" | 8 #include "base/files/file.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| 11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
| 12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 13 #include "third_party/zlib/google/zip_internal.h" | 13 #include "third_party/zlib/google/zip_internal.h" |
| 14 | 14 |
| 15 #if defined(USE_SYSTEM_MINIZIP) | 15 #if defined(USE_SYSTEM_MINIZIP) |
| 16 #include <minizip/unzip.h> | 16 #include <minizip/unzip.h> |
| 17 #else | 17 #else |
| 18 #include "third_party/zlib/contrib/minizip/unzip.h" | 18 #include "third_party/zlib/contrib/minizip/unzip.h" |
| 19 #if defined(OS_WIN) | 19 #if defined(OS_WIN) |
| 20 #include "third_party/zlib/contrib/minizip/iowin32.h" | 20 #include "third_party/zlib/contrib/minizip/iowin32.h" |
| 21 #endif // defined(OS_WIN) | 21 #endif // defined(OS_WIN) |
| 22 #endif // defined(USE_SYSTEM_MINIZIP) | 22 #endif // defined(USE_SYSTEM_MINIZIP) |
| 23 | 23 |
| 24 namespace zip { | 24 namespace zip { |
| 25 | 25 |
| 26 namespace { |
| 27 |
| 28 // FilePathWriterDelegate ------------------------------------------------------ |
| 29 |
| 30 // A writer delegate that writes a file at a given path. |
| 31 class FilePathWriterDelegate : public WriterDelegate { |
| 32 public: |
| 33 explicit FilePathWriterDelegate(const base::FilePath& output_file_path); |
| 34 ~FilePathWriterDelegate() override; |
| 35 |
| 36 // WriterDelegate methods: |
| 37 |
| 38 // Creates the output file and any necessary intermediate directories. |
| 39 bool PrepareOutput() override; |
| 40 |
| 41 // Writes |num_bytes| bytes of |data| to the file, returning false if not all |
| 42 // bytes could be written. |
| 43 bool WriteBytes(const char* data, int num_bytes) override; |
| 44 |
| 45 private: |
| 46 base::FilePath output_file_path_; |
| 47 base::File file_; |
| 48 |
| 49 DISALLOW_COPY_AND_ASSIGN(FilePathWriterDelegate); |
| 50 }; |
| 51 |
| 52 FilePathWriterDelegate::FilePathWriterDelegate( |
| 53 const base::FilePath& output_file_path) |
| 54 : output_file_path_(output_file_path) { |
| 55 } |
| 56 |
| 57 FilePathWriterDelegate::~FilePathWriterDelegate() { |
| 58 } |
| 59 |
| 60 bool FilePathWriterDelegate::PrepareOutput() { |
| 61 // We can't rely on parent directory entries being specified in the |
| 62 // zip, so we make sure they are created. |
| 63 if (!base::CreateDirectory(output_file_path_.DirName())) |
| 64 return false; |
| 65 |
| 66 file_.Initialize(output_file_path_, |
| 67 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); |
| 68 return file_.IsValid(); |
| 69 } |
| 70 |
| 71 bool FilePathWriterDelegate::WriteBytes(const char* data, int num_bytes) { |
| 72 return num_bytes == file_.WriteAtCurrentPos(data, num_bytes); |
| 73 } |
| 74 |
| 75 |
| 76 // StringWriterDelegate -------------------------------------------------------- |
| 77 |
| 78 // A writer delegate that writes no more than |max_read_bytes| to a given |
| 79 // std::string. |
| 80 class StringWriterDelegate : public WriterDelegate { |
| 81 public: |
| 82 StringWriterDelegate(size_t max_read_bytes, std::string* output); |
| 83 ~StringWriterDelegate() override; |
| 84 |
| 85 // WriterDelegate methods: |
| 86 |
| 87 // Returns true. |
| 88 bool PrepareOutput() override; |
| 89 |
| 90 // Appends |num_bytes| bytes from |data| to the output string. Returns false |
| 91 // if |num_bytes| will cause the string to exceed |max_read_bytes|. |
| 92 bool WriteBytes(const char* data, int num_bytes) override; |
| 93 |
| 94 private: |
| 95 size_t max_read_bytes_; |
| 96 std::string* output_; |
| 97 |
| 98 DISALLOW_COPY_AND_ASSIGN(StringWriterDelegate); |
| 99 }; |
| 100 |
| 101 StringWriterDelegate::StringWriterDelegate(size_t max_read_bytes, |
| 102 std::string* output) |
| 103 : max_read_bytes_(max_read_bytes), |
| 104 output_(output) { |
| 105 } |
| 106 |
| 107 StringWriterDelegate::~StringWriterDelegate() { |
| 108 } |
| 109 |
| 110 bool StringWriterDelegate::PrepareOutput() { |
| 111 return true; |
| 112 } |
| 113 |
| 114 bool StringWriterDelegate::WriteBytes(const char* data, int num_bytes) { |
| 115 if (output_->size() + num_bytes > max_read_bytes_) |
| 116 return false; |
| 117 output_->append(data, num_bytes); |
| 118 return true; |
| 119 } |
| 120 |
| 121 } // namespace |
| 122 |
| 26 // TODO(satorux): The implementation assumes that file names in zip files | 123 // TODO(satorux): The implementation assumes that file names in zip files |
| 27 // are encoded in UTF-8. This is true for zip files created by Zip() | 124 // are encoded in UTF-8. This is true for zip files created by Zip() |
| 28 // function in zip.h, but not true for user-supplied random zip files. | 125 // function in zip.h, but not true for user-supplied random zip files. |
| 29 ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip, | 126 ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip, |
| 30 const unz_file_info& raw_file_info) | 127 const unz_file_info& raw_file_info) |
| 31 : file_path_(base::FilePath::FromUTF8Unsafe(file_name_in_zip)), | 128 : file_path_(base::FilePath::FromUTF8Unsafe(file_name_in_zip)), |
| 32 is_directory_(false) { | 129 is_directory_(false) { |
| 33 original_size_ = raw_file_info.uncompressed_size; | 130 original_size_ = raw_file_info.uncompressed_size; |
| 34 | 131 |
| 35 // Directory entries in zip files end with "/". | 132 // Directory entries in zip files end with "/". |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 const int result = unzLocateFile(zip_file_, | 277 const int result = unzLocateFile(zip_file_, |
| 181 path_in_zip.AsUTF8Unsafe().c_str(), | 278 path_in_zip.AsUTF8Unsafe().c_str(), |
| 182 kDefaultCaseSensivityOfOS); | 279 kDefaultCaseSensivityOfOS); |
| 183 if (result != UNZ_OK) | 280 if (result != UNZ_OK) |
| 184 return false; | 281 return false; |
| 185 | 282 |
| 186 // Then Open the entry. | 283 // Then Open the entry. |
| 187 return OpenCurrentEntryInZip(); | 284 return OpenCurrentEntryInZip(); |
| 188 } | 285 } |
| 189 | 286 |
| 190 bool ZipReader::ExtractCurrentEntryToFilePath( | 287 bool ZipReader::ExtractCurrentEntry(WriterDelegate* delegate) const { |
| 191 const base::FilePath& output_file_path) { | |
| 192 DCHECK(zip_file_); | 288 DCHECK(zip_file_); |
| 193 | 289 |
| 194 // If this is a directory, just create it and return. | |
| 195 if (current_entry_info()->is_directory()) | |
| 196 return base::CreateDirectory(output_file_path); | |
| 197 | |
| 198 const int open_result = unzOpenCurrentFile(zip_file_); | 290 const int open_result = unzOpenCurrentFile(zip_file_); |
| 199 if (open_result != UNZ_OK) | 291 if (open_result != UNZ_OK) |
| 200 return false; | 292 return false; |
| 201 | 293 |
| 202 // We can't rely on parent directory entries being specified in the | 294 if (!delegate->PrepareOutput()) |
| 203 // zip, so we make sure they are created. | |
| 204 base::FilePath output_dir_path = output_file_path.DirName(); | |
| 205 if (!base::CreateDirectory(output_dir_path)) | |
| 206 return false; | |
| 207 | |
| 208 base::File file(output_file_path, | |
| 209 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); | |
| 210 if (!file.IsValid()) | |
| 211 return false; | 295 return false; |
| 212 | 296 |
| 213 bool success = true; // This becomes false when something bad happens. | 297 bool success = true; // This becomes false when something bad happens. |
| 298 scoped_ptr<char[]> buf(new char[internal::kZipBufSize]); |
| 214 while (true) { | 299 while (true) { |
| 215 char buf[internal::kZipBufSize]; | 300 const int num_bytes_read = unzReadCurrentFile(zip_file_, buf.get(), |
| 216 const int num_bytes_read = unzReadCurrentFile(zip_file_, buf, | |
| 217 internal::kZipBufSize); | 301 internal::kZipBufSize); |
| 218 if (num_bytes_read == 0) { | 302 if (num_bytes_read == 0) { |
| 219 // Reached the end of the file. | 303 // Reached the end of the file. |
| 220 break; | 304 break; |
| 221 } else if (num_bytes_read < 0) { | 305 } else if (num_bytes_read < 0) { |
| 222 // If num_bytes_read < 0, then it's a specific UNZ_* error code. | 306 // If num_bytes_read < 0, then it's a specific UNZ_* error code. |
| 223 success = false; | 307 success = false; |
| 224 break; | 308 break; |
| 225 } else if (num_bytes_read > 0) { | 309 } else if (num_bytes_read > 0) { |
| 226 // Some data is read. Write it to the output file. | 310 // Some data is read. |
| 227 if (num_bytes_read != file.WriteAtCurrentPos(buf, num_bytes_read)) { | 311 if (!delegate->WriteBytes(buf.get(), num_bytes_read)) { |
| 228 success = false; | 312 success = false; |
| 229 break; | 313 break; |
| 230 } | 314 } |
| 231 } | 315 } |
| 232 } | 316 } |
| 233 | 317 |
| 234 file.Close(); | |
| 235 unzCloseCurrentFile(zip_file_); | 318 unzCloseCurrentFile(zip_file_); |
| 236 | 319 |
| 237 if (current_entry_info()->last_modified() != base::Time::UnixEpoch()) | 320 return success; |
| 321 } |
| 322 |
| 323 bool ZipReader::ExtractCurrentEntryToFilePath( |
| 324 const base::FilePath& output_file_path) const { |
| 325 DCHECK(zip_file_); |
| 326 |
| 327 // If this is a directory, just create it and return. |
| 328 if (current_entry_info()->is_directory()) |
| 329 return base::CreateDirectory(output_file_path); |
| 330 |
| 331 bool success = false; |
| 332 { |
| 333 FilePathWriterDelegate writer(output_file_path); |
| 334 success = ExtractCurrentEntry(&writer); |
| 335 } |
| 336 |
| 337 if (success && |
| 338 current_entry_info()->last_modified() != base::Time::UnixEpoch()) { |
| 238 base::TouchFile(output_file_path, | 339 base::TouchFile(output_file_path, |
| 239 base::Time::Now(), | 340 base::Time::Now(), |
| 240 current_entry_info()->last_modified()); | 341 current_entry_info()->last_modified()); |
| 342 } |
| 241 | 343 |
| 242 return success; | 344 return success; |
| 243 } | 345 } |
| 244 | 346 |
| 245 void ZipReader::ExtractCurrentEntryToFilePathAsync( | 347 void ZipReader::ExtractCurrentEntryToFilePathAsync( |
| 246 const base::FilePath& output_file_path, | 348 const base::FilePath& output_file_path, |
| 247 const SuccessCallback& success_callback, | 349 const SuccessCallback& success_callback, |
| 248 const FailureCallback& failure_callback, | 350 const FailureCallback& failure_callback, |
| 249 const ProgressCallback& progress_callback) { | 351 const ProgressCallback& progress_callback) { |
| 250 DCHECK(zip_file_); | 352 DCHECK(zip_file_); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 base::Bind(&ZipReader::ExtractChunk, | 391 base::Bind(&ZipReader::ExtractChunk, |
| 290 weak_ptr_factory_.GetWeakPtr(), | 392 weak_ptr_factory_.GetWeakPtr(), |
| 291 Passed(output_file.Pass()), | 393 Passed(output_file.Pass()), |
| 292 success_callback, | 394 success_callback, |
| 293 failure_callback, | 395 failure_callback, |
| 294 progress_callback, | 396 progress_callback, |
| 295 0 /* initial offset */)); | 397 0 /* initial offset */)); |
| 296 } | 398 } |
| 297 | 399 |
| 298 bool ZipReader::ExtractCurrentEntryIntoDirectory( | 400 bool ZipReader::ExtractCurrentEntryIntoDirectory( |
| 299 const base::FilePath& output_directory_path) { | 401 const base::FilePath& output_directory_path) const { |
| 300 DCHECK(current_entry_info_.get()); | 402 DCHECK(current_entry_info_.get()); |
| 301 | 403 |
| 302 base::FilePath output_file_path = output_directory_path.Append( | 404 base::FilePath output_file_path = output_directory_path.Append( |
| 303 current_entry_info()->file_path()); | 405 current_entry_info()->file_path()); |
| 304 return ExtractCurrentEntryToFilePath(output_file_path); | 406 return ExtractCurrentEntryToFilePath(output_file_path); |
| 305 } | 407 } |
| 306 | 408 |
| 307 #if defined(OS_POSIX) | 409 bool ZipReader::ExtractCurrentEntryToFile(base::File* file) const { |
| 308 bool ZipReader::ExtractCurrentEntryToFd(const int fd) { | |
| 309 DCHECK(zip_file_); | 410 DCHECK(zip_file_); |
| 310 | 411 |
| 311 // If this is a directory, there's nothing to extract to the file descriptor, | 412 // If this is a directory, there's nothing to extract to the file, so return |
| 312 // so return false. | 413 // false. |
| 313 if (current_entry_info()->is_directory()) | 414 if (current_entry_info()->is_directory()) |
| 314 return false; | 415 return false; |
| 315 | 416 |
| 316 const int open_result = unzOpenCurrentFile(zip_file_); | 417 FileWriterDelegate writer(file); |
| 317 if (open_result != UNZ_OK) | 418 return ExtractCurrentEntry(&writer); |
| 318 return false; | 419 } |
| 319 | 420 |
| 320 bool success = true; // This becomes false when something bad happens. | 421 bool ZipReader::ExtractCurrentEntryToString(size_t max_read_bytes, |
| 321 while (true) { | 422 std::string* output) const { |
| 322 char buf[internal::kZipBufSize]; | |
| 323 const int num_bytes_read = unzReadCurrentFile(zip_file_, buf, | |
| 324 internal::kZipBufSize); | |
| 325 if (num_bytes_read == 0) { | |
| 326 // Reached the end of the file. | |
| 327 break; | |
| 328 } else if (num_bytes_read < 0) { | |
| 329 // If num_bytes_read < 0, then it's a specific UNZ_* error code. | |
| 330 success = false; | |
| 331 break; | |
| 332 } else if (num_bytes_read > 0) { | |
| 333 // Some data is read. Write it to the output file descriptor. | |
| 334 if (!base::WriteFileDescriptor(fd, buf, num_bytes_read)) { | |
| 335 success = false; | |
| 336 break; | |
| 337 } | |
| 338 } | |
| 339 } | |
| 340 | |
| 341 unzCloseCurrentFile(zip_file_); | |
| 342 return success; | |
| 343 } | |
| 344 #endif // defined(OS_POSIX) | |
| 345 | |
| 346 bool ZipReader::ExtractCurrentEntryToString( | |
| 347 size_t max_read_bytes, | |
| 348 std::string* output) const { | |
| 349 DCHECK(output); | 423 DCHECK(output); |
| 350 DCHECK(zip_file_); | 424 DCHECK(zip_file_); |
| 351 DCHECK(max_read_bytes != 0); | 425 DCHECK_NE(0U, max_read_bytes); |
| 352 | 426 |
| 353 if (current_entry_info()->is_directory()) { | 427 if (current_entry_info()->is_directory()) { |
| 354 output->clear(); | 428 output->clear(); |
| 355 return true; | 429 return true; |
| 356 } | 430 } |
| 357 | 431 |
| 358 const int open_result = unzOpenCurrentFile(zip_file_); | |
| 359 if (open_result != UNZ_OK) | |
| 360 return false; | |
| 361 | |
| 362 // The original_size() is the best hint for the real size, so it saves | 432 // The original_size() is the best hint for the real size, so it saves |
| 363 // doing reallocations for the common case when the uncompressed size is | 433 // doing reallocations for the common case when the uncompressed size is |
| 364 // correct. However, we need to assume that the uncompressed size could be | 434 // correct. However, we need to assume that the uncompressed size could be |
| 365 // incorrect therefore this function needs to read as much data as possible. | 435 // incorrect therefore this function needs to read as much data as possible. |
| 366 std::string contents; | 436 std::string contents; |
| 367 contents.reserve(static_cast<size_t>(std::min( | 437 contents.reserve(static_cast<size_t>(std::min( |
| 368 static_cast<int64>(max_read_bytes), | 438 static_cast<int64>(max_read_bytes), |
| 369 current_entry_info()->original_size()))); | 439 current_entry_info()->original_size()))); |
| 370 | 440 |
| 371 bool success = true; // This becomes false when something bad happens. | 441 StringWriterDelegate writer(max_read_bytes, &contents); |
| 372 char buf[internal::kZipBufSize]; | 442 if (!ExtractCurrentEntry(&writer)) |
| 373 while (true) { | 443 return false; |
| 374 const int num_bytes_read = unzReadCurrentFile(zip_file_, buf, | 444 output->swap(contents); |
| 375 internal::kZipBufSize); | 445 return true; |
| 376 if (num_bytes_read == 0) { | |
| 377 // Reached the end of the file. | |
| 378 break; | |
| 379 } else if (num_bytes_read < 0) { | |
| 380 // If num_bytes_read < 0, then it's a specific UNZ_* error code. | |
| 381 success = false; | |
| 382 break; | |
| 383 } else if (num_bytes_read > 0) { | |
| 384 if (contents.size() + num_bytes_read > max_read_bytes) { | |
| 385 success = false; | |
| 386 break; | |
| 387 } | |
| 388 contents.append(buf, num_bytes_read); | |
| 389 } | |
| 390 } | |
| 391 | |
| 392 unzCloseCurrentFile(zip_file_); | |
| 393 if (success) | |
| 394 output->swap(contents); | |
| 395 | |
| 396 return success; | |
| 397 } | 446 } |
| 398 | 447 |
| 399 bool ZipReader::OpenInternal() { | 448 bool ZipReader::OpenInternal() { |
| 400 DCHECK(zip_file_); | 449 DCHECK(zip_file_); |
| 401 | 450 |
| 402 unz_global_info zip_info = {}; // Zero-clear. | 451 unz_global_info zip_info = {}; // Zero-clear. |
| 403 if (unzGetGlobalInfo(zip_file_, &zip_info) != UNZ_OK) { | 452 if (unzGetGlobalInfo(zip_file_, &zip_info) != UNZ_OK) { |
| 404 return false; | 453 return false; |
| 405 } | 454 } |
| 406 num_entries_ = zip_info.number_entry; | 455 num_entries_ = zip_info.number_entry; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 weak_ptr_factory_.GetWeakPtr(), | 503 weak_ptr_factory_.GetWeakPtr(), |
| 455 Passed(output_file.Pass()), | 504 Passed(output_file.Pass()), |
| 456 success_callback, | 505 success_callback, |
| 457 failure_callback, | 506 failure_callback, |
| 458 progress_callback, | 507 progress_callback, |
| 459 current_progress)); | 508 current_progress)); |
| 460 | 509 |
| 461 } | 510 } |
| 462 } | 511 } |
| 463 | 512 |
| 513 // FileWriterDelegate ---------------------------------------------------------- |
| 514 |
| 515 FileWriterDelegate::FileWriterDelegate(base::File* file) |
| 516 : file_(file), |
| 517 file_length_(0) { |
| 518 } |
| 519 |
| 520 FileWriterDelegate::~FileWriterDelegate() { |
| 521 #if !defined(NDEBUG) |
| 522 const bool success = |
| 523 #endif |
| 524 file_->SetLength(file_length_); |
| 525 DPLOG_IF(ERROR, !success) << "Failed updating length of written file"; |
| 526 } |
| 527 |
| 528 bool FileWriterDelegate::PrepareOutput() { |
| 529 return file_->Seek(base::File::FROM_BEGIN, 0) >= 0; |
| 530 } |
| 531 |
| 532 bool FileWriterDelegate::WriteBytes(const char* data, int num_bytes) { |
| 533 int bytes_written = file_->WriteAtCurrentPos(data, num_bytes); |
| 534 if (bytes_written > 0) |
| 535 file_length_ += bytes_written; |
| 536 return bytes_written == num_bytes; |
| 537 } |
| 464 | 538 |
| 465 } // namespace zip | 539 } // namespace zip |
| OLD | NEW |