aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.cpp')
-rw-r--r--Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.cpp147
1 files changed, 147 insertions, 0 deletions
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