From 2979dc5b6b1e5e0df93acd02c28c5d87344da9b1 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 6 May 2020 22:31:50 +0200 Subject: [PATCH] Fix compatibility of MapBlock decoding also properly drop support for version < 22, which hasn't worked in years --- BlockDecoder.cpp | 41 ++++++++++++++++++++++++++--------------- include/BlockDecoder.h | 2 +- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/BlockDecoder.cpp b/BlockDecoder.cpp index 3b6c5b1..2b6065d 100644 --- a/BlockDecoder.cpp +++ b/BlockDecoder.cpp @@ -11,20 +11,18 @@ static inline uint16_t readU16(const unsigned char *data) return data[0] << 8 | data[1]; } -static int readBlockContent(const unsigned char *mapData, u8 version, unsigned int datapos) +static int readBlockContent(const unsigned char *mapData, u8 contentWidth, unsigned int datapos) { - if (version >= 24) { + if (contentWidth == 2) { size_t index = datapos << 1; return (mapData[index] << 8) | mapData[index + 1]; - } else if (version >= 20) { - if (mapData[datapos] <= 0x80) - return mapData[datapos]; + } else { + u8 param = mapData[datapos]; + if (param <= 0x7f) + return param; else - return (int(mapData[datapos]) << 4) | (int(mapData[datapos + 0x2000]) >> 4); + return (int(param) << 4) | (int(mapData[datapos + 0x2000]) >> 4); } - std::ostringstream oss; - oss << "Unsupported map version " << version; - throw std::runtime_error(oss.str()); } BlockDecoder::BlockDecoder() @@ -39,6 +37,7 @@ void BlockDecoder::reset() m_nameMap.clear(); m_version = 0; + m_contentWidth = 0; m_mapData = ustring(); } @@ -50,16 +49,30 @@ void BlockDecoder::decode(const ustring &datastr) uint8_t version = data[0]; //uint8_t flags = data[1]; + if (version < 22) { + std::ostringstream oss; + oss << "Unsupported map version " << (int)version; + throw std::runtime_error(oss.str()); + } m_version = version; size_t dataOffset = 0; if (version >= 27) - dataOffset = 6; - else if (version >= 22) dataOffset = 4; else dataOffset = 2; + uint8_t contentWidth = data[dataOffset]; + dataOffset++; + uint8_t paramsWidth = data[dataOffset]; + dataOffset++; + if (contentWidth != 1 && contentWidth != 2) + throw std::runtime_error("unsupported map version (contentWidth)"); + if (paramsWidth != 2) + throw std::runtime_error("unsupported map version (paramsWidth)"); + m_contentWidth = contentWidth; + + ZlibDecompressor decompressor(data, length); decompressor.setSeekPos(dataOffset); m_mapData = decompressor.decompress(); @@ -67,8 +80,6 @@ void BlockDecoder::decode(const ustring &datastr) dataOffset = decompressor.seekPos(); // Skip unused data - if (version <= 21) - dataOffset += 2; if (version == 23) dataOffset += 1; if (version == 24) { @@ -92,7 +103,7 @@ void BlockDecoder::decode(const ustring &datastr) dataOffset += 4; // Skip timestamp // Read mapping - if (version >= 22) { + { dataOffset++; // mapping version uint16_t numMappings = readU16(data + dataOffset); dataOffset += 2; @@ -130,7 +141,7 @@ bool BlockDecoder::isEmpty() const std::string BlockDecoder::getNode(u8 x, u8 y, u8 z) const { unsigned int position = x + (y << 4) + (z << 8); - int content = readBlockContent(m_mapData.c_str(), m_version, position); + int content = readBlockContent(m_mapData.c_str(), m_contentWidth, position); if (content == m_blockAirId || content == m_blockIgnoreId) return ""; NameMap::const_iterator it = m_nameMap.find(content); diff --git a/include/BlockDecoder.h b/include/BlockDecoder.h index 38e3d5f..c9ecc1e 100644 --- a/include/BlockDecoder.h +++ b/include/BlockDecoder.h @@ -20,7 +20,7 @@ private: int m_blockAirId; int m_blockIgnoreId; - u8 m_version; + u8 m_version, m_contentWidth; ustring m_mapData; };