blob: 30822165c5312c474418d9d8e6645f7b32884e43 [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
17#include "ziparchive/zip_archive.h"
18
Narayan Kamath00a258c2013-12-13 16:06:19 +000019#include <errno.h>
20#include <getopt.h>
Narayan Kamath7462f022013-11-21 13:05:04 +000021#include <stdio.h>
Narayan Kamath00a258c2013-12-13 16:06:19 +000022#include <unistd.h>
23#include <vector>
24
Narayan Kamath7462f022013-11-21 13:05:04 +000025#include <gtest/gtest.h>
26
Narayan Kamath58aaf462013-12-10 16:47:14 +000027static std::string test_data_dir;
Narayan Kamath7462f022013-11-21 13:05:04 +000028
Narayan Kamath58aaf462013-12-10 16:47:14 +000029static const std::string kValidZip = "valid.zip";
30
31static const uint8_t kATxtContents[] = {
32 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
33 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
34 '\n'
35};
36
37static const uint8_t kBTxtContents[] = {
38 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
39 '\n'
40};
41
42static int32_t OpenArchiveWrapper(const std::string& name,
43 ZipArchiveHandle* handle) {
44 const std::string abs_path = test_data_dir + "/" + name;
45 return OpenArchive(abs_path.c_str(), handle);
46}
47
48static void AssertNameEquals(const std::string& name_str,
49 const ZipEntryName& name) {
50 ASSERT_EQ(name_str.size(), name.name_length);
51 ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
52}
53
54TEST(ziparchive, Open) {
55 ZipArchiveHandle handle;
56 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
57
58 CloseArchive(handle);
59}
60
61TEST(ziparchive, Iteration) {
62 ZipArchiveHandle handle;
63 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
64
65 void* iteration_cookie;
66 ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL));
Narayan Kamath7462f022013-11-21 13:05:04 +000067
68 ZipEntry data;
69 ZipEntryName name;
Narayan Kamath58aaf462013-12-10 16:47:14 +000070
71 // b/c.txt
72 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
73 AssertNameEquals("b/c.txt", name);
74
75 // b/d.txt
76 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
77 AssertNameEquals("b/d.txt", name);
78
79 // a.txt
80 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
81 AssertNameEquals("a.txt", name);
82
83 // b.txt
84 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
85 AssertNameEquals("b.txt", name);
86
87 // b/
88 ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
89 AssertNameEquals("b/", name);
90
91 // End of iteration.
92 ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
93
94 CloseArchive(handle);
95}
96
97TEST(ziparchive, FindEntry) {
98 ZipArchiveHandle handle;
99 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
100
101 ZipEntry data;
102 ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
103
104 // Known facts about a.txt, from zipinfo -v.
105 ASSERT_EQ(63, data.offset);
106 ASSERT_EQ(kCompressDeflated, data.method);
107 ASSERT_EQ(static_cast<uint32_t>(17), data.uncompressed_length);
108 ASSERT_EQ(static_cast<uint32_t>(13), data.compressed_length);
109 ASSERT_EQ(0x950821c5, data.crc32);
110
111 // An entry that doesn't exist. Should be a negative return code.
112 ASSERT_LT(FindEntry(handle, "nonexistent.txt", &data), 0);
113
114 CloseArchive(handle);
115}
116
117TEST(ziparchive, ExtractToMemory) {
118 ZipArchiveHandle handle;
119 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
120
121 // An entry that's deflated.
122 ZipEntry data;
123 ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
124 const uint32_t a_size = data.uncompressed_length;
125 ASSERT_EQ(a_size, sizeof(kATxtContents));
126 uint8_t* buffer = new uint8_t[a_size];
127 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
128 ASSERT_EQ(0, memcmp(buffer, kATxtContents, a_size));
129 delete[] buffer;
130
131 // An entry that's stored.
132 ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
133 const uint32_t b_size = data.uncompressed_length;
134 ASSERT_EQ(b_size, sizeof(kBTxtContents));
135 buffer = new uint8_t[b_size];
136 ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
137 ASSERT_EQ(0, memcmp(buffer, kBTxtContents, b_size));
138 delete[] buffer;
139
140 CloseArchive(handle);
141}
142
Narayan Kamath48953a12014-01-24 12:32:39 +0000143TEST(ziparchive, EmptyEntries) {
144 char temp_file_pattern[] = "empty_entries_test_XXXXXX";
145 int fd = mkstemp(temp_file_pattern);
146 ASSERT_NE(-1, fd);
147 const uint32_t data[] = {
148 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000,
149 0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13,
150 0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b,
151 0x00000a03, 0x60000000, 0x00443863, 0x00000000, 0x00000000, 0x09000000,
152 0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974,
153 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
154 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
155 const ssize_t file_size = 168;
156 ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, data, file_size)));
157
158 ZipArchiveHandle handle;
159 ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
160
161 ZipEntry entry;
162 ASSERT_EQ(0, FindEntry(handle, "empty.txt", &entry));
163 ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
164 uint8_t buffer[1];
165 ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
166
167 char output_file_pattern[] = "empty_entries_output_XXXXXX";
168 int output_fd = mkstemp(output_file_pattern);
169 ASSERT_NE(-1, output_fd);
170 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
171
172 struct stat stat_buf;
173 ASSERT_EQ(0, fstat(output_fd, &stat_buf));
174 ASSERT_EQ(0, stat_buf.st_size);
175
176 close(fd);
177 close(output_fd);
178}
179
Narayan Kamath00a258c2013-12-13 16:06:19 +0000180TEST(ziparchive, ExtractToFile) {
Narayan Kamath48953a12014-01-24 12:32:39 +0000181 char kTempFilePattern[] = "zip_archive_input_XXXXXX";
Narayan Kamath00a258c2013-12-13 16:06:19 +0000182 int fd = mkstemp(kTempFilePattern);
183 ASSERT_NE(-1, fd);
184 const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' };
185 const ssize_t data_size = sizeof(data);
186
187 ASSERT_EQ(data_size, TEMP_FAILURE_RETRY(write(fd, data, data_size)));
188
189 ZipArchiveHandle handle;
190 ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
191
192 ZipEntry entry;
193 ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
194 ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, fd));
195
196
197 // Assert that the first 8 bytes of the file haven't been clobbered.
198 uint8_t read_buffer[data_size];
199 ASSERT_EQ(0, lseek64(fd, 0, SEEK_SET));
200 ASSERT_EQ(data_size, TEMP_FAILURE_RETRY(read(fd, read_buffer, data_size)));
201 ASSERT_EQ(0, memcmp(read_buffer, data, data_size));
202
203 // Assert that the remainder of the file contains the incompressed data.
204 std::vector<uint8_t> uncompressed_data(entry.uncompressed_length);
205 ASSERT_EQ(static_cast<ssize_t>(entry.uncompressed_length),
206 TEMP_FAILURE_RETRY(
207 read(fd, &uncompressed_data[0], entry.uncompressed_length)));
208 ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents,
209 sizeof(kATxtContents)));
210
211 // Assert that the total length of the file is sane
212 ASSERT_EQ(data_size + sizeof(kATxtContents), lseek64(fd, 0, SEEK_END));
213
214 close(fd);
215}
216
Narayan Kamath58aaf462013-12-10 16:47:14 +0000217int main(int argc, char** argv) {
218 ::testing::InitGoogleTest(&argc, argv);
219
220 static struct option options[] = {
221 { "test_data_dir", required_argument, NULL, 't' },
222 { NULL, 0, NULL, 0 }
223 };
224
225 while (true) {
226 int option_index;
227 const int c = getopt_long_only(argc, argv, "", options, &option_index);
228 if (c == -1) {
229 break;
230 }
231
232 if (c == 't') {
233 test_data_dir = optarg;
234 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000235 }
236
Narayan Kamath58aaf462013-12-10 16:47:14 +0000237 if (test_data_dir.size() == 0) {
238 printf("Test data flag (--test_data_dir) required\n\n");
239 return -1;
240 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000241
Narayan Kamath58aaf462013-12-10 16:47:14 +0000242 if (test_data_dir[0] != '/') {
243 printf("Test data must be an absolute path, was %s\n\n",
244 test_data_dir.c_str());
245 return -2;
246 }
Narayan Kamath7462f022013-11-21 13:05:04 +0000247
Narayan Kamath58aaf462013-12-10 16:47:14 +0000248 return RUN_ALL_TESTS();
Narayan Kamath7462f022013-11-21 13:05:04 +0000249}
250