Home | History | Annotate | Download | only in libziparchive
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <errno.h>
     18 #include <fcntl.h>
     19 #include <getopt.h>
     20 #include <stdio.h>
     21 #include <string.h>
     22 #include <unistd.h>
     23 
     24 #include <memory>
     25 #include <vector>
     26 
     27 #include <android-base/file.h>
     28 #include <android-base/test_utils.h>
     29 #include <gtest/gtest.h>
     30 #include <ziparchive/zip_archive.h>
     31 #include <ziparchive/zip_archive_stream_entry.h>
     32 
     33 static std::string test_data_dir;
     34 
     35 static const std::string kMissingZip = "missing.zip";
     36 static const std::string kValidZip = "valid.zip";
     37 static const std::string kLargeZip = "large.zip";
     38 static const std::string kBadCrcZip = "bad_crc.zip";
     39 
     40 static const std::vector<uint8_t> kATxtContents {
     41   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
     42   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
     43   '\n'
     44 };
     45 
     46 static const std::vector<uint8_t> kATxtContentsCompressed {
     47   'K', 'L', 'J', 'N', 'I', 'M', 'K', 207, 'H',
     48   132, 210, '\\', '\0'
     49 };
     50 
     51 static const std::vector<uint8_t> kBTxtContents {
     52   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
     53   '\n'
     54 };
     55 
     56 static const std::string kATxtName("a.txt");
     57 static const std::string kBTxtName("b.txt");
     58 static const std::string kNonexistentTxtName("nonexistent.txt");
     59 static const std::string kEmptyTxtName("empty.txt");
     60 static const std::string kLargeCompressTxtName("compress.txt");
     61 static const std::string kLargeUncompressTxtName("uncompress.txt");
     62 
     63 static int32_t OpenArchiveWrapper(const std::string& name,
     64                                   ZipArchiveHandle* handle) {
     65   const std::string abs_path = test_data_dir + "/" + name;
     66   return OpenArchive(abs_path.c_str(), handle);
     67 }
     68 
     69 static void AssertNameEquals(const std::string& name_str,
     70                              const ZipString& name) {
     71   ASSERT_EQ(name_str.size(), name.name_length);
     72   ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
     73 }
     74 
     75 static void SetZipString(ZipString* zip_str, const std::string& str) {
     76   zip_str->name = reinterpret_cast<const uint8_t*>(str.c_str());
     77   zip_str->name_length = str.size();
     78 }
     79 
     80 TEST(ziparchive, Open) {
     81   ZipArchiveHandle handle;
     82   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
     83 
     84   CloseArchive(handle);
     85 }
     86 
     87 TEST(ziparchive, OpenMissing) {
     88   ZipArchiveHandle handle;
     89   ASSERT_NE(0, OpenArchiveWrapper(kMissingZip, &handle));
     90 
     91   // Confirm the file descriptor is not going to be mistaken for a valid one.
     92   ASSERT_EQ(-1, GetFileDescriptor(handle));
     93 }
     94 
     95 TEST(ziparchive, OpenAssumeFdOwnership) {
     96   int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
     97   ASSERT_NE(-1, fd);
     98   ZipArchiveHandle handle;
     99   ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle));
    100   CloseArchive(handle);
    101   ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
    102   ASSERT_EQ(EBADF, errno);
    103 }
    104 
    105 TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
    106   int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
    107   ASSERT_NE(-1, fd);
    108   ZipArchiveHandle handle;
    109   ASSERT_EQ(0, OpenArchiveFd(fd, "OpenWithAssumeFdOwnership", &handle, false));
    110   CloseArchive(handle);
    111   ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
    112   close(fd);
    113 }
    114 
    115 TEST(ziparchive, Iteration) {
    116   ZipArchiveHandle handle;
    117   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    118 
    119   void* iteration_cookie;
    120   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
    121 
    122   ZipEntry data;
    123   ZipString name;
    124 
    125   // b/c.txt
    126   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    127   AssertNameEquals("b/c.txt", name);
    128 
    129   // b/d.txt
    130   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    131   AssertNameEquals("b/d.txt", name);
    132 
    133   // a.txt
    134   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    135   AssertNameEquals("a.txt", name);
    136 
    137   // b.txt
    138   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    139   AssertNameEquals("b.txt", name);
    140 
    141   // b/
    142   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    143   AssertNameEquals("b/", name);
    144 
    145   // End of iteration.
    146   ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
    147 
    148   CloseArchive(handle);
    149 }
    150 
    151 TEST(ziparchive, IterationWithPrefix) {
    152   ZipArchiveHandle handle;
    153   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    154 
    155   void* iteration_cookie;
    156   ZipString prefix("b/");
    157   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, nullptr));
    158 
    159   ZipEntry data;
    160   ZipString name;
    161 
    162   // b/c.txt
    163   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    164   AssertNameEquals("b/c.txt", name);
    165 
    166   // b/d.txt
    167   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    168   AssertNameEquals("b/d.txt", name);
    169 
    170   // b/
    171   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    172   AssertNameEquals("b/", name);
    173 
    174   // End of iteration.
    175   ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
    176 
    177   CloseArchive(handle);
    178 }
    179 
    180 TEST(ziparchive, IterationWithSuffix) {
    181   ZipArchiveHandle handle;
    182   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    183 
    184   void* iteration_cookie;
    185   ZipString suffix(".txt");
    186   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, &suffix));
    187 
    188   ZipEntry data;
    189   ZipString name;
    190 
    191   // b/c.txt
    192   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    193   AssertNameEquals("b/c.txt", name);
    194 
    195   // b/d.txt
    196   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    197   AssertNameEquals("b/d.txt", name);
    198 
    199   // a.txt
    200   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    201   AssertNameEquals("a.txt", name);
    202 
    203   // b.txt
    204   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    205   AssertNameEquals("b.txt", name);
    206 
    207   // End of iteration.
    208   ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
    209 
    210   CloseArchive(handle);
    211 }
    212 
    213 TEST(ziparchive, IterationWithPrefixAndSuffix) {
    214   ZipArchiveHandle handle;
    215   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    216 
    217   void* iteration_cookie;
    218   ZipString prefix("b");
    219   ZipString suffix(".txt");
    220   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
    221 
    222   ZipEntry data;
    223   ZipString name;
    224 
    225   // b/c.txt
    226   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    227   AssertNameEquals("b/c.txt", name);
    228 
    229   // b/d.txt
    230   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    231   AssertNameEquals("b/d.txt", name);
    232 
    233   // b.txt
    234   ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
    235   AssertNameEquals("b.txt", name);
    236 
    237   // End of iteration.
    238   ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
    239 
    240   CloseArchive(handle);
    241 }
    242 
    243 TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
    244   ZipArchiveHandle handle;
    245   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    246 
    247   void* iteration_cookie;
    248   ZipString prefix("x");
    249   ZipString suffix("y");
    250   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
    251 
    252   ZipEntry data;
    253   ZipString name;
    254 
    255   // End of iteration.
    256   ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
    257 
    258   CloseArchive(handle);
    259 }
    260 
    261 TEST(ziparchive, FindEntry) {
    262   ZipArchiveHandle handle;
    263   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    264 
    265   ZipEntry data;
    266   ZipString name;
    267   SetZipString(&name, kATxtName);
    268   ASSERT_EQ(0, FindEntry(handle, name, &data));
    269 
    270   // Known facts about a.txt, from zipinfo -v.
    271   ASSERT_EQ(63, data.offset);
    272   ASSERT_EQ(kCompressDeflated, data.method);
    273   ASSERT_EQ(static_cast<uint32_t>(17), data.uncompressed_length);
    274   ASSERT_EQ(static_cast<uint32_t>(13), data.compressed_length);
    275   ASSERT_EQ(0x950821c5, data.crc32);
    276   ASSERT_EQ(static_cast<uint32_t>(0x438a8005), data.mod_time);
    277 
    278   // An entry that doesn't exist. Should be a negative return code.
    279   ZipString absent_name;
    280   SetZipString(&absent_name, kNonexistentTxtName);
    281   ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
    282 
    283   CloseArchive(handle);
    284 }
    285 
    286 TEST(ziparchive, TestInvalidDeclaredLength) {
    287   ZipArchiveHandle handle;
    288   ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
    289 
    290   void* iteration_cookie;
    291   ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
    292 
    293   ZipString name;
    294   ZipEntry data;
    295 
    296   ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
    297   ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
    298 
    299   CloseArchive(handle);
    300 }
    301 
    302 TEST(ziparchive, ExtractToMemory) {
    303   ZipArchiveHandle handle;
    304   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    305 
    306   // An entry that's deflated.
    307   ZipEntry data;
    308   ZipString a_name;
    309   SetZipString(&a_name, kATxtName);
    310   ASSERT_EQ(0, FindEntry(handle, a_name, &data));
    311   const uint32_t a_size = data.uncompressed_length;
    312   ASSERT_EQ(a_size, kATxtContents.size());
    313   uint8_t* buffer = new uint8_t[a_size];
    314   ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
    315   ASSERT_EQ(0, memcmp(buffer, kATxtContents.data(), a_size));
    316   delete[] buffer;
    317 
    318   // An entry that's stored.
    319   ZipString b_name;
    320   SetZipString(&b_name, kBTxtName);
    321   ASSERT_EQ(0, FindEntry(handle, b_name, &data));
    322   const uint32_t b_size = data.uncompressed_length;
    323   ASSERT_EQ(b_size, kBTxtContents.size());
    324   buffer = new uint8_t[b_size];
    325   ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
    326   ASSERT_EQ(0, memcmp(buffer, kBTxtContents.data(), b_size));
    327   delete[] buffer;
    328 
    329   CloseArchive(handle);
    330 }
    331 
    332 static const uint32_t kEmptyEntriesZip[] = {
    333       0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
    334       0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
    335       0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
    336       0x00000a03, 0x60000000, 0x00443863, 0x00000000, 0x00000000, 0x09000000,
    337       0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
    338       0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
    339       0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
    340 
    341 // This is a zip file containing a single entry (ab.txt) that contains
    342 // 90072 repetitions of the string "ab\n" and has an uncompressed length
    343 // of 270216 bytes.
    344 static const uint16_t kAbZip[] = {
    345   0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0,
    346   0x2cda, 0x011b, 0x0000, 0x1f88, 0x0004, 0x0006, 0x001c, 0x6261,
    347   0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
    348   0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000,
    349   0xc2ed, 0x0d31, 0x0000, 0x030c, 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa,
    350   0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    351   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    352   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    353   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    354   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    355   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    356   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    357   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    358   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    359   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    360   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    361   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    362   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    363   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    364   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    365   0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
    366   0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02,
    367   0x1403, 0x0000, 0x0800, 0xd200, 0x9851, 0xb046, 0xdac4, 0x1b2c,
    368   0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
    369   0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574,
    370   0x0554, 0x0300, 0x097c, 0x553a, 0x7875, 0x000b, 0x0401, 0x4289,
    371   0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
    372   0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
    373 };
    374 
    375 static const std::string kAbTxtName("ab.txt");
    376 static const size_t kAbUncompressedSize = 270216;
    377 
    378 TEST(ziparchive, EmptyEntries) {
    379   TemporaryFile tmp_file;
    380   ASSERT_NE(-1, tmp_file.fd);
    381   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
    382 
    383   ZipArchiveHandle handle;
    384   ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
    385 
    386   ZipEntry entry;
    387   ZipString empty_name;
    388   SetZipString(&empty_name, kEmptyTxtName);
    389   ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
    390   ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
    391   uint8_t buffer[1];
    392   ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
    393 
    394 
    395   TemporaryFile tmp_output_file;
    396   ASSERT_NE(-1, tmp_output_file.fd);
    397   ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
    398 
    399   struct stat stat_buf;
    400   ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
    401   ASSERT_EQ(0, stat_buf.st_size);
    402 }
    403 
    404 TEST(ziparchive, EntryLargerThan32K) {
    405   TemporaryFile tmp_file;
    406   ASSERT_NE(-1, tmp_file.fd);
    407   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, reinterpret_cast<const uint8_t*>(kAbZip),
    408                          sizeof(kAbZip) - 1));
    409   ZipArchiveHandle handle;
    410   ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle));
    411 
    412   ZipEntry entry;
    413   ZipString ab_name;
    414   SetZipString(&ab_name, kAbTxtName);
    415   ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
    416   ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
    417 
    418   // Extract the entry to memory.
    419   std::vector<uint8_t> buffer(kAbUncompressedSize);
    420   ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
    421 
    422   // Extract the entry to a file.
    423   TemporaryFile tmp_output_file;
    424   ASSERT_NE(-1, tmp_output_file.fd);
    425   ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
    426 
    427   // Make sure the extracted file size is as expected.
    428   struct stat stat_buf;
    429   ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
    430   ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
    431 
    432   // Read the file back to a buffer and make sure the contents are
    433   // the same as the memory buffer we extracted directly to.
    434   std::vector<uint8_t> file_contents(kAbUncompressedSize);
    435   ASSERT_EQ(0, lseek64(tmp_output_file.fd, 0, SEEK_SET));
    436   ASSERT_TRUE(android::base::ReadFully(tmp_output_file.fd, &file_contents[0],
    437                                        file_contents.size()));
    438   ASSERT_EQ(file_contents, buffer);
    439 
    440   for (int i = 0; i < 90072; ++i) {
    441     const uint8_t* line = &file_contents[0] + (3 * i);
    442     ASSERT_EQ('a', line[0]);
    443     ASSERT_EQ('b', line[1]);
    444     ASSERT_EQ('\n', line[2]);
    445   }
    446 }
    447 
    448 TEST(ziparchive, TrailerAfterEOCD) {
    449   TemporaryFile tmp_file;
    450   ASSERT_NE(-1, tmp_file.fd);
    451 
    452   // Create a file with 8 bytes of random garbage.
    453   static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
    454   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
    455   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
    456 
    457   ZipArchiveHandle handle;
    458   ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
    459 }
    460 
    461 TEST(ziparchive, ExtractToFile) {
    462   TemporaryFile tmp_file;
    463   ASSERT_NE(-1, tmp_file.fd);
    464   const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
    465   const size_t data_size = sizeof(data);
    466 
    467   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, data, data_size));
    468 
    469   ZipArchiveHandle handle;
    470   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
    471 
    472   ZipEntry entry;
    473   ZipString name;
    474   SetZipString(&name, kATxtName);
    475   ASSERT_EQ(0, FindEntry(handle, name, &entry));
    476   ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
    477 
    478 
    479   // Assert that the first 8 bytes of the file haven't been clobbered.
    480   uint8_t read_buffer[data_size];
    481   ASSERT_EQ(0, lseek64(tmp_file.fd, 0, SEEK_SET));
    482   ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, read_buffer, data_size));
    483   ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
    484 
    485   // Assert that the remainder of the file contains the incompressed data.
    486   std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
    487   ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, uncompressed_data.data(),
    488                                        entry.uncompressed_length));
    489   ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(),
    490                       kATxtContents.size()));
    491 
    492   // Assert that the total length of the file is sane
    493   ASSERT_EQ(static_cast<ssize_t>(data_size + kATxtContents.size()),
    494             lseek64(tmp_file.fd, 0, SEEK_END));
    495 }
    496 
    497 static void ZipArchiveStreamTest(
    498     ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
    499     bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
    500   ZipString name;
    501   SetZipString(&name, entry_name);
    502   ASSERT_EQ(0, FindEntry(handle, name, entry));
    503   std::unique_ptr<ZipArchiveStreamEntry> stream;
    504   if (raw) {
    505     stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
    506     if (entry->method == kCompressStored) {
    507       read_data->resize(entry->uncompressed_length);
    508     } else {
    509       read_data->resize(entry->compressed_length);
    510     }
    511   } else {
    512     stream.reset(ZipArchiveStreamEntry::Create(handle, *entry));
    513     read_data->resize(entry->uncompressed_length);
    514   }
    515   uint8_t* read_data_ptr = read_data->data();
    516   ASSERT_TRUE(stream.get() != nullptr);
    517   const std::vector<uint8_t>* data;
    518   uint64_t total_size = 0;
    519   while ((data = stream->Read()) != nullptr) {
    520     total_size += data->size();
    521     memcpy(read_data_ptr, data->data(), data->size());
    522     read_data_ptr += data->size();
    523   }
    524   ASSERT_EQ(verified, stream->Verify());
    525   ASSERT_EQ(total_size, read_data->size());
    526 }
    527 
    528 static void ZipArchiveStreamTestUsingContents(
    529     const std::string& zip_file, const std::string& entry_name,
    530     const std::vector<uint8_t>& contents, bool raw) {
    531   ZipArchiveHandle handle;
    532   ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
    533 
    534   ZipEntry entry;
    535   std::vector<uint8_t> read_data;
    536   ZipArchiveStreamTest(handle, entry_name, raw, true, &entry, &read_data);
    537 
    538   ASSERT_EQ(contents.size(), read_data.size());
    539   ASSERT_TRUE(memcmp(read_data.data(), contents.data(), read_data.size()) == 0);
    540 
    541   CloseArchive(handle);
    542 }
    543 
    544 static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file, const std::string& entry_name) {
    545   ZipArchiveHandle handle;
    546   ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
    547 
    548   ZipEntry entry;
    549   std::vector<uint8_t> read_data;
    550   ZipArchiveStreamTest(handle, entry_name, false, true, &entry, &read_data);
    551 
    552   std::vector<uint8_t> cmp_data(entry.uncompressed_length);
    553   ASSERT_EQ(entry.uncompressed_length, read_data.size());
    554   ASSERT_EQ(0, ExtractToMemory(handle, &entry, cmp_data.data(), cmp_data.size()));
    555   ASSERT_TRUE(memcmp(read_data.data(), cmp_data.data(), read_data.size()) == 0);
    556 
    557   CloseArchive(handle);
    558 }
    559 
    560 TEST(ziparchive, StreamCompressed) {
    561   ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContents, false);
    562 }
    563 
    564 TEST(ziparchive, StreamUncompressed) {
    565   ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, false);
    566 }
    567 
    568 TEST(ziparchive, StreamRawCompressed) {
    569   ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContentsCompressed, true);
    570 }
    571 
    572 TEST(ziparchive, StreamRawUncompressed) {
    573   ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, true);
    574 }
    575 
    576 TEST(ziparchive, StreamLargeCompressed) {
    577   ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeCompressTxtName);
    578 }
    579 
    580 TEST(ziparchive, StreamLargeUncompressed) {
    581   ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeUncompressTxtName);
    582 }
    583 
    584 TEST(ziparchive, StreamCompressedBadCrc) {
    585   ZipArchiveHandle handle;
    586   ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
    587 
    588   ZipEntry entry;
    589   std::vector<uint8_t> read_data;
    590   ZipArchiveStreamTest(handle, kATxtName, false, false, &entry, &read_data);
    591 
    592   CloseArchive(handle);
    593 }
    594 
    595 TEST(ziparchive, StreamUncompressedBadCrc) {
    596   ZipArchiveHandle handle;
    597   ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
    598 
    599   ZipEntry entry;
    600   std::vector<uint8_t> read_data;
    601   ZipArchiveStreamTest(handle, kBTxtName, false, false, &entry, &read_data);
    602 
    603   CloseArchive(handle);
    604 }
    605 
    606 int main(int argc, char** argv) {
    607   ::testing::InitGoogleTest(&argc, argv);
    608 
    609   static struct option options[] = {
    610     { "test_data_dir", required_argument, nullptr, 't' },
    611     { nullptr, 0, nullptr, 0 }
    612   };
    613 
    614   while (true) {
    615     int option_index;
    616     const int c = getopt_long_only(argc, argv, "", options, &option_index);
    617     if (c == -1) {
    618       break;
    619     }
    620 
    621     if (c == 't') {
    622       test_data_dir = optarg;
    623     }
    624   }
    625 
    626   if (test_data_dir.size() == 0) {
    627     printf("Test data flag (--test_data_dir) required\n\n");
    628     return -1;
    629   }
    630 
    631   if (test_data_dir[0] != '/') {
    632     std::vector<char> cwd_buffer(1024);
    633     const char* cwd = getcwd(cwd_buffer.data(), cwd_buffer.size() - 1);
    634     if (cwd == nullptr) {
    635       printf("Cannot get current working directory, use an absolute path instead, was %s\n\n",
    636              test_data_dir.c_str());
    637       return -2;
    638     }
    639     test_data_dir = '/' + test_data_dir;
    640     test_data_dir = cwd + test_data_dir;
    641   }
    642 
    643   return RUN_ALL_TESTS();
    644 }
    645