1 /**
2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "zip_archive.h"
17 #include "libpandafile/file.h"
18 #include "os/file.h"
19 #include "os/mem.h"
20
21 #include "assembly-emitter.h"
22 #include "assembly-parser.h"
23
24 #include <cstdio>
25 #include <cstdint>
26 #include <vector>
27 #include <sstream>
28 #include <gtest/gtest.h>
29 #include <cstddef>
30 #include <memory>
31 #include <securec.h>
32
33 #include <climits>
34 #include <cstdlib>
35 #include <fcntl.h>
36 #include <sys/stat.h>
37
38 namespace ark::test {
39
40 #define GTEST_COUT std::cerr << "[ ] [ INFO ]"
41
42 constexpr char const *FILLER_TEXT =
43 "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras feugiat et odio ac sollicitudin. Maecenas "
44 "lobortis ultrices eros sed pharetra. Phasellus in tortor rhoncus, aliquam augue ac, gravida elit. Sed "
45 "molestie dolor a vulputate tincidunt. Proin a tellus quam. Suspendisse id feugiat elit, non ornare lacus. "
46 "Mauris arcu ex, pretium quis dolor ut, porta iaculis eros. Vestibulum sagittis placerat diam, vitae efficitur "
47 "turpis ultrices sit amet. Etiam elementum bibendum congue. In sit amet dolor ultricies, suscipit arcu ac, "
48 "molestie urna. Mauris ultrices volutpat massa quis ultrices. Suspendisse rutrum lectus sit amet metus "
49 "laoreet, non porta sapien venenatis. Fusce ut massa et purus elementum lacinia. Sed tempus bibendum pretium.";
50
51 constexpr size_t MAX_BUFFER_SIZE = 2048;
52 constexpr size_t MAX_DIR_SIZE = 64;
53
GenerateZipfile(const char * data,const char * archivename,int n,std::vector<uint8_t> & pfData,int level=Z_BEST_COMPRESSION)54 static void GenerateZipfile(const char *data, const char *archivename, int n, std::vector<uint8_t> &pfData,
55 int level = Z_BEST_COMPRESSION)
56 {
57 // Delete the test archive, so it doesn't keep growing as we run this test
58 remove(archivename);
59
60 // Create and append a directory entry for testing
61 std::vector<uint8_t> emptyVector;
62 int ret = CreateOrAddFileIntoZip(archivename, "directory/", &emptyVector, APPEND_STATUS_CREATE, level);
63 if (ret != 0) {
64 ASSERT_EQ(1, 0) << "CreateOrAddFileIntoZip for directory failed!";
65 return;
66 }
67
68 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
69 char archiveFilename[MAX_DIR_SIZE];
70 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
71 char buf[MAX_BUFFER_SIZE];
72
73 // Append a bunch of text files to the test archive
74 for (int i = (n - 1); i >= 0; --i) {
75 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
76 (void)sprintf_s(archiveFilename, sizeof(archiveFilename), "%u.txt", i);
77 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
78 (void)sprintf_s(buf, sizeof(buf), "%u %s %u", (n - 1) - i, data, i);
79 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
80 std::vector<uint8_t> fillerData(buf, buf + strlen(buf) + 1);
81 ret = CreateOrAddFileIntoZip(archivename, archiveFilename, &fillerData, APPEND_STATUS_ADDINZIP, level);
82 if (ret != 0) {
83 ASSERT_EQ(1, 0) << "CreateOrAddFileIntoZip for " << i << ".txt failed!";
84 return;
85 }
86 }
87
88 // Append a file into directory entry for testing
89 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
90 (void)sprintf_s(buf, sizeof(buf), "%u %s %u", n, data, n);
91 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
92 std::vector<uint8_t> fillerData(buf, buf + strlen(buf) + 1);
93 ret = CreateOrAddFileIntoZip(archivename, "directory/indirectory.txt", &fillerData, APPEND_STATUS_ADDINZIP, level);
94 if (ret != 0) {
95 ASSERT_EQ(1, 0) << "CreateOrAddFileIntoZip for directory/indirectory.txt failed!";
96 return;
97 }
98
99 // Add a pandafile into zip for testing
100 ret = CreateOrAddFileIntoZip(archivename, "classes.abc", &pfData, APPEND_STATUS_ADDINZIP, level);
101 if (ret != 0) {
102 ASSERT_EQ(1, 0) << "CreateOrAddFileIntoZip for classes.abc failed!";
103 return;
104 }
105 }
106
UnzipFileCheckDirectory(const char * archivename,char * filename,int level=Z_BEST_COMPRESSION)107 static void UnzipFileCheckDirectory(const char *archivename, char *filename, int level = Z_BEST_COMPRESSION)
108 {
109 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
110 (void)sprintf_s(filename, MAX_DIR_SIZE, "directory/");
111
112 ZipArchiveHandle zipfile = nullptr;
113 FILE *myfile = fopen(archivename, "rbe");
114
115 if (OpenArchiveFile(zipfile, myfile) != 0) {
116 fclose(myfile);
117 ASSERT_EQ(1, 0) << "OpenArchiveFILE error.";
118 return;
119 }
120 if (LocateFile(zipfile, filename) != 0) {
121 CloseArchiveFile(zipfile);
122 fclose(myfile);
123 ASSERT_EQ(1, 0) << "LocateFile error.";
124 return;
125 }
126 EntryFileStat entry = EntryFileStat();
127 if (GetCurrentFileInfo(zipfile, &entry) != 0) {
128 CloseArchiveFile(zipfile);
129 fclose(myfile);
130 ASSERT_EQ(1, 0) << "GetCurrentFileInfo test error.";
131 return;
132 }
133 if (OpenCurrentFile(zipfile) != 0) {
134 CloseCurrentFile(zipfile);
135 CloseArchiveFile(zipfile);
136 fclose(myfile);
137 ASSERT_EQ(1, 0) << "OpenCurrentFile test error.";
138 return;
139 }
140
141 GetCurrentFileOffset(zipfile, &entry);
142
143 uint32_t uncompressedLength = entry.GetUncompressedSize();
144
145 ASSERT_GT(entry.GetOffset(), 0);
146 if (level == Z_NO_COMPRESSION) {
147 ASSERT_FALSE(entry.IsCompressed());
148 } else {
149 ASSERT_TRUE(entry.IsCompressed());
150 }
151
152 GTEST_COUT << "Filename: " << filename << ", Uncompressed size: " << uncompressedLength
153 << "Compressed size: " << entry.GetCompressedSize() << "Compressed(): " << entry.IsCompressed()
154 << "entry offset: " << entry.GetOffset() << "\n";
155
156 CloseCurrentFile(zipfile);
157 CloseArchiveFile(zipfile);
158 fclose(myfile);
159 }
160
CloseArchiveAndCurrentFile(ZipArchiveHandle zipfile,FILE * myfile)161 static void CloseArchiveAndCurrentFile(ZipArchiveHandle zipfile, FILE *myfile)
162 {
163 CloseCurrentFile(zipfile);
164 CloseArchiveFile(zipfile);
165 (void)fclose(myfile);
166 }
167
OpenArchiveAndCurrentFile(ZipArchiveHandle & zipfile,char * filename,FILE * myfile,EntryFileStat * entry)168 static std::string OpenArchiveAndCurrentFile(ZipArchiveHandle &zipfile, char *filename, FILE *myfile,
169 EntryFileStat *entry)
170 {
171 if (OpenArchiveFile(zipfile, myfile) != 0) {
172 fclose(myfile);
173 return "OpenArchiveFILE error.";
174 }
175 if (LocateFile(zipfile, filename) != 0) {
176 CloseArchiveFile(zipfile);
177 fclose(myfile);
178 return "LocateFile error.";
179 }
180
181 if (GetCurrentFileInfo(zipfile, entry) != 0) {
182 CloseArchiveFile(zipfile);
183 fclose(myfile);
184 return "GetCurrentFileInfo test error.";
185 }
186 if (OpenCurrentFile(zipfile) != 0) {
187 CloseArchiveAndCurrentFile(zipfile, myfile);
188 return "OpenCurrentFile test error.";
189 }
190
191 return {};
192 }
193
ExtractFile(ZipArchiveHandle & zipfile,FILE * myfile,uint32_t uncompressedLength,char * buf)194 static std::string ExtractFile(ZipArchiveHandle &zipfile, FILE *myfile, uint32_t uncompressedLength, char *buf)
195 {
196 // Extract to mem buffer accroding to entry info.
197 uint32_t pageSize = os::mem::GetPageSize();
198 ASSERT(pageSize != 0);
199 uint32_t minPages = uncompressedLength / pageSize;
200 uint32_t sizeToMmap = uncompressedLength % pageSize == 0 ? minPages * pageSize : (minPages + 1) * pageSize;
201 // we will use mem in memcmp, so donnot poision it!
202 void *mem = os::mem::MapRWAnonymousRaw(sizeToMmap, false);
203 if (mem == nullptr) {
204 CloseArchiveAndCurrentFile(zipfile, myfile);
205 return "Can't mmap anonymous!";
206 }
207
208 if (ExtractToMemory(zipfile, reinterpret_cast<uint8_t *>(mem), sizeToMmap) != 0) {
209 os::mem::UnmapRaw(mem, sizeToMmap);
210 CloseArchiveAndCurrentFile(zipfile, myfile);
211 return "Can't extract!";
212 }
213
214 // Make sure the extraction really succeeded.
215 size_t dlen = strlen(buf);
216 if (uncompressedLength != (dlen + 1)) {
217 os::mem::UnmapRaw(mem, sizeToMmap);
218 CloseArchiveAndCurrentFile(zipfile, myfile);
219 std::ostringstream out;
220 out << "ExtractToMemory() failed!, uncompressed_length is " << (uncompressedLength - 1)
221 << ", original strlen is " << dlen;
222 return out.str();
223 }
224
225 if (memcmp(mem, buf, dlen) != 0) {
226 os::mem::UnmapRaw(mem, sizeToMmap);
227 CloseArchiveAndCurrentFile(zipfile, myfile);
228 return "ExtractToMemory() memcmp failed!";
229 }
230
231 os::mem::UnmapRaw(mem, sizeToMmap);
232
233 return {};
234 }
235
ExtractPandaFile(ZipArchiveHandle & zipfile,FILE * myfile,uint32_t uncompressedLength,std::vector<uint8_t> & pfData)236 static std::string ExtractPandaFile(ZipArchiveHandle &zipfile, FILE *myfile, uint32_t uncompressedLength,
237 std::vector<uint8_t> &pfData)
238 {
239 // Extract to mem buffer accroding to entry info.
240 uint32_t pageSize = os::mem::GetPageSize();
241 ASSERT(pageSize != 0);
242 uint32_t minPages = uncompressedLength / pageSize;
243 uint32_t sizeToMmap = uncompressedLength % pageSize == 0 ? minPages * pageSize : (minPages + 1) * pageSize;
244 // we will use mem in memcmp, so donnot poision it!
245 void *mem = os::mem::MapRWAnonymousRaw(sizeToMmap, false);
246 if (mem == nullptr) {
247 CloseArchiveAndCurrentFile(zipfile, myfile);
248 return "Can't mmap anonymous!";
249 }
250
251 int ret = ExtractToMemory(zipfile, reinterpret_cast<uint8_t *>(mem), sizeToMmap);
252 if (ret != 0) {
253 os::mem::UnmapRaw(mem, sizeToMmap);
254 CloseArchiveAndCurrentFile(zipfile, myfile);
255 return "Can't extract!";
256 }
257
258 // Make sure the extraction really succeeded.
259 if (uncompressedLength != pfData.size()) {
260 os::mem::UnmapRaw(mem, sizeToMmap);
261 CloseArchiveAndCurrentFile(zipfile, myfile);
262 std::ostringstream out;
263 out << "ExtractToMemory() failed!, uncompressed_length is " << uncompressedLength
264 << ", original pf_data size is " << pfData.size() << "\n";
265 return out.str();
266 }
267
268 if (memcmp(mem, pfData.data(), pfData.size()) != 0) {
269 os::mem::UnmapRaw(mem, sizeToMmap);
270 CloseArchiveAndCurrentFile(zipfile, myfile);
271 return "ExtractToMemory() memcmp failed!";
272 }
273
274 os::mem::UnmapRaw(mem, sizeToMmap);
275
276 return {};
277 }
278
UnzipFileCheckTxt(const char * archivename,char * filename,const char * data,int n,int level=Z_BEST_COMPRESSION)279 static void UnzipFileCheckTxt(const char *archivename, char *filename, const char *data, int n,
280 int level = Z_BEST_COMPRESSION)
281 {
282 for (int i = 0; i < n; i++) {
283 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
284 (void)sprintf_s(filename, MAX_DIR_SIZE, "%u.txt", i);
285
286 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
287 char buf[MAX_BUFFER_SIZE];
288 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
289 (void)sprintf_s(buf, sizeof(buf), "%u %s %u", (n - 1) - i, data, i);
290
291 ZipArchiveHandle zipfile = nullptr;
292 FILE *myfile = fopen(archivename, "rbe");
293 EntryFileStat entry = EntryFileStat();
294
295 std::string errorMessage = OpenArchiveAndCurrentFile(zipfile, filename, myfile, &entry);
296 if (!errorMessage.empty()) {
297 ASSERT_EQ(1, 0) << errorMessage.c_str();
298 }
299
300 GetCurrentFileOffset(zipfile, &entry);
301
302 uint32_t uncompressedLength = entry.GetUncompressedSize();
303 if (uncompressedLength == 0) {
304 CloseArchiveAndCurrentFile(zipfile, myfile);
305 ASSERT_EQ(1, 0) << "Entry file has zero length! Readed bad data!";
306 }
307 ASSERT_GT(entry.GetOffset(), 0);
308 ASSERT_EQ(uncompressedLength, strlen(buf) + 1);
309 if (level == Z_NO_COMPRESSION) {
310 ASSERT_EQ(uncompressedLength, entry.GetCompressedSize());
311 ASSERT_FALSE(entry.IsCompressed());
312 } else {
313 ASSERT_GE(uncompressedLength, entry.GetCompressedSize());
314 ASSERT_TRUE(entry.IsCompressed());
315 }
316
317 GTEST_COUT << "Filename: " << filename << ", Uncompressed size: " << uncompressedLength
318 << "Compressed size: " << entry.GetCompressedSize() << "Compressed(): " << entry.IsCompressed()
319 << "entry offset: " << entry.GetOffset() << "\n";
320
321 {
322 errorMessage = ExtractFile(zipfile, myfile, uncompressedLength, buf);
323 if (!errorMessage.empty()) {
324 ASSERT_EQ(1, 0) << errorMessage.c_str();
325 }
326
327 GTEST_COUT << "Successfully extracted file " << filename << " from " << archivename << ", size is "
328 << uncompressedLength << "\n";
329 }
330
331 CloseArchiveAndCurrentFile(zipfile, myfile);
332 }
333 }
334
UnzipFileCheckPandaFile(const char * archivename,char * filename,std::vector<uint8_t> & pfData,int level=Z_BEST_COMPRESSION)335 static void UnzipFileCheckPandaFile(const char *archivename, char *filename, std::vector<uint8_t> &pfData,
336 int level = Z_BEST_COMPRESSION)
337 {
338 {
339 ZipArchiveHandle zipfile = nullptr;
340 FILE *myfile = fopen(archivename, "rbe");
341 EntryFileStat entry = EntryFileStat();
342
343 std::string errorMessage = OpenArchiveAndCurrentFile(zipfile, filename, myfile, &entry);
344 if (!errorMessage.empty()) {
345 ASSERT_EQ(1, 0) << errorMessage.c_str();
346 }
347
348 GetCurrentFileOffset(zipfile, &entry);
349
350 uint32_t uncompressedLength = entry.GetUncompressedSize();
351 if (uncompressedLength == 0) {
352 CloseCurrentFile(zipfile);
353 CloseArchiveFile(zipfile);
354 fclose(myfile);
355 ASSERT_EQ(1, 0) << "Entry file has zero length! Readed bad data!";
356 return;
357 }
358 ASSERT_GT(entry.GetOffset(), 0);
359 ASSERT_EQ(uncompressedLength, pfData.size());
360 if (level == Z_NO_COMPRESSION) {
361 ASSERT_EQ(uncompressedLength, entry.GetCompressedSize());
362 ASSERT_FALSE(entry.IsCompressed());
363 } else {
364 ASSERT_GE(uncompressedLength, entry.GetCompressedSize());
365 ASSERT_TRUE(entry.IsCompressed());
366 }
367
368 GTEST_COUT << "Filename: " << filename << ", Uncompressed size: " << uncompressedLength
369 << "Compressed size: " << entry.GetCompressedSize() << "Compressed(): " << entry.IsCompressed()
370 << "entry offset: " << entry.GetOffset() << "\n";
371
372 {
373 errorMessage = ExtractPandaFile(zipfile, myfile, uncompressedLength, pfData);
374 if (!errorMessage.empty()) {
375 ASSERT_EQ(1, 0) << errorMessage.c_str();
376 }
377 GTEST_COUT << "Successfully extracted file " << filename << " from " << archivename << ", size is "
378 << uncompressedLength << "\n";
379 }
380 CloseArchiveAndCurrentFile(zipfile, myfile);
381 }
382 }
383
UnzipFileCheckInDirectory(const char * archivename,char * filename,const char * data,int n,int level=Z_BEST_COMPRESSION)384 static void UnzipFileCheckInDirectory(const char *archivename, char *filename, const char *data, int n,
385 int level = Z_BEST_COMPRESSION)
386 {
387 {
388 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
389 (void)sprintf_s(filename, MAX_DIR_SIZE, "directory/indirectory.txt");
390
391 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
392 char buf[MAX_BUFFER_SIZE];
393 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
394 (void)sprintf_s(buf, sizeof(buf), "%u %s %u", n, data, n);
395
396 // Unzip Check
397 ZipArchiveHandle zipfile = nullptr;
398 FILE *myfile = fopen(archivename, "rbe");
399 EntryFileStat entry = EntryFileStat();
400
401 std::string errorMessage = OpenArchiveAndCurrentFile(zipfile, filename, myfile, &entry);
402 if (!errorMessage.empty()) {
403 ASSERT_EQ(1, 0) << errorMessage.c_str();
404 }
405
406 GetCurrentFileOffset(zipfile, &entry);
407
408 uint32_t uncompressedLength = entry.GetUncompressedSize();
409 if (uncompressedLength == 0) {
410 CloseCurrentFile(zipfile);
411 CloseArchiveFile(zipfile);
412 fclose(myfile);
413 ASSERT_EQ(1, 0) << "Entry file has zero length! Readed bad data!";
414 return;
415 }
416 ASSERT_GT(entry.GetOffset(), 0);
417 ASSERT_EQ(uncompressedLength, strlen(buf) + 1);
418 if (level == Z_NO_COMPRESSION) {
419 ASSERT_EQ(uncompressedLength, entry.GetCompressedSize());
420 ASSERT_FALSE(entry.IsCompressed());
421 } else {
422 ASSERT_GE(uncompressedLength, entry.GetCompressedSize());
423 ASSERT_TRUE(entry.IsCompressed());
424 }
425 GTEST_COUT << "Filename: " << filename << ", Uncompressed size: " << uncompressedLength
426 << "Compressed size: " << entry.GetCompressedSize() << "Compressed(): " << entry.IsCompressed()
427 << "entry offset: " << entry.GetOffset() << "\n";
428
429 {
430 errorMessage = ExtractFile(zipfile, myfile, uncompressedLength, buf);
431 if (!errorMessage.empty()) {
432 ASSERT_EQ(1, 0) << errorMessage.c_str();
433 }
434
435 GTEST_COUT << "Successfully extracted file " << filename << " from " << archivename << ", size is "
436 << uncompressedLength << "\n";
437 }
438
439 CloseArchiveAndCurrentFile(zipfile, myfile);
440 }
441 }
442
TEST(LIBZIPARCHIVE,ZipFile)443 TEST(LIBZIPARCHIVE, ZipFile)
444 {
445 /*
446 * creating an empty pandafile
447 */
448 std::vector<uint8_t> pfData {};
449 {
450 pandasm::Parser p;
451
452 auto source = R"()";
453
454 std::string srcFilename = "src.pa";
455 auto res = p.Parse(source, srcFilename);
456 ASSERT_EQ(p.ShowError().err, pandasm::Error::ErrorType::ERR_NONE);
457
458 auto pf = pandasm::AsmEmitter::Emit(res.Value());
459 ASSERT_NE(pf, nullptr);
460
461 const auto headerPtr = reinterpret_cast<const uint8_t *>(pf->GetHeader());
462 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
463 pfData.assign(headerPtr, headerPtr + sizeof(panda_file::File::Header));
464 }
465
466 static const char *archivename = "__LIBZIPARCHIVE__ZipFile__.zip";
467 const int n = 3;
468
469 GenerateZipfile(FILLER_TEXT, archivename, n, pfData);
470
471 // Quick Check
472 ZipArchiveHandle zipfile = nullptr;
473 if (OpenArchive(zipfile, archivename) != 0) {
474 ASSERT_EQ(1, 0) << "OpenArchive error.";
475 return;
476 }
477
478 GlobalStat gi = GlobalStat();
479 if (GetGlobalFileInfo(zipfile, &gi) != 0) {
480 ASSERT_EQ(1, 0) << "GetGlobalFileInfo error.";
481 return;
482 }
483 for (int i = 0; i < (int)gi.GetNumberOfEntry(); ++i) {
484 EntryFileStat fileStat {};
485 if (GetCurrentFileInfo(zipfile, &fileStat) != 0) {
486 CloseArchive(zipfile);
487 ASSERT_EQ(1, 0) << "GetCurrentFileInfo error. Current index i = " << i;
488 return;
489 }
490 GTEST_COUT << "Index: " << i << ", Uncompressed size: " << fileStat.GetUncompressedSize()
491 << "Compressed size: " << fileStat.GetCompressedSize() << "Compressed(): " << fileStat.IsCompressed()
492 << "entry offset: " << fileStat.GetOffset() << "\n";
493 if ((i + 1) < (int)gi.GetNumberOfEntry()) {
494 if (GoToNextFile(zipfile) != 0) {
495 CloseArchive(zipfile);
496 ASSERT_EQ(1, 0) << "GoToNextFile error. Current index i = " << i;
497 return;
498 }
499 }
500 }
501
502 CloseArchive(zipfile);
503 remove(archivename);
504 GTEST_COUT << "Success.\n";
505 }
506
TEST(LIBZIPARCHIVE,UnZipFile)507 TEST(LIBZIPARCHIVE, UnZipFile)
508 {
509 /*
510 * creating an empty pandafile
511 */
512 std::vector<uint8_t> pfData {};
513 {
514 pandasm::Parser p;
515
516 auto source = R"()";
517
518 std::string srcFilename = "src.pa";
519 auto res = p.Parse(source, srcFilename);
520 ASSERT_EQ(p.ShowError().err, pandasm::Error::ErrorType::ERR_NONE);
521
522 auto pf = pandasm::AsmEmitter::Emit(res.Value());
523 ASSERT_NE(pf, nullptr);
524
525 const auto headerPtr = reinterpret_cast<const uint8_t *>(pf->GetHeader());
526 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
527 pfData.assign(headerPtr, headerPtr + sizeof(panda_file::File::Header));
528 }
529
530 // The zip filename
531 static const char *archivename = "__LIBZIPARCHIVE__UnZipFile__.zip";
532 const int n = 3;
533 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
534 char filename[MAX_DIR_SIZE];
535
536 GenerateZipfile(FILLER_TEXT, archivename, n, pfData);
537
538 UnzipFileCheckDirectory(archivename, filename);
539
540 UnzipFileCheckTxt(archivename, filename, FILLER_TEXT, n);
541
542 UnzipFileCheckInDirectory(archivename, filename, FILLER_TEXT, n);
543
544 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
545 sprintf_s(filename, MAX_DIR_SIZE, "classes.abc");
546 UnzipFileCheckPandaFile(archivename, filename, pfData);
547
548 remove(archivename);
549 GTEST_COUT << "Success.\n";
550 }
551
TEST(LIBZIPARCHIVE,UnZipUncompressedFile)552 TEST(LIBZIPARCHIVE, UnZipUncompressedFile)
553 {
554 /*
555 * creating an empty pandafile
556 */
557 std::vector<uint8_t> pfData {};
558 {
559 pandasm::Parser p;
560
561 auto source = R"()";
562
563 std::string srcFilename = "src.pa";
564 auto res = p.Parse(source, srcFilename);
565 ASSERT_EQ(p.ShowError().err, pandasm::Error::ErrorType::ERR_NONE);
566
567 auto pf = pandasm::AsmEmitter::Emit(res.Value());
568 ASSERT_NE(pf, nullptr);
569
570 const auto headerPtr = reinterpret_cast<const uint8_t *>(pf->GetHeader());
571 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
572 pfData.assign(headerPtr, headerPtr + sizeof(panda_file::File::Header));
573 }
574
575 // The zip filename
576 static const char *archivename = "__LIBZIPARCHIVE__UnZipUncompressedFile__.zip";
577 const int n = 3;
578
579 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
580 char filename[MAX_DIR_SIZE];
581
582 GenerateZipfile(FILLER_TEXT, archivename, n, pfData, Z_NO_COMPRESSION);
583
584 UnzipFileCheckDirectory(archivename, filename, Z_NO_COMPRESSION);
585
586 UnzipFileCheckTxt(archivename, filename, FILLER_TEXT, n, Z_NO_COMPRESSION);
587
588 UnzipFileCheckInDirectory(archivename, filename, FILLER_TEXT, n, Z_NO_COMPRESSION);
589
590 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
591 (void)sprintf_s(filename, MAX_DIR_SIZE, "classes.abc");
592 UnzipFileCheckPandaFile(archivename, filename, pfData, Z_NO_COMPRESSION);
593
594 remove(archivename);
595 GTEST_COUT << "Success.\n";
596 }
597
TEST(LIBZIPARCHIVE,UnZipUncompressedPandaFile)598 TEST(LIBZIPARCHIVE, UnZipUncompressedPandaFile)
599 {
600 /*
601 * creating an empty pandafile
602 */
603 std::vector<uint8_t> pfData {};
604 {
605 pandasm::Parser p;
606
607 auto source = R"()";
608
609 std::string srcFilename = "src.pa";
610 auto res = p.Parse(source, srcFilename);
611 ASSERT_EQ(p.ShowError().err, pandasm::Error::ErrorType::ERR_NONE);
612
613 auto pf = pandasm::AsmEmitter::Emit(res.Value());
614 ASSERT_NE(pf, nullptr);
615
616 const auto headerPtr = reinterpret_cast<const uint8_t *>(pf->GetHeader());
617 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
618 pfData.assign(headerPtr, headerPtr + sizeof(panda_file::File::Header));
619 }
620
621 // The zip filename
622 static const char *archivename = "__LIBZIPARCHIVE__UnZipUncompressedPandaFile__.zip";
623 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
624 char filename[MAX_DIR_SIZE];
625
626 // Delete the test archive, so it doesn't keep growing as we run this test
627 remove(archivename);
628
629 // Add pandafile into zip for testing
630 int ret = CreateOrAddFileIntoZip(archivename, "class.abc", &pfData, APPEND_STATUS_CREATE, Z_NO_COMPRESSION);
631 if (ret != 0) {
632 ASSERT_EQ(1, 0) << "CreateOrAddFileIntoZip failed!";
633 return;
634 }
635 ret = CreateOrAddFileIntoZip(archivename, "classes.abc", &pfData, APPEND_STATUS_ADDINZIP, Z_NO_COMPRESSION);
636 if (ret != 0) {
637 ASSERT_EQ(1, 0) << "CreateOrAddFileIntoZip failed!";
638 return;
639 }
640
641 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
642 sprintf_s(filename, MAX_DIR_SIZE, "class.abc");
643 UnzipFileCheckPandaFile(archivename, filename, pfData, Z_NO_COMPRESSION);
644 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
645 sprintf_s(filename, MAX_DIR_SIZE, "classes.abc");
646 UnzipFileCheckPandaFile(archivename, filename, pfData, Z_NO_COMPRESSION);
647
648 remove(archivename);
649 GTEST_COUT << "Success.\n";
650 }
651
TEST(LIBZIPARCHIVE,IllegalPathTest)652 TEST(LIBZIPARCHIVE, IllegalPathTest)
653 {
654 static const char *archivename = "__LIBZIPARCHIVE__ILLEGALPATHTEST__.zip";
655 int ret =
656 CreateOrAddFileIntoZip(archivename, "illegal_path.abc", nullptr, APPEND_STATUS_ADDINZIP, Z_NO_COMPRESSION);
657 ASSERT_EQ(ret, ZIPARCHIVE_ERR);
658 ZipArchiveHandle zipfile = nullptr;
659 ASSERT_EQ(OpenArchive(zipfile, archivename), ZIPARCHIVE_ERR);
660 GlobalStat gi = GlobalStat();
661 ASSERT_EQ(GetGlobalFileInfo(zipfile, &gi), ZIPARCHIVE_ERR);
662 ASSERT_EQ(GoToNextFile(zipfile), ZIPARCHIVE_ERR);
663 ASSERT_EQ(LocateFile(zipfile, "illegal_path.abc"), ZIPARCHIVE_ERR);
664 EntryFileStat entry = EntryFileStat();
665 ASSERT_EQ(GetCurrentFileInfo(zipfile, &entry), ZIPARCHIVE_ERR);
666 ASSERT_EQ(CloseArchive(zipfile), ZIPARCHIVE_ERR);
667
668 ASSERT_EQ(OpenArchiveFile(zipfile, nullptr), ZIPARCHIVE_ERR);
669 ASSERT_EQ(OpenCurrentFile(zipfile), ZIPARCHIVE_ERR);
670 ASSERT_EQ(CloseCurrentFile(zipfile), ZIPARCHIVE_ERR);
671 ASSERT_EQ(CloseArchiveFile(zipfile), ZIPARCHIVE_ERR);
672 }
673 } // namespace ark::test
674