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
OpenArchiveWrapper(const std::string & name,ZipArchiveHandle * handle)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
AssertNameEquals(const std::string & name_str,const ZipString & name)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
SetZipString(ZipString * zip_str,const std::string & str)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
TEST(ziparchive,Open)80 TEST(ziparchive, Open) {
81 ZipArchiveHandle handle;
82 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
83
84 CloseArchive(handle);
85 }
86
TEST(ziparchive,OpenMissing)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
TEST(ziparchive,OpenAssumeFdOwnership)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
TEST(ziparchive,OpenDoNotAssumeFdOwnership)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
TEST(ziparchive,Iteration)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
TEST(ziparchive,IterationWithPrefix)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
TEST(ziparchive,IterationWithSuffix)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
TEST(ziparchive,IterationWithPrefixAndSuffix)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
TEST(ziparchive,IterationWithBadPrefixAndSuffix)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
TEST(ziparchive,FindEntry)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
TEST(ziparchive,TestInvalidDeclaredLength)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
TEST(ziparchive,ExtractToMemory)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
TEST(ziparchive,EmptyEntries)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
TEST(ziparchive,EntryLargerThan32K)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
TEST(ziparchive,TrailerAfterEOCD)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
TEST(ziparchive,ExtractToFile)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
ZipArchiveStreamTest(ZipArchiveHandle & handle,const std::string & entry_name,bool raw,bool verified,ZipEntry * entry,std::vector<uint8_t> * read_data)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
ZipArchiveStreamTestUsingContents(const std::string & zip_file,const std::string & entry_name,const std::vector<uint8_t> & contents,bool raw)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
ZipArchiveStreamTestUsingMemory(const std::string & zip_file,const std::string & entry_name)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
TEST(ziparchive,StreamCompressed)560 TEST(ziparchive, StreamCompressed) {
561 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContents, false);
562 }
563
TEST(ziparchive,StreamUncompressed)564 TEST(ziparchive, StreamUncompressed) {
565 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, false);
566 }
567
TEST(ziparchive,StreamRawCompressed)568 TEST(ziparchive, StreamRawCompressed) {
569 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContentsCompressed, true);
570 }
571
TEST(ziparchive,StreamRawUncompressed)572 TEST(ziparchive, StreamRawUncompressed) {
573 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, true);
574 }
575
TEST(ziparchive,StreamLargeCompressed)576 TEST(ziparchive, StreamLargeCompressed) {
577 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeCompressTxtName);
578 }
579
TEST(ziparchive,StreamLargeUncompressed)580 TEST(ziparchive, StreamLargeUncompressed) {
581 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeUncompressTxtName);
582 }
583
TEST(ziparchive,StreamCompressedBadCrc)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
TEST(ziparchive,StreamUncompressedBadCrc)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
main(int argc,char ** argv)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