diff --git a/libpandafile/BUILD.gn b/libpandafile/BUILD.gn index ee9080e488c6f115c947d8cd7198167a5a25e69a..6d9b5e656ff6f32dff21761fc56375ed431150c6 100644 --- a/libpandafile/BUILD.gn +++ b/libpandafile/BUILD.gn @@ -23,7 +23,10 @@ config("arkfile_public_config") { ] if (!ark_standalone_build) { - include_dirs += [ "//third_party/miniz/amalgamation" ] + include_dirs += [ + "//third_party/zlib", + "//third_party/zlib/contrib/minizip", + ] } else { include_dirs += [ "$ark_third_party_root/miniz" ] } diff --git a/libpandafile/file.cpp b/libpandafile/file.cpp index 39773442b3faa6b2a0edf984885f9a2ebfdd289a..5bedc3cc04da6166ff43a02c592ff5447e99cf47 100644 --- a/libpandafile/file.cpp +++ b/libpandafile/file.cpp @@ -46,13 +46,10 @@ constexpr int EOK = 0; #endif // EOK // NOLINTNEXTLINE(readability-identifier-naming, modernize-avoid-c-arrays) -const char *ARCHIVE_FILENAME = "classes.aex"; +const char *ARCHIVE_FILENAME = "classes.abc"; // NOLINTNEXTLINE(readability-identifier-naming, modernize-avoid-c-arrays) const char *ARCHIVE_SPLIT = "!/"; -// NOLINTNEXTLINE(readability-identifier-naming, modernize-avoid-c-arrays) -const char *ARCHIVE_FILENAME_ABC = "classes.abc"; - const std::array File::MAGIC {'P', 'A', 'N', 'D', 'A', '\0', '\0', '\0'}; // Name anonymous maps for perfing tools finding symbol file correctly. @@ -108,38 +105,77 @@ std::unique_ptr OpenPandaFileOrZip(std::string_view location, panda_ return OpenPandaFile(location, archive_filename, open_mode); } -std::unique_ptr HandleArchive(FILE *fp, std::string_view location, - std::string_view archive_filename, - panda_file::File::OpenMode open_mode) +// NOLINTNEXTLINE(google-runtime-references) +void OpenPandaFileFromZipErrorHandler(ZipArchiveHandle &handle) { - EntryFileStat entry = EntryFileStat(); - std::string archive_fn = std::string(archive_filename); - if (!archive_fn.empty()) { - if (!GetArchiveFileEntry(fp, archive_fn.c_str(), &entry)) { - LOG(ERROR, PANDAFILE) << "Can't find entry with name '" << archive_fn << "'"; - return nullptr; - } - } else { - if (!GetArchiveFileEntry(fp, ARCHIVE_FILENAME, &entry)) { - if (!GetArchiveFileEntry(fp, ARCHIVE_FILENAME_ABC, &entry)) { - LOG(ERROR, PANDAFILE) << "Can't find entry with name '" << ARCHIVE_FILENAME << "' or '" - << ARCHIVE_FILENAME_ABC << "'"; - return nullptr; - } + if (handle != nullptr) { + if (panda::CloseArchiveFile(handle) != ZIPARCHIVE_OK) { + LOG(ERROR, PANDAFILE) << "CloseArchiveFile failed!"; } } +} + +std::unique_ptr OpenPandaFileFromZipFile(ZipArchiveHandle &handle, std::string_view location, + EntryFileStat &entry, std::string_view archive_name) +{ + uint32_t uncompressed_length = entry.GetUncompressedSize(); + if (uncompressed_length == 0) { + CloseCurrentFile(handle); + OpenPandaFileFromZipErrorHandler(handle); + LOG(ERROR, PANDAFILE) << "Panda file has zero length!"; + return nullptr; + } + size_t size_to_mmap = AlignUp(uncompressed_length, panda::os::mem::GetPageSize()); + void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false); + if (mem == nullptr) { + CloseCurrentFile(handle); + OpenPandaFileFromZipErrorHandler(handle); + LOG(ERROR, PANDAFILE) << "Can't mmap anonymous!"; + return nullptr; + } + os::mem::BytePtr ptr(reinterpret_cast(mem), size_to_mmap, os::mem::MmapDeleter); + std::stringstream ss; + ss << ANONMAPNAME_PERFIX << archive_name << " extracted in memory from " << location; + auto it = AnonMemSet::GetInstance().Insert(std::string(location), ss.str()); + auto ret = os::mem::TagAnonymousMemory(reinterpret_cast(ptr.Get()), size_to_mmap, it->second.c_str()); + if (ret.has_value()) { + CloseCurrentFile(handle); + OpenPandaFileFromZipErrorHandler(handle); + LOG(ERROR, PANDAFILE) << "Can't tag mmap anonymous!"; + return nullptr; + } + + auto extract_error = ExtractToMemory(handle, reinterpret_cast(ptr.Get()), size_to_mmap); + if (extract_error != 0) { + CloseCurrentFile(handle); + OpenPandaFileFromZipErrorHandler(handle); + LOG(ERROR, PANDAFILE) << "Can't extract!"; + return nullptr; + } + + os::mem::ConstBytePtr ConstPtr = ptr.ToConst(); + return panda_file::File::OpenFromMemory(std::move(ConstPtr), location); +} + +// NOLINTNEXTLINE(google-runtime-references) +std::unique_ptr HandleArchive(ZipArchiveHandle &handle, FILE *fp, std::string_view location, + EntryFileStat &entry, std::string_view archive_filename, + panda_file::File::OpenMode open_mode) +{ std::unique_ptr file; // compressed or not 4 aligned, use anonymous memory if (entry.IsCompressed() || (entry.GetOffset() & 0x3U) != 0) { - file = OpenPandaFileFromZipFILE(fp, location, archive_filename); + file = OpenPandaFileFromZipFile(handle, location, entry, archive_filename); } else { + LOG(INFO, PANDAFILE) << "Pandafile is uncompressed and 4 bytes aligned"; file = panda_file::File::OpenUncompressedArchive(fileno(fp), location, entry.GetUncompressedSize(), entry.GetOffset(), open_mode); } return file; } +// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE) std::unique_ptr OpenPandaFile(std::string_view location, std::string_view archive_filename, panda_file::File::OpenMode open_mode) { @@ -166,151 +202,58 @@ std::unique_ptr OpenPandaFile(std::string_view location, fseek(fp, 0, SEEK_SET); std::unique_ptr file; if (IsZipMagic(magic)) { - file = HandleArchive(fp, location, archive_filename, open_mode); - } else { - file = panda_file::File::Open(location, open_mode); - } - fclose(fp); - return file; -} - -// NOLINTNEXTLINE(google-runtime-references) -void OpenPandaFileFromZipErrorHandler(ZipArchiveHandle &handle, const char *message) -{ - if (handle != nullptr) { - if (!panda::CloseArchive(&handle)) { - LOG(ERROR, PANDAFILE) << "CloseArchive failed!"; + // Open Zipfile and do the extraction. + ZipArchiveHandle zipfile = nullptr; + auto open_error = OpenArchiveFile(zipfile, fp); + if (open_error != ZIPARCHIVE_OK) { + LOG(ERROR, PANDAFILE) << "Can't open archive " << location; + return nullptr; } - } - LOG(ERROR, PANDAFILE) << message; -} - -std::unique_ptr OpenPandaFileFromZip(std::string_view location) -{ - trace::ScopedTrace scoped_trace("Panda file open Zip " + std::string(location)); - panda::ZipArchive archive_holder; - panda::ZipArchiveHandle handle = &archive_holder; - auto open_error = panda::OpenArchive(std::string(location).c_str(), &handle); - if (open_error != 0) { - LOG(ERROR, PANDAFILE) << "Can't open archive\n"; - return nullptr; - } - - auto entry = std::make_unique(); - - const char *filename = ARCHIVE_FILENAME; - if (panda::FindEntry(&handle, entry.get(), filename) != 0) { - filename = ARCHIVE_FILENAME_ABC; - auto find_error = panda::FindEntry(&handle, entry.get(), filename); - if (find_error != 0) { - OpenPandaFileFromZipErrorHandler(handle, "Can't find entry!"); + bool try_default = archive_filename.empty(); + if (!try_default) { + if (LocateFile(zipfile, archive_filename.data()) != ZIPARCHIVE_OK) { + LOG(INFO, PANDAFILE) << "Can't find entry with name '" << archive_filename << "', will try " + << ARCHIVE_FILENAME; + try_default = true; + } + } + if (try_default) { + if (LocateFile(zipfile, ARCHIVE_FILENAME) != ZIPARCHIVE_OK) { + OpenPandaFileFromZipErrorHandler(zipfile); + LOG(ERROR, PANDAFILE) << "Can't find entry with " << ARCHIVE_FILENAME; + fclose(fp); + return nullptr; + } + } + EntryFileStat entry = EntryFileStat(); + if (GetCurrentFileInfo(zipfile, &entry) != ZIPARCHIVE_OK) { + OpenPandaFileFromZipErrorHandler(zipfile); + LOG(ERROR, PANDAFILE) << "GetCurrentFileInfo error"; return nullptr; } - } - uint32_t uncompressed_length = entry->GetUncompressedSize(); - if (entry->GetUncompressedSize() == 0) { - OpenPandaFileFromZipErrorHandler(handle, "Panda file has zero length!"); - return nullptr; - } - - size_t size_to_mmap = AlignUp(uncompressed_length, panda::os::mem::GetPageSize()); - // NB! This mem is mapped in OpenPandaFileFromZip, we want to use it otherwhere, better unposion it! - void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false); - if (mem == nullptr) { - OpenPandaFileFromZipErrorHandler(handle, "Can't mmap anonymous!"); - return nullptr; - } - - std::stringstream ss; - ss << ANONMAPNAME_PERFIX << ARCHIVE_FILENAME << " extracted in memory from " << location; - auto it = AnonMemSet::GetInstance().Insert(std::string(location), ss.str()); - auto ret = os::mem::TagAnonymousMemory(mem, size_to_mmap, it->second.c_str()); - if (ret.has_value()) { - return nullptr; - } - - auto extract_error = panda::ExtractToMemory(&handle, entry.get(), reinterpret_cast(mem), size_to_mmap); - if (extract_error != 0) { - os::mem::UnmapRaw(mem, size_to_mmap); - OpenPandaFileFromZipErrorHandler(handle, "Can't extract!"); - return nullptr; - } - - if (!panda::CloseArchive(&handle)) { - LOG(ERROR, PANDAFILE) << "CloseArchive failed!"; - return nullptr; - } - - os::mem::ConstBytePtr ptr(reinterpret_cast(mem), size_to_mmap, os::mem::MmapDeleter); - return panda_file::File::OpenFromMemory(std::move(ptr), location); -} - -std::unique_ptr OpenPandaFileFromZipFILE(FILE *inputfile, std::string_view location, - std::string_view archive_filename) -{ - panda::ZipArchive archive_holder; - panda::ZipArchiveHandle handle = &archive_holder; - auto open_error = panda::OpenArchiveFILE(inputfile, &handle); - if (open_error != 0) { - LOG(ERROR, PANDAFILE) << "Can't open archive\n"; - return nullptr; - } - - auto entry = std::make_unique(); - - std::string archive_fn = std::string(archive_filename); - const char *filename = archive_fn.empty() ? ARCHIVE_FILENAME : archive_fn.c_str(); - if (panda::FindEntry(&handle, entry.get(), filename) != 0) { - filename = ARCHIVE_FILENAME_ABC; - auto find_error = panda::FindEntry(&handle, entry.get(), filename); - if (find_error != 0) { - OpenPandaFileFromZipErrorHandler(handle, "Can't find entry!"); + if (OpenCurrentFile(zipfile) != ZIPARCHIVE_OK) { + CloseCurrentFile(zipfile); + OpenPandaFileFromZipErrorHandler(zipfile); + LOG(ERROR, PANDAFILE) << "Can't OpenCurrentFile!"; return nullptr; } + GetCurrentFileOffset(zipfile, &entry); + file = HandleArchive(zipfile, fp, location, entry, archive_filename, open_mode); + CloseCurrentFile(zipfile); + if (panda::CloseArchiveFile(zipfile) != 0) { + LOG(ERROR, PANDAFILE) << "CloseArchive failed!"; + return nullptr; + } + } else { + file = panda_file::File::Open(location, open_mode); } - uint32_t uncompressed_length = entry->GetUncompressedSize(); - if (entry->GetUncompressedSize() == 0) { - OpenPandaFileFromZipErrorHandler(handle, "Panda file has zero length!"); - return nullptr; - } - - size_t size_to_mmap = AlignUp(uncompressed_length, panda::os::mem::GetPageSize()); - // NB! This mem is mapped in OpenPandaFileFromZip, we want to use it otherwhere, better unposion it! - void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false); - if (mem == nullptr) { - OpenPandaFileFromZipErrorHandler(handle, "Can't mmap anonymous!"); - return nullptr; - } - - std::stringstream ss; - ss << ANONMAPNAME_PERFIX << ARCHIVE_FILENAME << " extracted in memory from " << location; - auto it = AnonMemSet::GetInstance().Insert(std::string(location), ss.str()); - auto ret = os::mem::TagAnonymousMemory(mem, size_to_mmap, it->second.c_str()); - if (ret.has_value()) { - OpenPandaFileFromZipErrorHandler(handle, "Can't tag mmap anonymous!"); - return nullptr; - } - - auto extract_error = panda::ExtractToMemory(&handle, entry.get(), reinterpret_cast(mem), size_to_mmap); - if (extract_error != 0) { - os::mem::UnmapRaw(mem, size_to_mmap); - OpenPandaFileFromZipErrorHandler(handle, "Can't extract!"); - return nullptr; - } - - if (!panda::CloseArchive(&handle)) { - LOG(ERROR, PANDAFILE) << "CloseArchive failed!"; - return nullptr; - } - - os::mem::ConstBytePtr ptr(reinterpret_cast(mem), size_to_mmap, os::mem::MmapDeleter); - return panda_file::File::OpenFromMemory(std::move(ptr), location); + fclose(fp); + return file; } std::unique_ptr OpenPandaFileFromMemory(const void *buffer, size_t size) { size_t size_to_mmap = AlignUp(size, panda::os::mem::GetPageSize()); - // NB! This mem is mapped in OpenPandaFileFromZip, we want to use it otherwhere, better unposion it! void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false); if (mem == nullptr) { return nullptr; diff --git a/libpandafile/file.h b/libpandafile/file.h index cfa15a734c6c43eb0d107f1263727fe356b8f12d..20fc48376163a011aadd458ccd0cb448af45886f 100644 --- a/libpandafile/file.h +++ b/libpandafile/file.h @@ -28,6 +28,10 @@ #include #include +namespace panda { +struct EntryFileStat; +} // namespace panda + namespace panda::panda_file { class PandaCache; @@ -350,24 +354,6 @@ std::unique_ptr OpenPandaFileFromMemory(const void *buffer, size_t s std::unique_ptr OpenPandaFile(std::string_view location, std::string_view archive_filename = "", panda_file::File::OpenMode open_mode = panda_file::File::READ_ONLY); -/* - * OpenPandaFileFromZip from location which specicify the name. - */ -std::unique_ptr OpenPandaFileFromZip(std::string_view location); - -/* - * Open Archive file. - */ -std::unique_ptr HandleArchive( - FILE *fp, std::string_view location, std::string_view archive_filename = "", - panda_file::File::OpenMode open_mode = panda_file::File::READ_ONLY); - -/* - * OpenPandaFileFromZip from FILE* inputfile - */ -std::unique_ptr OpenPandaFileFromZipFILE(FILE *inputfile, std::string_view location, - std::string_view archive_filename); - /* * Check ptr point valid panda file: magic */ @@ -375,10 +361,6 @@ bool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filen // NOLINTNEXTLINE(readability-identifier-naming) extern const char *ARCHIVE_FILENAME; - -// NOLINTNEXTLINE(readability-identifier-naming) -extern const char *ARCHIVE_FILENAME_ABC; - } // namespace panda::panda_file #endif // PANDA_LIBPANDAFILE_FILE_H_ diff --git a/libpandafile/file_writer.cpp b/libpandafile/file_writer.cpp index 3517459e16d01b0a65db65a05552100d0d9a31bc..363f54ae7be9469683ea9948c54db4f0d3a5959c 100644 --- a/libpandafile/file_writer.cpp +++ b/libpandafile/file_writer.cpp @@ -14,7 +14,7 @@ */ #include "file_writer.h" -#include "miniz.h" +#include "zlib.h" namespace panda::panda_file { diff --git a/libpandafile/tests/file_test.cpp b/libpandafile/tests/file_test.cpp index ad4a03783b0eb5c1458b74f27d2c01e9bf1ba30b..e7399a1c32de48401ae7dc94ea62f7cdfefe450f 100644 --- a/libpandafile/tests/file_test.cpp +++ b/libpandafile/tests/file_test.cpp @@ -63,14 +63,15 @@ static std::vector GetEmptyPandaFileBytes() return data; } -int CreateOrAddZipPandaFile(std::vector *data, const char *zip_archive_name, const char *filename) +int CreateOrAddZipPandaFile(std::vector *data, const char *zip_archive_name, const char *filename, int append, + int level) { - return CreateOrAddFileIntoZip(zip_archive_name, filename, (*data).data(), (*data).size()); + return CreateOrAddFileIntoZip(zip_archive_name, filename, (*data).data(), (*data).size(), append, level); } bool CheckAnonMemoryName([[maybe_unused]] const char *zip_archive_name) { - // check if [annon:panda-classes.aex extracted in memory from /xx/__OpenPandaFileFromZip__.zip] + // check if [annon:panda-classes.abc extracted in memory from /xx/__OpenPandaFileFromZip__.zip] #ifdef PANDA_TARGET_MOBILE bool result = false; const char *prefix = "[anon:panda-"; @@ -135,65 +136,82 @@ TEST(File, GetClassByName) } } -TEST(File, OpenPandaFileFromZip) +TEST(File, OpenPandaFile) { - { - // Create ZIP - auto data = GetEmptyPandaFileBytes(); - int ret; - const char *zip_filename = "__OpenPandaFileFromZip__.zip"; - const char *filename1 = ARCHIVE_FILENAME; - const char *filename2 = "classses2.aex"; // just for testing. - ret = CreateOrAddZipPandaFile(&data, zip_filename, filename1); - ASSERT_EQ(ret, 0); - ret = CreateOrAddZipPandaFile(&data, zip_filename, filename2); - ASSERT_EQ(ret, 0); - - // Open from ZIP - auto pf = OpenPandaFile(zip_filename); - EXPECT_NE(pf, nullptr); - EXPECT_STREQ((pf->GetFilename()).c_str(), zip_filename); - } + // Create ZIP + auto data = GetEmptyPandaFileBytes(); + int ret; + const char *zip_filename = "__OpenPandaFile__.zip"; + const char *filename1 = ARCHIVE_FILENAME; + const char *filename2 = "classses2.abc"; // just for testing. + ret = CreateOrAddZipPandaFile(&data, zip_filename, filename1, APPEND_STATUS_CREATE, Z_BEST_COMPRESSION); + ASSERT_EQ(ret, 0); + ret = CreateOrAddZipPandaFile(&data, zip_filename, filename2, APPEND_STATUS_ADDINZIP, Z_BEST_COMPRESSION); + ASSERT_EQ(ret, 0); + + // Open from ZIP + auto pf = OpenPandaFile(zip_filename); + EXPECT_NE(pf, nullptr); + EXPECT_STREQ((pf->GetFilename()).c_str(), zip_filename); + remove(zip_filename); } -TEST(File, OpenPandaFileABCFromZip) +TEST(File, OpenPandaFileFromZipNameAnonMem) { - { - // Create ZIP - auto data = GetEmptyPandaFileBytes(); - int ret; - const char *zip_filename = "__OpenPandaFileABCFromZip__.zip"; - const char *filename1 = ARCHIVE_FILENAME_ABC; - const char *filename2 = "classses2.aex"; // just for testing. - ret = CreateOrAddZipPandaFile(&data, zip_filename, filename1); - ASSERT_EQ(ret, 0); - ret = CreateOrAddZipPandaFile(&data, zip_filename, filename2); - ASSERT_EQ(ret, 0); - - // Open from ZIP - auto pf = OpenPandaFile(zip_filename); - EXPECT_NE(pf, nullptr); - EXPECT_STREQ((pf->GetFilename()).c_str(), zip_filename); - } + // Create ZIP + auto data = GetEmptyPandaFileBytes(); + int ret; + const char *zip_filename = "__OpenPandaFileFromZipNameAnonMem__.zip"; + const char *filename1 = ARCHIVE_FILENAME; + ret = CreateOrAddZipPandaFile(&data, zip_filename, filename1, APPEND_STATUS_CREATE, Z_BEST_COMPRESSION); + ASSERT_EQ(ret, 0); + + // Open from ZIP + auto pf = OpenPandaFile(zip_filename); + EXPECT_NE(pf, nullptr); + EXPECT_STREQ((pf->GetFilename()).c_str(), zip_filename); + ASSERT_TRUE(CheckAnonMemoryName(zip_filename)); + remove(zip_filename); } -TEST(File, OpenPandaFileFromZipNameAnonMem) +TEST(File, OpenPandaFileOrZip) { - { - // Create ZIP - auto data = GetEmptyPandaFileBytes(); - int ret; - const char *zip_filename = "__OpenPandaFileFromZip__.zip"; - const char *filename1 = ARCHIVE_FILENAME; - ret = CreateOrAddZipPandaFile(&data, zip_filename, filename1); - ASSERT_EQ(ret, 0); - - // Open from ZIP - auto pf = OpenPandaFile(zip_filename); - EXPECT_NE(pf, nullptr); - EXPECT_STREQ((pf->GetFilename()).c_str(), zip_filename); - ASSERT_TRUE(CheckAnonMemoryName(zip_filename)); - } + // Create ZIP + auto data = GetEmptyPandaFileBytes(); + int ret; + const char *zip_filename = "__OpenPandaFileOrZip__.zip"; + const char *filename1 = ARCHIVE_FILENAME; + const char *filename2 = "classes2.abc"; // just for testing. + ret = CreateOrAddZipPandaFile(&data, zip_filename, filename1, APPEND_STATUS_CREATE, Z_BEST_COMPRESSION); + ASSERT_EQ(ret, 0); + ret = CreateOrAddZipPandaFile(&data, zip_filename, filename2, APPEND_STATUS_ADDINZIP, Z_BEST_COMPRESSION); + ASSERT_EQ(ret, 0); + + // Open from ZIP + auto pf = OpenPandaFileOrZip(zip_filename); + EXPECT_NE(pf, nullptr); + EXPECT_STREQ((pf->GetFilename()).c_str(), zip_filename); + remove(zip_filename); } +TEST(File, OpenPandaFileUncompressed) +{ + // Create ZIP + auto data = GetEmptyPandaFileBytes(); + std::cout << "pandafile size = " << data.size() << std::endl; + int ret; + const char *zip_filename = "__OpenPandaFileUncompressed__.zip"; + const char *filename1 = ARCHIVE_FILENAME; + const char *filename2 = "class.abc"; // just for testing. + ret = CreateOrAddZipPandaFile(&data, zip_filename, filename2, APPEND_STATUS_CREATE, Z_NO_COMPRESSION); + ASSERT_EQ(ret, 0); + ret = CreateOrAddZipPandaFile(&data, zip_filename, filename1, APPEND_STATUS_ADDINZIP, Z_NO_COMPRESSION); + ASSERT_EQ(ret, 0); + + // Open from ZIP + auto pf = OpenPandaFileOrZip(zip_filename); + EXPECT_NE(pf, nullptr); + EXPECT_STREQ((pf->GetFilename()).c_str(), zip_filename); + remove(zip_filename); +} } // namespace panda::panda_file::test diff --git a/libziparchive/BUILD.gn b/libziparchive/BUILD.gn index b5108d0062cb233758ba3ae2aa961e8f7168a987..7b050e19ef62ae3ebdc3029c5957f2b6dd73ed8a 100644 --- a/libziparchive/BUILD.gn +++ b/libziparchive/BUILD.gn @@ -21,7 +21,10 @@ config("arkziparchive_config") { ] if (!ark_standalone_build) { - include_dirs += [ "//third_party/miniz/amalgamation" ] + include_dirs += [ + "//third_party/zlib", + "//third_party/zlib/contrib/minizip", + ] } else { include_dirs += [ "$ark_third_party_root/miniz" ] } @@ -42,7 +45,7 @@ ohos_shared_library("libarkziparchive") { ] if (!ark_standalone_build) { - deps += [ "//third_party/miniz/amalgamation:libminiz" ] + deps += [ "//third_party/zlib:libz" ] } else { deps += [ "$ark_third_party_root/miniz:libminiz" ] } @@ -68,7 +71,7 @@ ohos_static_library("libarkziparchive_frontend_static") { ] if (!ark_standalone_build) { - deps += [ "//third_party/miniz/amalgamation:libminiz" ] + deps += [ "//third_party/zlib:libz" ] } else { deps += [ "$ark_third_party_root/miniz:libminiz" ] } diff --git a/libziparchive/tests/libziparchive_tests.cpp b/libziparchive/tests/libziparchive_tests.cpp index 547cfe4466c768040cd1d6356ec3fb1d876be7b3..e419e9f55640ed46d920258db97304852ebc80c3 100644 --- a/libziparchive/tests/libziparchive_tests.cpp +++ b/libziparchive/tests/libziparchive_tests.cpp @@ -1,4 +1,4 @@ -/* +/** * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,693 +29,498 @@ #include #include +#include +#include +#include +#include +#include + namespace panda::test { -using std::unique_ptr; +constexpr int ZIP_FILENAME_LEN = 64; +constexpr int ZIP_BUFFER_LEN = 2048; -TEST(LIBZIPARCHIVE, ZipTest) +static void GenerateZipfile(const char *data, const char *archivename, int N, char *buf, char *archive_filename, int &i, + int &ret, std::vector &pf_data, int level = Z_BEST_COMPRESSION) { - using uint16 = unsigned short; - - // The string to compress. - static const char *s_pTest_str = - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras feugiat et odio ac sollicitudin. Maecenas " - "lobortis ultrices eros sed pharetra. Phasellus in tortor rhoncus, aliquam augue ac, gravida elit. Sed " - "molestie dolor a vulputate tincidunt. Proin a tellus quam. Suspendisse id feugiat elit, non ornare lacus. " - "Mauris arcu ex, pretium quis dolor ut, porta iaculis eros. Vestibulum sagittis placerat diam, vitae efficitur " - "turpis ultrices sit amet. Etiam elementum bibendum congue. In sit amet dolor ultricies, suscipit arcu ac, " - "molestie urna. Mauris ultrices volutpat massa quis ultrices. Suspendisse rutrum lectus sit amet metus " - "laoreet, non porta sapien venenatis. Fusce ut massa et purus elementum lacinia. Sed tempus bibendum pretium."; - - // The comment - static const char *s_pComment = "This is a comment"; - - // The zip filename - static const char *s_Test_archive_filename = "__LIBZIPARCHIVE__ZipTest__.zip"; - - int i, ret; - const int N = 3; - char data[2048]; - char archive_filename[64]; - assert((strlen(s_pTest_str) + 64) < sizeof(data)); - - ZipArchive object; // on stack, but this is tmp obj as we will CloseArchive this. - ZipArchiveHandle zip_archive_handler = &object; - // Delete the test archive, so it doesn't keep growing as we run this test - remove(s_Test_archive_filename); + (void)remove(archivename); + + // Create and append a directory entry for testing + ret = CreateOrAddFileIntoZip(archivename, "directory/", NULL, 0, APPEND_STATUS_CREATE, level); + if (ret != 0) { + printf("CreateOrAddFileIntoZip for directory failed!\n"); + ASSERT_EQ(1, 0); + return; + } - // ************* Create Zip file ************* // Append a bunch of text files to the test archive for (i = (N - 1); i >= 0; --i) { - (void)sprintf_s(archive_filename, 64, "%u.txt", i); - (void)sprintf_s(data, 2048, "%u %s %u", (N - 1) - i, s_pTest_str, i); - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, archive_filename, data, strlen(data) + 1, s_pComment, - static_cast(strlen(s_pComment))); + (void)sprintf_s(archive_filename, ZIP_FILENAME_LEN, "%d.txt", i); + (void)sprintf_s(buf, ZIP_BUFFER_LEN, "%d %s %d", (N - 1) - i, data, i); + ret = CreateOrAddFileIntoZip(archivename, archive_filename, buf, strlen(buf) + 1, + APPEND_STATUS_ADDINZIP, level); if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); + printf("CreateOrAddFileIntoZip for %d.txt failed!\n", i); ASSERT_EQ(1, 0); return; } } - // Add a directory entry for testing - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "directory/", NULL, 0, "no comment", - static_cast(strlen("no comment"))); + // Append a file into directory entry for testing + (void)sprintf_s(buf, ZIP_BUFFER_LEN, "%d %s %d", N, data, N); + ret = CreateOrAddFileIntoZip(archivename, "directory/indirectory.txt", buf, strlen(buf) + 1, + APPEND_STATUS_ADDINZIP, level); if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); + printf("CreateOrAddFileIntoZip for directory/indirectory.txt failed!\n"); ASSERT_EQ(1, 0); return; } - // Add a file into directory entry for testing - (void)sprintf_s(data, 2048, "%u %s %u", N, s_pTest_str, N); - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "directory/indirectory.txt", data, strlen(data) + 1, - s_pComment, static_cast(strlen(s_pComment))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); - ASSERT_EQ(1, 0); - return; - } - - // Now try to open the archive. - ret = OpenArchive(s_Test_archive_filename, &zip_archive_handler); + // Add a pandafile into zip for testing + ret = CreateOrAddFileIntoZip(archivename, "classes.abc", pf_data.data(), pf_data.size(), + APPEND_STATUS_ADDINZIP, level); if (ret != 0) { - printf("OpenArchive failed!\n"); + printf("CreateOrAddFileIntoZip for classes.abc failed!\n"); ASSERT_EQ(1, 0); return; } - - // Get and print information about each file in the archive. - for (i = 0; i < GetFileCount(&zip_archive_handler); i++) { - EntryFileStat file_stat; - if (!StatFileWithIndex(&zip_archive_handler, &file_stat, i)) { - printf("StatFileWithIndex() failed!\n"); - CloseArchive(&zip_archive_handler); - ASSERT_EQ(1, 0); - return; - } - - printf("Filename: \"%s\", Comment: \"%s\", Uncompressed size: %u, Compressed size: %u, Is Dir: %u\n", - file_stat.GetFileName(), file_stat.GetComment(), file_stat.GetUncompressedSize(), - static_cast(file_stat.GetCompressedSize()), IsFileDirectory(&zip_archive_handler, i)); - - if (!strcmp(file_stat.GetFileName(), "directory/")) { - if (!IsFileDirectory(&zip_archive_handler, i)) { - printf("IsFileDirectory() didn't return the expected results!\n"); - CloseArchive(&zip_archive_handler); - ASSERT_EQ(1, 0); - return; - } - } - } - - // Close the archive, freeing any resources it was using - CloseArchive(&zip_archive_handler); } -TEST(LIBZIPARCHIVE, UnzipWithHeapTest) +static void UnzipFileCheckDirectory(const char *archivename, char *filename, int level = Z_BEST_COMPRESSION) { - using uint16 = unsigned short; - using uint = unsigned int; - - // The string to compress. - static const char *s_pTest_str = - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras feugiat et odio ac sollicitudin. Maecenas " - "lobortis ultrices eros sed pharetra. Phasellus in tortor rhoncus, aliquam augue ac, gravida elit. Sed " - "molestie dolor a vulputate tincidunt. Proin a tellus quam. Suspendisse id feugiat elit, non ornare lacus. " - "Mauris arcu ex, pretium quis dolor ut, porta iaculis eros. Vestibulum sagittis placerat diam, vitae efficitur " - "turpis ultrices sit amet. Etiam elementum bibendum congue. In sit amet dolor ultricies, suscipit arcu ac, " - "molestie urna. Mauris ultrices volutpat massa quis ultrices. Suspendisse rutrum lectus sit amet metus " - "laoreet, non porta sapien venenatis. Fusce ut massa et purus elementum lacinia. Sed tempus bibendum pretium."; - - // The comment - static const char *s_pComment = "This is a comment"; - - // The zip filename - static const char *s_Test_archive_filename = "__LIBZIPARCHIVE__UnzipWithHeapTest__.zip"; - - int i, ret; - const int N = 3; - char data[2048]; - char archive_filename[64]; - assert((strlen(s_pTest_str) + 64) < sizeof(data)); + (void)sprintf_s(filename, ZIP_FILENAME_LEN, "directory/"); - ZipArchive object; // on stack, but this is tmp obj as we will CloseArchive this. - ZipArchiveHandle zip_archive_handler = &object; + ZipArchiveHandle zipfile = nullptr; + FILE *myfile = fopen(archivename, "rbe"); - // Delete the test archive, so it doesn't keep growing as we run this test - remove(s_Test_archive_filename); - - // ************* Create Zip file ************* - // Append a bunch of text files to the test archive - for (i = (N - 1); i >= 0; --i) { - (void)sprintf_s(archive_filename, 64, "%u.txt", i); - (void)sprintf_s(data, 2048, "%u %s %u", (N - 1) - i, s_pTest_str, i); - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, archive_filename, data, strlen(data) + 1, s_pComment, - static_cast(strlen(s_pComment))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); - ASSERT_EQ(1, 0); - return; - } + if (OpenArchiveFile(zipfile, myfile) != 0) { + (void)fclose(myfile); + printf("OpenArchiveFILE error.\n"); + ASSERT_EQ(1, 0); + return; } - - // Add a directory entry for testing - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "directory/", NULL, 0, "no comment", - static_cast(strlen("no comment"))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); + if (LocateFile(zipfile, filename) != 0) { + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("LocateFile error.\n"); ASSERT_EQ(1, 0); return; } - - // Add a file into directory entry for testing - (void)sprintf_s(data, 2048, "%u %s %u", N, s_pTest_str, N); - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "directory/indirectory.txt", data, strlen(data) + 1, - s_pComment, static_cast(strlen(s_pComment))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); + EntryFileStat entry = EntryFileStat(); + if (GetCurrentFileInfo(zipfile, &entry) != 0) { + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("GetCurrentFileInfo test error.\n"); ASSERT_EQ(1, 0); return; } - - // Now try to open the archive. - ret = OpenArchive(s_Test_archive_filename, &zip_archive_handler); - if (ret != 0) { - printf("OpenArchive failed!\n"); + if (OpenCurrentFile(zipfile) != 0) { + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("OpenCurrentFile test error.\n"); ASSERT_EQ(1, 0); return; } - // Get and print information about each file in the archive. - for (i = 0; i < GetFileCount(&zip_archive_handler); i++) { - EntryFileStat file_stat; - if (!StatFileWithIndex(&zip_archive_handler, &file_stat, i)) { - printf("StatFileWithIndex() failed!\n"); - CloseArchive(&zip_archive_handler); - ASSERT_EQ(1, 0); - return; - } + GetCurrentFileOffset(zipfile, &entry); - printf("Filename: \"%s\", Comment: \"%s\", Uncompressed size: %u, Compressed size: %u, Is Dir: %u\n", - file_stat.GetFileName(), file_stat.GetComment(), file_stat.GetUncompressedSize(), - static_cast(file_stat.GetCompressedSize()), IsFileDirectory(&zip_archive_handler, i)); + uint32_t uncompressed_length = entry.GetUncompressedSize(); - if (!strcmp(file_stat.GetFileName(), "directory/")) { - if (!IsFileDirectory(&zip_archive_handler, i)) { - printf("IsFileDirectory() didn't return the expected results!\n"); - CloseArchive(&zip_archive_handler); - ASSERT_EQ(1, 0); - return; - } - } + ASSERT_GT(entry.GetOffset(), 0); + if (level == Z_NO_COMPRESSION) { + ASSERT_EQ(entry.IsCompressed(), false); + } else { + ASSERT_EQ(entry.IsCompressed(), true); } - // Close the archive, freeing any resources it was using - CloseArchive(&zip_archive_handler); + printf("Filename: \"%s\", Uncompressed size: %u, Compressed size: %u, , Compressed(): %d, entry offset: %u\n", + filename, static_cast(uncompressed_length), (uint)entry.GetCompressedSize(), entry.IsCompressed(), + (uint)entry.GetOffset()); - // ************* Unzip ************* - // Now verify the compressed data - ret = OpenArchive(s_Test_archive_filename, &zip_archive_handler); - if (ret != 0) { - printf("OpenArchive failed!\n"); - ASSERT_EQ(ret, 0); - return; - } + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); +} + +static void UnzipFileCheckTxt(const char *archivename, char *filename, const char *data, int N, char *buf, int &ret, + int level = Z_BEST_COMPRESSION) +{ + for (int i = 0; i < N; i++) { + (void)sprintf_s(filename, ZIP_FILENAME_LEN, "%d.txt", i); + (void)sprintf_s(buf, ZIP_BUFFER_LEN, "%d %s %d", (N - 1) - i, data, i); - void *p; - size_t uncomp_size; - for (i = 0; i < N; i++) { - (void)sprintf_s(archive_filename, 64, "%u.txt", i); - (void)sprintf_s(data, 2048, "%u %s %u", (N - 1) - i, s_pTest_str, i); - - // Try to extract all the files to the heap. - p = ExtractToHeap(&zip_archive_handler, archive_filename, &uncomp_size); - if (!p) { - printf("ExtractToHeap() failed!\n"); - CloseArchive(&zip_archive_handler); + ZipArchiveHandle zipfile = nullptr; + FILE *myfile = fopen(archivename, "rbe"); + + if (OpenArchiveFile(zipfile, myfile) != 0) { + (void)fclose(myfile); + printf("OpenArchiveFILE error.\n"); ASSERT_EQ(1, 0); return; } - - // Make sure the extraction really succeeded. - size_t dlen = strlen(data); - if ((uncomp_size != (dlen + 1)) || (memcmp(p, data, dlen))) { - printf("ExtractToHeap() failed to extract the proper data\n"); - FreeHeap(p); - CloseArchive(&zip_archive_handler); + if (LocateFile(zipfile, filename) != 0) { + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("LocateFile error.\n"); + ASSERT_EQ(1, 0); + return; + } + EntryFileStat entry = EntryFileStat(); + if (GetCurrentFileInfo(zipfile, &entry) != 0) { + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("GetCurrentFileInfo test error.\n"); + ASSERT_EQ(1, 0); + return; + } + if (OpenCurrentFile(zipfile) != 0) { + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("OpenCurrentFile test error.\n"); ASSERT_EQ(1, 0); return; } - printf("Successfully extracted file \"%s\", size %u\n", archive_filename, static_cast(uncomp_size)); + GetCurrentFileOffset(zipfile, &entry); - // We're done. - FreeHeap(p); - } + uint32_t uncompressed_length = entry.GetUncompressedSize(); + if (uncompressed_length == 0) { + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("Entry file has zero length! Readed bad data!\n"); + ASSERT_EQ(1, 0); + return; + } + ASSERT_GT(entry.GetOffset(), 0); + ASSERT_EQ(uncompressed_length, strlen(buf) + 1); + if (level == Z_NO_COMPRESSION) { + ASSERT_EQ(uncompressed_length, entry.GetCompressedSize()); + ASSERT_EQ(entry.IsCompressed(), false); + } else { + ASSERT_GE(uncompressed_length, entry.GetCompressedSize()); + ASSERT_EQ(entry.IsCompressed(), true); + } - (void)sprintf_s(archive_filename, 64, "directory/indirectory.txt"); - (void)sprintf_s(data, 2048, "%u %s %u", N, s_pTest_str, N); + printf("Filename: \"%s\", Uncompressed size: %u, Compressed size: %u, , Compressed(): %d, entry offset: %u\n", + filename, static_cast(uncompressed_length), (uint)entry.GetCompressedSize(), entry.IsCompressed(), + (uint)entry.GetOffset()); + + { + // Extract to mem buffer accroding to entry info. + uint32_t page_size = os::mem::GetPageSize(); + uint32_t min_pages = uncompressed_length / page_size; + uint32_t size_to_mmap = + uncompressed_length % page_size == 0 ? min_pages * page_size : (min_pages + 1) * page_size; + // we will use mem in memcmp, so donnot poision it! + void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false); + if (mem == nullptr) { + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("Can't mmap anonymous!\n"); + ASSERT_EQ(1, 0); + return; + } - // Try to extract all the files to the heap. - p = ExtractToHeap(&zip_archive_handler, archive_filename, &uncomp_size); - if (!p) { - printf("ExtractToHeap() failed!\n"); - CloseArchive(&zip_archive_handler); - ASSERT_EQ(1, 0); - return; - } + ret = ExtractToMemory(zipfile, reinterpret_cast(mem), size_to_mmap); + if (ret != 0) { + os::mem::UnmapRaw(mem, size_to_mmap); + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("Can't extract!\n"); + ASSERT_EQ(1, 0); + return; + } - // Make sure the extraction really succeeded. - size_t dlen = strlen(data); - if ((uncomp_size != (dlen + 1)) || (memcmp(p, data, dlen))) { - printf("ExtractToHeap() failed to extract the proper data\n"); - FreeHeap(p); - CloseArchive(&zip_archive_handler); - ASSERT_EQ(1, 0); - return; - } + // Make sure the extraction really succeeded. + size_t dlen = strlen(buf); + if (uncompressed_length != (dlen + 1)) { + os::mem::UnmapRaw(mem, size_to_mmap); + CloseCurrentFile(zipfile); + CloseArchive(zipfile); + printf("ExtractToMemory() failed!, uncompressed_length is %u, original strlen is %u\n", + static_cast(uncompressed_length) - 1, static_cast(dlen)); + ASSERT_EQ(1, 0); + return; + } - printf("Successfully extracted file \"%s\", size %u\n", archive_filename, static_cast(uncomp_size)); + if (memcmp(mem, buf, dlen)) { + os::mem::UnmapRaw(mem, size_to_mmap); + CloseCurrentFile(zipfile); + CloseArchive(zipfile); + printf("ExtractToMemory() memcmp failed!"); + ASSERT_EQ(1, 0); + return; + } - // We're done. - FreeHeap(p); + printf("Successfully extracted file \"%s\" from \"%s\", size %u\n", filename, archivename, + static_cast(uncompressed_length)); - CloseArchive(&zip_archive_handler); + os::mem::UnmapRaw(mem, size_to_mmap); + } - printf("Success.\n"); + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + } } -TEST(LIBZIPARCHIVE, UnzipWithMemBufferTest) +static void UnzipFileCheckPandaFile(const char *archivename, char *filename, std::vector &pf_data, int &ret, + int level = Z_BEST_COMPRESSION) { - using uint16 = unsigned short; - using uint = unsigned int; - - // The string to compress. - static const char *s_pTest_str = - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras feugiat et odio ac sollicitudin. Maecenas " - "lobortis ultrices eros sed pharetra. Phasellus in tortor rhoncus, aliquam augue ac, gravida elit. Sed " - "molestie dolor a vulputate tincidunt. Proin a tellus quam. Suspendisse id feugiat elit, non ornare lacus. " - "Mauris arcu ex, pretium quis dolor ut, porta iaculis eros. Vestibulum sagittis placerat diam, vitae efficitur " - "turpis ultrices sit amet. Etiam elementum bibendum congue. In sit amet dolor ultricies, suscipit arcu ac, " - "molestie urna. Mauris ultrices volutpat massa quis ultrices. Suspendisse rutrum lectus sit amet metus " - "laoreet, non porta sapien venenatis. Fusce ut massa et purus elementum lacinia. Sed tempus bibendum pretium."; - - // The comment - static const char *s_pComment = "This is a comment"; - - // The zip filename - static const char *s_Test_archive_filename = "__LIBZIPARCHIVE__UnzipWithMemBufferTest__.zip"; - - int i, ret; - const int N = 3; - char data[2048]; - char archive_filename[64]; - assert((strlen(s_pTest_str) + 64) < sizeof(data)); - - ZipArchive object; // on stack, but this is tmp obj as we will CloseArchive this. - ZipArchiveHandle zip_archive_handler = &object; - - // Delete the test archive, so it doesn't keep growing as we run this test - remove(s_Test_archive_filename); + { + ZipArchiveHandle zipfile = nullptr; + FILE *myfile = fopen(archivename, "rbe"); - // ************* Create Zip file ************* - // Append a bunch of text files to the test archive - for (i = (N - 1); i >= 0; --i) { - (void)sprintf_s(archive_filename, 64, "%u.txt", i); - (void)sprintf_s(data, 2048, "%u %s %u", (N - 1) - i, s_pTest_str, i); - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, archive_filename, data, strlen(data) + 1, s_pComment, - static_cast(strlen(s_pComment))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); + if (OpenArchiveFile(zipfile, myfile) != 0) { + (void)fclose(myfile); + printf("OpenArchiveFILE error.\n"); ASSERT_EQ(1, 0); return; } - } - - // Add a directory entry for testing - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "directory/", NULL, 0, "no comment", - static_cast(strlen("no comment"))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); - ASSERT_EQ(1, 0); - return; - } - - // Add a file into directory entry for testing - (void)sprintf_s(data, 2048, "%u %s %u", N, s_pTest_str, N); - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "directory/indirectory.txt", data, strlen(data) + 1, - s_pComment, static_cast(strlen(s_pComment))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); - ASSERT_EQ(1, 0); - return; - } - - // Now try to open the archive. - ret = OpenArchive(s_Test_archive_filename, &zip_archive_handler); - if (ret != 0) { - printf("OpenArchive failed!\n"); - ASSERT_EQ(1, 0); - return; - } - - // Get and print information about each file in the archive. - for (i = 0; i < GetFileCount(&zip_archive_handler); i++) { - EntryFileStat file_stat; - if (!StatFileWithIndex(&zip_archive_handler, &file_stat, i)) { - printf("StatFileWithIndex() failed!\n"); - CloseArchive(&zip_archive_handler); + if (LocateFile(zipfile, filename) != 0) { + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("LocateFile error.\n"); + ASSERT_EQ(1, 0); + return; + } + EntryFileStat entry = EntryFileStat(); + if (GetCurrentFileInfo(zipfile, &entry) != 0) { + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("GetCurrentFileInfo test error.\n"); + ASSERT_EQ(1, 0); + return; + } + if (OpenCurrentFile(zipfile) != 0) { + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("OpenCurrentFile test error.\n"); ASSERT_EQ(1, 0); return; } - printf("Filename: \"%s\", Comment: \"%s\", Uncompressed size: %u, Compressed size: %u, Is Dir: %u\n", - file_stat.GetFileName(), file_stat.GetComment(), file_stat.GetUncompressedSize(), - static_cast(file_stat.GetCompressedSize()), IsFileDirectory(&zip_archive_handler, i)); + GetCurrentFileOffset(zipfile, &entry); - if (!strcmp(file_stat.GetFileName(), "directory/")) { - if (!IsFileDirectory(&zip_archive_handler, i)) { - printf("IsFileDirectory() didn't return the expected results!\n"); - CloseArchive(&zip_archive_handler); + uint32_t uncompressed_length = entry.GetUncompressedSize(); + if (uncompressed_length == 0) { + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("Entry file has zero length! Readed bad data!\n"); + ASSERT_EQ(1, 0); + return; + } + ASSERT_GT(entry.GetOffset(), 0); + ASSERT_EQ(uncompressed_length, pf_data.size()); + if (level == Z_NO_COMPRESSION) { + ASSERT_EQ(uncompressed_length, entry.GetCompressedSize()); + ASSERT_EQ(entry.IsCompressed(), false); + } else { + ASSERT_GE(uncompressed_length, entry.GetCompressedSize()); + ASSERT_EQ(entry.IsCompressed(), true); + } + printf("Filename: \"%s\", Uncompressed size: %u, Compressed size: %u, , Compressed(): %d, entry offset: %u\n", + filename, static_cast(uncompressed_length), (uint)entry.GetCompressedSize(), entry.IsCompressed(), + (uint)entry.GetOffset()); + + { + // Extract to mem buffer accroding to entry info. + uint32_t page_size = os::mem::GetPageSize(); + uint32_t min_pages = uncompressed_length / page_size; + uint32_t size_to_mmap = + uncompressed_length % page_size == 0 ? min_pages * page_size : (min_pages + 1) * page_size; + // we will use mem in memcmp, so donnot poision it! + void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false); + if (mem == nullptr) { + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("Can't mmap anonymous!\n"); ASSERT_EQ(1, 0); return; } - } - } - - // Close the archive, freeing any resources it was using - CloseArchive(&zip_archive_handler); - - // ************* Unzip ************* - ret = OpenArchive(s_Test_archive_filename, &zip_archive_handler); - if (ret != 0) { - printf("Can't open archive\n"); - ASSERT_EQ(ret, 0); - return; - } - i = 1; - (void)sprintf_s(data, 2048, "%u %s %u", (N - 1) - i, s_pTest_str, i); + ret = ExtractToMemory(zipfile, reinterpret_cast(mem), size_to_mmap); + if (ret != 0) { + os::mem::UnmapRaw(mem, size_to_mmap); + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("Can't extract!\n"); + ASSERT_EQ(1, 0); + return; + } - // Find entry info. - const char *myname = "1.txt"; - const char *mycomment = "This is a comment"; + // Make sure the extraction really succeeded. + if (uncompressed_length != pf_data.size()) { + os::mem::UnmapRaw(mem, size_to_mmap); + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("ExtractToMemory() failed!, uncompressed_length is %u, original pf_data size is %u\n", + static_cast(uncompressed_length) - 1, (uint)pf_data.size()); + ASSERT_EQ(1, 0); + return; + } - EntryFileStat *entry = new EntryFileStat; - ret = FindEntry(&zip_archive_handler, entry, myname, mycomment); - if (ret != 0) { - CloseArchive(&zip_archive_handler); - delete entry; - printf("FindEntry() can't find entry: %s!\n", myname); - ASSERT_EQ(1, 0); - return; - } - uint32_t uncompressed_length = entry->GetUncompressedSize(); - if (entry->GetUncompressedSize() == 0) { - panda::CloseArchive(&zip_archive_handler); - delete entry; - printf("Entry file has zero length! Readed bad data!\n"); - ASSERT_EQ(1, 0); - return; - } + if (memcmp(mem, pf_data.data(), pf_data.size())) { + os::mem::UnmapRaw(mem, size_to_mmap); + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("ExtractToMemory() memcmp failed!"); + ASSERT_EQ(1, 0); + return; + } - printf("Filename: \"%s\", Comment: \"%s\", Uncompressed size: %u, Compressed size: %u, Is Dir: %u\n", - entry->GetFileName(), entry->GetComment(), uncompressed_length, - static_cast(entry->GetCompressedSize()), - IsFileDirectory(&zip_archive_handler, static_cast(entry->GetIndex()))); - - // Extract to mem buffer accroding to entry info. - uint32_t page_size = os::mem::GetPageSize(); - uint32_t min_pages = uncompressed_length / page_size; - uint32_t size_to_mmap = uncompressed_length % page_size == 0 ? min_pages * page_size : (min_pages + 1) * page_size; - // we will use mem in memcmp, so donnot poision it! - void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false); - if (mem == nullptr) { - CloseArchive(&zip_archive_handler); - delete entry; - printf("Can't mmap anonymous!\n"); - ASSERT_EQ(1, 0); - return; - } - ret = ExtractToMemory(&zip_archive_handler, entry, reinterpret_cast(mem), size_to_mmap); - if (ret != 0) { - os::mem::UnmapRaw(mem, size_to_mmap); - panda::CloseArchive(&zip_archive_handler); - delete entry; - printf("Can't extract!\n"); - ASSERT_EQ(1, 0); - return; - } + printf("Successfully extracted file \"%s\" from \"%s\", size %u\n", filename, archivename, + static_cast(uncompressed_length)); - // Make sure the extraction really succeeded. - size_t dlen = strlen(data); - if ((uncompressed_length != (dlen + 1)) || (memcmp(mem, data, dlen))) { - os::mem::UnmapRaw(mem, size_to_mmap); - CloseArchive(&zip_archive_handler); - delete entry; - printf("ExtractToMemory() failed to extract the proper data\n"); - ASSERT_EQ(1, 0); - return; + os::mem::UnmapRaw(mem, size_to_mmap); + } + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); } - - printf("Successfully extracted file \"%s\", size %u\n", myname, static_cast(uncompressed_length)); - - // CloseArchive and release resource. - os::mem::UnmapRaw(mem, size_to_mmap); - panda::CloseArchive(&zip_archive_handler); - delete entry; - - printf("Success.\n"); } -TEST(LIBZIPARCHIVE, UnzipForPandafileTest) +static void UnzipFileCheckInDirectory(const char *archivename, char *filename, const char *data, int N, char *buf, + int &ret, int level = Z_BEST_COMPRESSION) { - using uint16 = unsigned short; - using uint = unsigned int; - - // The string to compress. - static const char *s_pTest_str = - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras feugiat et odio ac sollicitudin. Maecenas " - "lobortis ultrices eros sed pharetra. Phasellus in tortor rhoncus, aliquam augue ac, gravida elit. Sed " - "molestie dolor a vulputate tincidunt. Proin a tellus quam. Suspendisse id feugiat elit, non ornare lacus. " - "Mauris arcu ex, pretium quis dolor ut, porta iaculis eros. Vestibulum sagittis placerat diam, vitae efficitur " - "turpis ultrices sit amet. Etiam elementum bibendum congue. In sit amet dolor ultricies, suscipit arcu ac, " - "molestie urna. Mauris ultrices volutpat massa quis ultrices. Suspendisse rutrum lectus sit amet metus " - "laoreet, non porta sapien venenatis. Fusce ut massa et purus elementum lacinia. Sed tempus bibendum pretium."; - - // The comment - static const char *s_pComment = "This is a comment"; - - /* - * creating an empty pandafile - */ - pandasm::Parser p; - - auto source = R"()"; - - std::string src_filename = "src.pa"; - auto res = p.Parse(source, src_filename); - ASSERT_EQ(p.ShowError().err, pandasm::Error::ErrorType::ERR_NONE); - - auto pf = pandasm::AsmEmitter::Emit(res.Value()); - ASSERT_NE(pf, nullptr); - - std::vector pf_data {}; - const auto header_ptr = reinterpret_cast(pf->GetHeader()); - pf_data.assign(header_ptr, header_ptr + sizeof(panda_file::File::Header)); - - // The zip filename - static const char *s_Test_archive_filename = "__LIBZIPARCHIVE__UnzipForPandafileTest__.zip"; - - int i, ret; - const int N = 3; - char data[2048]; - char archive_filename[64]; - assert((strlen(s_pTest_str) + 64) < sizeof(data)); + { + (void)sprintf_s(filename, ZIP_FILENAME_LEN, "directory/indirectory.txt"); + (void)sprintf_s(buf, ZIP_BUFFER_LEN, "%d %s %d", N, data, N); - ZipArchive object; // on stack, but this is tmp obj as we will CloseArchive this. - ZipArchiveHandle zip_archive_handler = &object; + // Unzip Check + ZipArchiveHandle zipfile = nullptr; + FILE *myfile = fopen(archivename, "rbe"); - // Delete the test archive, so it doesn't keep growing as we run this test - remove(s_Test_archive_filename); - - // ************* Create Zip file ************* - // Append a bunch of text files to the test archive - for (i = (N - 1); i >= 0; --i) { - (void)sprintf_s(archive_filename, 64, "%u.txt", i); - (void)sprintf_s(data, 2048, "%u %s %u", (N - 1) - i, s_pTest_str, i); - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, archive_filename, data, strlen(data) + 1, s_pComment, - static_cast(strlen(s_pComment))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); + if (OpenArchiveFile(zipfile, myfile) != 0) { + (void)fclose(myfile); + printf("OpenArchiveFILE error.\n"); ASSERT_EQ(1, 0); return; } - } - - // Add a directory entry for testing - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "directory/", NULL, 0, "no comment", - static_cast(strlen("no comment"))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); - ASSERT_EQ(1, 0); - return; - } - - // Add a file into directory entry for testing - (void)sprintf_s(data, 2048, "%u %s %u", N, s_pTest_str, N); - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "directory/indirectory.txt", data, strlen(data) + 1, - s_pComment, static_cast(strlen(s_pComment))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); - ASSERT_EQ(1, 0); - return; - } - - // Add a pandafile into zip for testing - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "classes.aex", pf_data.data(), pf_data.size(), s_pComment, - static_cast(strlen(s_pComment))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); - ASSERT_EQ(1, 0); - return; - } - - // Now try to open the archive. - ret = OpenArchive(s_Test_archive_filename, &zip_archive_handler); - if (ret != 0) { - printf("OpenArchive failed!\n"); - ASSERT_EQ(1, 0); - return; - } - - // Get and print information about each file in the archive. - for (i = 0; i < GetFileCount(&zip_archive_handler); i++) { - EntryFileStat file_stat; - if (!StatFileWithIndex(&zip_archive_handler, &file_stat, i)) { - printf("StatFileWithIndex() failed!\n"); - CloseArchive(&zip_archive_handler); + if (LocateFile(zipfile, filename) != 0) { + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("LocateFile error.\n"); + ASSERT_EQ(1, 0); + return; + } + EntryFileStat entry = EntryFileStat(); + if (GetCurrentFileInfo(zipfile, &entry) != 0) { + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("GetCurrentFileInfo test error.\n"); + ASSERT_EQ(1, 0); + return; + } + if (OpenCurrentFile(zipfile) != 0) { + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("OpenCurrentFile test error.\n"); ASSERT_EQ(1, 0); return; } - printf("Filename: \"%s\", Comment: \"%s\", Uncompressed size: %u, Compressed size: %u, Is Dir: %u\n", - file_stat.GetFileName(), file_stat.GetComment(), file_stat.GetUncompressedSize(), - static_cast(file_stat.GetCompressedSize()), IsFileDirectory(&zip_archive_handler, i)); + GetCurrentFileOffset(zipfile, &entry); - if (!strcmp(file_stat.GetFileName(), "directory/")) { - if (!IsFileDirectory(&zip_archive_handler, i)) { - printf("IsFileDirectory() didn't return the expected results!\n"); - CloseArchive(&zip_archive_handler); + uint32_t uncompressed_length = entry.GetUncompressedSize(); + if (uncompressed_length == 0) { + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("Entry file has zero length! Readed bad data!\n"); + ASSERT_EQ(1, 0); + return; + } + ASSERT_GT(entry.GetOffset(), 0); + ASSERT_EQ(uncompressed_length, strlen(buf) + 1); + if (level == Z_NO_COMPRESSION) { + ASSERT_EQ(uncompressed_length, entry.GetCompressedSize()); + ASSERT_EQ(entry.IsCompressed(), false); + } else { + ASSERT_GE(uncompressed_length, entry.GetCompressedSize()); + ASSERT_EQ(entry.IsCompressed(), true); + } + printf("Filename: \"%s\", Uncompressed size: %u, Compressed size: %u, , Compressed(): %d, entry offset: %u\n", + filename, static_cast(uncompressed_length), (uint)entry.GetCompressedSize(), entry.IsCompressed(), + (uint)entry.GetOffset()); + + { + // Extract to mem buffer accroding to entry info. + uint32_t page_size = os::mem::GetPageSize(); + uint32_t min_pages = uncompressed_length / page_size; + uint32_t size_to_mmap = + uncompressed_length % page_size == 0 ? min_pages * page_size : (min_pages + 1) * page_size; + // we will use mem in memcmp, so donnot poision it! + void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false); + if (mem == nullptr) { + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("Can't mmap anonymous!\n"); ASSERT_EQ(1, 0); return; } - } - } - - // Close the archive, freeing any resources it was using - CloseArchive(&zip_archive_handler); - // ************* Unzip ************* - ret = OpenArchive(s_Test_archive_filename, &zip_archive_handler); - if (ret != 0) { - printf("Can't open archive\n"); - ASSERT_EQ(ret, 0); - return; - } - - // Find entry info. - const char *myname = "classes.aex"; - const char *mycomment = "This is a comment"; - - EntryFileStat *entry = new EntryFileStat; - ret = FindEntry(&zip_archive_handler, entry, myname, mycomment); - if (ret != 0) { - CloseArchive(&zip_archive_handler); - delete entry; - printf("FindEntry() can't find entry: %s!\n", myname); - ASSERT_EQ(1, 0); - return; - } - uint32_t uncompressed_length = entry->GetUncompressedSize(); - if (entry->GetUncompressedSize() == 0) { - panda::CloseArchive(&zip_archive_handler); - delete entry; - printf("Entry file has zero length! Readed bad data!\n"); - ASSERT_EQ(1, 0); - return; - } + ret = ExtractToMemory(zipfile, reinterpret_cast(mem), size_to_mmap); + if (ret != 0) { + os::mem::UnmapRaw(mem, size_to_mmap); + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + printf("Can't extract!\n"); + ASSERT_EQ(1, 0); + return; + } - printf("Filename: \"%s\", Comment: \"%s\", Uncompressed size: %u, Compressed size: %u, Is Dir: %u\n", - entry->GetFileName(), entry->GetComment(), uncompressed_length, - static_cast(entry->GetCompressedSize()), - IsFileDirectory(&zip_archive_handler, static_cast(entry->GetIndex()))); - - // Extract to mem buffer accroding to entry info. - uint32_t page_size = os::mem::GetPageSize(); - uint32_t min_pages = uncompressed_length / page_size; - uint32_t size_to_mmap = uncompressed_length % page_size == 0 ? min_pages * page_size : (min_pages + 1) * page_size; - // we will using mem in memcmp, so donnot poision it! - void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false); - if (mem == nullptr) { - CloseArchive(&zip_archive_handler); - delete entry; - printf("Can't mmap anonymous!\n"); - ASSERT_EQ(1, 0); - return; - } - ret = ExtractToMemory(&zip_archive_handler, entry, reinterpret_cast(mem), size_to_mmap); - if (ret != 0) { - os::mem::UnmapRaw(mem, size_to_mmap); - panda::CloseArchive(&zip_archive_handler); - delete entry; - printf("Can't extract!\n"); - ASSERT_EQ(1, 0); - return; - } + // Make sure the extraction really succeeded. + size_t dlen = strlen(buf); + if (uncompressed_length != (dlen + 1)) { + os::mem::UnmapRaw(mem, size_to_mmap); + CloseCurrentFile(zipfile); + CloseArchive(zipfile); + printf("ExtractToMemory() failed!, uncompressed_length is %u, original strlen is %u\n", + static_cast(uncompressed_length) - 1, static_cast(dlen)); + ASSERT_EQ(1, 0); + return; + } - // Make sure the extraction really succeeded. - if ((uncompressed_length != pf_data.size()) || (memcmp(mem, pf_data.data(), pf_data.size()))) { - os::mem::UnmapRaw(mem, size_to_mmap); - CloseArchive(&zip_archive_handler); - delete entry; - printf("ExtractToMemory() failed to extract the proper data\n"); - ASSERT_EQ(1, 0); - return; - } + if (memcmp(mem, buf, dlen)) { + os::mem::UnmapRaw(mem, size_to_mmap); + CloseCurrentFile(zipfile); + CloseArchive(zipfile); + printf("ExtractToMemory() memcmp failed!"); + ASSERT_EQ(1, 0); + return; + } - printf("Successfully extracted file \"%s\", size %u\n", myname, static_cast(uncompressed_length)); + printf("Successfully extracted file \"%s\" from \"%s\", size %u\n", filename, archivename, + static_cast(uncompressed_length)); - // Testing with OpenFromMemory ... - { - os::mem::ConstBytePtr ptr(reinterpret_cast(mem), size_to_mmap, os::mem::MmapDeleter); - auto ofm_pf = panda_file::File::OpenFromMemory(std::move(ptr), myname); - if (ofm_pf == nullptr) { - panda::CloseArchive(&zip_archive_handler); - delete entry; - printf("OpenFromMemory() failed!\n"); - ASSERT_EQ(1, 0); - return; + os::mem::UnmapRaw(mem, size_to_mmap); } - EXPECT_STREQ((ofm_pf->GetFilename()).c_str(), myname); - } - // CloseArchive and release resource. - panda::CloseArchive(&zip_archive_handler); - delete entry; - - printf("Success.\n"); + CloseCurrentFile(zipfile); + CloseArchiveFile(zipfile); + (void)fclose(myfile); + } } -TEST(LIBZIPARCHIVE, OpenArchiveFILE) +TEST(LIBZIPARCHIVE, ZipFile) { - using uint16 = unsigned short; - using uint = unsigned int; - - // The string to compress. - static const char *s_pTest_str = + static const char *data = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras feugiat et odio ac sollicitudin. Maecenas " "lobortis ultrices eros sed pharetra. Phasellus in tortor rhoncus, aliquam augue ac, gravida elit. Sed " "molestie dolor a vulputate tincidunt. Proin a tellus quam. Suspendisse id feugiat elit, non ornare lacus. " @@ -724,231 +529,77 @@ TEST(LIBZIPARCHIVE, OpenArchiveFILE) "molestie urna. Mauris ultrices volutpat massa quis ultrices. Suspendisse rutrum lectus sit amet metus " "laoreet, non porta sapien venenatis. Fusce ut massa et purus elementum lacinia. Sed tempus bibendum pretium."; - // The comment - static const char *s_pComment = "This is a comment"; - /* * creating an empty pandafile */ - pandasm::Parser p; - - auto source = R"()"; - - std::string src_filename = "src.pa"; - auto res = p.Parse(source, src_filename); - ASSERT_EQ(p.ShowError().err, pandasm::Error::ErrorType::ERR_NONE); - - auto pf = pandasm::AsmEmitter::Emit(res.Value()); - ASSERT_NE(pf, nullptr); - std::vector pf_data {}; - const auto header_ptr = reinterpret_cast(pf->GetHeader()); - pf_data.assign(header_ptr, header_ptr + sizeof(panda_file::File::Header)); - - // The zip filename - static const char *s_Test_archive_filename = "__LIBZIPARCHIVE__OpenArchiveFILE__.zip"; + { + pandasm::Parser p; - int i, ret; - const int N = 3; - char data[2048]; - char archive_filename[64]; - assert((strlen(s_pTest_str) + 64) < sizeof(data)); + auto source = R"()"; - ZipArchive object; // on stack, but this is tmp obj as we will CloseArchive this. - ZipArchiveHandle zip_archive_handler = &object; + std::string src_filename = "src.pa"; + auto res = p.Parse(source, src_filename); + ASSERT_EQ(p.ShowError().err, pandasm::Error::ErrorType::ERR_NONE); - // Delete the test archive, so it doesn't keep growing as we run this test - remove(s_Test_archive_filename); + auto pf = pandasm::AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); - // ************* Create Zip file ************* - // Append a bunch of text files to the test archive - for (i = (N - 1); i >= 0; --i) { - (void)sprintf_s(archive_filename, 64, "%u.txt", i); - (void)sprintf_s(data, 2048, "%u %s %u", (N - 1) - i, s_pTest_str, i); - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, archive_filename, data, strlen(data) + 1, s_pComment, - static_cast(strlen(s_pComment))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); - ASSERT_EQ(1, 0); - return; - } + const auto header_ptr = reinterpret_cast(pf->GetHeader()); + pf_data.assign(header_ptr, header_ptr + sizeof(panda_file::File::Header)); } - // Add a directory entry for testing - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "directory/", NULL, 0, "no comment", - static_cast(strlen("no comment"))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); - ASSERT_EQ(1, 0); - return; - } + static const char *archivename = "__LIBZIPARCHIVE__ZipFile__.zip"; + const int N = 3; + char buf[ZIP_BUFFER_LEN]; + char archive_filename[ZIP_FILENAME_LEN]; + int i = 0; + int ret = 0; - // Add a file into directory entry for testing - (void)sprintf_s(data, 2048, "%u %s %u", N, s_pTest_str, N); - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "directory/indirectory.txt", data, strlen(data) + 1, - s_pComment, static_cast(strlen(s_pComment))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); - ASSERT_EQ(1, 0); - return; - } + GenerateZipfile(data, archivename, N, buf, archive_filename, i, ret, pf_data); - // Add a pandafile into zip for testing - ret = CreateOrAddFileIntoZip(s_Test_archive_filename, "classes.aex", pf_data.data(), pf_data.size(), s_pComment, - static_cast(strlen(s_pComment))); - if (ret != 0) { - printf("CreateOrAddFileIntoZip failed!\n"); + // Quick Check + ZipArchiveHandle zipfile = nullptr; + if (OpenArchive(zipfile, archivename) != 0) { + printf("OpenArchive error.\n"); ASSERT_EQ(1, 0); return; } - // Now try to open the archive. - ret = OpenArchive(s_Test_archive_filename, &zip_archive_handler); - if (ret != 0) { - printf("OpenArchive failed!\n"); + GlobalStat gi = GlobalStat(); + if (GetGlobalFileInfo(zipfile, &gi) != 0) { + printf("GetGlobalFileInfo error.\n"); ASSERT_EQ(1, 0); return; } - - // Get and print information about each file in the archive. - for (i = 0; i < GetFileCount(&zip_archive_handler); i++) { + for (i = 0; i < (int)gi.GetNumberOfEntry(); ++i) { EntryFileStat file_stat; - if (!StatFileWithIndex(&zip_archive_handler, &file_stat, i)) { - printf("StatFileWithIndex() failed!\n"); - CloseArchive(&zip_archive_handler); + if (GetCurrentFileInfo(zipfile, &file_stat) != 0) { + CloseArchive(zipfile); + printf("GetCurrentFileInfo error. Current index i = %d \n", i); ASSERT_EQ(1, 0); return; } - - printf("Filename: \"%s\", Comment: \"%s\", Uncompressed size: %u, Compressed size: %u, Is Dir: %u\n", - file_stat.GetFileName(), file_stat.GetComment(), file_stat.GetUncompressedSize(), - static_cast(file_stat.GetCompressedSize()), IsFileDirectory(&zip_archive_handler, i)); - - if (!strcmp(file_stat.GetFileName(), "directory/")) { - if (!IsFileDirectory(&zip_archive_handler, i)) { - printf("IsFileDirectory() didn't return the expected results!\n"); - CloseArchive(&zip_archive_handler); + printf("Index: \"%u\", Uncompressed size: %u, Compressed size: %u, Compressed(): %d\n", i, + (uint)file_stat.GetUncompressedSize(), file_stat.GetCompressedSize(), file_stat.IsCompressed()); + if ((i + 1) < (int)gi.GetNumberOfEntry()) { + if (GoToNextFile(zipfile) != 0) { + CloseArchive(zipfile); + printf("GoToNextFile error. Current index i = %d \n", i); ASSERT_EQ(1, 0); return; } } } - // Close the archive, freeing any resources it was using - CloseArchive(&zip_archive_handler); - - // ************* Unzip ************* - FILE *myfile = fopen(s_Test_archive_filename, "rbe"); - ret = OpenArchiveFILE(myfile, &zip_archive_handler); - if (ret != 0) { - CloseArchive(&zip_archive_handler); - printf("Can't open archive\n"); - ASSERT_EQ(ret, 0); - return; - } - - // Find entry info. - const char *myname = "classes.aex"; - const char *mycomment = "This is a comment"; - - EntryFileStat *entry = new EntryFileStat; - ret = FindEntry(&zip_archive_handler, entry, myname, mycomment); - if (ret != 0) { - CloseArchive(&zip_archive_handler); - delete entry; - printf("FindEntry() can't find entry: %s!\n", myname); - ASSERT_EQ(1, 0); - return; - } - uint32_t uncompressed_length = entry->GetUncompressedSize(); - if (entry->GetUncompressedSize() == 0) { - panda::CloseArchive(&zip_archive_handler); - delete entry; - printf("Entry file has zero length! Readed bad data!\n"); - ASSERT_EQ(1, 0); - return; - } - - printf( - "Filename: \"%s\", Comment: \"%s\", Uncompressed size: %u, Compressed size: %u, Compressed(): %d, " - "Is Dir: %u, m_method %d \n", - entry->GetFileName(), entry->GetComment(), uncompressed_length, static_cast(entry->GetCompressedSize()), - entry->IsCompressed(), IsFileDirectory(&zip_archive_handler, static_cast(entry->GetIndex())), - entry->file_stat.m_method); - - if (entry->IsCompressed() == 0) { - panda::CloseArchive(&zip_archive_handler); - delete entry; - printf("%s Compressed Entry file %s entry->IsCompressed() == 0!\n", s_Test_archive_filename, myname); - ASSERT_EQ(1, 0); - return; - } - - // Extract to mem buffer accroding to entry info. - uint32_t page_size = os::mem::GetPageSize(); - uint32_t min_pages = uncompressed_length / page_size; - uint32_t size_to_mmap = uncompressed_length % page_size == 0 ? min_pages * page_size : (min_pages + 1) * page_size; - // We will use mem in memcmp, so don not poision it. - void *mem = os::mem::MapRWAnonymousRaw(size_to_mmap, false); - if (mem == nullptr) { - CloseArchive(&zip_archive_handler); - delete entry; - printf("Can't mmap anonymous!\n"); - ASSERT_EQ(1, 0); - return; - } - ret = ExtractToMemory(&zip_archive_handler, entry, reinterpret_cast(mem), size_to_mmap); - if (ret != 0) { - os::mem::UnmapRaw(mem, size_to_mmap); - panda::CloseArchive(&zip_archive_handler); - delete entry; - printf("Can't extract!\n"); - ASSERT_EQ(1, 0); - return; - } - - // Make sure the extraction really succeeded. - if ((uncompressed_length != pf_data.size()) || (memcmp(mem, pf_data.data(), pf_data.size()))) { - os::mem::UnmapRaw(mem, size_to_mmap); - CloseArchive(&zip_archive_handler); - delete entry; - printf("ExtractToMemory() failed to extract the proper data\n"); - ASSERT_EQ(1, 0); - return; - } - - printf("Successfully extracted file \"%s\", size %u\n", myname, static_cast(uncompressed_length)); - - // Testing with OpenFromMemory ... - { - os::mem::ConstBytePtr ptr(reinterpret_cast(mem), size_to_mmap, os::mem::MmapDeleter); - auto ofm_pf = panda_file::File::OpenFromMemory(std::move(ptr), myname); - if (ofm_pf == nullptr) { - fclose(myfile); - panda::CloseArchive(&zip_archive_handler); - delete entry; - printf("OpenFromMemory() failed!\n"); - ASSERT_EQ(1, 0); - return; - } - EXPECT_STREQ((ofm_pf->GetFilename()).c_str(), myname); - } - - // CloseArchive and release resource. - fclose(myfile); - panda::CloseArchive(&zip_archive_handler); - delete entry; - + CloseArchive(zipfile); + (void)remove(archivename); printf("Success.\n"); } -TEST(LIBZIPARCHIVE, OpenUncompressedArchiveFILE) +TEST(LIBZIPARCHIVE, UnZipFile) { - using uint16 = unsigned short; - using uint = unsigned int; - - // The string to compress. - static const char *s_pTest_str = + static const char *data = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras feugiat et odio ac sollicitudin. Maecenas " "lobortis ultrices eros sed pharetra. Phasellus in tortor rhoncus, aliquam augue ac, gravida elit. Sed " "molestie dolor a vulputate tincidunt. Proin a tellus quam. Suspendisse id feugiat elit, non ornare lacus. " @@ -957,154 +608,47 @@ TEST(LIBZIPARCHIVE, OpenUncompressedArchiveFILE) "molestie urna. Mauris ultrices volutpat massa quis ultrices. Suspendisse rutrum lectus sit amet metus " "laoreet, non porta sapien venenatis. Fusce ut massa et purus elementum lacinia. Sed tempus bibendum pretium."; - // The comment - static const char *s_pComment = "This is a comment"; - /* * creating an empty pandafile */ - pandasm::Parser p; - - auto source = R"()"; - - std::string src_filename = "src.pa"; - auto res = p.Parse(source, src_filename); - ASSERT_EQ(p.ShowError().err, pandasm::Error::ErrorType::ERR_NONE); - - auto pf = pandasm::AsmEmitter::Emit(res.Value()); - ASSERT_NE(pf, nullptr); - std::vector pf_data {}; - const auto header_ptr = reinterpret_cast(pf->GetHeader()); - pf_data.assign(header_ptr, header_ptr + sizeof(panda_file::File::Header)); - - // The zip filename - static const char *s_Test_archive_filename = "__LIBZIPARCHIVE__OpenUncompressedArchiveFILE__.zip"; - - int i, ret; - const int N = 3; - char data[2048]; - char archive_filename[64]; - assert((strlen(s_pTest_str) + 64) < sizeof(data)); - - ZipArchive object; // on stack, but this is tmp obj as we will CloseArchive this. - ZipArchiveHandle zip_archive_handler = &object; - - // Delete the test archive, so it doesn't keep growing as we run this test - remove(s_Test_archive_filename); - - // ************* Create Zip file ************* - // Append a bunch of text files to the test archive - for (i = (N - 1); i >= 0; --i) { - (void)sprintf_s(archive_filename, 64, "%u.txt", i); - (void)sprintf_s(data, 2048, "%u %s %u", (N - 1) - i, s_pTest_str, i); - ret = CreateOrAddUncompressedFileIntoZip(s_Test_archive_filename, archive_filename, data, strlen(data) + 1, - s_pComment, static_cast(strlen(s_pComment))); - ASSERT_EQ(ret, 0) << "CreateOrAddUncompressedFileIntoZip failed!"; - } - - // Add a directory entry for testing - ret = CreateOrAddUncompressedFileIntoZip(s_Test_archive_filename, "directory/", NULL, 0, "no comment", - static_cast(strlen("no comment"))); - ASSERT_EQ(ret, 0) << "CreateOrAddUncompressedFileIntoZip failed!"; + { + pandasm::Parser p; - // Add a file into directory entry for testing - (void)sprintf_s(data, 2048, "%u %s %u", N, s_pTest_str, N); - ret = CreateOrAddUncompressedFileIntoZip(s_Test_archive_filename, "directory/indirectory.txt", data, - strlen(data) + 1, s_pComment, static_cast(strlen(s_pComment))); - ASSERT_EQ(ret, 0) << "CreateOrAddUncompressedFileIntoZip failed!"; + auto source = R"()"; - // Add a pandafile into zip for testing - ret = CreateOrAddUncompressedFileIntoZip(s_Test_archive_filename, "classes.aex", pf_data.data(), pf_data.size(), - s_pComment, static_cast(strlen(s_pComment))); - ASSERT_EQ(ret, 0) << "CreateOrAddUncompressedFileIntoZip failed!"; + std::string src_filename = "src.pa"; + auto res = p.Parse(source, src_filename); + ASSERT_EQ(p.ShowError().err, pandasm::Error::ErrorType::ERR_NONE); - // Now try to open the archive. - ret = OpenArchive(s_Test_archive_filename, &zip_archive_handler); - ASSERT_EQ(ret, 0) << "OpenArchive failed!\n"; + auto pf = pandasm::AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); - // Get and print information about each file in the archive. - for (i = 0; i < GetFileCount(&zip_archive_handler); i++) { - EntryFileStat file_stat; - if (!StatFileWithIndex(&zip_archive_handler, &file_stat, i)) { - printf("StatFileWithIndex() failed!\n"); - CloseArchive(&zip_archive_handler); - ASSERT_EQ(1, 0); - return; - } - - printf( - "Filename: \"%s\", Comment: \"%s\", Uncompressed size: %u, Compressed size: %u, Is Dir: %u, Offset: %u\n", - file_stat.GetFileName(), file_stat.GetComment(), file_stat.GetUncompressedSize(), - static_cast(file_stat.GetCompressedSize()), IsFileDirectory(&zip_archive_handler, i), - file_stat.offset); - - if (!strcmp(file_stat.GetFileName(), "directory/")) { - if (!IsFileDirectory(&zip_archive_handler, i)) { - printf("IsFileDirectory() didn't return the expected results!\n"); - CloseArchive(&zip_archive_handler); - ASSERT_EQ(1, 0); - return; - } - } + const auto header_ptr = reinterpret_cast(pf->GetHeader()); + pf_data.assign(header_ptr, header_ptr + sizeof(panda_file::File::Header)); } - // Close the archive, freeing any resources it was using - CloseArchive(&zip_archive_handler); - - // ************* Unzip ************* - FILE *tmpfile = fopen(s_Test_archive_filename, "rbe"); - ret = OpenArchiveFILE(tmpfile, &zip_archive_handler); - ASSERT_EQ(ret, 0) << "Can't open archive\n"; - - // Find entry info. - const char *myname = "classes.aex"; - const char *mycomment = "This is a comment"; - - unique_ptr fileentry = std::make_unique(); - EntryFileStat *entry = fileentry.get(); - unique_ptr myfile(tmpfile, [](FILE *file) { fclose(file); }); - unique_ptr zfile(&zip_archive_handler, CloseArchive); - ret = FindEntry(&zip_archive_handler, entry, myname, mycomment); - - ASSERT_EQ(ret, 0) << "FindEntry() can't find entry: " << myname << "!" << std::endl; - - std::cout << "Filename: \"" << entry->GetFileName() << "\", Comment: \"" << entry->GetComment() - << "\", Uncompressed size: " << entry->GetUncompressedSize() - << ", Compressed size: " << entry->GetCompressedSize() << ", IsCompressed(): " << entry->IsCompressed() - << ", Is Dir: " << IsFileDirectory(&zip_archive_handler, static_cast(entry->GetIndex())) - << ", archive offset: " << entry->GetOffset() << std::endl; - - ASSERT_NE(entry->GetUncompressedSize(), 0); - - ASSERT_EQ(entry->GetUncompressedSize(), entry->GetCompressedSize()) - << "Uncompressed archive:" << myname << "GetUncompressedSize():" << entry->GetUncompressedSize() - << " GetCompressedSize():" << entry->GetCompressedSize() << std::endl; - ASSERT_NE(entry->GetOffset(), 0) << "Uncompressed archive:" << myname << " entry->GetOffset()=0" << std::endl; - - ASSERT_NE(entry->IsCompressed(), 1) << s_Test_archive_filename << " Compressed Entry file " << myname - << " entry->IsCompressed() == 0!" << std::endl; + // The zip filename + static const char *archivename = "__LIBZIPARCHIVE__UnZipFile__.zip"; + const int N = 3; + char buf[ZIP_BUFFER_LEN]; + char archive_filename[ZIP_FILENAME_LEN]; + char filename[ZIP_FILENAME_LEN]; + int i = 0; + int ret = 0; - zfile.reset(); - CloseArchive(&zip_archive_handler); + GenerateZipfile(data, archivename, N, buf, archive_filename, i, ret, pf_data); - std::string_view filename(s_Test_archive_filename); + UnzipFileCheckDirectory(archivename, filename); - std::cout << "HandleArchivee filename: " << filename.data() << std::endl; - std::unique_ptr file = panda_file::HandleArchive(tmpfile, filename); - ASSERT_NE(file, nullptr) << "Fail to map " << s_Test_archive_filename << " archive " << entry->GetFileName() - << " GetOffset()=" << entry->GetOffset() << std::endl; + UnzipFileCheckTxt(archivename, filename, data, N, buf, ret); - ASSERT_EQ(pf_data.size(), entry->GetUncompressedSize()) - << "pf_data.size()=" << pf_data.size() << " GetUncompressedSize=" << entry->GetUncompressedSize() << std::endl; + UnzipFileCheckInDirectory(archivename, filename, data, N, buf, ret); - for (uint32_t j = 0; j < entry->GetUncompressedSize(); j++) { - ASSERT_EQ(pf_data[j], *(file->GetBase() + j)) - << "Fail to map " << s_Test_archive_filename << " archive " << entry->GetFileName() << ", pf[" << j - << "]=" << pf_data[j] << ", file[" << j << "]=" << *(file->GetBase() + j) << std::endl; - } + (void)sprintf_s(filename, ZIP_FILENAME_LEN, "classes.abc"); + UnzipFileCheckPandaFile(archivename, filename, pf_data, ret); + (void)remove(archivename); printf("Success.\n"); } - } // namespace panda::test diff --git a/libziparchive/zip_archive.cpp b/libziparchive/zip_archive.cpp index 8d36072810b529a7a6f12e83cbd5f0341768609f..becbc503092fd8b76e4d44200b06fdbe192ae9ed 100644 --- a/libziparchive/zip_archive.cpp +++ b/libziparchive/zip_archive.cpp @@ -18,11 +18,6 @@ #include "utils/logger.h" #include -#include -#include -#include -#include -#include namespace panda { @@ -34,200 +29,159 @@ bool IsZipMagic(uint32_t magic) return (('P' == ((magic >> 0U) & ZIP_MAGIC_MASK)) && ('K' == ((magic >> ZIP_MAGIC_OFFSET) & ZIP_MAGIC_MASK))); } -int32_t OpenArchive(const char *zip_filename, ZipArchiveHandle *handle) +int OpenArchive(ZipArchiveHandle &handle, const char *path) { - if (handle == nullptr || memset_s(*handle, sizeof(ZipArchive), 0, sizeof(ZipArchive)) != EOK) { - LOG(ERROR, ZIPARCHIVE) << "ZipArchiveHandle handle should not be nullptr"; - return -1; - } - - if (mz_zip_reader_init_file(*handle, zip_filename, 0) == 0) { - LOG(ERROR, ZIPARCHIVE) << "mz_zip_reader_init_file() failed!"; - return -1; - } - - return 0; -} - -int32_t OpenArchiveFILE(FILE *fp, ZipArchiveHandle *handle) -{ - if (handle == nullptr || memset_s(*handle, sizeof(ZipArchive), 0, sizeof(ZipArchive)) != EOK) { - LOG(ERROR, ZIPARCHIVE) << "ZipArchiveHandle handle should not be nullptr"; - return -1; - } - - auto file = std::make_unique(fileno(fp)); - if (file == nullptr) { - LOG(ERROR, ZIPARCHIVE) << "Failed to get get file\n"; - return -1; - } - - auto res = file->GetFileSize(); - if (!res) { - LOG(ERROR, ZIPARCHIVE) << "Failed to get size of panda file\n"; - return -1; - } - - size_t file_size = res.Value(); - if (mz_zip_reader_init_cfile(*handle, fp, file_size, 0) == 0) { - LOG(ERROR, ZIPARCHIVE) << "mz_zip_reader_init_cfile() failed!\n"; - return -1; + handle = unzOpen(path); + if (handle == nullptr) { + LOG(ERROR, ZIPARCHIVE) << "OpenArchive failed, filename is " << path; + return ZIPARCHIVE_ERR; } - - return 0; + return ZIPARCHIVE_OK; } -bool CloseArchive(ZipArchiveHandle *handle) +int OpenArchiveFile(ZipArchiveHandle &handle, FILE *fp) { + handle = unzOpenFile(fp); if (handle == nullptr) { - LOG(ERROR, ZIPARCHIVE) << "ZipArchiveHandle handle should not be nullptr"; - return false; + LOG(ERROR, ZIPARCHIVE) << "OpenArchive failed from FILE *fp"; + return ZIPARCHIVE_ERR; } - return mz_zip_reader_end(*handle) != 0; + return ZIPARCHIVE_OK; } -int32_t FindEntry(ZipArchiveHandle *handle, EntryFileStat *entry, const char *entryname, const char *pcomment) +int CloseArchive(ZipArchiveHandle &handle) { if (handle == nullptr) { LOG(ERROR, ZIPARCHIVE) << "ZipArchiveHandle handle should not be nullptr"; - return -1; + return ZIPARCHIVE_ERR; } - int32_t index = LocateFileIndex(handle, entryname, pcomment); - if (index == -1) { - LOG(INFO, ZIPARCHIVE) << "LocateFileIndex() failed!"; - return -1; - } - - if (!StatFileWithIndex(handle, entry, static_cast(index))) { - LOG(INFO, ZIPARCHIVE) << "StatFileWithIndex() failed!"; - return -1; + int err = unzClose(handle); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << "unzClose with error: " << err; + return ZIPARCHIVE_ERR; } - - return 0; + return ZIPARCHIVE_OK; } -int32_t GetFileCount(ZipArchiveHandle *handle) +int CloseArchiveFile(ZipArchiveHandle &handle) { if (handle == nullptr) { LOG(ERROR, ZIPARCHIVE) << "ZipArchiveHandle handle should not be nullptr"; - return -1; + return ZIPARCHIVE_ERR; + } + int err = unzCloseFile(handle); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << "unzCloseFile with error: " << err; + return ZIPARCHIVE_ERR; } - return static_cast(mz_zip_reader_get_num_files(*handle)); + return ZIPARCHIVE_OK; } -int32_t LocateFileIndex(ZipArchiveHandle *handle, const char *filename, const char *comment) +int GetGlobalFileInfo(ZipArchiveHandle &handle, GlobalStat *gstat) { - if (handle == nullptr) { - LOG(ERROR, ZIPARCHIVE) << "ZipArchiveHandle handle should not be nullptr"; - return -1; + int err = unzGetGlobalInfo(handle, &gstat->ginfo); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << "GetGlobalFileInfo with error: " << err; + return ZIPARCHIVE_ERR; } - return static_cast(mz_zip_reader_locate_file(*handle, filename, comment, MZ_ZIP_FLAG_CASE_SENSITIVE)); + return ZIPARCHIVE_OK; } -bool StatFileWithIndex(ZipArchiveHandle *handle, EntryFileStat *entry, unsigned int index) +int GoToNextFile(ZipArchiveHandle &handle) { - if (handle == nullptr) { - LOG(ERROR, ZIPARCHIVE) << "ZipArchiveHandle handle should not be nullptr"; - return false; - } - if (mz_zip_reader_file_stat(*handle, index, &(entry->file_stat)) == 0) { - LOG(ERROR, ZIPARCHIVE) << "mz_zip_reader_file_stat() failed!"; - return false; + int err = unzGoToNextFile(handle); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << "GoToNextFile with error: " << err; + return ZIPARCHIVE_ERR; } - - if (mz_zip_reader_file_ofs(*handle, &(entry->file_stat), &(entry->offset)) == 0) { - LOG(ERROR, ZIPARCHIVE) << "mz_zip_reader_file_offset() failed!"; - return false; - } - - return true; + return ZIPARCHIVE_OK; } -bool IsFileDirectory(ZipArchiveHandle *handle, unsigned int index) +int LocateFile(ZipArchiveHandle &handle, const char *filename) { - if (handle == nullptr) { - LOG(ERROR, ZIPARCHIVE) << "ZipArchiveHandle handle should not be nullptr"; - return false; + int err = unzLocateFile2(handle, filename, 0); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << filename << " is not found in the zipfile"; + return ZIPARCHIVE_ERR; } - return mz_zip_reader_is_file_a_directory(*handle, index) != 0; + return ZIPARCHIVE_OK; } -int32_t ExtractToMemory(ZipArchiveHandle *handle, EntryFileStat *entry, void *buf, size_t buf_size) +int GetCurrentFileInfo(ZipArchiveHandle &handle, EntryFileStat *entry) { - if (handle == nullptr) { - LOG(ERROR, ZIPARCHIVE) << "ZipArchiveHandle handle should not be nullptr"; - return -1; - } - if (mz_zip_reader_extract_to_mem(*handle, entry->GetIndex(), buf, buf_size, 0) == 0) { - LOG(ERROR, ZIPARCHIVE) << "mz_zip_reader_extract_to_mem() failed!\n"; - return -1; + int err = unzGetCurrentFileInfo(handle, &entry->file_stat, nullptr, 0, nullptr, 0, nullptr, 0); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << "unzGetCurrentFileInfo failed!"; + return ZIPARCHIVE_ERR; } - return 0; + return ZIPARCHIVE_OK; } -void *ExtractToHeap(ZipArchiveHandle *handle, const char *filename, size_t *puncomp_size) +int OpenCurrentFile(ZipArchiveHandle &handle) { - if (handle == nullptr) { - LOG(ERROR, ZIPARCHIVE) << "ZipArchiveHandle handle should not be nullptr"; - return nullptr; + int err = unzOpenCurrentFile(handle); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << "OpenCurrentFile failed!"; + return ZIPARCHIVE_ERR; } - void *heap_buf = mz_zip_reader_extract_file_to_heap(*handle, filename, puncomp_size, 0); - if (heap_buf == nullptr) { - LOG(ERROR, ZIPARCHIVE) << "mz_zip_reader_extract_file_to_heap() failed!\n"; - return nullptr; - } - return heap_buf; + return ZIPARCHIVE_OK; } -void FreeHeap(void *heapbuf) +void GetCurrentFileOffset(ZipArchiveHandle &handle, EntryFileStat *entry) { - mz_free(heapbuf); + entry->offset = static_cast(unzGetCurrentFileZStreamPos64(handle)); } -int32_t CreateOrAddFileIntoZip(const char *zip_filename, const char *filename, const void *pbuf, size_t buf_size, - const void *pcomment, mz_uint16 comment_size) +int CloseCurrentFile(ZipArchiveHandle &handle) { - if (mz_zip_add_mem_to_archive_file_in_place(zip_filename, filename, pbuf, buf_size, pcomment, comment_size, - MZ_BEST_COMPRESSION) == 0) { - LOG(ERROR, ZIPARCHIVE) << "mz_zip_add_mem_to_archive_file_in_place failed!\n"; - return -1; + int err = unzCloseCurrentFile(handle); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << "CloseCurrentFile failed!"; + return ZIPARCHIVE_ERR; } - return 0; + return ZIPARCHIVE_OK; } -int32_t CreateOrAddUncompressedFileIntoZip(const char *zip_filename, const char *filename, const void *pbuf, - size_t buf_size, const void *pcomment, mz_uint16 comment_size) +int ExtractToMemory(ZipArchiveHandle &handle, void *buf, size_t buf_size) { - if (mz_zip_add_mem_to_archive_file_in_place(zip_filename, filename, pbuf, buf_size, pcomment, comment_size, - MZ_NO_COMPRESSION) == 0) { - LOG(ERROR, ZIPARCHIVE) << "mz_zip_add_mem_to_archive_file_in_place failed!\n"; - return -1; + int size = unzReadCurrentFile(handle, buf, buf_size); + if (size < 0) { + LOG(ERROR, ZIPARCHIVE) << "ExtractToMemory failed!"; + return ZIPARCHIVE_ERR; } - return 0; + LOG(INFO, ZIPARCHIVE) << "ExtractToMemory size is " << size; + return ZIPARCHIVE_OK; } -bool GetArchiveFileEntry(FILE *inputfile, const char *archive_filename, EntryFileStat *entry) +int CreateOrAddFileIntoZip(const char *zipname, const char *filename, const void *pbuf, size_t buf_size, int append, + int level) { - panda::ZipArchive archive_holder; - panda::ZipArchiveHandle handle = &archive_holder; - fseek(inputfile, 0, SEEK_SET); - auto open_error = panda::OpenArchiveFILE(inputfile, &handle); - if (open_error != 0) { - LOG(ERROR, ZIPARCHIVE) << "Can't open archive\n"; - return false; - } - - auto find_error = panda::FindEntry(&handle, entry, archive_filename); - if (!panda::CloseArchive(&handle)) { - LOG(ERROR, ZIPARCHIVE) << "CloseArchive failed!"; - return false; - } - fseek(inputfile, 0, SEEK_SET); - if (find_error != 0) { - LOG(INFO, ZIPARCHIVE) << "Can't find entry with name '" << archive_filename << "'"; - return false; - } - return true; + zipFile zfile = nullptr; + zfile = zipOpen(zipname, append); + if (zfile == nullptr) { + LOG(ERROR, ZIPARCHIVE) << "CreateArchive failed, zipname is " << zipname; + return ZIPARCHIVE_ERR; + } + int success = ZIPARCHIVE_OK; + int err = zipOpenNewFileInZip(zfile, filename, nullptr, nullptr, 0, nullptr, 0, nullptr, + (level != 0) ? Z_DEFLATED : 0, level); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << "zipOpenNewFileInZip failed!, zipname is" << zipname << ", filename is " << filename; + return ZIPARCHIVE_ERR; + } + err = zipWriteInFileInZip(zfile, pbuf, buf_size); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << "zipWriteInFileInZip failed!, zipname is" << zipname << ", filename is " << filename; + success = ZIPARCHIVE_ERR; + } + err = zipCloseFileInZip(zfile); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << "zipCloseFileInZip failed!, zipname is" << zipname << ", filename is " << filename; + } + err = zipClose(zfile, nullptr); + if (err != UNZ_OK) { + LOG(ERROR, ZIPARCHIVE) << "CloseArcive failed!, zipname is" << zipname; + } + return success; } - } // namespace panda diff --git a/libziparchive/zip_archive.h b/libziparchive/zip_archive.h index 903c2a708409979304b7fe8836f81fdf980f6a5b..a65e3295b03d6ed78f957897224b2dbcc5db2d1e 100644 --- a/libziparchive/zip_archive.h +++ b/libziparchive/zip_archive.h @@ -16,38 +16,27 @@ #ifndef PANDA_LIBZIPARCHIVE_ZIP_ARCHIVE_H_ #define PANDA_LIBZIPARCHIVE_ZIP_ARCHIVE_H_ -#include "miniz.h" +#include +#include "unzip.h" +#include "zip.h" namespace panda { -using ZipArchive = mz_zip_archive; -using ZipArchiveHandle = mz_zip_archive *; +constexpr int ZIPARCHIVE_OK = 0; +constexpr int ZIPARCHIVE_ERR = 1; + +using ZipArchiveHandle = unzFile; struct EntryFileStat { public: - const char *GetFileName() const - { - return file_stat.m_filename; - } - - const char *GetComment() const - { - return file_stat.m_comment; - } - uint32_t GetUncompressedSize() const { - return (uint32_t)file_stat.m_uncomp_size; + return (uint32_t)file_stat.uncompressed_size; } uint32_t GetCompressedSize() const { - return (uint32_t)file_stat.m_comp_size; - } - - uint32_t GetIndex() const - { - return file_stat.m_file_index; + return (uint32_t)file_stat.compressed_size; } inline uint32_t GetOffset() const @@ -55,116 +44,127 @@ public: return offset; } - inline bool IsCompressed() + inline bool IsCompressed() const { - return mz_zip_reader_file_is_compressed(&file_stat); + return file_stat.compression_method != 0; } - mz_zip_archive_file_stat file_stat; + unz_file_info file_stat; uint32_t offset; }; +struct GlobalStat { +public: + uint32_t GetNumberOfEntry() const + { + return (uint32_t)ginfo.number_entry; + } + unz_global_info ginfo; +}; + /* * Judge whether magic is zip magic. */ bool IsZipMagic(uint32_t magic); /* - * Open a Zip archive, and set handle for the file. + * Open a Zip archive from filename path, and sets handle for the file. * This handle must be released by calling CloseArchive with this handle. - * CloseArchive will close the file zip_filename opened. + * CloseArchive will close the file opened. * - * Returns 0 on success, and -1 on failure. + * Returns 0 on success, and 1 on failure. */ -int32_t OpenArchive(const char *zip_filename, ZipArchiveHandle *handle); +int OpenArchive(ZipArchiveHandle &handle, const char *path); /* - * Open a Zip archive FILE, and set handle for the file. - * This handle must be released by calling CloseArchive with this handle. - * CloseArchive will not close the fp. It is the caller's responsibility. - * - * Returns 0 on success, and -1 on failure. + * Close archive opened with OpenArchive, releasing internal resources associated with it. */ -int32_t OpenArchiveFILE(FILE *fp, ZipArchiveHandle *handle); +int CloseArchive(ZipArchiveHandle &handle); /* - * Close archive, releasing internal resources associated with it. - */ -bool CloseArchive(ZipArchiveHandle *handle); - -/* - * Find an entry in the Zip archive by entryname as well as comment name. - * comment name defaultly is nullptr. - * - * stat must point to a writeable memory location (e.g. new/malloc). + * Open a Zip archive from opened file FILE* fp, and sets handle for the file. + * This handle must be released by calling CloseArchiveFile with this handle. + * CloseArchiveFile will not close the fp. It is the caller's responsibility. * - * Return 0 if an entry is found, and populate stat with information about this entry, - * Return -1 otherwise. + * Returns 0 on success, and 1 on failure. */ -int32_t FindEntry(ZipArchiveHandle *handle, EntryFileStat *entry, const char *entryname, - const char *pcomment = nullptr); +int OpenArchiveFile(ZipArchiveHandle &handle, FILE *fp); /* - * Return the total number of files in the archive. + * Close archive opened with OpenArchiveFile, releasing internal resources associated with it. + * + * Returns 0 on success, and 1 on failure. */ -int32_t GetFileCount(ZipArchiveHandle *handle); +int CloseArchiveFile(ZipArchiveHandle &handle); /* - * Attempt to locate a file in the archive's central directory. - * Return the index if file be found, otherwise -1. + * Write the info about the ZipFile into *gstat structure. + * + * Returns 0 on success, and 1 on failure. */ -int32_t LocateFileIndex(ZipArchiveHandle *handle, const char *filename, const char *comment = nullptr); +int GetGlobalFileInfo(ZipArchiveHandle &handle, GlobalStat *gstat); /* - * Return detailed information about an archive file entry according to index. + * Set the current file of the zipfile to the next file. + * + * Returns 0 on success, and 1 on failure. */ -bool StatFileWithIndex(ZipArchiveHandle *handle, EntryFileStat *entry, unsigned int index); +int GoToNextFile(ZipArchiveHandle &handle); /* - * Return true if the archive file entry index is a directory, otherwise false + * Try locate the file filename in the zipfile. + * + * Returns 0 on success, and 1 on failure. */ -bool IsFileDirectory(ZipArchiveHandle *handle, unsigned int index); +int LocateFile(ZipArchiveHandle &handle, const char *filename); /* - * Uncompress a given zip entry to the memory buf of size |buf_size|. - * This size is expected to be equal or larger than the uncompressed length of the zip entry. - * Returns 0 on success and -1 on failure. + * Get Info about the current file within ZipFile and write info into the *entry structure. + * No preparation of the structure is needed + * + * Returns 0 on success, and 1 on failure. */ -int32_t ExtractToMemory(ZipArchiveHandle *handle, EntryFileStat *entry, void *buf, size_t buf_size); +int GetCurrentFileInfo(ZipArchiveHandle &handle, EntryFileStat *entry); /* - * Uncompress a given filename in zip to heap memory. - * The corresponding uncompressed_size is returned in puncomp_size by pointer. - * Returns the heap address on success and nullptr on failure. + * Open for reading data the current file in the zipfile. + * This handle must be released by calling CloseCurrentFile with this handle. + * + * Returns 0 on success, and 1 on failure. */ -void *ExtractToHeap(ZipArchiveHandle *handle, const char *filename, size_t *puncomp_size); +int OpenCurrentFile(ZipArchiveHandle &handle); /* - * Release a block allocated from the heap. + * Get the current file offset opened with OpenCurrentFile. The offset will be stored into entry->offset. */ -void FreeHeap(void *heapbuf); +void GetCurrentFileOffset(ZipArchiveHandle &handle, EntryFileStat *entry); /* - * Add a new file (in memory) to the archive. Note this is an IN-PLACE operation, - * so if it fails your archive is probably hosed (its central directory may not be complete) but it should be - * recoverable using zip -F or -FF. So use this with caution. + * Close the file in zip opened with unzOpenCurrentFile + * + * Returns 0 on success, and 1 on failure. */ -int32_t CreateOrAddFileIntoZip(const char *zip_filename, const char *filename, const void *pbuf, size_t buf_size, - const void *pcomment = nullptr, mz_uint16 comment_size = 0); +int CloseCurrentFile(ZipArchiveHandle &handle); /* - * Add a new file (in memory) to the archive without compression. Note this is an IN-PLACE operation, - * so if it fails your archive is probably hosed (its central directory may not be complete) but it should be - * recoverable using zip -F or -FF. So use this with caution. + * Uncompress a given zip archive represented with handle to buf of size |buf_size|. + * This size is expected to be equal or larger than the uncompressed length of the zip entry. + * + * Returns 0 on success and 1 on failure. */ -int32_t CreateOrAddUncompressedFileIntoZip(const char *zip_filename, const char *filename, const void *pbuf, - size_t buf_size, const void *pcomment, mz_uint16 comment_size); +int ExtractToMemory(ZipArchiveHandle &handle, void *buf, size_t buf_size); /* - * GetArchiveFileEntry from FILE* inputfile + * Add a new file filename(resident in memory pbuf which has size of size |buf_size|) to the archive zipname, + * append takes value from APPEND_STATUS_CREATE(which will create the archive zipname for first time) and + * APPEND_STATUS_ADDINZIP(which willappend filename into exsisted zip archive zipname). + * level takes value from Z_BEST_COMPRESSION(which will deflate the pbuf with best compression effect) and + * Z_NO_COMPRESSION(which will store the pbuf into zipname without compression). + * + * Returns 0 on success and 1 on failure. */ -bool GetArchiveFileEntry(FILE *inputfile, const char *archive_filename, EntryFileStat *entry); - +int CreateOrAddFileIntoZip(const char *zipname, const char *filename, const void *pbuf, size_t buf_size, + int append = APPEND_STATUS_CREATE, int level = Z_BEST_COMPRESSION); } // namespace panda #endif // PANDA_LIBZIPARCHIVE_ZIP_ARCHIVE_H_