1
0
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:
2024-04-10 06:31:43 +10:00
parent c2e9f5c974
commit e6bb098e15
14 changed files with 116 additions and 3499 deletions

View File

@@ -41,7 +41,6 @@ else()
endif()
add_subdirectory(ext/base64)
add_subdirectory(ext/rapidxml)
# Main tmx2gba sources
add_subdirectory(src)

View File

@@ -1,4 +0,0 @@
add_library(rapidxml INTERFACE)
add_library(External::rapidxml ALIAS rapidxml)
target_include_directories(rapidxml
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -1,52 +0,0 @@
Use of this software is granted under one of the following two licenses,
to be chosen freely by the user.
1. Boost Software License - Version 1.0 - August 17th, 2003
===============================================================================
Copyright (c) 2006, 2007 Marcin Kalicinski
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
2. The MIT License
===============================================================================
Copyright (c) 2006, 2007 Marcin Kalicinski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@@ -1,174 +0,0 @@
#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED
#define RAPIDXML_ITERATORS_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_iterators.hpp This file contains rapidxml iterators
#include "rapidxml.hpp"
namespace rapidxml
{
//! Iterator of child nodes of xml_node
template<class Ch>
class node_iterator
{
public:
typedef typename xml_node<Ch> value_type;
typedef typename xml_node<Ch> &reference;
typedef typename xml_node<Ch> *pointer;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
node_iterator()
: m_node(0)
{
}
node_iterator(xml_node<Ch> *node)
: m_node(node->first_node())
{
}
reference operator *() const
{
assert(m_node);
return *m_node;
}
pointer operator->() const
{
assert(m_node);
return m_node;
}
node_iterator& operator++()
{
assert(m_node);
m_node = m_node->next_sibling();
return *this;
}
node_iterator operator++(int)
{
node_iterator tmp = *this;
++this;
return tmp;
}
node_iterator& operator--()
{
assert(m_node && m_node->previous_sibling());
m_node = m_node->previous_sibling();
return *this;
}
node_iterator operator--(int)
{
node_iterator tmp = *this;
++this;
return tmp;
}
bool operator ==(const node_iterator<Ch> &rhs)
{
return m_node == rhs.m_node;
}
bool operator !=(const node_iterator<Ch> &rhs)
{
return m_node != rhs.m_node;
}
private:
xml_node<Ch> *m_node;
};
//! Iterator of child attributes of xml_node
template<class Ch>
class attribute_iterator
{
public:
typedef typename xml_attribute<Ch> value_type;
typedef typename xml_attribute<Ch> &reference;
typedef typename xml_attribute<Ch> *pointer;
typedef std::ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
attribute_iterator()
: m_attribute(0)
{
}
attribute_iterator(xml_node<Ch> *node)
: m_attribute(node->first_attribute())
{
}
reference operator *() const
{
assert(m_attribute);
return *m_attribute;
}
pointer operator->() const
{
assert(m_attribute);
return m_attribute;
}
attribute_iterator& operator++()
{
assert(m_attribute);
m_attribute = m_attribute->next_attribute();
return *this;
}
attribute_iterator operator++(int)
{
attribute_iterator tmp = *this;
++this;
return tmp;
}
attribute_iterator& operator--()
{
assert(m_attribute && m_attribute->previous_attribute());
m_attribute = m_attribute->previous_attribute();
return *this;
}
attribute_iterator operator--(int)
{
attribute_iterator tmp = *this;
++this;
return tmp;
}
bool operator ==(const attribute_iterator<Ch> &rhs)
{
return m_attribute == rhs.m_attribute;
}
bool operator !=(const attribute_iterator<Ch> &rhs)
{
return m_attribute != rhs.m_attribute;
}
private:
xml_attribute<Ch> *m_attribute;
};
}
#endif

View File

@@ -1,421 +0,0 @@
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
#define RAPIDXML_PRINT_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
#include "rapidxml.hpp"
// Only include streams if not disabled
#ifndef RAPIDXML_NO_STREAMS
#include <ostream>
#include <iterator>
#endif
namespace rapidxml
{
///////////////////////////////////////////////////////////////////////
// Printing flags
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
///////////////////////////////////////////////////////////////////////
// Internal
//! \cond internal
namespace internal
{
///////////////////////////////////////////////////////////////////////////
// Internal character operations
// Copy characters from given range to given output iterator
template<class OutIt, class Ch>
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
{
while (begin != end)
*out++ = *begin++;
return out;
}
// Copy characters from given range to given output iterator and expand
// characters into references (&lt; &gt; &apos; &quot; &amp;)
template<class OutIt, class Ch>
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
{
while (begin != end)
{
if (*begin == noexpand)
{
*out++ = *begin; // No expansion, copy character
}
else
{
switch (*begin)
{
case Ch('<'):
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('>'):
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('\''):
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
break;
case Ch('"'):
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('&'):
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
break;
default:
*out++ = *begin; // No expansion, copy character
}
}
++begin; // Step to next character
}
return out;
}
// Fill given output iterator with repetitions of the same character
template<class OutIt, class Ch>
inline OutIt fill_chars(OutIt out, int n, Ch ch)
{
for (int i = 0; i < n; ++i)
*out++ = ch;
return out;
}
// Find character
template<class Ch, Ch ch>
inline bool find_char(const Ch *begin, const Ch *end)
{
while (begin != end)
if (*begin++ == ch)
return true;
return false;
}
///////////////////////////////////////////////////////////////////////////
// Internal printing operations
// Print node
template<class OutIt, class Ch>
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
// Print proper node type
switch (node->type())
{
// Document
case node_document:
out = print_children(out, node, flags, indent);
break;
// Element
case node_element:
out = print_element_node(out, node, flags, indent);
break;
// Data
case node_data:
out = print_data_node(out, node, flags, indent);
break;
// CDATA
case node_cdata:
out = print_cdata_node(out, node, flags, indent);
break;
// Declaration
case node_declaration:
out = print_declaration_node(out, node, flags, indent);
break;
// Comment
case node_comment:
out = print_comment_node(out, node, flags, indent);
break;
// Doctype
case node_doctype:
out = print_doctype_node(out, node, flags, indent);
break;
// Pi
case node_pi:
out = print_pi_node(out, node, flags, indent);
break;
// Unknown
default:
assert(0);
break;
}
// If indenting not disabled, add line break after node
if (!(flags & print_no_indenting))
*out = Ch('\n'), ++out;
// Return modified iterator
return out;
}
// Print children of the node
template<class OutIt, class Ch>
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
out = print_node(out, child, flags, indent);
return out;
}
// Print attributes of the node
template<class OutIt, class Ch>
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
{
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
{
if (attribute->name() && attribute->value())
{
// Print attribute name
*out = Ch(' '), ++out;
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
*out = Ch('='), ++out;
// Print attribute value using appropriate quote type
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
{
*out = Ch('\''), ++out;
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
*out = Ch('\''), ++out;
}
else
{
*out = Ch('"'), ++out;
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
*out = Ch('"'), ++out;
}
}
}
return out;
}
// Print data node
template<class OutIt, class Ch>
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_data);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
return out;
}
// Print data node
template<class OutIt, class Ch>
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_cdata);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'); ++out;
*out = Ch('!'); ++out;
*out = Ch('['); ++out;
*out = Ch('C'); ++out;
*out = Ch('D'); ++out;
*out = Ch('A'); ++out;
*out = Ch('T'); ++out;
*out = Ch('A'); ++out;
*out = Ch('['); ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch(']'); ++out;
*out = Ch(']'); ++out;
*out = Ch('>'); ++out;
return out;
}
// Print element node
template<class OutIt, class Ch>
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_element);
// Print element name and attributes, if any
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
out = print_attributes(out, node, flags);
// If node is childless
if (node->value_size() == 0 && !node->first_node())
{
// Print childless node tag ending
*out = Ch('/'), ++out;
*out = Ch('>'), ++out;
}
else
{
// Print normal node tag ending
*out = Ch('>'), ++out;
// Test if node contains a single data node only (and no other nodes)
xml_node<Ch> *child = node->first_node();
if (!child)
{
// If node has no children, only print its value without indenting
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
}
else if (child->next_sibling() == 0 && child->type() == node_data)
{
// If node has a sole data child, only print its value without indenting
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
}
else
{
// Print all children with full indenting
if (!(flags & print_no_indenting))
*out = Ch('\n'), ++out;
out = print_children(out, node, flags, indent + 1);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
}
// Print node end
*out = Ch('<'), ++out;
*out = Ch('/'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
*out = Ch('>'), ++out;
}
return out;
}
// Print declaration node
template<class OutIt, class Ch>
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
// Print declaration start
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('?'), ++out;
*out = Ch('x'), ++out;
*out = Ch('m'), ++out;
*out = Ch('l'), ++out;
// Print attributes
out = print_attributes(out, node, flags);
// Print declaration end
*out = Ch('?'), ++out;
*out = Ch('>'), ++out;
return out;
}
// Print comment node
template<class OutIt, class Ch>
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_comment);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('!'), ++out;
*out = Ch('-'), ++out;
*out = Ch('-'), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('-'), ++out;
*out = Ch('-'), ++out;
*out = Ch('>'), ++out;
return out;
}
// Print doctype node
template<class OutIt, class Ch>
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_doctype);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('!'), ++out;
*out = Ch('D'), ++out;
*out = Ch('O'), ++out;
*out = Ch('C'), ++out;
*out = Ch('T'), ++out;
*out = Ch('Y'), ++out;
*out = Ch('P'), ++out;
*out = Ch('E'), ++out;
*out = Ch(' '), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('>'), ++out;
return out;
}
// Print pi node
template<class OutIt, class Ch>
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_pi);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('?'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
*out = Ch(' '), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('?'), ++out;
*out = Ch('>'), ++out;
return out;
}
}
//! \endcond
///////////////////////////////////////////////////////////////////////////
// Printing
//! Prints XML to given output iterator.
//! \param out Output iterator to print to.
//! \param node Node to be printed. Pass xml_document to print entire document.
//! \param flags Flags controlling how XML is printed.
//! \return Output iterator pointing to position immediately after last character of printed text.
template<class OutIt, class Ch>
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
{
return internal::print_node(out, &node, flags, 0);
}
#ifndef RAPIDXML_NO_STREAMS
//! Prints XML to given output stream.
//! \param out Output stream to print to.
//! \param node Node to be printed. Pass xml_document to print entire document.
//! \param flags Flags controlling how XML is printed.
//! \return Output stream.
template<class Ch>
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
{
print(std::ostream_iterator<Ch>(out), node, flags);
return out;
}
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
//! \param out Output stream to print to.
//! \param node Node to be printed.
//! \return Output stream.
template<class Ch>
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
{
return print(out, node);
}
#endif
}
#endif

