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

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

Issue 1014653002: Add ZipReader::ExtractCurrentEntry with a delegate interface. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix unused var error and add a new test Created 5 years, 9 months 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
« no previous file with comments | « third_party/zlib/google/zip_reader.h ('k') | third_party/zlib/google/zip_reader_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/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
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
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
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
OLDNEW
« no previous file with comments | « third_party/zlib/google/zip_reader.h ('k') | third_party/zlib/google/zip_reader_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698