mirror of
https://github.com/ScrelliCopter/tmx2gba.git
synced 2025-02-21 03:29:25 +11:00
replace rapidxml uses with pugixml
This commit is contained in:
194
src/tmxmap.cpp
194
src/tmxmap.cpp
@@ -2,14 +2,70 @@
|
||||
// SPDX-FileCopyrightText: (c) 2015-2024 a dinosaur
|
||||
|
||||
#include "tmxmap.hpp"
|
||||
#include "base64.h"
|
||||
#include <pugixml.hpp>
|
||||
#include <base64.h>
|
||||
#ifdef USE_ZLIB
|
||||
# include <zlib.h>
|
||||
#else
|
||||
# include "gzip.hpp"
|
||||
#endif
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <cerrno>
|
||||
#include <optional>
|
||||
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] static std::optional<T> IntFromStr(const char* str, int base = 0) noexcept
|
||||
{
|
||||
using std::numeric_limits;
|
||||
|
||||
errno = 0;
|
||||
char* end = nullptr;
|
||||
long res = std::strtol(str, &end, base);
|
||||
if (errno == ERANGE) { return std::nullopt; }
|
||||
if (str == end) { return std::nullopt; }
|
||||
if constexpr (sizeof(long) > sizeof(T))
|
||||
{
|
||||
if (res > numeric_limits<T>::max() || res < numeric_limits<T>::min())
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return static_cast<T>(res);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] static std::optional<T> UintFromStr(const char* str, int base = 0) noexcept
|
||||
{
|
||||
using std::numeric_limits;
|
||||
|
||||
char* end = nullptr;
|
||||
errno = 0;
|
||||
unsigned long res = std::strtoul(str, &end, base);
|
||||
if (errno == ERANGE) { return std::nullopt; }
|
||||
if (str == end) { return std::nullopt; }
|
||||
if constexpr (numeric_limits<unsigned long>::max() > numeric_limits<T>::max())
|
||||
{
|
||||
if (res > numeric_limits<T>::max()) { return std::nullopt; }
|
||||
}
|
||||
|
||||
return static_cast<T>(res);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] static std::optional<T> FloatFromStr(const char* str) noexcept
|
||||
{
|
||||
char* end = nullptr;
|
||||
T res;
|
||||
errno = 0;
|
||||
if constexpr (std::is_same_v<T, float>)
|
||||
res = std::strtof(str, &end);
|
||||
else
|
||||
res = static_cast<T>(std::strtod(str, &end));
|
||||
if (errno == ERANGE) { return std::nullopt; }
|
||||
if (str == end) { return std::nullopt; }
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool TmxMap::Decode(std::span<uint32_t> out, const std::string_view base64)
|
||||
@@ -37,132 +93,78 @@ bool TmxMap::Decode(std::span<uint32_t> out, const std::string_view base64)
|
||||
return res >= 0;
|
||||
}
|
||||
|
||||
void TmxMap::ReadTileset(rapidxml::xml_node<>* aXNode)
|
||||
void TmxMap::ReadTileset(const pugi::xml_node& xNode)
|
||||
{
|
||||
std::string_view name, source;
|
||||
uint32_t firstGid = 0, lastGid = 0;
|
||||
std::string_view name = xNode.attribute("name").value();
|
||||
std::string_view source = xNode.attribute("source").value();
|
||||
|
||||
// Read name
|
||||
auto xAttrib = aXNode->first_attribute("name");
|
||||
if (xAttrib != nullptr)
|
||||
name = xAttrib->value();
|
||||
|
||||
// Read source
|
||||
xAttrib = aXNode->first_attribute("source");
|
||||
if (xAttrib != nullptr)
|
||||
source = xAttrib->value();
|
||||
|
||||
// Read first global ID
|
||||
xAttrib = aXNode->first_attribute("firstgid");
|
||||
if (xAttrib != nullptr)
|
||||
firstGid = static_cast<uint32_t>(std::stoul(xAttrib->value()));
|
||||
|
||||
// Read last global ID
|
||||
xAttrib = aXNode->first_attribute("lastgid");
|
||||
if (xAttrib)
|
||||
lastGid = static_cast<uint32_t>(std::stoul(xAttrib->value()));
|
||||
auto firstGid = UintFromStr<uint32_t>(xNode.attribute("firstgid").value()).value_or(0);
|
||||
auto lastGid = UintFromStr<uint32_t>(xNode.attribute("lastgid").value()).value_or(0);
|
||||
|
||||
mTilesets.emplace_back(TmxTileset(name, source, firstGid, lastGid));
|
||||
}
|
||||
|
||||
void TmxMap::ReadLayer(rapidxml::xml_node<>* aXNode)
|
||||
void TmxMap::ReadLayer(const pugi::xml_node& xNode)
|
||||
{
|
||||
std::string_view name;
|
||||
int width = 0, height = 0;
|
||||
std::string_view name = xNode.attribute("name").value();
|
||||
|
||||
// Read name
|
||||
auto xAttrib = aXNode->first_attribute("name");
|
||||
if (xAttrib != nullptr)
|
||||
name = xAttrib->value();
|
||||
|
||||
// Read width
|
||||
xAttrib = aXNode->first_attribute("width");
|
||||
if (xAttrib != nullptr)
|
||||
width = std::stoi(xAttrib->value());
|
||||
|
||||
// Read height
|
||||
xAttrib = aXNode->first_attribute("height");
|
||||
if (xAttrib != nullptr)
|
||||
height = std::stoi(xAttrib->value());
|
||||
|
||||
// Read tile data
|
||||
auto xData = aXNode->first_node("data");
|
||||
if (xData == nullptr)
|
||||
// Read layer size
|
||||
int width = IntFromStr<int>(xNode.attribute("width").value()).value_or(0);
|
||||
int height = IntFromStr<int>(xNode.attribute("height").value()).value_or(0);
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
// Read tile data
|
||||
auto xData = xNode.child("data");
|
||||
if (xData.empty() || xData.first_child().empty())
|
||||
return;
|
||||
// TODO: don't assume base64
|
||||
std::vector<uint32_t> tileDat(width * height);
|
||||
if (!Decode(tileDat, xData->value()))
|
||||
if (!Decode(tileDat, xData.child_value()))
|
||||
return;
|
||||
|
||||
mLayers.emplace_back(TmxLayer(width, height, name, std::move(tileDat)));
|
||||
}
|
||||
|
||||
void TmxMap::ReadObjects(rapidxml::xml_node<>* aXNode)
|
||||
void TmxMap::ReadObjects(const pugi::xml_node& xNode)
|
||||
{
|
||||
for (auto xNode = aXNode->first_node(); xNode != nullptr; xNode = xNode->next_sibling())
|
||||
for (const auto it : xNode.children("object"))
|
||||
{
|
||||
if (strcmp(xNode->name(), "object") != 0)
|
||||
continue;
|
||||
std::string_view name = it.attribute("name").value();
|
||||
|
||||
std::string_view name;
|
||||
float x = 0.0f, y = 0.0f;
|
||||
|
||||
// Read name
|
||||
auto xAttrib = xNode->first_attribute("name");
|
||||
if (xAttrib != nullptr)
|
||||
name = xAttrib->value();
|
||||
|
||||
// Read X pos
|
||||
xAttrib = xNode->first_attribute("x");
|
||||
if (xAttrib != nullptr)
|
||||
x = std::stof(xAttrib->value());
|
||||
|
||||
// Read Y pos
|
||||
xAttrib = xNode->first_attribute("y");
|
||||
if (xAttrib != nullptr)
|
||||
y = std::stof(xAttrib->value());
|
||||
// Read position
|
||||
auto x = FloatFromStr<float>(it.attribute("x").value()).value_or(0.0f);
|
||||
auto y = FloatFromStr<float>(it.attribute("y").value()).value_or(0.0f);
|
||||
|
||||
mObjects.emplace_back(TmxObject(name, x, y));
|
||||
}
|
||||
}
|
||||
|
||||
bool TmxMap::Load(const std::string_view inPath)
|
||||
bool TmxMap::Load(const std::string& inPath)
|
||||
{
|
||||
// Read file into a buffer
|
||||
auto inFile = std::ifstream(inPath);
|
||||
std::stringstream buf;
|
||||
buf << inFile.rdbuf();
|
||||
std::string strXml = buf.str();
|
||||
buf.clear();
|
||||
|
||||
// Parse document
|
||||
rapidxml::xml_document<> xDoc;
|
||||
xDoc.parse<0>(const_cast<char*>(strXml.c_str()));
|
||||
|
||||
// Get map node
|
||||
auto xMap = xDoc.first_node("map");
|
||||
if (xMap == nullptr)
|
||||
pugi::xml_document xDoc;
|
||||
auto res = xDoc.load_file(inPath.c_str());
|
||||
if (res.status != pugi::xml_parse_status::status_ok)
|
||||
return false;
|
||||
|
||||
// Get map node
|
||||
auto xMap = xDoc.child("map");
|
||||
//if (xMap == nullptr)
|
||||
// return false;
|
||||
|
||||
// Read map attribs
|
||||
rapidxml::xml_attribute<>* xAttrib = nullptr;
|
||||
if ((xAttrib = xMap->first_attribute("width")) != nullptr)
|
||||
mWidth = std::stoi(xAttrib->value());
|
||||
if ((xAttrib = xMap->first_attribute("height")) != nullptr)
|
||||
mHeight = std::stoi(xAttrib->value());
|
||||
mWidth = IntFromStr<int>(xMap.attribute("width").value()).value_or(0);
|
||||
mHeight = IntFromStr<int>(xMap.attribute("height").value()).value_or(0);
|
||||
|
||||
// Read nodes
|
||||
for (auto xNode = xMap->first_node(); xNode != nullptr; xNode = xNode->next_sibling())
|
||||
//for (auto it = xMap.begin(); it != xMap.end(); ++it)
|
||||
for (auto it : xMap.children())
|
||||
{
|
||||
// Read layer nodes
|
||||
const auto xName = xNode->name();
|
||||
if (std::strcmp(xName, "layer") == 0)
|
||||
ReadLayer(xNode);
|
||||
else if (std::strcmp(xName, "tileset") == 0)
|
||||
ReadTileset(xNode);
|
||||
else if (std::strcmp(xName, "objectgroup") == 0)
|
||||
ReadObjects(xNode);
|
||||
std::string_view name(it.name());
|
||||
if (!name.compare("layer")) { ReadLayer(it); }
|
||||
else if (!name.compare("tileset")) { ReadTileset(it); }
|
||||
else if (!name.compare("objectgroup")) { ReadObjects(it); }
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user