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 |