diff --git a/src/tmxmap.cpp b/src/tmxmap.cpp index 3d91b0e..3248963 100644 --- a/src/tmxmap.cpp +++ b/src/tmxmap.cpp @@ -37,32 +37,39 @@ enum class Compression { NONE, GZIP, ZLIB, ZSTD, INVALID }; } -[[nodiscard]] static bool Decompress(Compression compression, std::span out, const std::string_view decoded) +[[nodiscard]] static bool DecodeBase64( + std::vector& out, size_t numTiles, + const std::string_view base64, Compression compression) { - //FIXME: lmao what is big endian + auto decoded = base64_decode(TrimWhitespace(base64)); + if (decoded.empty()) { return false; } const std::span source(reinterpret_cast(decoded.data()), decoded.size()); - std::span destination(reinterpret_cast(out.data()), sizeof(uint32_t) * out.size()); + //FIXME: lmao what is big endian switch (compression) { case Compression::GZIP: #ifndef USE_ZLIB { + out.resize(numTiles); GZipReader reader; - if (!reader.OpenMemory(source) || !reader.Read(destination) || !reader.Check()) + if (!reader.OpenMemory(source) || + !reader.Read({ reinterpret_cast(out.data()), sizeof(uint32_t) * numTiles }) || + !reader.Check()) return false; return true; } #endif case Compression::ZLIB: { + out.resize(numTiles); // Decompress gzip/zlib data with zlib/zlib data miniz z_stream s = { .next_in = const_cast(source.data()), .avail_in = static_cast(source.size()), - .next_out = static_cast(destination.data()), - .avail_out = static_cast(destination.size()), + .next_out = reinterpret_cast(out.data()), + .avail_out = static_cast(sizeof(uint32_t) * numTiles), .zalloc = nullptr, .zfree = nullptr, .opaque = nullptr }; #ifdef USE_ZLIB @@ -78,16 +85,29 @@ enum class Compression { NONE, GZIP, ZLIB, ZSTD, INVALID }; } case Compression::ZSTD: { + out.resize(numTiles); auto res = ZSTD_decompress( - destination.data(), destination.size(), + reinterpret_cast(out.data()), + sizeof(uint32_t) * numTiles, source.data(), source.size()); return !ZSTD_isError(res); } - // Define all labels to shut up linters case Compression::NONE: + { + out.reserve(numTiles); + const auto end = source.end(); + for (auto it = source.begin(); it < end - 3;) + { + uint32_t tile = *it++; + tile |= static_cast(*it++) << 8u; + tile |= static_cast(*it++) << 16u; + tile |= static_cast(*it++) << 24u; + out.emplace_back(tile); + } + return true; + } case Compression::INVALID: - //default: - return false; + default: return false; } } @@ -123,32 +143,13 @@ void TmxMap::ReadLayer(const pugi::xml_node& xNode) auto encoding = EncodingFromStr(xData.attribute("encoding").value()); if (encoding == Encoding::BASE64) { - // Decode base64 string - auto decoded = base64_decode(TrimWhitespace(xData.child_value())); - if (decoded.empty()) + const std::string_view base64(xData.child_value()); + if (base64.empty()) return; - auto compression = CompressionFromStr(xData.attribute("compression").value()); - if (compression == Compression::GZIP || compression == Compression::ZLIB || compression == Compression::ZSTD) - { - tileDat.resize(numTiles); - if (!Decompress(compression, tileDat, decoded)) - return; - } - else if (compression == Compression::NONE) - { - tileDat.reserve(numTiles); - const auto end = decoded.end(); - for (auto it = decoded.begin(); it < end - 3;) - { - uint32_t tile = static_cast(static_cast(*it++)); - tile |= static_cast(static_cast(*it++)) << 8u; - tile |= static_cast(static_cast(*it++)) << 16u; - tile |= static_cast(static_cast(*it++)) << 24u; - tileDat.emplace_back(tile); - } - } - else { return; } + const auto compression = CompressionFromStr(xData.attribute("compression").value()); + if (compression == Compression::INVALID || !DecodeBase64(tileDat, numTiles, base64, compression)) + return; } else if (encoding == Encoding::XML) {