| 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 | |
| 123 // TODO(satorux): The implementation assumes that file names in zip files | 26 // TODO(satorux): The implementation assumes that file names in zip files |
| 124 // are encoded in UTF-8. This is true for zip files created by Zip() | 27 // are encoded in UTF-8. This is true for zip files created by Zip() |
| 125 // function in zip.h, but not true for user-supplied random zip files. | 28 // function in zip.h, but not true for user-supplied random zip files. |
| 126 ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip, | 29 ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip, |
| 127 const unz_file_info& raw_file_info) | 30 const unz_file_info& raw_file_info) |
| 128 : file_path_(base::FilePath::FromUTF8Unsafe(file_name_in_zip)), | 31 : file_path_(base::FilePath::FromUTF8Unsafe(file_name_in_zip)), |
| 129 is_directory_(false) { | 32 is_directory_(false) { |
| 130 original_size_ = raw_file_info.uncompressed_size; | 33 original_size_ = raw_file_info.uncompressed_size; |
| 131 | 34 |
| 132 // Directory entries in zip files end with "/". | 35 // Directory entries in zip files end with "/". |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 const int result = unzLocateFile(zip_file_, | 180 const int result = unzLocateFile(zip_file_, |
| 278 path_in_zip.AsUTF8Unsafe().c_str(), | 181 path_in_zip.AsUTF8Unsafe().c_str(), |
| 279 kDefaultCaseSensivityOfOS); | 182 kDefaultCaseSensivityOfOS); |
| 280 if (result != UNZ_OK) | 183 if (result != UNZ_OK) |
| 281 return false; | 184 return false; |
| 282 | 185 |
| 283 // Then Open the entry. | 186 // Then Open the entry. |
| 284 return OpenCurrentEntryInZip(); | 187 return OpenCurrentEntryInZip(); |
| 285 } | 188 } |
| 286 | 189 |
| 287 bool ZipReader::ExtractCurrentEntry(WriterDelegate* delegate) const { | 190 bool ZipReader::ExtractCurrentEntryToFilePath( |
| 191 const base::FilePath& output_file_path) { |
| 288 DCHECK(zip_file_); | 192 DCHECK(zip_file_); |
| 289 | 193 |
| 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 |
| 290 const int open_result = unzOpenCurrentFile(zip_file_); | 198 const int open_result = unzOpenCurrentFile(zip_file_); |
| 291 if (open_result != UNZ_OK) | 199 if (open_result != UNZ_OK) |
| 292 return false; | 200 return false; |
| 293 | 201 |
| 294 if (!delegate->PrepareOutput()) | 202 // We can't rely on parent directory entries being specified in the |
| 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()) |
| 295 return false; | 211 return false; |
| 296 | 212 |
| 297 bool success = true; // This becomes false when something bad happens. | 213 bool success = true; // This becomes false when something bad happens. |
| 298 scoped_ptr<char[]> buf(new char[internal::kZipBufSize]); | |
| 299 while (true) { | 214 while (true) { |
| 300 const int num_bytes_read = unzReadCurrentFile(zip_file_, buf.get(), | 215 char buf[internal::kZipBufSize]; |
| 216 const int num_bytes_read = unzReadCurrentFile(zip_file_, buf, |
| 301 internal::kZipBufSize); | 217 internal::kZipBufSize); |
| 302 if (num_bytes_read == 0) { | 218 if (num_bytes_read == 0) { |
| 303 // Reached the end of the file. | 219 // Reached the end of the file. |
| 304 break; | 220 break; |
| 305 } else if (num_bytes_read < 0) { | 221 } else if (num_bytes_read < 0) { |
| 306 // If num_bytes_read < 0, then it's a specific UNZ_* error code. | 222 // If num_bytes_read < 0, then it's a specific UNZ_* error code. |
| 307 success = false; | 223 success = false; |
| 308 break; | 224 break; |
| 309 } else if (num_bytes_read > 0) { | 225 } else if (num_bytes_read > 0) { |
| 310 // Some data is read. | 226 // Some data is read. Write it to the output file. |
| 311 if (!delegate->WriteBytes(buf.get(), num_bytes_read)) { | 227 if (num_bytes_read != file.WriteAtCurrentPos(buf, num_bytes_read)) { |
| 312 success = false; | 228 success = false; |
| 313 break; | 229 break; |
| 314 } | 230 } |
| 315 } | 231 } |
| 316 } | 232 } |
| 317 | 233 |
| 234 file.Close(); |
| 318 unzCloseCurrentFile(zip_file_); | 235 unzCloseCurrentFile(zip_file_); |
| 319 | 236 |
| 237 if (current_entry_info()->last_modified() != base::Time::UnixEpoch()) |
| 238 base::TouchFile(output_file_path, |
| 239 base::Time::Now(), |
| 240 current_entry_info()->last_modified()); |
| 241 |
| 320 return success; | 242 return success; |
| 321 } | 243 } |
| 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()) { | |
| 339 base::TouchFile(output_file_path, | |
| 340 base::Time::Now(), | |
| 341 current_entry_info()->last_modified()); | |
| 342 } | |
| 343 | |
| 344 return success; | |
| 345 } | |
| 346 | 244 |
| 347 void ZipReader::ExtractCurrentEntryToFilePathAsync( | 245 void ZipReader::ExtractCurrentEntryToFilePathAsync( |
| 348 const base::FilePath& output_file_path, | 246 const base::FilePath& output_file_path, |
| 349 const SuccessCallback& success_callback, | 247 const SuccessCallback& success_callback, |
| 350 const FailureCallback& failure_callback, | 248 const FailureCallback& failure_callback, |
| 351 const ProgressCallback& progress_callback) { | 249 const ProgressCallback& progress_callback) { |
| 352 DCHECK(zip_file_); | 250 DCHECK(zip_file_); |
| 353 DCHECK(current_entry_info_.get()); | 251 DCHECK(current_entry_info_.get()); |
| 354 | 252 |
| 355 // If this is a directory, just create it and return. | 253 // If this is a directory, just create it and return. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 base::Bind(&ZipReader::ExtractChunk, | 289 base::Bind(&ZipReader::ExtractChunk, |
| 392 weak_ptr_factory_.GetWeakPtr(), | 290 weak_ptr_factory_.GetWeakPtr(), |
| 393 Passed(output_file.Pass()), | 291 Passed(output_file.Pass()), |
| 394 success_callback, | 292 success_callback, |
| 395 failure_callback, | 293 failure_callback, |
| 396 progress_callback, | 294 progress_callback, |
| 397 0 /* initial offset */)); | 295 0 /* initial offset */)); |
| 398 } | 296 } |
| 399 | 297 |
| 400 bool ZipReader::ExtractCurrentEntryIntoDirectory( | 298 bool ZipReader::ExtractCurrentEntryIntoDirectory( |
| 401 const base::FilePath& output_directory_path) const { | 299 const base::FilePath& output_directory_path) { |
| 402 DCHECK(current_entry_info_.get()); | 300 DCHECK(current_entry_info_.get()); |
| 403 | 301 |
| 404 base::FilePath output_file_path = output_directory_path.Append( | 302 base::FilePath output_file_path = output_directory_path.Append( |
| 405 current_entry_info()->file_path()); | 303 current_entry_info()->file_path()); |
| 406 return ExtractCurrentEntryToFilePath(output_file_path); | 304 return ExtractCurrentEntryToFilePath(output_file_path); |
| 407 } | 305 } |
| 408 | 306 |
| 409 bool ZipReader::ExtractCurrentEntryToFile(base::File* file) const { | 307 #if defined(OS_POSIX) |
| 308 bool ZipReader::ExtractCurrentEntryToFd(const int fd) { |
| 410 DCHECK(zip_file_); | 309 DCHECK(zip_file_); |
| 411 | 310 |
| 412 // If this is a directory, there's nothing to extract to the file, so return | 311 // If this is a directory, there's nothing to extract to the file descriptor, |
| 413 // false. | 312 // so return false. |
| 414 if (current_entry_info()->is_directory()) | 313 if (current_entry_info()->is_directory()) |
| 415 return false; | 314 return false; |
| 416 | 315 |
| 417 FileWriterDelegate writer(file); | 316 const int open_result = unzOpenCurrentFile(zip_file_); |
| 418 return ExtractCurrentEntry(&writer); | 317 if (open_result != UNZ_OK) |
| 318 return false; |
| 319 |
| 320 bool success = true; // This becomes false when something bad happens. |
| 321 while (true) { |
| 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; |
| 419 } | 343 } |
| 344 #endif // defined(OS_POSIX) |
| 420 | 345 |
| 421 bool ZipReader::ExtractCurrentEntryToString(size_t max_read_bytes, | 346 bool ZipReader::ExtractCurrentEntryToString( |
| 422 std::string* output) const { | 347 size_t max_read_bytes, |
| 348 std::string* output) const { |
| 423 DCHECK(output); | 349 DCHECK(output); |
| 424 DCHECK(zip_file_); | 350 DCHECK(zip_file_); |
| 425 DCHECK_NE(0U, max_read_bytes); | 351 DCHECK(max_read_bytes != 0); |
| 426 | 352 |
| 427 if (current_entry_info()->is_directory()) { | 353 if (current_entry_info()->is_directory()) { |
| 428 output->clear(); | 354 output->clear(); |
| 429 return true; | 355 return true; |
| 430 } | 356 } |
| 431 | 357 |
| 358 const int open_result = unzOpenCurrentFile(zip_file_); |
| 359 if (open_result != UNZ_OK) |
| 360 return false; |
| 361 |
| 432 // The original_size() is the best hint for the real size, so it saves | 362 // The original_size() is the best hint for the real size, so it saves |
| 433 // doing reallocations for the common case when the uncompressed size is | 363 // doing reallocations for the common case when the uncompressed size is |
| 434 // correct. However, we need to assume that the uncompressed size could be | 364 // correct. However, we need to assume that the uncompressed size could be |
| 435 // incorrect therefore this function needs to read as much data as possible. | 365 // incorrect therefore this function needs to read as much data as possible. |
| 436 std::string contents; | 366 std::string contents; |
| 437 contents.reserve(static_cast<size_t>(std::min( | 367 contents.reserve(static_cast<size_t>(std::min( |
| 438 static_cast<int64>(max_read_bytes), | 368 static_cast<int64>(max_read_bytes), |
| 439 current_entry_info()->original_size()))); | 369 current_entry_info()->original_size()))); |
| 440 | 370 |
| 441 StringWriterDelegate writer(max_read_bytes, &contents); | 371 bool success = true; // This becomes false when something bad happens. |
| 442 if (!ExtractCurrentEntry(&writer)) | 372 char buf[internal::kZipBufSize]; |
| 443 return false; | 373 while (true) { |
| 444 output->swap(contents); | 374 const int num_bytes_read = unzReadCurrentFile(zip_file_, buf, |
| 445 return true; | 375 internal::kZipBufSize); |
| 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; |
| 446 } | 397 } |
| 447 | 398 |
| 448 bool ZipReader::OpenInternal() { | 399 bool ZipReader::OpenInternal() { |
| 449 DCHECK(zip_file_); | 400 DCHECK(zip_file_); |
| 450 | 401 |
| 451 unz_global_info zip_info = {}; // Zero-clear. | 402 unz_global_info zip_info = {}; // Zero-clear. |
| 452 if (unzGetGlobalInfo(zip_file_, &zip_info) != UNZ_OK) { | 403 if (unzGetGlobalInfo(zip_file_, &zip_info) != UNZ_OK) { |
| 453 return false; | 404 return false; |
| 454 } | 405 } |
| 455 num_entries_ = zip_info.number_entry; | 406 num_entries_ = zip_info.number_entry; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 weak_ptr_factory_.GetWeakPtr(), | 454 weak_ptr_factory_.GetWeakPtr(), |
| 504 Passed(output_file.Pass()), | 455 Passed(output_file.Pass()), |
| 505 success_callback, | 456 success_callback, |
| 506 failure_callback, | 457 failure_callback, |
| 507 progress_callback, | 458 progress_callback, |
| 508 current_progress)); | 459 current_progress)); |
| 509 | 460 |
| 510 } | 461 } |
| 511 } | 462 } |
| 512 | 463 |
| 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 } | |
| 538 | 464 |
| 539 } // namespace zip | 465 } // namespace zip |
| OLD | NEW |