• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 #include "ziparchive/zip_writer.h"
19 
20 #include <android-base/test_utils.h>
21 #include <gtest/gtest.h>
22 #include <time.h>
23 #include <memory>
24 #include <vector>
25 
26 struct zipwriter : public ::testing::Test {
27   TemporaryFile* temp_file_;
28   int fd_;
29   FILE* file_;
30 
SetUpzipwriter31   void SetUp() override {
32     temp_file_ = new TemporaryFile();
33     fd_ = temp_file_->fd;
34     file_ = fdopen(fd_, "w");
35     ASSERT_NE(file_, nullptr);
36   }
37 
TearDownzipwriter38   void TearDown() override {
39     fclose(file_);
40     delete temp_file_;
41   }
42 };
43 
TEST_F(zipwriter,WriteUncompressedZipWithOneFile)44 TEST_F(zipwriter, WriteUncompressedZipWithOneFile) {
45   ZipWriter writer(file_);
46 
47   const char* expected = "hello";
48 
49   ASSERT_EQ(0, writer.StartEntry("file.txt", 0));
50   ASSERT_EQ(0, writer.WriteBytes("he", 2));
51   ASSERT_EQ(0, writer.WriteBytes("llo", 3));
52   ASSERT_EQ(0, writer.FinishEntry());
53   ASSERT_EQ(0, writer.Finish());
54 
55   ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
56 
57   ZipArchiveHandle handle;
58   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
59 
60   ZipEntry data;
61   ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
62   EXPECT_EQ(strlen(expected), data.compressed_length);
63   EXPECT_EQ(strlen(expected), data.uncompressed_length);
64   EXPECT_EQ(kCompressStored, data.method);
65 
66   char buffer[6];
67   EXPECT_EQ(0,
68             ExtractToMemory(handle, &data, reinterpret_cast<uint8_t*>(&buffer), sizeof(buffer)));
69   buffer[5] = 0;
70 
71   EXPECT_STREQ(expected, buffer);
72 
73   CloseArchive(handle);
74 }
75 
TEST_F(zipwriter,WriteUncompressedZipWithMultipleFiles)76 TEST_F(zipwriter, WriteUncompressedZipWithMultipleFiles) {
77   ZipWriter writer(file_);
78 
79   ASSERT_EQ(0, writer.StartEntry("file.txt", 0));
80   ASSERT_EQ(0, writer.WriteBytes("he", 2));
81   ASSERT_EQ(0, writer.FinishEntry());
82 
83   ASSERT_EQ(0, writer.StartEntry("file/file.txt", 0));
84   ASSERT_EQ(0, writer.WriteBytes("llo", 3));
85   ASSERT_EQ(0, writer.FinishEntry());
86 
87   ASSERT_EQ(0, writer.StartEntry("file/file2.txt", 0));
88   ASSERT_EQ(0, writer.FinishEntry());
89 
90   ASSERT_EQ(0, writer.Finish());
91 
92   ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
93 
94   ZipArchiveHandle handle;
95   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
96 
97   char buffer[4];
98   ZipEntry data;
99 
100   ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
101   EXPECT_EQ(kCompressStored, data.method);
102   EXPECT_EQ(2u, data.compressed_length);
103   EXPECT_EQ(2u, data.uncompressed_length);
104   ASSERT_EQ(0,
105             ExtractToMemory(handle, &data, reinterpret_cast<uint8_t*>(buffer), arraysize(buffer)));
106   buffer[2] = 0;
107   EXPECT_STREQ("he", buffer);
108 
109   ASSERT_EQ(0, FindEntry(handle, ZipString("file/file.txt"), &data));
110   EXPECT_EQ(kCompressStored, data.method);
111   EXPECT_EQ(3u, data.compressed_length);
112   EXPECT_EQ(3u, data.uncompressed_length);
113   ASSERT_EQ(0,
114             ExtractToMemory(handle, &data, reinterpret_cast<uint8_t*>(buffer), arraysize(buffer)));
115   buffer[3] = 0;
116   EXPECT_STREQ("llo", buffer);
117 
118   ASSERT_EQ(0, FindEntry(handle, ZipString("file/file2.txt"), &data));
119   EXPECT_EQ(kCompressStored, data.method);
120   EXPECT_EQ(0u, data.compressed_length);
121   EXPECT_EQ(0u, data.uncompressed_length);
122 
123   CloseArchive(handle);
124 }
125 
TEST_F(zipwriter,WriteUncompressedZipFileWithAlignedFlag)126 TEST_F(zipwriter, WriteUncompressedZipFileWithAlignedFlag) {
127   ZipWriter writer(file_);
128 
129   ASSERT_EQ(0, writer.StartEntry("align.txt", ZipWriter::kAlign32));
130   ASSERT_EQ(0, writer.WriteBytes("he", 2));
131   ASSERT_EQ(0, writer.FinishEntry());
132   ASSERT_EQ(0, writer.Finish());
133 
134   ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
135 
136   ZipArchiveHandle handle;
137   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
138 
139   ZipEntry data;
140   ASSERT_EQ(0, FindEntry(handle, ZipString("align.txt"), &data));
141   EXPECT_EQ(0, data.offset & 0x03);
142 
143   CloseArchive(handle);
144 }
145 
ConvertZipTimeToTm(uint32_t & zip_time,struct tm * tm)146 void ConvertZipTimeToTm(uint32_t& zip_time, struct tm* tm) {
147   memset(tm, 0, sizeof(struct tm));
148   tm->tm_hour = (zip_time >> 11) & 0x1f;
149   tm->tm_min = (zip_time >> 5) & 0x3f;
150   tm->tm_sec = (zip_time & 0x1f) << 1;
151 
152   tm->tm_year = ((zip_time >> 25) & 0x7f) + 80;
153   tm->tm_mon = ((zip_time >> 21) & 0xf) - 1;
154   tm->tm_mday = (zip_time >> 16) & 0x1f;
155 }
156 
MakeTm()157 static struct tm MakeTm() {
158   struct tm tm;
159   memset(&tm, 0, sizeof(struct tm));
160   tm.tm_year = 2001 - 1900;
161   tm.tm_mon = 1;
162   tm.tm_mday = 12;
163   tm.tm_hour = 18;
164   tm.tm_min = 30;
165   tm.tm_sec = 20;
166   return tm;
167 }
168 
TEST_F(zipwriter,WriteUncompressedZipFileWithAlignedFlagAndTime)169 TEST_F(zipwriter, WriteUncompressedZipFileWithAlignedFlagAndTime) {
170   ZipWriter writer(file_);
171 
172   struct tm tm = MakeTm();
173   time_t time = mktime(&tm);
174   ASSERT_EQ(0, writer.StartEntryWithTime("align.txt", ZipWriter::kAlign32, time));
175   ASSERT_EQ(0, writer.WriteBytes("he", 2));
176   ASSERT_EQ(0, writer.FinishEntry());
177   ASSERT_EQ(0, writer.Finish());
178 
179   ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
180 
181   ZipArchiveHandle handle;
182   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
183 
184   ZipEntry data;
185   ASSERT_EQ(0, FindEntry(handle, ZipString("align.txt"), &data));
186   EXPECT_EQ(0, data.offset & 0x03);
187 
188   struct tm mod;
189   ConvertZipTimeToTm(data.mod_time, &mod);
190   EXPECT_EQ(tm.tm_sec, mod.tm_sec);
191   EXPECT_EQ(tm.tm_min, mod.tm_min);
192   EXPECT_EQ(tm.tm_hour, mod.tm_hour);
193   EXPECT_EQ(tm.tm_mday, mod.tm_mday);
194   EXPECT_EQ(tm.tm_mon, mod.tm_mon);
195   EXPECT_EQ(tm.tm_year, mod.tm_year);
196 
197   CloseArchive(handle);
198 }
199 
TEST_F(zipwriter,WriteUncompressedZipFileWithAlignedValue)200 TEST_F(zipwriter, WriteUncompressedZipFileWithAlignedValue) {
201   ZipWriter writer(file_);
202 
203   ASSERT_EQ(0, writer.StartAlignedEntry("align.txt", 0, 4096));
204   ASSERT_EQ(0, writer.WriteBytes("he", 2));
205   ASSERT_EQ(0, writer.FinishEntry());
206   ASSERT_EQ(0, writer.Finish());
207 
208   ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
209 
210   ZipArchiveHandle handle;
211   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
212 
213   ZipEntry data;
214   ASSERT_EQ(0, FindEntry(handle, ZipString("align.txt"), &data));
215   EXPECT_EQ(0, data.offset & 0xfff);
216 
217   CloseArchive(handle);
218 }
219 
TEST_F(zipwriter,WriteUncompressedZipFileWithAlignedValueAndTime)220 TEST_F(zipwriter, WriteUncompressedZipFileWithAlignedValueAndTime) {
221   ZipWriter writer(file_);
222 
223   struct tm tm = MakeTm();
224   time_t time = mktime(&tm);
225   ASSERT_EQ(0, writer.StartAlignedEntryWithTime("align.txt", 0, time, 4096));
226   ASSERT_EQ(0, writer.WriteBytes("he", 2));
227   ASSERT_EQ(0, writer.FinishEntry());
228   ASSERT_EQ(0, writer.Finish());
229 
230   ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
231 
232   ZipArchiveHandle handle;
233   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
234 
235   ZipEntry data;
236   ASSERT_EQ(0, FindEntry(handle, ZipString("align.txt"), &data));
237   EXPECT_EQ(0, data.offset & 0xfff);
238 
239   struct tm mod;
240   ConvertZipTimeToTm(data.mod_time, &mod);
241   EXPECT_EQ(tm.tm_sec, mod.tm_sec);
242   EXPECT_EQ(tm.tm_min, mod.tm_min);
243   EXPECT_EQ(tm.tm_hour, mod.tm_hour);
244   EXPECT_EQ(tm.tm_mday, mod.tm_mday);
245   EXPECT_EQ(tm.tm_mon, mod.tm_mon);
246   EXPECT_EQ(tm.tm_year, mod.tm_year);
247 
248   CloseArchive(handle);
249 }
250 
TEST_F(zipwriter,WriteCompressedZipWithOneFile)251 TEST_F(zipwriter, WriteCompressedZipWithOneFile) {
252   ZipWriter writer(file_);
253 
254   ASSERT_EQ(0, writer.StartEntry("file.txt", ZipWriter::kCompress));
255   ASSERT_EQ(0, writer.WriteBytes("helo", 4));
256   ASSERT_EQ(0, writer.FinishEntry());
257   ASSERT_EQ(0, writer.Finish());
258 
259   ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
260 
261   ZipArchiveHandle handle;
262   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
263 
264   ZipEntry data;
265   ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
266   EXPECT_EQ(kCompressDeflated, data.method);
267   EXPECT_EQ(4u, data.uncompressed_length);
268 
269   char buffer[5];
270   ASSERT_EQ(0,
271             ExtractToMemory(handle, &data, reinterpret_cast<uint8_t*>(buffer), arraysize(buffer)));
272   buffer[4] = 0;
273 
274   EXPECT_STREQ("helo", buffer);
275 
276   CloseArchive(handle);
277 }
278 
TEST_F(zipwriter,WriteCompressedZipFlushFull)279 TEST_F(zipwriter, WriteCompressedZipFlushFull) {
280   // This exact data will cause the Finish() to require multiple calls
281   // to deflate() because the ZipWriter buffer isn't big enough to hold
282   // the entire compressed data buffer.
283   constexpr size_t kBufSize = 10000000;
284   std::vector<uint8_t> buffer(kBufSize);
285   size_t prev = 1;
286   for (size_t i = 0; i < kBufSize; i++) {
287     buffer[i] = i + prev;
288     prev = i;
289   }
290 
291   ZipWriter writer(file_);
292   ASSERT_EQ(0, writer.StartEntry("file.txt", ZipWriter::kCompress));
293   ASSERT_EQ(0, writer.WriteBytes(buffer.data(), buffer.size()));
294   ASSERT_EQ(0, writer.FinishEntry());
295   ASSERT_EQ(0, writer.Finish());
296 
297   ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
298 
299   ZipArchiveHandle handle;
300   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
301 
302   ZipEntry data;
303   ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
304   EXPECT_EQ(kCompressDeflated, data.method);
305   EXPECT_EQ(kBufSize, data.uncompressed_length);
306 
307   std::vector<uint8_t> decompress(kBufSize);
308   memset(decompress.data(), 0, kBufSize);
309   ASSERT_EQ(0, ExtractToMemory(handle, &data, decompress.data(), decompress.size()));
310   EXPECT_EQ(0, memcmp(decompress.data(), buffer.data(), kBufSize))
311       << "Input buffer and output buffer are different.";
312 
313   CloseArchive(handle);
314 }
315 
TEST_F(zipwriter,CheckStartEntryErrors)316 TEST_F(zipwriter, CheckStartEntryErrors) {
317   ZipWriter writer(file_);
318 
319   ASSERT_EQ(-5, writer.StartAlignedEntry("align.txt", ZipWriter::kAlign32, 4096));
320   ASSERT_EQ(-6, writer.StartAlignedEntry("align.txt", 0, 3));
321 }
322