diff options
author | joaoe@opera.com <joaoe@opera.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-20 18:12:13 +0000 |
---|---|---|
committer | joaoe@opera.com <joaoe@opera.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-20 18:12:13 +0000 |
commit | aeea2725ce362b96bb2a47d5b218e69e4aa34c3c (patch) | |
tree | c20029240076cadf6830d02783861e9c5a5ff068 /third_party/zlib | |
parent | 72fbe9a8fbe731f84ed916ce7a03d237b97d835f (diff) | |
download | chromium_src-aeea2725ce362b96bb2a47d5b218e69e4aa34c3c.zip chromium_src-aeea2725ce362b96bb2a47d5b218e69e4aa34c3c.tar.gz chromium_src-aeea2725ce362b96bb2a47d5b218e69e4aa34c3c.tar.bz2 |
New ZipReader::ExtractCurrentEntryToString API.
New API which extract a zip entry into a memory buffer.
BUG=359428
Review URL: https://codereview.chromium.org/292443006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278766 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party/zlib')
-rw-r--r-- | third_party/zlib/google/zip_reader.cc | 52 | ||||
-rw-r--r-- | third_party/zlib/google/zip_reader.h | 17 | ||||
-rw-r--r-- | third_party/zlib/google/zip_reader_unittest.cc | 39 |
3 files changed, 107 insertions, 1 deletions
diff --git a/third_party/zlib/google/zip_reader.cc b/third_party/zlib/google/zip_reader.cc index aa85fa3..80b60b3 100644 --- a/third_party/zlib/google/zip_reader.cc +++ b/third_party/zlib/google/zip_reader.cc @@ -344,6 +344,58 @@ bool ZipReader::ExtractCurrentEntryToFd(const int fd) { } #endif // defined(OS_POSIX) +bool ZipReader::ExtractCurrentEntryToString( + size_t max_read_bytes, + std::string* output) const { + DCHECK(output); + DCHECK(zip_file_); + DCHECK(max_read_bytes != 0); + + if (current_entry_info()->is_directory()) { + output->clear(); + return true; + } + + const int open_result = unzOpenCurrentFile(zip_file_); + if (open_result != UNZ_OK) + return false; + + // The original_size() is the best hint for the real size, so it saves + // doing reallocations for the common case when the uncompressed size is + // correct. However, we need to assume that the uncompressed size could be + // incorrect therefore this function needs to read as much data as possible. + std::string contents; + contents.reserve(std::min<size_t>( + max_read_bytes, current_entry_info()->original_size())); + + bool success = true; // This becomes false when something bad happens. + char buf[internal::kZipBufSize]; + while (true) { + const int num_bytes_read = unzReadCurrentFile(zip_file_, buf, + internal::kZipBufSize); + if (num_bytes_read == 0) { + // Reached the end of the file. + break; + } else if (num_bytes_read < 0) { + // If num_bytes_read < 0, then it's a specific UNZ_* error code. + success = false; + break; + } else if (num_bytes_read > 0) { + if (contents.size() + num_bytes_read > max_read_bytes) { + success = false; + break; + } + contents.append(buf, num_bytes_read); + } + } + + unzCloseCurrentFile(zip_file_); + if (success) + output->swap(contents); + + return success; +} + bool ZipReader::OpenInternal() { DCHECK(zip_file_); diff --git a/third_party/zlib/google/zip_reader.h b/third_party/zlib/google/zip_reader.h index 60b53ee..fa4186b 100644 --- a/third_party/zlib/google/zip_reader.h +++ b/third_party/zlib/google/zip_reader.h @@ -35,7 +35,7 @@ namespace zip { // reader.AdvanceToNextEntry(); // } // -// For simplicty, error checking is omitted in the example code above. The +// For simplicity, error checking is omitted in the example code above. The // production code should check return values from all of these functions. // // This calls can also be used for random access of contents in a zip file @@ -182,6 +182,21 @@ class ZipReader { bool ExtractCurrentEntryToFd(int fd); #endif + // Extracts the current entry into memory. If the current entry is a directory + // the |output| parameter is set to the empty string. If the current entry is + // a file, the |output| parameter is filled with its contents. Returns true on + // success. OpenCurrentEntryInZip() must be called beforehand. + // Note: the |output| parameter can be filled with a big amount of data, avoid + // passing it around by value, but by reference or pointer. + // Note: the value returned by EntryInfo::original_size() cannot be + // trusted, so the real size of the uncompressed contents can be different. + // Use max_read_bytes to limit the ammount of memory used to carry the entry. + // If the real size of the uncompressed data is bigger than max_read_bytes + // then false is returned. |max_read_bytes| must be non-zero. + bool ExtractCurrentEntryToString( + size_t max_read_bytes, + std::string* output) const; + // Returns the current entry info. Returns NULL if the current entry is // not yet opened. OpenCurrentEntryInZip() must be called beforehand. EntryInfo* current_entry_info() const { diff --git a/third_party/zlib/google/zip_reader_unittest.cc b/third_party/zlib/google/zip_reader_unittest.cc index df20e6f..a137d9d 100644 --- a/third_party/zlib/google/zip_reader_unittest.cc +++ b/third_party/zlib/google/zip_reader_unittest.cc @@ -15,6 +15,7 @@ #include "base/md5.h" #include "base/path_service.h" #include "base/run_loop.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" @@ -534,4 +535,42 @@ TEST_F(ZipReaderTest, ExtractToFileAsync_Directory) { ASSERT_TRUE(base::DirectoryExists(target_file)); } +TEST_F(ZipReaderTest, ExtractCurrentEntryToString) { + // test_mismatch_size.zip contains files with names from 0.txt to 7.txt with + // sizes from 0 to 7 bytes respectively, being the contents of each file a + // substring of "0123456" starting at '0'. + base::FilePath test_zip_file = + test_data_dir_.AppendASCII("test_mismatch_size.zip"); + + ZipReader reader; + std::string contents; + ASSERT_TRUE(reader.Open(test_zip_file)); + + for (size_t i = 0; i < 8; i++) { + SCOPED_TRACE(base::StringPrintf("Processing %d.txt", static_cast<int>(i))); + + base::FilePath file_name = base::FilePath::FromUTF8Unsafe( + base::StringPrintf("%d.txt", static_cast<int>(i))); + ASSERT_TRUE(reader.LocateAndOpenEntry(file_name)); + + if (i > 1) { + // Off by one byte read limit: must fail. + EXPECT_FALSE(reader.ExtractCurrentEntryToString(i - 1, &contents)); + } + + if (i > 0) { + // Exact byte read limit: must pass. + EXPECT_TRUE(reader.ExtractCurrentEntryToString(i, &contents)); + EXPECT_EQ(i, contents.size()); + EXPECT_EQ(0, memcmp(contents.c_str(), "0123456", i)); + } + + // More than necessary byte read limit: must pass. + EXPECT_TRUE(reader.ExtractCurrentEntryToString(16, &contents)); + EXPECT_EQ(i, contents.size()); + EXPECT_EQ(0, memcmp(contents.c_str(), "0123456", i)); + } + reader.Close(); +} + } // namespace zip |