View File

@@ -1,122 +0,0 @@
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
#define RAPIDXML_UTILS_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
#include "rapidxml.hpp"
#include <vector>
#include <string>
#include <fstream>
#include <stdexcept>
namespace rapidxml
{
//! Represents data loaded from a file
template<class Ch = char>
class file
{
public:
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
//! \param filename Filename to load.
file(const char *filename)
{
using namespace std;
// Open stream
basic_ifstream<Ch> stream(filename, ios::binary);
if (!stream)
throw runtime_error(string("cannot open file ") + filename);
stream.unsetf(ios::skipws);
// Determine stream size
stream.seekg(0, ios::end);
size_t size = stream.tellg();
stream.seekg(0);
// Load data and add terminating 0
m_data.resize(size + 1);
stream.read(&m_data.front(), static_cast<streamsize>(size));
m_data[size] = 0;
}
//! Loads file into the memory. Data will be automatically destroyed by the destructor
//! \param stream Stream to load from
file(std::basic_istream<Ch> &stream)
{
using namespace std;
// Load data and add terminating 0
stream.unsetf(ios::skipws);
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
if (stream.fail() || stream.bad())
throw runtime_error("error reading stream");
m_data.push_back(0);
}
//! Gets file data.
//! \return Pointer to data of file.
Ch *data()
{
return &m_data.front();
}
//! Gets file data.
//! \return Pointer to data of file.
const Ch *data() const
{
return &m_data.front();
}
//! Gets file data size.
//! \return Size of file data, in characters.
std::size_t size() const
{
return m_data.size();
}
private:
std::vector<Ch> m_data; // File data
};
//! Counts children of node. Time complexity is O(n).
//! \return Number of children of node
template<class Ch>
inline std::size_t count_children(xml_node<Ch> *node)
{
xml_node<Ch> *child = node->first_node();
std::size_t count = 0;
while (child)
{
++count;
child = child->next_sibling();
}
return count;
}
//! Counts attributes of node. Time complexity is O(n).
//! \return Number of attributes of node
template<class Ch>
inline std::size_t count_attributes(xml_node<Ch> *node)
{
xml_attribute<Ch> *attr = node->first_attribute();
std::size_t count = 0;
while (attr)
{
++count;
attr = attr->next_attribute();
}
return count;
}
}
#endif

