aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/unarchiver
diff options
context:
space:
mode:
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/unarchiver')
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/archive.h96
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/unancient.cpp83
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/unancient.h32
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/unarchiver.cpp173
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/unarchiver.h88
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.cpp147
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.h74
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/unlha.cpp162
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/unlha.h46
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/unrar.cpp279
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/unrar.h48
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/unzip.cpp315
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/unzip.h29
13 files changed, 1572 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/archive.h b/Src/external_dependencies/openmpt-trunk/unarchiver/archive.h
new file mode 100644
index 00000000..87b508b1
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/archive.h
@@ -0,0 +1,96 @@
+/*
+ * archive.h
+ * ---------
+ * Purpose: archive loader
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#pragma once
+
+#include "openmpt/all/BuildSettings.hpp"
+
+#include "../common/FileReader.h"
+#include <string>
+#include <vector>
+
+OPENMPT_NAMESPACE_BEGIN
+
+enum class ArchiveFileType
+{
+ Invalid,
+ Normal,
+ Special,
+};
+
+struct ArchiveFileInfo
+{
+ mpt::PathString name;
+ ArchiveFileType type = ArchiveFileType::Invalid;
+ uint64 size = 0;
+ mpt::ustring comment;
+ uint64 cookie1 = 0;
+ uint64 cookie2 = 0;
+};
+
+class IArchive
+{
+public:
+ using const_iterator = std::vector<ArchiveFileInfo>::const_iterator;
+protected:
+ IArchive() {}
+public:
+ virtual ~IArchive() {}
+
+public:
+ virtual bool IsArchive() const = 0;
+ virtual mpt::ustring GetComment() const = 0;
+ virtual bool ExtractFile(std::size_t index) = 0;
+ virtual FileReader GetOutputFile() const = 0;
+ virtual std::size_t size() const = 0;
+ virtual IArchive::const_iterator begin() const = 0;
+ virtual IArchive::const_iterator end() const = 0;
+ virtual const ArchiveFileInfo & operator [] (std::size_t index) const = 0;
+};
+
+class ArchiveBase
+ : public IArchive
+{
+protected:
+ FileReader inFile;
+ mpt::ustring comment;
+ std::vector<ArchiveFileInfo> contents;
+ std::vector<char> data;
+public:
+ ArchiveBase(const FileReader &inFile)
+ : inFile(inFile)
+ {
+ return;
+ }
+ ~ArchiveBase() override
+ {
+ return;
+ }
+ bool ExtractFile(std::size_t index) override { MPT_UNREFERENCED_PARAMETER(index); return false; } // overwrite this
+public:
+ bool IsArchive() const override
+ {
+ return !contents.empty();
+ }
+ mpt::ustring GetComment() const override
+ {
+ return comment;
+ }
+ FileReader GetOutputFile() const override
+ {
+ return FileReader(mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(data)));
+ }
+ std::size_t size() const override { return contents.size(); }
+ IArchive::const_iterator begin() const override { return contents.begin(); }
+ IArchive::const_iterator end() const override { return contents.end(); }
+ const ArchiveFileInfo & operator [] (std::size_t index) const override { return contents[index]; }
+};
+
+
+OPENMPT_NAMESPACE_END
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/unancient.cpp b/Src/external_dependencies/openmpt-trunk/unarchiver/unancient.cpp
new file mode 100644
index 00000000..a2b8001e
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/unancient.cpp
@@ -0,0 +1,83 @@
+/*
+ * unancient.cpp
+ * -------------
+ * Purpose: Implementation file for extracting modules from compressed files supported by libancient
+ * 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 "unancient.h"
+
+#ifdef MPT_WITH_ANCIENT
+#include <ancient/ancient.hpp>
+#endif // MPT_WITH_ANCIENT
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#ifdef MPT_WITH_ANCIENT
+
+
+CAncientArchive::CAncientArchive(FileReader &file)
+ : ArchiveBase(file)
+{
+ inFile.Rewind();
+ try
+ {
+ auto dataView = inFile.GetPinnedView();
+ if(!ancient::Decompressor::detect(mpt::byte_cast<const std::uint8_t*>(dataView.data()), dataView.size()))
+ {
+ return;
+ }
+ ancient::Decompressor decompressor{mpt::byte_cast<const std::uint8_t*>(dataView.data()), dataView.size(), true, true};
+ if(decompressor.getImageSize() || decompressor.getImageOffset())
+ {
+ // skip disk images
+ return;
+ }
+ ArchiveFileInfo fileInfo;
+ fileInfo.name = inFile.GetOptionalFileName().value_or(P_(""));
+ fileInfo.type = ArchiveFileType::Normal;
+ fileInfo.size = decompressor.getRawSize().value_or(0);
+ contents.push_back(fileInfo);
+ } catch(const ancient::Error &)
+ {
+ return;
+ }
+}
+
+
+CAncientArchive::~CAncientArchive()
+{
+ return;
+}
+
+
+bool CAncientArchive::ExtractFile(std::size_t index)
+{
+ if(index >= contents.size())
+ {
+ return false;
+ }
+ data.clear();
+ inFile.Rewind();
+ try
+ {
+ auto dataView = inFile.GetPinnedView();
+ ancient::Decompressor decompressor{mpt::byte_cast<const std::uint8_t*>(dataView.data()), dataView.size(), true, true};
+ data = mpt::buffer_cast<std::vector<char>>(decompressor.decompress(true));
+ } catch (const ancient::Error &)
+ {
+ return false;
+ }
+ return (data.size() > 0);
+}
+
+
+#endif // MPT_WITH_ANCIENT
+
+
+OPENMPT_NAMESPACE_END
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/unancient.h b/Src/external_dependencies/openmpt-trunk/unarchiver/unancient.h
new file mode 100644
index 00000000..dff2e944
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/unancient.h
@@ -0,0 +1,32 @@
+/*
+ * ununancient.h
+ * -------------
+ * Purpose: Header file extracting modules from compressed files supported by libancient
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#pragma once
+
+#include "openmpt/all/BuildSettings.hpp"
+
+#include "archive.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+#ifdef MPT_WITH_ANCIENT
+
+class CAncientArchive
+ : public ArchiveBase
+{
+public:
+ CAncientArchive(FileReader &file);
+ virtual ~CAncientArchive();
+public:
+ bool ExtractFile(std::size_t index) override;
+};
+
+#endif // MPT_WITH_ANCIENT
+
+OPENMPT_NAMESPACE_END
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/unarchiver.cpp b/Src/external_dependencies/openmpt-trunk/unarchiver/unarchiver.cpp
new file mode 100644
index 00000000..8351be38
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/unarchiver.cpp
@@ -0,0 +1,173 @@
+/*
+ * unarchiver.cpp
+ * --------------
+ * Purpose: archive loader
+ * 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 "unarchiver.h"
+#include "../common/FileReader.h"
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+CUnarchiver::CUnarchiver(FileReader &file)
+ : impl(nullptr)
+ , inFile(file)
+ , emptyArchive(inFile)
+#if (defined(MPT_WITH_ZLIB) && defined(MPT_WITH_MINIZIP)) || defined(MPT_WITH_MINIZ)
+ , zipArchive(inFile)
+#endif
+#ifdef MPT_WITH_LHASA
+ , lhaArchive(inFile)
+#endif
+#if defined(MPT_WITH_ZLIB) || defined(MPT_WITH_MINIZ)
+ , gzipArchive(inFile)
+#endif
+#ifdef MPT_WITH_UNRAR
+ , rarArchive(inFile)
+#endif
+#ifdef MPT_WITH_ANCIENT
+ , ancientArchive(inFile)
+#endif
+{
+ inFile.Rewind();
+#if (defined(MPT_WITH_ZLIB) && defined(MPT_WITH_MINIZIP)) || defined(MPT_WITH_MINIZ)
+ if(zipArchive.IsArchive()) { impl = &zipArchive; return; }
+#endif
+#ifdef MPT_WITH_LHASA
+ if(lhaArchive.IsArchive()) { impl = &lhaArchive; return; }
+#endif
+#if defined(MPT_WITH_ZLIB) || defined(MPT_WITH_MINIZ)
+ if(gzipArchive.IsArchive()) { impl = &gzipArchive; return; }
+#endif
+#ifdef MPT_WITH_UNRAR
+ if(rarArchive.IsArchive()) { impl = &rarArchive; return; }
+#endif
+#ifdef MPT_WITH_ANCIENT
+ if(ancientArchive.IsArchive()) { impl = &ancientArchive; return; }
+#endif
+ impl = &emptyArchive;
+}
+
+
+CUnarchiver::~CUnarchiver()
+{
+ return;
+}
+
+
+static inline std::string GetExtension(const std::string &filename)
+{
+ if(filename.find_last_of(".") != std::string::npos)
+ {
+ return mpt::ToLowerCaseAscii(filename.substr(filename.find_last_of(".") + 1));
+ }
+ return std::string();
+}
+
+
+std::size_t CUnarchiver::FindBestFile(const std::vector<const char *> &extensions)
+{
+ if(!IsArchive())
+ {
+ return failIndex;
+ }
+ uint64 biggestSize = 0;
+ std::size_t bestIndex = failIndex;
+ for(std::size_t i = 0; i < size(); ++i)
+ {
+ if(operator[](i).type != ArchiveFileType::Normal)
+ {
+ continue;
+ }
+ const std::string ext = GetExtension(operator[](i).name.ToUTF8());
+
+ if(ext == "diz" || ext == "nfo" || ext == "txt")
+ {
+ // we do not want these
+ continue;
+ }
+
+ // Compare with list of preferred extensions
+ if(mpt::contains(extensions, ext))
+ {
+ bestIndex = i;
+ break;
+ }
+
+ if(operator[](i).size >= biggestSize)
+ {
+ biggestSize = operator[](i).size;
+ bestIndex = i;
+ }
+ }
+ return bestIndex;
+}
+
+
+bool CUnarchiver::ExtractBestFile(const std::vector<const char *> &extensions)
+{
+ std::size_t bestFile = FindBestFile(extensions);
+ if(bestFile == failIndex)
+ {
+ return false;
+ }
+ return ExtractFile(bestFile);
+}
+
+
+bool CUnarchiver::IsArchive() const
+{
+ return impl->IsArchive();
+}
+
+
+mpt::ustring CUnarchiver::GetComment() const
+{
+ return impl->GetComment();
+}
+
+
+bool CUnarchiver::ExtractFile(std::size_t index)
+{
+ return impl->ExtractFile(index);
+}
+
+
+FileReader CUnarchiver::GetOutputFile() const
+{
+ return impl->GetOutputFile();
+}
+
+
+std::size_t CUnarchiver::size() const
+{
+ return impl->size();
+}
+
+
+IArchive::const_iterator CUnarchiver::begin() const
+{
+ return impl->begin();
+}
+
+
+IArchive::const_iterator CUnarchiver::end() const
+{
+ return impl->end();
+}
+
+
+const ArchiveFileInfo & CUnarchiver::operator [] (std::size_t index) const
+{
+ return impl->operator[](index);
+}
+
+
+OPENMPT_NAMESPACE_END
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/unarchiver.h b/Src/external_dependencies/openmpt-trunk/unarchiver/unarchiver.h
new file mode 100644
index 00000000..83d73701
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/unarchiver.h
@@ -0,0 +1,88 @@
+/*
+ * unarchiver.h
+ * ------------
+ * Purpose: archive loader
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#pragma once
+
+#include "openmpt/all/BuildSettings.hpp"
+
+#include "../common/FileReader.h"
+
+#include "archive.h"
+
+#if (defined(MPT_WITH_ZLIB) && defined(MPT_WITH_MINIZIP)) || defined(MPT_WITH_MINIZ)
+#include "unzip.h"
+#endif
+#ifdef MPT_WITH_LHASA
+#include "unlha.h"
+#endif
+#if defined(MPT_WITH_ZLIB) || defined(MPT_WITH_MINIZ)
+#include "ungzip.h"
+#endif
+#ifdef MPT_WITH_UNRAR
+#include "unrar.h"
+#endif
+#ifdef MPT_WITH_ANCIENT
+#include "unancient.h"
+#endif
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+class CUnarchiver : public IArchive
+{
+
+private:
+
+ IArchive *impl;
+
+ FileReader inFile;
+
+ ArchiveBase emptyArchive;
+#if (defined(MPT_WITH_ZLIB) && defined(MPT_WITH_MINIZIP)) || defined(MPT_WITH_MINIZ)
+ CZipArchive zipArchive;
+#endif
+#ifdef MPT_WITH_LHASA
+ CLhaArchive lhaArchive;
+#endif
+#if defined(MPT_WITH_ZLIB) || defined(MPT_WITH_MINIZ)
+ CGzipArchive gzipArchive;
+#endif
+#ifdef MPT_WITH_UNRAR
+ CRarArchive rarArchive;
+#endif
+#ifdef MPT_WITH_ANCIENT
+ CAncientArchive ancientArchive;
+#endif
+
+public:
+
+ CUnarchiver(FileReader &file);
+ ~CUnarchiver() override;
+
+ bool IsArchive() const override;
+ mpt::ustring GetComment() const override;
+ bool ExtractFile(std::size_t index) override;
+ FileReader GetOutputFile() const override;
+ std::size_t size() const override;
+ IArchive::const_iterator begin() const override;
+ IArchive::const_iterator end() const override;
+ const ArchiveFileInfo & operator [] (std::size_t index) const override;
+
+public:
+
+ static const std::size_t failIndex = (std::size_t)-1;
+
+ std::size_t FindBestFile(const std::vector<const char *> &extensions);
+ bool ExtractBestFile(const std::vector<const char *> &extensions);
+
+};
+
+
+OPENMPT_NAMESPACE_END
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.cpp b/Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.cpp
new file mode 100644
index 00000000..0731a0ef
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.cpp
@@ -0,0 +1,147 @@
+/*
+ * ungzip.cpp
+ * ----------
+ * Purpose: Implementation file for extracting modules from .gz archives
+ * 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 "ungzip.h"
+
+#if defined(MPT_WITH_ZLIB) || defined(MPT_WITH_MINIZ)
+
+#if defined(MPT_WITH_ZLIB)
+#include <zlib.h>
+#elif defined(MPT_WITH_MINIZ)
+#include <miniz/miniz.h>
+#endif
+
+#endif // MPT_WITH_ZLIB || MPT_WITH_MINIZ
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#if defined(MPT_WITH_ZLIB) || defined(MPT_WITH_MINIZ)
+
+
+CGzipArchive::CGzipArchive(const FileReader &file) : ArchiveBase(file)
+{
+ inFile.Rewind();
+ inFile.ReadStruct(header);
+
+ // Check header data + file size
+ if(header.magic1 != GZ_HMAGIC1 || header.magic2 != GZ_HMAGIC2 || header.method != GZ_HMDEFLATE || (header.flags & GZ_FRESERVED) != 0
+ || inFile.GetLength() <= sizeof(GZheader) + sizeof(GZtrailer))
+ {
+ return;
+ }
+ ArchiveFileInfo info;
+ info.type = ArchiveFileType::Normal;
+ contents.push_back(info);
+}
+
+
+CGzipArchive::~CGzipArchive()
+{
+ return;
+}
+
+
+bool CGzipArchive::ExtractFile(std::size_t index)
+{
+ if(index >= contents.size())
+ {
+ return false;
+ }
+
+ // Read trailer
+ GZtrailer trailer;
+ inFile.Seek(inFile.GetLength() - sizeof(GZtrailer));
+ inFile.ReadStruct(trailer);
+
+ // Continue reading header
+ inFile.Seek(sizeof(GZheader));
+
+ // Extra block present? (skip the extra data)
+ if(header.flags & GZ_FEXTRA)
+ {
+ inFile.Skip(inFile.ReadUint16LE());
+ }
+
+ // Filename present? (ignore)
+ if(header.flags & GZ_FNAME)
+ {
+ while(inFile.ReadUint8() != 0);
+ }
+
+ // Comment present? (ignore)
+ if(header.flags & GZ_FCOMMENT)
+ {
+ while(inFile.ReadUint8() != 0);
+ }
+
+ // CRC16 present? (ignore)
+ if(header.flags & GZ_FHCRC)
+ {
+ inFile.Skip(2);
+ }
+
+ // Well, this is a bit small when deflated.
+ if(!inFile.CanRead(sizeof(GZtrailer)))
+ {
+ return false;
+ }
+
+ try
+ {
+ data.reserve(inFile.BytesLeft());
+ } catch(...)
+ {
+ return false;
+ }
+
+ // Inflate!
+ z_stream strm{};
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = Z_NULL;
+ if(inflateInit2(&strm, -15) != Z_OK)
+ return false;
+ int retVal = Z_OK;
+ uint32 crc = 0;
+ auto bytesLeft = inFile.BytesLeft() - sizeof(GZtrailer);
+ do
+ {
+ std::array<char, mpt::IO::BUFFERSIZE_SMALL> inBuffer, outBuffer;
+ strm.avail_in = static_cast<uInt>(std::min(static_cast<FileReader::pos_type>(inBuffer.size()), bytesLeft));
+ inFile.ReadStructPartial(inBuffer, strm.avail_in);
+ strm.next_in = reinterpret_cast<Bytef *>(inBuffer.data());
+ bytesLeft -= strm.avail_in;
+ do
+ {
+ strm.avail_out = static_cast<uInt>(outBuffer.size());
+ strm.next_out = reinterpret_cast<Bytef *>(outBuffer.data());
+ retVal = inflate(&strm, Z_NO_FLUSH);
+ const auto output = mpt::as_span(outBuffer.data(), outBuffer.data() + outBuffer.size() - strm.avail_out);
+ crc = crc32(crc, reinterpret_cast<Bytef *>(output.data()), static_cast<uInt>(output.size()));
+ data.insert(data.end(), output.begin(), output.end());
+ } while(strm.avail_out == 0);
+ } while(retVal == Z_OK && bytesLeft);
+ inflateEnd(&strm);
+
+ // Everything went OK? Check return code, number of written bytes and CRC32.
+ return retVal == Z_STREAM_END && trailer.isize == static_cast<uint32>(strm.total_out) && trailer.crc32_ == crc;
+}
+
+
+#endif // MPT_WITH_ZLIB || MPT_WITH_MINIZ
+
+
+OPENMPT_NAMESPACE_END
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.h b/Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.h
new file mode 100644
index 00000000..85019141
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.h
@@ -0,0 +1,74 @@
+/*
+ * ungzip.h
+ * --------
+ * Purpose: Header file for .gz loader
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#pragma once
+
+#include "openmpt/all/BuildSettings.hpp"
+#include "openmpt/base/Endian.hpp"
+
+#include "archive.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+#if defined(MPT_WITH_ZLIB) || defined(MPT_WITH_MINIZ)
+
+class CGzipArchive : public ArchiveBase
+{
+public:
+ struct GZheader
+ {
+ uint8le magic1; // 0x1F
+ uint8le magic2; // 0x8B
+ uint8le method; // 0-7 = reserved, 8 = deflate
+ uint8le flags; // See GZ_F* constants
+ uint32le mtime; // UNIX time
+ uint8le xflags; // Available for use by specific compression methods. We ignore this.
+ uint8le os; // Which OS was used to compress the file? We also ignore this.
+ };
+
+ struct GZtrailer
+ {
+ uint32le crc32_; // CRC32 of decompressed data
+ uint32le isize; // Size of decompressed data modulo 2^32
+ };
+
+protected:
+ enum MagicBytes
+ {
+ GZ_HMAGIC1 = 0x1F,
+ GZ_HMAGIC2 = 0x8B,
+ GZ_HMDEFLATE = 0x08,
+ };
+
+ enum HeaderFlags
+ {
+ GZ_FTEXT = 0x01, // File is probably ASCII text (who cares)
+ GZ_FHCRC = 0x02, // CRC16 present
+ GZ_FEXTRA = 0x04, // Extra fields present
+ GZ_FNAME = 0x08, // Original filename present
+ GZ_FCOMMENT = 0x10, // Comment is present
+ GZ_FRESERVED = (~(GZ_FTEXT | GZ_FHCRC | GZ_FEXTRA | GZ_FNAME | GZ_FCOMMENT))
+ };
+
+ GZheader header;
+
+public:
+
+ bool ExtractFile(std::size_t index) override;
+
+ CGzipArchive(const FileReader &file);
+ ~CGzipArchive() override;
+};
+
+MPT_BINARY_STRUCT(CGzipArchive::GZheader, 10)
+MPT_BINARY_STRUCT(CGzipArchive::GZtrailer, 8)
+
+#endif // MPT_WITH_ZLIB || MPT_WITH_MINIZ
+
+OPENMPT_NAMESPACE_END
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/unlha.cpp b/Src/external_dependencies/openmpt-trunk/unarchiver/unlha.cpp
new file mode 100644
index 00000000..e243d1d1
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/unlha.cpp
@@ -0,0 +1,162 @@
+/*
+ * unlha.cpp
+ * ---------
+ * Purpose: Implementation file for extracting modules from .lha archives, making use of lhasa
+ * 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 "unlha.h"
+
+#ifdef MPT_WITH_LHASA
+#include "lhasa.h"
+#endif // MPT_WITH_LHASA
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#ifdef MPT_WITH_LHASA
+
+
+static int LHAreadFileReader(void *handle, void *buf, size_t buf_len)
+{
+ FileReader *f = reinterpret_cast<FileReader*>(handle);
+ int read_len = mpt::saturate_cast<int>(buf_len);
+ int result = mpt::saturate_cast<int>(f->ReadRaw(mpt::span(mpt::void_cast<std::byte*>(buf), read_len)).size());
+ if(result == 0)
+ {
+ return -1;
+ }
+ return result;
+}
+
+static int LHAskipFileReader(void *handle, size_t bytes)
+{
+ FileReader *f = reinterpret_cast<FileReader*>(handle);
+ if(f->CanRead(bytes))
+ {
+ f->Skip(bytes);
+ return 1;
+ }
+ return 0;
+}
+
+static void LHAcloseFileReader(void * /*handle*/)
+{
+ return;
+}
+
+static LHAInputStreamType vtable =
+{
+ LHAreadFileReader,
+ LHAskipFileReader,
+ LHAcloseFileReader
+};
+
+
+CLhaArchive::CLhaArchive(FileReader &file) : ArchiveBase(file), inputstream(nullptr), reader(nullptr), firstfile(nullptr)
+{
+ OpenArchive();
+ for(LHAFileHeader *fileheader = firstfile; fileheader; fileheader = lha_reader_next_file(reader))
+ {
+ ArchiveFileInfo info;
+ info.name = mpt::PathString::FromUnicode(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, fileheader->filename));
+ info.size = fileheader->length;
+ info.type = ArchiveFileType::Normal;
+ contents.push_back(info);
+ }
+ CloseArchive();
+}
+
+
+CLhaArchive::~CLhaArchive()
+{
+ return;
+}
+
+
+void CLhaArchive::OpenArchive()
+{
+ inFile.Rewind();
+ inputstream = lha_input_stream_new(&vtable, &inFile);
+ if(inputstream)
+ {
+ reader = lha_reader_new(inputstream);
+ }
+ if(reader)
+ {
+ lha_reader_set_dir_policy(reader, LHA_READER_DIR_END_OF_DIR);
+ firstfile = lha_reader_next_file(reader);
+ }
+}
+
+
+void CLhaArchive::CloseArchive()
+{
+ if(reader)
+ {
+ lha_reader_free(reader);
+ reader = nullptr;
+ }
+ if(inputstream)
+ {
+ lha_input_stream_free(inputstream);
+ inputstream = nullptr;
+ }
+}
+
+
+bool CLhaArchive::ExtractFile(std::size_t index)
+{
+ if(index >= contents.size())
+ {
+ return false;
+ }
+ data.clear();
+ OpenArchive();
+ const std::size_t bufSize = 4096;
+ std::size_t i = 0;
+ for(LHAFileHeader *fileheader = firstfile; fileheader; fileheader = lha_reader_next_file(reader))
+ {
+ if(index == i)
+ {
+ data.clear();
+ std::size_t countRead = 0;
+ do
+ {
+ try
+ {
+ data.resize(data.size() + bufSize);
+ } catch(...)
+ {
+ CloseArchive();
+ return false;
+ }
+ countRead = lha_reader_read(reader, &data[data.size() - bufSize], bufSize);
+ if(countRead < bufSize)
+ {
+ try
+ {
+ data.resize(data.size() - (bufSize - countRead));
+ } catch(...)
+ {
+ CloseArchive();
+ return false;
+ }
+ }
+ } while(countRead > 0);
+ }
+ ++i;
+ }
+ CloseArchive();
+ return data.size() > 0;
+}
+
+
+#endif // MPT_WITH_LHASA
+
+
+OPENMPT_NAMESPACE_END
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/unlha.h b/Src/external_dependencies/openmpt-trunk/unarchiver/unlha.h
new file mode 100644
index 00000000..cf330255
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/unlha.h
@@ -0,0 +1,46 @@
+/*
+ * unlha.h
+ * -------
+ * Purpose: Header file for .lha loader
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#pragma once
+
+#include "openmpt/all/BuildSettings.hpp"
+
+#include "archive.h"
+
+
+#ifdef MPT_WITH_LHASA
+
+typedef struct _LHAInputStream LHAInputStream;
+typedef struct _LHAReader LHAReader;
+typedef struct _LHAFileHeader LHAFileHeader;
+
+#endif // MPT_WITH_LHASA
+
+OPENMPT_NAMESPACE_BEGIN
+
+#ifdef MPT_WITH_LHASA
+
+class CLhaArchive : public ArchiveBase
+{
+private:
+ LHAInputStream *inputstream;
+ LHAReader *reader;
+ LHAFileHeader *firstfile;
+ void OpenArchive();
+ void CloseArchive();
+public:
+ CLhaArchive(FileReader &file);
+ virtual ~CLhaArchive();
+public:
+ bool ExtractFile(std::size_t index) override;
+};
+
+#endif // MPT_WITH_LHASA
+
+OPENMPT_NAMESPACE_END
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/unrar.cpp b/Src/external_dependencies/openmpt-trunk/unarchiver/unrar.cpp
new file mode 100644
index 00000000..5aa0491f
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/unrar.cpp
@@ -0,0 +1,279 @@
+/*
+ * unrar.cpp
+ * ---------
+ * Purpose: Implementation file for extracting modules from .rar archives
+ * 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 "unrar.h"
+
+#ifdef MPT_WITH_UNRAR
+
+#include "../common/mptFileIO.h"
+
+#if MPT_OS_WINDOWS
+ #include <windows.h>
+#else // !MPT_OS_WINDOWS
+ #ifdef _UNIX
+ #define MPT_UNRAR_UNIX_WAS_DEFINED
+ #else
+ #define _UNIX
+ #endif
+#endif // MPT_OS_WINDOWS
+
+#include "unrar/dll.hpp"
+
+#if !MPT_OS_WINDOWS
+ #ifndef MPT_UNRAR_UNIX_WAS_DEFINED
+ #undef _UNIX
+ #undef MPT_UNRAR_UNIX_WAS_DEFINED
+ #endif
+#endif // !MPT_OS_WINDOWS
+
+#endif // MPT_WITH_UNRAR
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#ifdef MPT_WITH_UNRAR
+
+
+struct RARHandle // RAII
+{
+ HANDLE rar = nullptr;
+ explicit RARHandle(HANDLE rar_) : rar(rar_) { return; }
+ RARHandle(const RARHandle &) = delete;
+ ~RARHandle() { if(rar) RARCloseArchive(rar); }
+
+ operator HANDLE () const { return rar; }
+};
+
+
+static int CALLBACK RARCallback(unsigned int msg, LPARAM userData, LPARAM p1, LPARAM p2)
+{
+ int result = 0;
+ CRarArchive *that = reinterpret_cast<CRarArchive *>(userData);
+ switch(msg)
+ {
+ case UCM_PROCESSDATA:
+ // Receive extracted data
+ that->RARCallbackProcessData(reinterpret_cast<const char *>(p1), p2);
+ result = 1;
+ break;
+ default:
+ // No support for passwords or volumes
+ result = -1;
+ break;
+ }
+ return result;
+}
+
+
+void CRarArchive::RARCallbackProcessData(const char * buf, std::size_t size)
+{
+ if(!captureCurrentFile)
+ {
+ return;
+ }
+ mpt::append(data, buf, buf + size);
+}
+
+
+CRarArchive::CRarArchive(FileReader &file)
+ : ArchiveBase(file)
+{
+ // NOTE:
+ // We open the archive twice, once for listing the contents in the
+ // constructor and once for actual decompression in ExtractFile.
+ // For solid archives, listing the contents via RAR_OM_LIST is way faster.
+ // The overhead of opening twice for non-solid archives is negligable if the
+ // archive does not contain a lot of files (and archives with large amount of
+ // files are pretty useless for OpenMPT anyway).
+
+ // Early reject files with no Rar! magic
+ // so that we do not have to instantiate OnDiskFileWrapper.
+ inFile.Rewind();
+ if(!inFile.ReadMagic("Rar!\x1A"))
+ {
+ return;
+ }
+ inFile.Rewind();
+
+ diskFile = std::make_unique<OnDiskFileWrapper>(inFile);
+ if(!diskFile->IsValid())
+ {
+ return;
+ }
+
+ std::wstring ArcName = diskFile->GetFilename().ToWide();
+ std::vector<wchar_t> ArcNameBuf(ArcName.c_str(), ArcName.c_str() + ArcName.length() + 1);
+ std::vector<wchar_t> CmtBuf(65536);
+ RAROpenArchiveDataEx ArchiveData = {};
+ ArchiveData.OpenMode = RAR_OM_LIST;
+ ArchiveData.ArcNameW = ArcNameBuf.data();
+ ArchiveData.CmtBufW = CmtBuf.data();
+ ArchiveData.CmtBufSize = static_cast<unsigned int>(CmtBuf.size());
+ RARHandle rar(RAROpenArchiveEx(&ArchiveData));
+ if(!rar)
+ {
+ Reset();
+ return;
+ }
+
+ switch(ArchiveData.CmtState)
+ {
+ case 1:
+ if(ArchiveData.CmtSize)
+ {
+ comment = mpt::ToUnicode(std::wstring(ArchiveData.CmtBufW, ArchiveData.CmtBufW + ArchiveData.CmtSize - 1));
+ break;
+ }
+ [[fallthrough]];
+ case 0:
+ comment = mpt::ustring();
+ break;
+ default:
+ Reset();
+ return;
+ break;
+ }
+
+ bool eof = false;
+ int RARResult = 0;
+ while(!eof)
+ {
+ RARHeaderDataEx HeaderData = {};
+ RARResult = RARReadHeaderEx(rar, &HeaderData);
+ switch(RARResult)
+ {
+ case ERAR_SUCCESS:
+ break;
+ case ERAR_END_ARCHIVE:
+ eof = true;
+ continue;
+ break;
+ default:
+ Reset();
+ return;
+ break;
+ }
+ ArchiveFileInfo fileInfo;
+ fileInfo.name = mpt::PathString::FromWide(HeaderData.FileNameW);
+ fileInfo.type = ArchiveFileType::Normal;
+ fileInfo.size = HeaderData.UnpSize;
+ contents.push_back(fileInfo);
+ RARResult = RARProcessFileW(rar, RAR_SKIP, NULL, NULL);
+ switch(RARResult)
+ {
+ case ERAR_SUCCESS:
+ break;
+ default:
+ Reset();
+ return;
+ break;
+ }
+ }
+
+}
+
+
+CRarArchive::~CRarArchive()
+{
+}
+
+
+bool CRarArchive::ExtractFile(std::size_t index)
+{
+
+ if(!diskFile || !diskFile->IsValid())
+ {
+ return false;
+ }
+
+ if(index >= contents.size())
+ {
+ return false;
+ }
+
+ std::wstring ArcName = diskFile->GetFilename().ToWide();
+ std::vector<wchar_t> ArcNameBuf(ArcName.c_str(), ArcName.c_str() + ArcName.length() + 1);
+ RAROpenArchiveDataEx ArchiveData = {};
+ ArchiveData.OpenMode = RAR_OM_EXTRACT;
+ ArchiveData.ArcNameW = ArcNameBuf.data();
+ ArchiveData.Callback = RARCallback;
+ ArchiveData.UserData = reinterpret_cast<LPARAM>(this);
+ RARHandle rar(RAROpenArchiveEx(&ArchiveData));
+ if(!rar)
+ {
+ ResetFile();
+ return false;
+ }
+
+ std::size_t i = 0;
+ int RARResult = 0;
+ bool eof = false;
+ while(!eof)
+ {
+ RARHeaderDataEx HeaderData = {};
+ RARResult = RARReadHeaderEx(rar, &HeaderData);
+ switch(RARResult)
+ {
+ case ERAR_SUCCESS:
+ break;
+ case ERAR_END_ARCHIVE:
+ eof = true;
+ continue;
+ break;
+ default:
+ ResetFile();
+ return false;
+ break;
+ }
+ captureCurrentFile = (i == index);
+ RARResult = RARProcessFileW(rar, captureCurrentFile ? RAR_TEST : RAR_SKIP, NULL, NULL);
+ switch(RARResult)
+ {
+ case ERAR_SUCCESS:
+ break;
+ default:
+ ResetFile();
+ return false;
+ break;
+ }
+ if(captureCurrentFile)
+ { // done
+ return true;
+ }
+ captureCurrentFile = false;
+ ++i;
+ }
+
+ return false;
+
+}
+
+
+void CRarArchive::Reset()
+{
+ captureCurrentFile = false;
+ comment = mpt::ustring();
+ contents = std::vector<ArchiveFileInfo>();
+ data = std::vector<char>();
+}
+
+
+void CRarArchive::ResetFile()
+{
+ captureCurrentFile = false;
+ data = std::vector<char>();
+}
+
+
+#endif // MPT_WITH_UNRAR
+
+
+OPENMPT_NAMESPACE_END
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/unrar.h b/Src/external_dependencies/openmpt-trunk/unarchiver/unrar.h
new file mode 100644
index 00000000..056a9475
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/unrar.h
@@ -0,0 +1,48 @@
+/*
+ * unrar.h
+ * -------
+ * Purpose: Header file for .rar loader
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#pragma once
+
+#include "openmpt/all/BuildSettings.hpp"
+
+#include "archive.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+#ifdef MPT_WITH_UNRAR
+
+class CRarArchive
+ : public ArchiveBase
+{
+
+protected:
+
+ std::unique_ptr<OnDiskFileWrapper> diskFile;
+ bool captureCurrentFile = false;
+
+public:
+ CRarArchive(FileReader &file);
+ ~CRarArchive() override;
+
+ bool ExtractFile(std::size_t index) override;
+
+public:
+
+ void RARCallbackProcessData(const char * data, std::size_t size);
+
+private:
+
+ void Reset();
+ void ResetFile();
+
+};
+
+#endif // MPT_WITH_UNRAR
+
+OPENMPT_NAMESPACE_END
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
diff --git a/Src/external_dependencies/openmpt-trunk/unarchiver/unzip.h b/Src/external_dependencies/openmpt-trunk/unarchiver/unzip.h
new file mode 100644
index 00000000..dc080624
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/unarchiver/unzip.h
@@ -0,0 +1,29 @@
+/*
+ * unzip.h
+ * -------
+ * Purpose: Header file for .zip loader
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+#pragma once
+
+#include "openmpt/all/BuildSettings.hpp"
+
+#include "archive.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+class CZipArchive : public ArchiveBase
+{
+protected:
+ void *zipFile;
+public:
+ CZipArchive(FileReader &file);
+ ~CZipArchive() override;
+public:
+ bool ExtractFile(std::size_t index) override;
+};
+
+OPENMPT_NAMESPACE_END