mirror of
https://github.com/ScrelliCopter/tmx2gba.git
synced 2025-02-21 03:29:25 +11:00
gzip support for miniz
This commit is contained in:
@@ -3,15 +3,16 @@ project(tmxlite VERSION 1.3.1)
|
|||||||
# includes the list of source files in the src directory
|
# includes the list of source files in the src directory
|
||||||
set(PROJECT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
set(PROJECT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
file(GLOB PROJECT_SRC ${PROJECT_DIR}/*.cpp)
|
file(GLOB PROJECT_SRC ${PROJECT_DIR}/*.cpp)
|
||||||
|
file(GLOB PROJECT_SRC_DETAIL ${PROJECT_DIR}/detail/*.cpp)
|
||||||
file(GLOB PROJECT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/tmxlite/*.hpp)
|
file(GLOB PROJECT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/tmxlite/*.hpp)
|
||||||
file(GLOB PROJECT_HEADERS_INL ${CMAKE_CURRENT_SOURCE_DIR}/include/tmxlite/*.inl)
|
file(GLOB PROJECT_HEADERS_INL ${CMAKE_CURRENT_SOURCE_DIR}/include/tmxlite/*.inl)
|
||||||
file(GLOB PROJECT_HEADERS_DETAIL ${CMAKE_CURRENT_SOURCE_DIR}/include/tmxlite/detail/*.hpp)
|
file(GLOB PROJECT_HEADERS_DETAIL ${CMAKE_CURRENT_SOURCE_DIR}/include/tmxlite/detail/*.hpp)
|
||||||
list(APPEND PROJECT_SRC ${PROJECT_HEADERS} ${PROJECT_HEADERS_INL} ${PROJECT_HEADERS_DETAIL})
|
list(APPEND PROJECT_SRC ${PROJECT_SRC_DETAIL} ${PROJECT_HEADERS} ${PROJECT_HEADERS_INL} ${PROJECT_HEADERS_DETAIL})
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} STATIC ${PROJECT_SRC})
|
add_library(${PROJECT_NAME} STATIC ${PROJECT_SRC})
|
||||||
|
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||||
CXX_STANDARD 14
|
CXX_STANDARD 20
|
||||||
CXX_STANDARD_REQUIRED ON)
|
CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||||
|
|||||||
39
ext/tmxlite/include/tmxlite/detail/gzip.hpp
Normal file
39
ext/tmxlite/include/tmxlite/detail/gzip.hpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// gzip.hpp - portable memory miniz based gzip reader
|
||||||
|
// SPDX-License-Identifier: Zlib
|
||||||
|
// SPDX-FileCopyrightText: (c) 2024 a dinosaur
|
||||||
|
|
||||||
|
#ifndef GZIP_HPP
|
||||||
|
#define GZIP_HPP
|
||||||
|
|
||||||
|
#include "miniz.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
|
|
||||||
|
class GZipReader
|
||||||
|
{
|
||||||
|
static constexpr uint8_t
|
||||||
|
FTEXT = 1, FHCRC = 1<<1, FEXTRA = 1<<2, FNAME = 1<<3, FCOMMENT = 1<<4;
|
||||||
|
|
||||||
|
static constexpr uint8_t XFL_BEST = 2, XFL_FASTEST = 4;
|
||||||
|
|
||||||
|
tinfl_decompressor mState;
|
||||||
|
std::span<const uint8_t>::iterator mIt;
|
||||||
|
|
||||||
|
size_t mSourceLen, mBytesRead;
|
||||||
|
uint32_t mModificationTime, mCrc, mInputSize, mComputedCrc;
|
||||||
|
uint16_t crc16;
|
||||||
|
uint8_t mFlags, mXflags, mOsId;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GZipReader() noexcept;
|
||||||
|
|
||||||
|
constexpr size_t SourceLength() const noexcept { return mSourceLen; }
|
||||||
|
constexpr uint32_t OutputLength() const noexcept { return mInputSize; }
|
||||||
|
|
||||||
|
bool OpenMemory(const std::span<const uint8_t> source) noexcept;
|
||||||
|
bool Read(std::span<uint8_t> out) noexcept;
|
||||||
|
bool Check() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif//GZIP_HPP
|
||||||
@@ -29,10 +29,14 @@ source distribution.
|
|||||||
#include "tmxlite/FreeFuncs.hpp"
|
#include "tmxlite/FreeFuncs.hpp"
|
||||||
#include "tmxlite/TileLayer.hpp"
|
#include "tmxlite/TileLayer.hpp"
|
||||||
#include "tmxlite/detail/Log.hpp"
|
#include "tmxlite/detail/Log.hpp"
|
||||||
|
#ifndef USE_ZLIB
|
||||||
|
# include "tmxlite/detail/gzip.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <pugixml.hpp>
|
#include <pugixml.hpp>
|
||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
using namespace tmx;
|
using namespace tmx;
|
||||||
|
|
||||||
@@ -140,8 +144,18 @@ void TileLayer::parseBase64(const pugi::xml_node& node)
|
|||||||
break;
|
break;
|
||||||
case CompressionType::GZip:
|
case CompressionType::GZip:
|
||||||
#ifndef USE_ZLIB
|
#ifndef USE_ZLIB
|
||||||
Logger::log("Library must be built with USE_ZLIB for GZip compression", Logger::Type::Error);
|
{
|
||||||
|
byteData.resize(expectedSize);
|
||||||
|
const auto source = std::span(reinterpret_cast<const uint8_t*>(dataString.data()), dataString.size());
|
||||||
|
|
||||||
|
GZipReader reader;
|
||||||
|
if (!reader.OpenMemory(source) || !reader.Read(byteData) || !reader.Check())
|
||||||
|
{
|
||||||
|
LOG("Failed to decompress layer data, node skipped.", Logger::Type::Error);
|
||||||
return {};
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
//[[fallthrough]];
|
//[[fallthrough]];
|
||||||
case CompressionType::Zlib:
|
case CompressionType::Zlib:
|
||||||
|
|||||||
125
ext/tmxlite/src/detail/gzip.cpp
Normal file
125
ext/tmxlite/src/detail/gzip.cpp
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
// gzip.cpp - portable memory miniz based gzip reader
|
||||||
|
// SPDX-License-Identifier: Zlib
|
||||||
|
// SPDX-FileCopyrightText: (c) 2024 a dinosaur
|
||||||
|
|
||||||
|
#include "tmxlite/detail/gzip.hpp"
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
|
||||||
|
GZipReader::GZipReader() noexcept :
|
||||||
|
mSourceLen(0), mBytesRead(0),
|
||||||
|
mModificationTime(0), mCrc(0), mInputSize(0), mComputedCrc(0),
|
||||||
|
crc16(0), mFlags(0), mXflags(0), mOsId(0)
|
||||||
|
{
|
||||||
|
tinfl_init(&mState);
|
||||||
|
mComputedCrc = static_cast<uint32_t>(mz_crc32(0, nullptr, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GZipReader::OpenMemory(const std::span<const uint8_t> source) noexcept
|
||||||
|
{
|
||||||
|
if (source.size() < 20)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto it = std::cbegin(source), end = std::cend(source);
|
||||||
|
|
||||||
|
constexpr uint8_t magic[2] = { 0x1F, 0x8B };
|
||||||
|
if (*it++ != magic[0] || *it++ != magic[1])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
constexpr uint8_t CM_DEFLATE = 8;
|
||||||
|
uint8_t compression = *it++;
|
||||||
|
if (compression != CM_DEFLATE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mFlags = *it++;
|
||||||
|
mModificationTime = *it++;
|
||||||
|
mModificationTime |= *it++ << 8;
|
||||||
|
mModificationTime |= *it++ << 16;
|
||||||
|
mModificationTime |= *it++ << 24;
|
||||||
|
mXflags = *it++;
|
||||||
|
mOsId = *it++;
|
||||||
|
|
||||||
|
if (mFlags & FEXTRA)
|
||||||
|
{
|
||||||
|
// Skip "extra" field
|
||||||
|
if (it + 2 >= end)
|
||||||
|
return false;
|
||||||
|
uint16_t extraLen = *it++;
|
||||||
|
extraLen = *it++ << 8;
|
||||||
|
if (it + extraLen >= end)
|
||||||
|
return false;
|
||||||
|
it += extraLen;
|
||||||
|
}
|
||||||
|
if (mFlags & FNAME)
|
||||||
|
{
|
||||||
|
// Skip null-terminated name string
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (++it == end)
|
||||||
|
return false;
|
||||||
|
} while (*it != '\0');
|
||||||
|
if (++it == end)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mFlags & FCOMMENT)
|
||||||
|
{
|
||||||
|
// Skip null-terminated comment string
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (++it == end)
|
||||||
|
return false;
|
||||||
|
} while (*it != '\0');
|
||||||
|
if (++it == end)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mFlags & FHCRC)
|
||||||
|
{
|
||||||
|
if (it + 2 >= end)
|
||||||
|
return false;
|
||||||
|
crc16 = *it++;
|
||||||
|
crc16 |= *it++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mIt = it;
|
||||||
|
mSourceLen = end - it - 8;
|
||||||
|
|
||||||
|
it += mSourceLen;
|
||||||
|
mCrc = *it++;
|
||||||
|
mCrc |= *it++ << 8;
|
||||||
|
mCrc |= *it++ << 16;
|
||||||
|
mCrc |= *it++ << 24;
|
||||||
|
mInputSize = *it++;
|
||||||
|
mInputSize |= *it++ << 8;
|
||||||
|
mInputSize |= *it++ << 16;
|
||||||
|
mInputSize |= *it++ << 24;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GZipReader::Read(std::span<uint8_t> out) noexcept
|
||||||
|
{
|
||||||
|
size_t outLen = out.size();
|
||||||
|
auto res = tinfl_decompress(&mState,
|
||||||
|
static_cast<const mz_uint8*>(&*mIt), &mSourceLen,
|
||||||
|
static_cast<mz_uint8*>(out.data()), static_cast<mz_uint8*>(out.data()), &outLen,
|
||||||
|
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
|
||||||
|
if (res != TINFL_STATUS_DONE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mIt += outLen;
|
||||||
|
mBytesRead += outLen;
|
||||||
|
mComputedCrc = static_cast<uint32_t>(mz_crc32(static_cast<mz_ulong>(mComputedCrc), out.data(), outLen));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GZipReader::Check() const noexcept
|
||||||
|
{
|
||||||
|
if (mComputedCrc != mCrc)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (static_cast<uint32_t>(mBytesRead & UINT32_MAX) != mInputSize)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user