diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.cpp')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/unarchiver/ungzip.cpp | 147 |
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 |