blob: 6aee1bbdfe85ba6db3523aa7bd8f227d34d88d3d [file] [log] [blame]
Narayan Kamath7462f022013-11-21 13:05:04 +00001/*
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
Narayan Kamath00a258c2013-12-13 16:06:19 +000017#include <errno.h>
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -070018#include <fcntl.h>
Narayan Kamath00a258c2013-12-13 16:06:19 +000019#include <getopt.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000020#include <stdio.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080021#include <string.h>
Narayan Kamath00a258c2013-12-13 16:06:19 +000022#include <unistd.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080023
Yabin Cui8e6f7222016-02-08 16:26:33 -080024#include <memory>
Narayan Kamath00a258c2013-12-13 16:06:19 +000025#include <vector>
26
Elliott Hughes4f713192015-12-04 22:00:26 -080027#include <android-base/file.h>
Yabin Cui8e6f7222016-02-08 16:26:33 -080028#include <android-base/test_utils.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000029#include <gtest/gtest.h>
Christopher Ferrise6884ce2015-11-10 14:55:12 -080030#include <ziparchive/zip_archive.h>
31#include <ziparchive/zip_archive_stream_entry.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000032
Narayan Kamath58aaf462013-12-10 16:47:14 +000033static std::string test_data_dir;
Narayan Kamath7462f022013-11-21 13:05:04 +000034
Neil Fullerb1a113f2014-07-25 14:43:04 +010035static const std::string kMissingZip = "missing.zip";
Narayan Kamath58aaf462013-12-10 16:47:14 +000036static const std::string kValidZip = "valid.zip";
Christopher Ferrise6884ce2015-11-10 14:55:12 -080037static const std::string kLargeZip = "large.zip";
38static const std::string kBadCrcZip = "bad_crc.zip";
Narayan Kamath58aaf462013-12-10 16:47:14 +000039
Christopher Ferrise6884ce2015-11-10 14:55:12 -080040static const std::vector<uint8_t> kATxtContents {
Narayan Kamath58aaf462013-12-10 16:47:14 +000041 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
42 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
43 '\n'
44};
45
Christopher Ferrise6884ce2015-11-10 14:55:12 -080046static const std::vector<uint8_t> kATxtContentsCompressed {
47 'K', 'L', 'J', 'N', 'I', 'M', 'K', 207, 'H',
48 132, 210, '\\', '\0'
49};
50
51static const std::vector<uint8_t> kBTxtContents {
Narayan Kamath58aaf462013-12-10 16:47:14 +000052 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
53 '\n'
54};
55
Christopher Ferrise6884ce2015-11-10 14:55:12 -080056static const std::string kATxtName("a.txt");
57static const std::string kBTxtName("b.txt");
58static const std::string kNonexistentTxtName("nonexistent.txt");
59static const std::string kEmptyTxtName("empty.txt");
60static const std::string kLargeCompressTxtName("compress.txt");
61static const std::string kLargeUncompressTxtName("uncompress.txt");
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +010062
Narayan Kamath58aaf462013-12-10 16:47:14 +000063static 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
69static void AssertNameEquals(const std::string& name_str,
Yusuke Sato07447542015-06-25 14:39:19 -070070 const ZipString& name) {
Narayan Kamath58aaf462013-12-10 16:47:14 +000071 ASSERT_EQ(name_str.size(), name.name_length);
72 ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
73}
74
Christopher Ferrise6884ce2015-11-10 14:55:12 -080075static 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
Narayan Kamath58aaf462013-12-10 16:47:14 +000080TEST(ziparchive, Open) {
81 ZipArchiveHandle handle;
82 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
83
84 CloseArchive(handle);
85}
86
Neil Fullerb1a113f2014-07-25 14:43:04 +010087TEST(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
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -070095TEST(ziparchive, OpenAssumeFdOwnership) {
Yabin Cui8e6f7222016-02-08 16:26:33 -080096 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -070097 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
105TEST(ziparchive, OpenDoNotAssumeFdOwnership) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800106 int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
Dmitriy Ivanov40b52b22014-07-15 19:33:00 -0700107 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
Narayan Kamath58aaf462013-12-10 16:47:14 +0000115TEST(ziparchive, Iteration) {
116 ZipArchiveHandle handle;
117 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
118
119 void* iteration_cookie;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800120 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
Narayan Kamath7462f022013-11-21 13:05:04 +0000121
122 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700123 ZipString name;
Narayan Kamath58aaf462013-12-10 16:47:14 +0000124
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
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700151TEST(ziparchive, IterationWithPrefix) {
152 ZipArchiveHandle handle;
153 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
154
155 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700156 ZipString prefix("b/");
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800157 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, nullptr));
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700158
159 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700160 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700161
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
180TEST(ziparchive, IterationWithSuffix) {
181 ZipArchiveHandle handle;
182 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
183
184 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700185 ZipString suffix(".txt");
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800186 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, &suffix));
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700187
188 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700189 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700190
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
213TEST(ziparchive, IterationWithPrefixAndSuffix) {
214 ZipArchiveHandle handle;
215 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
216
217 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700218 ZipString prefix("b");
219 ZipString suffix(".txt");
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700220 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
221
222 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700223 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700224
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
243TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
244 ZipArchiveHandle handle;
245 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
246
247 void* iteration_cookie;
Yusuke Sato07447542015-06-25 14:39:19 -0700248 ZipString prefix("x");
249 ZipString suffix("y");
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700250 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
251
252 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700253 ZipString name;
Yusuke Satof1d3d3b2015-06-25 14:09:00 -0700254
255 // End of iteration.
256 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
257
258 CloseArchive(handle);
259}
260
Narayan Kamath58aaf462013-12-10 16:47:14 +0000261TEST(ziparchive, FindEntry) {
262 ZipArchiveHandle handle;
263 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
264
265 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700266 ZipString name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800267 SetZipString(&name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100268 ASSERT_EQ(0, FindEntry(handle, name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000269
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);
beonit0e99a2f2015-07-18 02:08:16 +0900276 ASSERT_EQ(static_cast<uint32_t>(0x438a8005), data.mod_time);
Narayan Kamath58aaf462013-12-10 16:47:14 +0000277
278 // An entry that doesn't exist. Should be a negative return code.
Yusuke Sato07447542015-06-25 14:39:19 -0700279 ZipString absent_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800280 SetZipString(&absent_name, kNonexistentTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100281 ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
Narayan Kamath58aaf462013-12-10 16:47:14 +0000282
283 CloseArchive(handle);
284}
285
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200286TEST(ziparchive, TestInvalidDeclaredLength) {
287 ZipArchiveHandle handle;
288 ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
289
290 void* iteration_cookie;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800291 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200292
Yusuke Sato07447542015-06-25 14:39:19 -0700293 ZipString name;
Mykola Kondratenko50afc152014-09-08 12:46:37 +0200294 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
Narayan Kamath58aaf462013-12-10 16:47:14 +0000302TEST(ziparchive, ExtractToMemory) {
303 ZipArchiveHandle handle;
304 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
305
306 // An entry that's deflated.
307 ZipEntry data;
Yusuke Sato07447542015-06-25 14:39:19 -0700308 ZipString a_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800309 SetZipString(&a_name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100310 ASSERT_EQ(0, FindEntry(handle, a_name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000311 const uint32_t a_size = data.uncompressed_length;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800312 ASSERT_EQ(a_size, kATxtContents.size());
Narayan Kamath58aaf462013-12-10 16:47:14 +0000313 uint8_t* buffer = new uint8_t[a_size];
314 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800315 ASSERT_EQ(0, memcmp(buffer, kATxtContents.data(), a_size));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000316 delete[] buffer;
317
318 // An entry that's stored.
Yusuke Sato07447542015-06-25 14:39:19 -0700319 ZipString b_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800320 SetZipString(&b_name, kBTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100321 ASSERT_EQ(0, FindEntry(handle, b_name, &data));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000322 const uint32_t b_size = data.uncompressed_length;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800323 ASSERT_EQ(b_size, kBTxtContents.size());
Narayan Kamath58aaf462013-12-10 16:47:14 +0000324 buffer = new uint8_t[b_size];
325 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800326 ASSERT_EQ(0, memcmp(buffer, kBTxtContents.data(), b_size));
Narayan Kamath58aaf462013-12-10 16:47:14 +0000327 delete[] buffer;
328
329 CloseArchive(handle);
330}
331
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100332static const uint32_t kEmptyEntriesZip[] = {
Narayan Kamath48953a12014-01-24 12:32:39 +0000333 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 };
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100340
Narayan Kamathf899bd52015-04-17 11:53:14 +0100341// 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.
344static 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
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800375static const std::string kAbTxtName("ab.txt");
Narayan Kamathf899bd52015-04-17 11:53:14 +0100376static const size_t kAbUncompressedSize = 270216;
377
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100378TEST(ziparchive, EmptyEntries) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800379 TemporaryFile tmp_file;
380 ASSERT_NE(-1, tmp_file.fd);
381 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
Narayan Kamath48953a12014-01-24 12:32:39 +0000382
383 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800384 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
Narayan Kamath48953a12014-01-24 12:32:39 +0000385
386 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700387 ZipString empty_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800388 SetZipString(&empty_name, kEmptyTxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100389 ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
Narayan Kamath48953a12014-01-24 12:32:39 +0000390 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
Yabin Cui8e6f7222016-02-08 16:26:33 -0800394
395 TemporaryFile tmp_output_file;
396 ASSERT_NE(-1, tmp_output_file.fd);
397 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
Narayan Kamath48953a12014-01-24 12:32:39 +0000398
399 struct stat stat_buf;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800400 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
Narayan Kamath48953a12014-01-24 12:32:39 +0000401 ASSERT_EQ(0, stat_buf.st_size);
Narayan Kamath48953a12014-01-24 12:32:39 +0000402}
403
Narayan Kamathf899bd52015-04-17 11:53:14 +0100404TEST(ziparchive, EntryLargerThan32K) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800405 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),
Narayan Kamathf899bd52015-04-17 11:53:14 +0100408 sizeof(kAbZip) - 1));
409 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800410 ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100411
412 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700413 ZipString ab_name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800414 SetZipString(&ab_name, kAbTxtName);
Narayan Kamathf899bd52015-04-17 11:53:14 +0100415 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.
Yabin Cui8e6f7222016-02-08 16:26:33 -0800423 TemporaryFile tmp_output_file;
424 ASSERT_NE(-1, tmp_output_file.fd);
425 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_output_file.fd));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100426
427 // Make sure the extracted file size is as expected.
428 struct stat stat_buf;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800429 ASSERT_EQ(0, fstat(tmp_output_file.fd, &stat_buf));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100430 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);
Yabin Cui8e6f7222016-02-08 16:26:33 -0800435 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()));
Narayan Kamathf899bd52015-04-17 11:53:14 +0100438 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 }
Narayan Kamathf899bd52015-04-17 11:53:14 +0100446}
447
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100448TEST(ziparchive, TrailerAfterEOCD) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800449 TemporaryFile tmp_file;
450 ASSERT_NE(-1, tmp_file.fd);
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100451
452 // Create a file with 8 bytes of random garbage.
453 static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' };
Yabin Cui8e6f7222016-02-08 16:26:33 -0800454 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, kEmptyEntriesZip, sizeof(kEmptyEntriesZip)));
455 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, trailer, sizeof(trailer)));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100456
457 ZipArchiveHandle handle;
Yabin Cui8e6f7222016-02-08 16:26:33 -0800458 ASSERT_GT(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle));
Narayan Kamath4f6b4992014-06-03 13:59:23 +0100459}
460
Narayan Kamath00a258c2013-12-13 16:06:19 +0000461TEST(ziparchive, ExtractToFile) {
Yabin Cui8e6f7222016-02-08 16:26:33 -0800462 TemporaryFile tmp_file;
463 ASSERT_NE(-1, tmp_file.fd);
Narayan Kamath00a258c2013-12-13 16:06:19 +0000464 const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
Yabin Cui8e6f7222016-02-08 16:26:33 -0800465 const size_t data_size = sizeof(data);
Narayan Kamath00a258c2013-12-13 16:06:19 +0000466
Yabin Cui8e6f7222016-02-08 16:26:33 -0800467 ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, data, data_size));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000468
469 ZipArchiveHandle handle;
470 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
471
472 ZipEntry entry;
Yusuke Sato07447542015-06-25 14:39:19 -0700473 ZipString name;
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800474 SetZipString(&name, kATxtName);
Piotr Jastrzebskiecccc5a2014-08-11 16:35:11 +0100475 ASSERT_EQ(0, FindEntry(handle, name, &entry));
Yabin Cui8e6f7222016-02-08 16:26:33 -0800476 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000477
478
479 // Assert that the first 8 bytes of the file haven't been clobbered.
480 uint8_t read_buffer[data_size];
Yabin Cui8e6f7222016-02-08 16:26:33 -0800481 ASSERT_EQ(0, lseek64(tmp_file.fd, 0, SEEK_SET));
482 ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, read_buffer, data_size));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000483 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);
Yabin Cui8e6f7222016-02-08 16:26:33 -0800487 ASSERT_TRUE(android::base::ReadFully(tmp_file.fd, uncompressed_data.data(),
488 entry.uncompressed_length));
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800489 ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(),
490 kATxtContents.size()));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000491
492 // Assert that the total length of the file is sane
Yabin Cui8e6f7222016-02-08 16:26:33 -0800493 ASSERT_EQ(static_cast<ssize_t>(data_size + kATxtContents.size()),
494 lseek64(tmp_file.fd, 0, SEEK_END));
Narayan Kamath00a258c2013-12-13 16:06:19 +0000495}
496
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800497static 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
528static 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
544static 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
560TEST(ziparchive, StreamCompressed) {
561 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContents, false);
562}
563
564TEST(ziparchive, StreamUncompressed) {
565 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, false);
566}
567
568TEST(ziparchive, StreamRawCompressed) {
569 ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContentsCompressed, true);
570}
571
572TEST(ziparchive, StreamRawUncompressed) {
573 ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, true);
574}
575
576TEST(ziparchive, StreamLargeCompressed) {
577 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeCompressTxtName);
578}
579
580TEST(ziparchive, StreamLargeUncompressed) {
581 ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeUncompressTxtName);
582}
583
584TEST(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
595TEST(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
Narayan Kamath58aaf462013-12-10 16:47:14 +0000606int main(int argc, char** argv) {
607 ::testing::InitGoogleTest(&argc, argv);
608
609 static struct option options[] = {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800610 { "test_data_dir", required_argument, nullptr, 't' },
611 { nullptr, 0, nullptr, 0 }
Narayan Kamath58aaf462013-12-10 16:47:14 +0000612 };
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 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000624 }
625
Narayan Kamath58aaf462013-12-10 16:47:14 +0000626 if (test_data_dir.size() == 0) {
627 printf("Test data flag (--test_data_dir) required\n\n");
628 return -1;
629 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000630
Narayan Kamath58aaf462013-12-10 16:47:14 +0000631 if (test_data_dir[0] != '/') {
Christopher Ferrise6884ce2015-11-10 14:55:12 -0800632 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;
Narayan Kamath58aaf462013-12-10 16:47:14 +0000641 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000642
Narayan Kamath58aaf462013-12-10 16:47:14 +0000643 return RUN_ALL_TESTS();
Narayan Kamath7462f022013-11-21 13:05:04 +0000644}