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