Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1092)

Side by Side Diff: third_party/zlib/google/zip_reader.cc

Issue 92873003: Adds asynchronous unzip functions to ZipReader (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Cleanup Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/file_util.h" 7 #include "base/file_util.h"
8 #include "base/location.h"
8 #include "base/logging.h" 9 #include "base/logging.h"
9 #include "base/strings/string_util.h" 10 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h" 11 #include "base/strings/utf_string_conversions.h"
11 #include "net/base/file_stream.h" 12 #include "net/base/file_stream.h"
12 #include "third_party/zlib/google/zip_internal.h" 13 #include "third_party/zlib/google/zip_internal.h"
13 14
14 #if defined(USE_SYSTEM_MINIZIP) 15 #if defined(USE_SYSTEM_MINIZIP)
15 #include <minizip/unzip.h> 16 #include <minizip/unzip.h>
16 #else 17 #else
17 #include "third_party/zlib/contrib/minizip/unzip.h" 18 #include "third_party/zlib/contrib/minizip/unzip.h"
18 #if defined(OS_WIN) 19 #if defined(OS_WIN)
19 #include "third_party/zlib/contrib/minizip/iowin32.h" 20 #include "third_party/zlib/contrib/minizip/iowin32.h"
20 #endif // defined(OS_WIN) 21 #endif // defined(OS_WIN)
21 #endif // defined(USE_SYSTEM_MINIZIP) 22 #endif // defined(USE_SYSTEM_MINIZIP)
22 23
23 namespace zip { 24 namespace zip {
24 25
26 namespace {
27
28 // A listener that will close a PlatformFile when the operation is complete,
29 // with a delegate to pass events to. This is used by some asynchronous
30 // functions to ensure a PlatformFile is closed when done.
31 class FileClosingListener : public ZipReader::Listener {
32 public:
33 FileClosingListener(scoped_refptr<ZipReader::Listener> delegate,
34 base::PlatformFile platform_file)
35 : delegate_(delegate),
36 platform_file_(platform_file) {
37 }
38
39 virtual void OnUnzipProgress(int progress) OVERRIDE {
40 delegate_->OnUnzipProgress(progress);
41 }
42
43 virtual void OnUnzipSuccess() OVERRIDE {
44 base::ClosePlatformFile(platform_file_);
45 delegate_->OnUnzipSuccess();
46 }
47
48 virtual void OnUnzipFailed() OVERRIDE {
49 base::ClosePlatformFile(platform_file_);
50 delegate_->OnUnzipFailed();
51 }
52
53 private:
54 scoped_refptr<ZipReader::Listener> delegate_;
55 base::PlatformFile platform_file_;
56 };
57
58 } // namespace
59
25 // TODO(satorux): The implementation assumes that file names in zip files 60 // TODO(satorux): The implementation assumes that file names in zip files
26 // are encoded in UTF-8. This is true for zip files created by Zip() 61 // are encoded in UTF-8. This is true for zip files created by Zip()
27 // function in zip.h, but not true for user-supplied random zip files. 62 // function in zip.h, but not true for user-supplied random zip files.
28 ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip, 63 ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip,
29 const unz_file_info& raw_file_info) 64 const unz_file_info& raw_file_info)
30 : file_path_(base::FilePath::FromUTF8Unsafe(file_name_in_zip)), 65 : file_path_(base::FilePath::FromUTF8Unsafe(file_name_in_zip)),
31 is_directory_(false) { 66 is_directory_(false) {
32 original_size_ = raw_file_info.uncompressed_size; 67 original_size_ = raw_file_info.uncompressed_size;
33 68
34 // Directory entries in zip files end with "/". 69 // Directory entries in zip files end with "/".
(...skipping 27 matching lines...) Expand all
62 exploded_time.second = raw_file_info.tmu_date.tm_sec; 97 exploded_time.second = raw_file_info.tmu_date.tm_sec;
63 exploded_time.millisecond = 0; 98 exploded_time.millisecond = 0;
64 if (exploded_time.HasValidValues()) { 99 if (exploded_time.HasValidValues()) {
65 last_modified_ = base::Time::FromLocalExploded(exploded_time); 100 last_modified_ = base::Time::FromLocalExploded(exploded_time);
66 } else { 101 } else {
67 // Use Unix time epoch if the time stamp data is invalid. 102 // Use Unix time epoch if the time stamp data is invalid.
68 last_modified_ = base::Time::UnixEpoch(); 103 last_modified_ = base::Time::UnixEpoch();
69 } 104 }
70 } 105 }
71 106
72 ZipReader::ZipReader() { 107 ZipReader::ZipReader()
108 : weak_factory_(this) {
73 Reset(); 109 Reset();
74 } 110 }
75 111
76 ZipReader::~ZipReader() { 112 ZipReader::~ZipReader() {
77 Close(); 113 Close();
78 } 114 }
79 115
80 bool ZipReader::Open(const base::FilePath& zip_file_path) { 116 bool ZipReader::Open(const base::FilePath& zip_file_path) {
81 DCHECK(!zip_file_); 117 DCHECK(!zip_file_);
82 118
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 success = false; 264 success = false;
229 break; 265 break;
230 } 266 }
231 } 267 }
232 } 268 }
233 269
234 unzCloseCurrentFile(zip_file_); 270 unzCloseCurrentFile(zip_file_);
235 return success; 271 return success;
236 } 272 }
237 273
274 void ZipReader::ExtractCurrentEntryToFilePathAsync(
275 const base::FilePath& output_file_path,
276 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
277 scoped_refptr<Listener> listener) {
278 DCHECK(zip_file_);
279 DCHECK(current_entry_info_.get());
280
281 // If this is a directory, just create it and return.
282 if (current_entry_info()->is_directory()) {
283 if (file_util::CreateDirectory(output_file_path)) {
284 listener->OnUnzipSuccess();
285 } else {
286 DVLOG(1) << "Unzip failed: unable to create directory.";
287 listener->OnUnzipFailed();
288 }
289 return;
290 }
291
292 base::FilePath output_dir_path = output_file_path.DirName();
293 if (!file_util::CreateDirectory(output_dir_path)) {
294 DVLOG(1) << "Unzip failed: unable to create containing directory.";
295 listener->OnUnzipFailed();
296 return;
297 }
298
299 const int flags = (base::PLATFORM_FILE_CREATE_ALWAYS |
300 base::PLATFORM_FILE_WRITE);
301 bool created = false;
302 base::PlatformFileError platform_file_error;
303 base::PlatformFile output_file = CreatePlatformFile(output_file_path,
304 flags,
305 &created,
306 &platform_file_error);
307
308 if (platform_file_error != base::PLATFORM_FILE_OK) {
309 DVLOG(1) << "Unzip failed: unable to create platform file at "
310 << output_file_path.value();
311 listener->OnUnzipFailed();
312 return;
313 }
314
315 ExtractCurrentEntryToPlatformFileAsync(output_file,
316 message_loop_proxy,
317 new FileClosingListener(listener,
318 output_file));
319 }
320
238 bool ZipReader::ExtractCurrentEntryIntoDirectory( 321 bool ZipReader::ExtractCurrentEntryIntoDirectory(
239 const base::FilePath& output_directory_path) { 322 const base::FilePath& output_directory_path) {
240 DCHECK(current_entry_info_.get()); 323 DCHECK(current_entry_info_.get());
241 324
242 base::FilePath output_file_path = output_directory_path.Append( 325 base::FilePath output_file_path = output_directory_path.Append(
243 current_entry_info()->file_path()); 326 current_entry_info()->file_path());
244 return ExtractCurrentEntryToFilePath(output_file_path); 327 return ExtractCurrentEntryToFilePath(output_file_path);
245 } 328 }
246 329
330 void ZipReader::ExtractCurrentEntryIntoDirectoryAsync(
331 const base::FilePath& output_directory_path,
332 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
333 scoped_refptr<Listener> listener) {
334 DCHECK(current_entry_info_.get());
335
336 base::FilePath output_file_path = output_directory_path.Append(
337 current_entry_info()->file_path());
338 ExtractCurrentEntryToFilePathAsync(output_file_path,
339 message_loop_proxy,
340 listener);
341 }
342
343 void ZipReader::ExtractCurrentEntryToPlatformFileAsync(
344 base::PlatformFile output_file,
345 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
346 scoped_refptr<Listener> listener) {
347 DCHECK(zip_file_);
348 DCHECK(current_entry_info_.get());
349
350 if (current_entry_info()->is_directory()) {
351 DVLOG(1) << "Unzip failed: Cannot unzip a directory to an open file.";
352 listener->OnUnzipFailed();
353 }
354
355 if (unzOpenCurrentFile(zip_file_) != UNZ_OK) {
356 DVLOG(1) << "Unzip failed: unable to open current zip entry.";
357 listener->OnUnzipFailed();
358 return;
359 }
360
361 message_loop_proxy->PostTask(
362 FROM_HERE,
363 base::Bind(&ZipReader::ExtractChunk,
364 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
365 output_file,
366 message_loop_proxy,
367 listener,
368 0,
369 current_entry_info()->original_size()));
370 }
371
372
247 #if defined(OS_POSIX) 373 #if defined(OS_POSIX)
248 bool ZipReader::ExtractCurrentEntryToFd(const int fd) { 374 bool ZipReader::ExtractCurrentEntryToFd(const int fd) {
249 DCHECK(zip_file_); 375 DCHECK(zip_file_);
250 376
251 // If this is a directory, there's nothing to extract to the file descriptor, 377 // If this is a directory, there's nothing to extract to the file descriptor,
252 // so return false. 378 // so return false.
253 if (current_entry_info()->is_directory()) 379 if (current_entry_info()->is_directory())
254 return false; 380 return false;
255 381
256 const int open_result = unzOpenCurrentFile(zip_file_); 382 const int open_result = unzOpenCurrentFile(zip_file_);
(...skipping 18 matching lines...) Expand all
275 file_util::WriteFileDescriptor(fd, buf, num_bytes_read)) { 401 file_util::WriteFileDescriptor(fd, buf, num_bytes_read)) {
276 success = false; 402 success = false;
277 break; 403 break;
278 } 404 }
279 } 405 }
280 } 406 }
281 407
282 unzCloseCurrentFile(zip_file_); 408 unzCloseCurrentFile(zip_file_);
283 return success; 409 return success;
284 } 410 }
411
412 void ZipReader::ExtractCurrentEntryToFdAsync(
413 int fd,
414 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
415 scoped_refptr<Listener> listener) {
416 // A POSIX PlatformFile is just an int, so we can use the same internal
417 // functions.
418 ExtractCurrentEntryToPlatformFileAsync(fd, message_loop_proxy, listener);
419 }
285 #endif // defined(OS_POSIX) 420 #endif // defined(OS_POSIX)
286 421
287 bool ZipReader::OpenInternal() { 422 bool ZipReader::OpenInternal() {
288 DCHECK(zip_file_); 423 DCHECK(zip_file_);
289 424
290 unz_global_info zip_info = {}; // Zero-clear. 425 unz_global_info zip_info = {}; // Zero-clear.
291 if (unzGetGlobalInfo(zip_file_, &zip_info) != UNZ_OK) { 426 if (unzGetGlobalInfo(zip_file_, &zip_info) != UNZ_OK) {
292 return false; 427 return false;
293 } 428 }
294 num_entries_ = zip_info.number_entry; 429 num_entries_ = zip_info.number_entry;
295 if (num_entries_ < 0) 430 if (num_entries_ < 0)
296 return false; 431 return false;
297 432
298 // We are already at the end if the zip file is empty. 433 // We are already at the end if the zip file is empty.
299 reached_end_ = (num_entries_ == 0); 434 reached_end_ = (num_entries_ == 0);
300 return true; 435 return true;
301 } 436 }
302 437
303 void ZipReader::Reset() { 438 void ZipReader::Reset() {
304 zip_file_ = NULL; 439 zip_file_ = NULL;
305 num_entries_ = 0; 440 num_entries_ = 0;
306 reached_end_ = false; 441 reached_end_ = false;
307 current_entry_info_.reset(); 442 current_entry_info_.reset();
308 } 443 }
309 444
445 void ZipReader::ExtractChunk(base::PlatformFile output_file,
446 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.
447 scoped_refptr<Listener> listener,
448 int offset,
449 int size) {
450 char buffer[internal::kZipBufSize];
451
452 const int num_bytes_read = unzReadCurrentFile(zip_file_,
453 buffer,
454 internal::kZipBufSize);
455
456 if (num_bytes_read == 0) {
457 unzCloseCurrentFile(zip_file_);
458 listener->OnUnzipSuccess();
459 } else if (num_bytes_read < 0) {
460 DVLOG(1) << "Unzip failed: error while reading zipfile "
461 << "(" << num_bytes_read << ")";
462 listener->OnUnzipFailed();
463 } else {
464 if (num_bytes_read != base::WritePlatformFileAtCurrentPos(output_file,
465 buffer,
466 num_bytes_read)) {
467 DVLOG(1) << "Unzip failed: unable to write all bytes to target.";
468 listener->OnUnzipFailed();
469 return;
470 }
471
472 const int prev_progress = offset / size;
473 const int curr_progress = (offset + num_bytes_read) / size;
474
475 if (curr_progress > prev_progress) {
476 listener->OnUnzipProgress(curr_progress);
477 }
478
479 message_loop_proxy->PostTask(
480 FROM_HERE,
481 base::Bind(&ZipReader::ExtractChunk,
482 weak_factory_.GetWeakPtr(),
483 output_file,
484 message_loop_proxy,
485 listener,
486 offset + num_bytes_read,
487 size));
488
489 }
490 }
491
492
310 } // namespace zip 493 } // namespace zip
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698