• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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