zip_archive: Allow crc_out to be nullptr in Inflate.

Only compute the crc32 if required. In addition :
- Add unit tests for Inflate that cover this addition.
- Fix an inconsistency in return codes that was revealed
  by this new test.

Bug: 35246701
Test: zip_archive_tests
Test: make; zipalign.
Merged-In: I31d7554378f94fc8995f707471d57cb98311e2c2
Change-Id: I05111bfa665c610f93d1c1dee987a509bf87aa65
This commit is contained in:
Narayan Kamath 2017-10-30 11:17:28 +00:00
parent 51ec0a1387
commit 2d1e23f5d6
3 changed files with 96 additions and 4 deletions

View file

@ -265,6 +265,9 @@ class Reader {
* Returns 0 on success and negative values on failure, for example if |reader|
* cannot supply the right amount of data, or if the number of bytes written to
* data does not match |uncompressed_length|.
*
* If |crc_out| is not nullptr, it is set to the crc32 checksum of the
* uncompressed data.
*/
int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out);

View file

@ -908,6 +908,7 @@ int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
const bool compute_crc = (crc_out != nullptr);
uint64_t crc = 0;
uint32_t remaining_bytes = compressed_length;
do {
@ -939,9 +940,8 @@ int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
if (zstream.avail_out == 0 || (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
const size_t write_size = zstream.next_out - &write_buf[0];
if (!writer->Append(&write_buf[0], write_size)) {
// The file might have declared a bogus length.
return kInconsistentInformation;
} else {
return kIoError;
} else if (compute_crc) {
crc = crc32(crc, &write_buf[0], write_size);
}
@ -958,7 +958,9 @@ int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
// it ourselves above because there are no additional gains to be made by
// having zlib calculate it for us, since they do it by calling crc32 in
// the same manner that we have above.
*crc_out = crc;
if (compute_crc) {
*crc_out = crc;
}
if (zstream.total_out != uncompressed_length || remaining_bytes != 0) {
ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")", zstream.total_out,

View file

@ -717,6 +717,93 @@ TEST(ziparchive, ErrorCodeString) {
ASSERT_STREQ("I/O error", ErrorCodeString(kIoError));
}
class VectorReader : public zip_archive::Reader {
public:
VectorReader(const std::vector<uint8_t>& input) : Reader(), input_(input) {}
bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
if ((offset + len) < input_.size()) {
return false;
}
memcpy(buf, &input_[offset], len);
return true;
}
private:
const std::vector<uint8_t>& input_;
};
class VectorWriter : public zip_archive::Writer {
public:
VectorWriter() : Writer() {}
bool Append(uint8_t* buf, size_t size) {
output_.insert(output_.end(), buf, buf + size);
return true;
}
std::vector<uint8_t>& GetOutput() { return output_; }
private:
std::vector<uint8_t> output_;
};
class BadReader : public zip_archive::Reader {
public:
BadReader() : Reader() {}
bool ReadAtOffset(uint8_t*, size_t, uint32_t) const { return false; }
};
class BadWriter : public zip_archive::Writer {
public:
BadWriter() : Writer() {}
bool Append(uint8_t*, size_t) { return false; }
};
TEST(ziparchive, Inflate) {
const uint32_t compressed_length = kATxtContentsCompressed.size();
const uint32_t uncompressed_length = kATxtContents.size();
const VectorReader reader(kATxtContentsCompressed);
{
VectorWriter writer;
uint64_t crc_out = 0;
int32_t ret =
zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, &crc_out);
ASSERT_EQ(0, ret);
ASSERT_EQ(kATxtContents, writer.GetOutput());
ASSERT_EQ(0x950821C5u, crc_out);
}
{
VectorWriter writer;
int32_t ret =
zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
ASSERT_EQ(0, ret);
ASSERT_EQ(kATxtContents, writer.GetOutput());
}
{
BadWriter writer;
int32_t ret =
zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
ASSERT_EQ(kIoError, ret);
}
{
BadReader reader;
VectorWriter writer;
int32_t ret =
zip_archive::Inflate(reader, compressed_length, uncompressed_length, &writer, nullptr);
ASSERT_EQ(kIoError, ret);
ASSERT_EQ(0u, writer.GetOutput().size());
}
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);