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