View File

@@ -27,9 +27,7 @@ target_compile_options(tmx2gba PRIVATE
$<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-Wall -Wextra -pedantic>
$<$<CXX_COMPILER_ID:Clang,AppleClang>:-Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded>)
target_link_libraries(tmx2gba External::rapidxml)
#pugixml)
target_link_libraries(tmx2gba base64::base64 Zstd::Zstd
target_link_libraries(tmx2gba pugixml base64::base64 Zstd::Zstd
$<$<TARGET_EXISTS:ZLIB::ZLIB>:ZLIB::ZLIB>
$<$<TARGET_EXISTS:miniz::miniz>:miniz::miniz>)

View File

@@ -25,7 +25,7 @@ public:
TmxLayer(int width, int height, const std::string_view name, std::vector<uint32_t>&& tileDat) noexcept
: mName(name), mWidth(width), mHeight(height), mTileDat(std::move(tileDat)) {}
[[nodiscard]] constexpr const std::string_view Name() const noexcept { return mName; }
[[nodiscard]] const std::string_view Name() const noexcept { return mName; }
[[nodiscard]] constexpr std::pair<int, int> TileCount() const noexcept { return { mWidth, mHeight }; }
[[nodiscard]] constexpr const std::span<const uint32_t> Tiles() const noexcept { return mTileDat; }
};

