diff options
Diffstat (limited to 'archived/projt-launcher/launcher/GZip.cpp')
| -rw-r--r-- | archived/projt-launcher/launcher/GZip.cpp | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/archived/projt-launcher/launcher/GZip.cpp b/archived/projt-launcher/launcher/GZip.cpp new file mode 100644 index 0000000000..0df1e18638 --- /dev/null +++ b/archived/projt-launcher/launcher/GZip.cpp @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-3.0-only +// SPDX-FileCopyrightText: 2026 Project Tick +// SPDX-FileContributor: Project Tick Team +/* + * ProjT Launcher - Minecraft Launcher + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +/* === Upstream License Block (Do Not Modify) ============================== + * + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ======================================================================== */ +#include "GZip.h" +#include <ptlibzippy.h> +#include <QByteArray> +#include <QDebug> +#include <QFile> + +bool GZip::unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes) +{ + if (compressedBytes.size() == 0) + { + uncompressedBytes = compressedBytes; + return true; + } + + unsigned uncompLength = compressedBytes.size(); + uncompressedBytes.clear(); + uncompressedBytes.resize(uncompLength); + + z_stream strm; + memset(&strm, 0, sizeof(strm)); + strm.next_in = (Bytef*)compressedBytes.data(); + strm.avail_in = compressedBytes.size(); + + bool done = false; + + if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) + { + return false; + } + + int err = Z_OK; + + while (!done) + { + // If our output buffer is too small + if (strm.total_out >= uncompLength) + { + uncompressedBytes.resize(uncompLength * 2); + uncompLength *= 2; + } + + strm.next_out = reinterpret_cast<Bytef*>((uncompressedBytes.data() + strm.total_out)); + strm.avail_out = uncompLength - strm.total_out; + + // Inflate another chunk. + err = inflate(&strm, Z_SYNC_FLUSH); + if (err == Z_STREAM_END) + done = true; + else if (err != Z_OK) + { + break; + } + } + + if (inflateEnd(&strm) != Z_OK || !done) + { + return false; + } + + uncompressedBytes.resize(strm.total_out); + return true; +} + +bool GZip::zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes) +{ + if (uncompressedBytes.size() == 0) + { + compressedBytes = uncompressedBytes; + return true; + } + + unsigned compLength = qMin(uncompressedBytes.size(), 16); + compressedBytes.clear(); + compressedBytes.resize(compLength); + + z_stream zs; + memset(&zs, 0, sizeof(zs)); + + if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (16 + MAX_WBITS), 8, Z_DEFAULT_STRATEGY) != Z_OK) + { + return false; + } + + zs.next_in = (Bytef*)uncompressedBytes.data(); + zs.avail_in = uncompressedBytes.size(); + + int ret; + compressedBytes.resize(uncompressedBytes.size()); + + unsigned offset = 0; + unsigned temp = 0; + do + { + auto remaining = compressedBytes.size() - offset; + if (remaining < 1) + { + compressedBytes.resize(compressedBytes.size() * 2); + } + zs.next_out = reinterpret_cast<Bytef*>((compressedBytes.data() + offset)); + temp = zs.avail_out = compressedBytes.size() - offset; + ret = deflate(&zs, Z_FINISH); + offset += temp - zs.avail_out; + } + while (ret == Z_OK); + + compressedBytes.resize(offset); + + if (deflateEnd(&zs) != Z_OK) + { + return false; + } + + if (ret != Z_STREAM_END) + { + return false; + } + return true; +} + +int inf(QFile* source, std::function<bool(const QByteArray&)> handleBlock) +{ + constexpr auto CHUNK = 16384; + int ret; + unsigned have; + z_stream strm; + memset(&strm, 0, sizeof(strm)); + char in[CHUNK]; + unsigned char out[CHUNK]; + + ret = inflateInit2(&strm, (16 + MAX_WBITS)); + if (ret != Z_OK) + return ret; + + /* decompress until deflate stream ends or end of file */ + do + { + strm.avail_in = source->read(in, CHUNK); + if (source->error()) + { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + if (strm.avail_in == 0) + break; + strm.next_in = reinterpret_cast<Bytef*>(in); + + /* run inflate() on input until output buffer not full */ + do + { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) + { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; + [[fallthrough]]; + case Z_DATA_ERROR: + case Z_MEM_ERROR: (void)inflateEnd(&strm); return ret; + } + have = CHUNK - strm.avail_out; + if (!handleBlock(QByteArray(reinterpret_cast<const char*>(out), have))) + { + (void)inflateEnd(&strm); + return Z_OK; + } + } + while (strm.avail_out == 0); + + /* done when inflate() says it's done */ + } + while (ret != Z_STREAM_END); + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +QString zerr(int ret) +{ + switch (ret) + { + case Z_ERRNO: return QObject::tr("error handling file"); + case Z_STREAM_ERROR: return QObject::tr("invalid compression level"); + case Z_DATA_ERROR: return QObject::tr("invalid or incomplete deflate data"); + case Z_MEM_ERROR: return QObject::tr("out of memory"); + case Z_VERSION_ERROR: return QObject::tr("zlib version mismatch!"); + } + return {}; +} + +QString GZip::readGzFileByBlocks(QFile* source, std::function<bool(const QByteArray&)> handleBlock) +{ + auto ret = inf(source, handleBlock); + return zerr(ret); +} |
