aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/unarchiver/unzip.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/unarchiver/unzip.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/unarchiver/unzip.cpp')
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/unzip.cpp315
1 files changed, 315 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/unzip.cpp b/Src/external_dependencies/openmpt-trunk/unarchiver/unzip.cpp
new file mode 100644
index 00000000..6094f630
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/unzip.cpp
@@ -0,0 +1,315 @@
+/*
+ * unzip.cpp
+ * ---------
+ * Purpose: Implementation file for extracting modules from .zip archives, making use of MiniZip (from the zlib contrib package)
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#include "stdafx.h"
+
+#include "../common/FileReader.h"
+#include "unzip.h"
+#include "../common/misc_util.h"
+#include <algorithm>
+#include <vector>
+
+#if defined(MPT_WITH_ZLIB) && defined(MPT_WITH_MINIZIP)
+#include <contrib/minizip/unzip.h>
+#elif defined(MPT_WITH_MINIZ)
+#include <miniz/miniz.h>
+#endif
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#if defined(MPT_WITH_ZLIB) && defined(MPT_WITH_MINIZIP)
+
+
+// Low-level file abstractions for in-memory file handling
+struct ZipFileAbstraction
+{
+ static voidpf ZCALLBACK fopen64_mem(voidpf opaque, const void *, int mode)
+ {
+ FileReader &file = *static_cast<FileReader *>(opaque);
+ if((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_WRITE)
+ {
+ return nullptr;
+ } else
+ {
+ file.Rewind();
+ return opaque;
+ }
+ }
+
+ static uLong ZCALLBACK fread_mem(voidpf opaque, voidpf, void *buf, uLong size)
+ {
+ FileReader &file = *static_cast<FileReader *>(opaque);
+ return mpt::saturate_cast<uLong>(file.ReadRaw(mpt::span(mpt::void_cast<std::byte*>(buf), size)).size());
+ }
+
+ static uLong ZCALLBACK fwrite_mem(voidpf, voidpf, const void *, uLong)
+ {
+ return 0;
+ }
+
+ static ZPOS64_T ZCALLBACK ftell64_mem(voidpf opaque, voidpf)
+ {
+ FileReader &file = *static_cast<FileReader *>(opaque);
+ return file.GetPosition();
+ }
+
+ static long ZCALLBACK fseek64_mem(voidpf opaque, voidpf, ZPOS64_T offset, int origin)
+ {
+ FileReader &file = *static_cast<FileReader *>(opaque);
+ ZPOS64_T destination = 0;
+ switch(origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR:
+ destination = static_cast<ZPOS64_T>(file.GetPosition()) + offset;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END:
+ destination = static_cast<ZPOS64_T>(file.GetLength()) + offset;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET:
+ destination = offset;
+ break;
+ default:
+ return -1;
+ }
+ if(!mpt::in_range<FileReader::off_t>(destination))
+ {
+ return 1;
+ }
+ return (file.Seek(static_cast<FileReader::off_t>(destination)) ? 0 : 1);
+ }
+
+ static int ZCALLBACK fclose_mem(voidpf, voidpf)
+ {
+ return 0;
+ }
+
+ static int ZCALLBACK ferror_mem(voidpf, voidpf)
+ {
+ return 0;
+ }
+};
+
+
+CZipArchive::CZipArchive(FileReader &file)
+ : ArchiveBase(file)
+ , zipFile(nullptr)
+{
+ zlib_filefunc64_def functions =
+ {
+ ZipFileAbstraction::fopen64_mem,
+ ZipFileAbstraction::fread_mem,
+ ZipFileAbstraction::fwrite_mem,
+ ZipFileAbstraction::ftell64_mem,
+ ZipFileAbstraction::fseek64_mem,
+ ZipFileAbstraction::fclose_mem,
+ ZipFileAbstraction::ferror_mem,
+ &inFile
+ };
+
+ zipFile = unzOpen2_64(nullptr, &functions);
+
+ if(zipFile == nullptr)
+ {
+ return;
+ }
+
+ // read comment
+ {
+ unz_global_info info;
+ if(unzGetGlobalInfo(zipFile, &info) == UNZ_OK)
+ {
+ if(info.size_comment > 0)
+ {
+ if(info.size_comment < Util::MaxValueOfType(info.size_comment))
+ {
+ info.size_comment++;
+ }
+ std::vector<char> commentData(info.size_comment);
+ if(unzGetGlobalComment(zipFile, commentData.data(), info.size_comment) >= 0)
+ {
+ commentData[info.size_comment - 1] = '\0';
+ comment = mpt::ToUnicode(mpt::IsUTF8(commentData.data()) ? mpt::Charset::UTF8 : mpt::Charset::CP437, commentData.data());
+ }
+ }
+ }
+ }
+
+ // read contents
+ unz_file_pos curFile;
+ int status = unzGoToFirstFile(zipFile);
+ unzGetFilePos(zipFile, &curFile);
+
+ while(status == UNZ_OK)
+ {
+ ArchiveFileInfo fileinfo;
+
+ fileinfo.type = ArchiveFileType::Normal;
+
+ unz_file_info info;
+ char name[256];
+ unzGetCurrentFileInfo(zipFile, &info, name, sizeof(name), nullptr, 0, nullptr, 0);
+ fileinfo.name = mpt::PathString::FromUnicode(mpt::ToUnicode((info.flag & (1<<11)) ? mpt::Charset::UTF8 : mpt::Charset::CP437, std::string(name)));
+ fileinfo.size = info.uncompressed_size;
+
+ unzGetFilePos(zipFile, &curFile);
+ fileinfo.cookie1 = curFile.pos_in_zip_directory;
+ fileinfo.cookie2 = curFile.num_of_file;
+
+ contents.push_back(fileinfo);
+
+ status = unzGoToNextFile(zipFile);
+ }
+
+}
+
+
+CZipArchive::~CZipArchive()
+{
+ unzClose(zipFile);
+}
+
+
+bool CZipArchive::ExtractFile(std::size_t index)
+{
+ if(index >= contents.size())
+ {
+ return false;
+ }
+
+ data.clear();
+
+ unz_file_pos bestFile;
+ unz_file_info info;
+
+ bestFile.pos_in_zip_directory = static_cast<uLong>(contents[index].cookie1);
+ bestFile.num_of_file = static_cast<uLong>(contents[index].cookie2);
+
+ if(unzGoToFilePos(zipFile, &bestFile) == UNZ_OK && unzOpenCurrentFile(zipFile) == UNZ_OK)
+ {
+ unzGetCurrentFileInfo(zipFile, &info, nullptr, 0, nullptr, 0, nullptr, 0);
+
+ try
+ {
+ data.resize(info.uncompressed_size);
+ } catch(...)
+ {
+ unzCloseCurrentFile(zipFile);
+ return false;
+ }
+ unzReadCurrentFile(zipFile, data.data(), info.uncompressed_size);
+ unzCloseCurrentFile(zipFile);
+
+ return true;
+ }
+
+ return false;
+}
+
+
+#elif defined(MPT_WITH_MINIZ)
+
+
+CZipArchive::CZipArchive(FileReader &file) : ArchiveBase(file)
+{
+ zipFile = new mz_zip_archive();
+
+ mz_zip_archive *zip = static_cast<mz_zip_archive*>(zipFile);
+
+ (*zip) = {};
+ const auto fileData = file.GetRawData();
+ if(!mz_zip_reader_init_mem(zip, fileData.data(), fileData.size(), 0))
+ {
+ delete zip;
+ zip = nullptr;
+ zipFile = nullptr;
+ }
+
+ if(!zip)
+ {
+ return;
+ }
+
+ for(mz_uint i = 0; i < mz_zip_reader_get_num_files(zip); ++i)
+ {
+ ArchiveFileInfo info;
+ info.type = ArchiveFileType::Invalid;
+ mz_zip_archive_file_stat stat = {};
+ if(mz_zip_reader_file_stat(zip, i, &stat))
+ {
+ info.type = ArchiveFileType::Normal;
+ info.name = mpt::PathString::FromUnicode(mpt::ToUnicode((stat.m_bit_flag & (1<<11)) ? mpt::Charset::UTF8 : mpt::Charset::CP437, stat.m_filename));
+ info.size = stat.m_uncomp_size;
+ }
+ if(mz_zip_reader_is_file_a_directory(zip, i))
+ {
+ info.type = ArchiveFileType::Special;
+ } else if(mz_zip_reader_is_file_encrypted(zip, i))
+ {
+ info.type = ArchiveFileType::Special;
+ }
+ contents.push_back(info);
+ }
+
+}
+
+
+CZipArchive::~CZipArchive()
+{
+ mz_zip_archive *zip = static_cast<mz_zip_archive*>(zipFile);
+
+ if(zip)
+ {
+ mz_zip_reader_end(zip);
+
+ delete zip;
+ zipFile = nullptr;
+ }
+
+}
+
+
+bool CZipArchive::ExtractFile(std::size_t index)
+{
+ mz_zip_archive *zip = static_cast<mz_zip_archive*>(zipFile);
+
+ if(index >= contents.size())
+ {
+ return false;
+ }
+
+ mz_uint bestFile = index;
+
+ mz_zip_archive_file_stat stat = {};
+ mz_zip_reader_file_stat(zip, bestFile, &stat);
+ if(stat.m_uncomp_size >= std::numeric_limits<std::size_t>::max())
+ {
+ return false;
+ }
+ try
+ {
+ data.resize(static_cast<std::size_t>(stat.m_uncomp_size));
+ } catch(...)
+ {
+ return false;
+ }
+ if(!mz_zip_reader_extract_to_mem(zip, bestFile, data.data(), static_cast<std::size_t>(stat.m_uncomp_size), 0))
+ {
+ return false;
+ }
+ comment = mpt::ToUnicode(mpt::Charset::CP437, std::string(stat.m_comment, stat.m_comment + stat.m_comment_size));
+ return true;
+}
+
+
+#endif // MPT_WITH_ZLIB || MPT_WITH_MINIZ
+
+
+OPENMPT_NAMESPACE_END