View File

@@ -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;

View File

@@ -7,11 +7,13 @@
#include "tmxtileset.hpp"
#include "tmxobject.hpp"
#include "tmxlayer.hpp"
#include <rapidxml/rapidxml.hpp>
#include <vector>
#include <span>
#include <string>
#include <string_view>
namespace pugi { class xml_node; }
class TmxMap
{
int mWidth = 0, mHeight = 0;
@@ -21,12 +23,12 @@ class TmxMap
std::vector<TmxObject> mObjects;
[[nodiscard]] bool Decode(std::span<uint32_t> out, const std::string_view base64);
void ReadTileset(rapidxml::xml_node<>* aXNode);
void ReadLayer(rapidxml::xml_node<>* aXNode);
void ReadObjects(rapidxml::xml_node<>* aXNode);
void ReadTileset(const pugi::xml_node& xNode);
void ReadLayer(const pugi::xml_node& xNode);
void ReadObjects(const pugi::xml_node& xNode);
public:
[[nodiscard]] bool Load(const std::string_view inPath);
[[nodiscard]] bool Load(const std::string& inPath);
constexpr std::pair<int, int> TileCount() const noexcept { return { mWidth, mHeight }; }
constexpr const std::vector<TmxTileset>& Tilesets() const noexcept { return mTilesets; }

View File

@@ -14,7 +14,7 @@ public:
template <typename T>
struct Position { T x, y; };
constexpr const std::string_view Name() const noexcept { return mName; }
const std::string_view Name() const noexcept { return mName; }
constexpr Position<float> Pos() const noexcept { return mPos; }
private:

View File

@@ -88,46 +88,31 @@ TmxReader::Error TmxReader::Open(const std::string& inPath,
mGidTable.emplace_back(set.GidRange());
// Read objects
/*
if (!objMapping.empty())
{
std::vector<Object> v;
for (const auto& tmxObj : objGroups.value().get())
{
auto it = objMapping.find(std::string(tmxObj.Name()));
if (it == objMapping.end())
continue;
const auto& pos = tmxObj.Pos();
Object obj;
obj.id = it->second;
obj.x = pos.x;
obj.y = pos.y;
v.emplace_back(obj);
}
/*
for (const auto& group : objGroups)
{
const auto& tmxObjects = group.get().Objects();
v.reserve(v.size() + tmxObjects.size());
for (const auto& tmxObj : tmxObjects)
{
auto it = objMapping.find(tmxObj.getName());
auto it = objMapping.find(std::string(tmxObj.Name()));
if (it == objMapping.end())
continue;
const auto& aabb = tmxObj.getAABB();
const auto& pos = tmxObj.Pos();
Object obj;
obj.id = it->second;
obj.x = aabb.left;
obj.y = aabb.top;
obj.x = pos.x;
obj.y = pos.y;
v.emplace_back(obj);
}
}
*/
mObjects.emplace(v);
}
*/
return Error::OK;
}

View File

@@ -16,8 +16,8 @@ public:
TmxTileset(const std::string_view name, const std::string_view source, uint32_t firstGid, uint32_t lastGid)
: mName(name), mSource(source), mFirstGid(firstGid), mLastGid(lastGid) {}
[[nodiscard]] constexpr const std::string_view Name() const noexcept { return mName; }
[[nodiscard]] constexpr const std::string_view Source() const noexcept { return mSource; }
[[nodiscard]] const std::string_view Name() const noexcept { return mName; }
[[nodiscard]] const std::string_view Source() const noexcept { return mSource; }
[[nodiscard]] constexpr const std::pair<uint32_t, uint32_t> GidRange() const noexcept { return { mFirstGid, mLastGid }; }
};