diff --git a/CMakeLists.txt b/CMakeLists.txt index d8997ad..75e4691 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,8 +41,7 @@ else() endif() add_subdirectory(ext/base64) - -add_subdirectory(ext/tmxlite) +add_subdirectory(ext/rapidxml) # Main tmx2gba sources add_subdirectory(src) diff --git a/ext/rapidxml/CMakeLists.txt b/ext/rapidxml/CMakeLists.txt new file mode 100644 index 0000000..e72f336 --- /dev/null +++ b/ext/rapidxml/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(rapidxml INTERFACE) +add_library(External::rapidxml ALIAS rapidxml) +target_include_directories(rapidxml + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/ext/rapidxml/license.txt b/ext/rapidxml/license.txt new file mode 100644 index 0000000..1409831 --- /dev/null +++ b/ext/rapidxml/license.txt @@ -0,0 +1,52 @@ +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. diff --git a/ext/rapidxml/rapidxml/rapidxml.hpp b/ext/rapidxml/rapidxml/rapidxml.hpp new file mode 100644 index 0000000..ae91e08 --- /dev/null +++ b/ext/rapidxml/rapidxml/rapidxml.hpp @@ -0,0 +1,2596 @@ +#ifndef RAPIDXML_HPP_INCLUDED +#define RAPIDXML_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation + +// If standard library is disabled, user must provide implementations of required functions and typedefs +#if !defined(RAPIDXML_NO_STDLIB) + #include // For std::size_t + #include // For assert + #include // For placement new +#endif + +// On MSVC, disable "conditional expression is constant" warning (level 4). +// This warning is almost impossible to avoid with certain types of templated code +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) // Conditional expression is constant +#endif + +/////////////////////////////////////////////////////////////////////////// +// RAPIDXML_PARSE_ERROR + +#if defined(RAPIDXML_NO_EXCEPTIONS) + +#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } + +namespace rapidxml +{ + //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, + //! this function is called to notify user about the error. + //! It must be defined by the user. + //!

+ //! This function cannot return. If it does, the results are undefined. + //!

+ //! A very simple definition might look like that: + //!
+    //! void %rapidxml::%parse_error_handler(const char *what, void *where)
+    //! {
+    //!     std::cout << "Parse error: " << what << "\n";
+    //!     std::abort();
+    //! }
+    //! 
+ //! \param what Human readable description of the error. + //! \param where Pointer to character data where error was detected. + void parse_error_handler(const char *what, void *where); +} + +#else + +#include // For std::exception + +#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) + +namespace rapidxml +{ + + //! Parse error exception. + //! This exception is thrown by the parser when an error occurs. + //! Use what() function to get human-readable error message. + //! Use where() function to get a pointer to position within source text where error was detected. + //!

+ //! If throwing exceptions by the parser is undesirable, + //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. + //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. + //! This function must be defined by the user. + //!

+ //! This class derives from std::exception class. + class parse_error: public std::exception + { + + public: + + //! Constructs parse error + parse_error(const char *what, void *where) + : m_what(what) + , m_where(where) + { + } + + //! Gets human readable description of error. + //! \return Pointer to null terminated description of the error. + virtual const char *what() const throw() + { + return m_what; + } + + //! Gets pointer to character data where error happened. + //! Ch should be the same as char type of xml_document that produced the error. + //! \return Pointer to location within the parsed string where error occured. + template + Ch *where() const + { + return reinterpret_cast(m_where); + } + + private: + + const char *m_what; + void *m_where; + + }; +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// Pool sizes + +#ifndef RAPIDXML_STATIC_POOL_SIZE + // Size of static memory block of memory_pool. + // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. + #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_DYNAMIC_POOL_SIZE + // Size of dynamic memory block of memory_pool. + // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. + #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_ALIGNMENT + // Memory allocation alignment. + // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. + // All memory allocations for nodes, attributes and strings will be aligned to this value. + // This must be a power of 2 and at least 1, otherwise memory_pool will not work. + #define RAPIDXML_ALIGNMENT sizeof(void *) +#endif + +namespace rapidxml +{ + // Forward declarations + template class xml_node; + template class xml_attribute; + template class xml_document; + + //! Enumeration listing all node types produced by the parser. + //! Use xml_node::type() function to query node type. + enum node_type + { + node_document, //!< A document node. Name and value are empty. + node_element, //!< An element node. Name contains element name. Value contains text of first data node. + node_data, //!< A data node. Name is empty. Value contains data text. + node_cdata, //!< A CDATA node. Name is empty. Value contains data text. + node_comment, //!< A comment node. Name is empty. Value contains comment text. + node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. + node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. + node_pi //!< A PI node. Name contains target. Value contains instructions. + }; + + /////////////////////////////////////////////////////////////////////// + // Parsing flags + + //! Parse flag instructing the parser to not create data nodes. + //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_data_nodes = 0x1; + + //! Parse flag instructing the parser to not use text of first data node as a value of parent element. + //! Can be combined with other flags by use of | operator. + //! Note that child data nodes of element node take precendence over its value when printing. + //! That is, if element has one or more child data nodes and a value, the value will be ignored. + //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. + //!

+ //! See xml_document::parse() function. + const int parse_no_element_values = 0x2; + + //! Parse flag instructing the parser to not place zero terminators after strings in the source text. + //! By default zero terminators are placed, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_string_terminators = 0x4; + + //! Parse flag instructing the parser to not translate entities in the source text. + //! By default entities are translated, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_entity_translation = 0x8; + + //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. + //! By default, UTF-8 handling is enabled. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_utf8 = 0x10; + + //! Parse flag instructing the parser to create XML declaration node. + //! By default, declaration node is not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_declaration_node = 0x20; + + //! Parse flag instructing the parser to create comments nodes. + //! By default, comment nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_comment_nodes = 0x40; + + //! Parse flag instructing the parser to create DOCTYPE node. + //! By default, doctype node is not created. + //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_doctype_node = 0x80; + + //! Parse flag instructing the parser to create PI nodes. + //! By default, PI nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_pi_nodes = 0x100; + + //! Parse flag instructing the parser to validate closing tag names. + //! If not set, name inside closing tag is irrelevant to the parser. + //! By default, closing tags are not validated. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_validate_closing_tags = 0x200; + + //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. + //! By default, whitespace is not trimmed. + //! This flag does not cause the parser to modify source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_trim_whitespace = 0x400; + + //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. + //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. + //! By default, whitespace is not normalized. + //! If this flag is specified, source text will be modified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_normalize_whitespace = 0x800; + + // Compound flags + + //! Parse flags which represent default behaviour of the parser. + //! This is always equal to 0, so that all other flags can be simply ored together. + //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. + //! This also means that meaning of each flag is a negation of the default setting. + //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, + //! and using the flag will disable it. + //!

+ //! See xml_document::parse() function. + const int parse_default = 0; + + //! A combination of parse flags that forbids any modifications of the source text. + //! This also results in faster parsing. However, note that the following will occur: + //!
    + //!
  • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
  • + //!
  • entities will not be translated
  • + //!
  • whitespace will not be normalized
  • + //!
+ //! See xml_document::parse() function. + const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; + + //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. + //!

+ //! See xml_document::parse() function. + const int parse_fastest = parse_non_destructive | parse_no_data_nodes; + + //! A combination of parse flags resulting in largest amount of data being extracted. + //! This usually results in slowest parsing. + //!

+ //! See xml_document::parse() function. + const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; + + /////////////////////////////////////////////////////////////////////// + // Internals + + //! \cond internal + namespace internal + { + + // Struct that contains lookup tables for the parser + // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). + template + struct lookup_tables + { + static const unsigned char lookup_whitespace[256]; // Whitespace table + static const unsigned char lookup_node_name[256]; // Node name table + static const unsigned char lookup_text[256]; // Text table + static const unsigned char lookup_text_pure_no_ws[256]; // Text table + static const unsigned char lookup_text_pure_with_ws[256]; // Text table + static const unsigned char lookup_attribute_name[256]; // Attribute name table + static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes + static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes + static const unsigned char lookup_digits[256]; // Digits + static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters + }; + + // Find length of the string + template + inline std::size_t measure(const Ch *p) + { + const Ch *tmp = p; + while (*tmp) + ++tmp; + return tmp - p; + } + + // Compare strings for equality + template + inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) + { + if (size1 != size2) + return false; + if (case_sensitive) + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (*p1 != *p2) + return false; + } + else + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != lookup_tables<0>::lookup_upcase[static_cast(*p2)]) + return false; + } + return true; + } + } + //! \endcond + + /////////////////////////////////////////////////////////////////////// + // Memory pool + + //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. + //! In most cases, you will not need to use this class directly. + //! However, if you need to create nodes manually or modify names/values of nodes, + //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. + //! Not only is this faster than allocating them by using new operator, + //! but also their lifetime will be tied to the lifetime of document, + //! possibly simplyfing memory management. + //!

+ //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. + //! You can also call allocate_string() function to allocate strings. + //! Such strings can then be used as names or values of nodes without worrying about their lifetime. + //! Note that there is no free() function -- all allocations are freed at once when clear() function is called, + //! or when the pool is destroyed. + //!

+ //! It is also possible to create a standalone memory_pool, and use it + //! to allocate nodes, whose lifetime will not be tied to any document. + //!

+ //! Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. + //! Until static memory is exhausted, no dynamic memory allocations are done. + //! When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, + //! by using global new[] and delete[] operators. + //! This behaviour can be changed by setting custom allocation routines. + //! Use set_allocator() function to set them. + //!

+ //! Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. + //! This value defaults to the size of pointer on target architecture. + //!

+ //! To obtain absolutely top performance from the parser, + //! it is important that all nodes are allocated from a single, contiguous block of memory. + //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. + //! If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT + //! to obtain best wasted memory to performance compromise. + //! To do it, define their values before rapidxml.hpp file is included. + //! \param Ch Character type of created nodes. + template + class memory_pool + { + + public: + + //! \cond internal + typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory + typedef void (free_func)(void *); // Type of user-defined function used to free memory + //! \endcond + + //! Constructs empty pool with default allocator functions. + memory_pool() + : m_alloc_func(0) + , m_free_func(0) + { + init(); + } + + //! Destroys pool and frees all the memory. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Nodes allocated from the pool are no longer valid. + ~memory_pool() + { + clear(); + } + + //! Allocates a new node from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param type Type of node to create. + //! \param name Name to assign to the node, or 0 to assign no name. + //! \param value Value to assign to the node, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated node. This pointer will never be NULL. + xml_node *allocate_node(node_type type, + const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_node)); + xml_node *node = new(memory) xml_node(type); + if (name) + { + if (name_size > 0) + node->name(name, name_size); + else + node->name(name); + } + if (value) + { + if (value_size > 0) + node->value(value, value_size); + else + node->value(value); + } + return node; + } + + //! Allocates a new attribute from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param name Name to assign to the attribute, or 0 to assign no name. + //! \param value Value to assign to the attribute, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated attribute. This pointer will never be NULL. + xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_attribute)); + xml_attribute *attribute = new(memory) xml_attribute; + if (name) + { + if (name_size > 0) + attribute->name(name, name_size); + else + attribute->name(name); + } + if (value) + { + if (value_size > 0) + attribute->value(value, value_size); + else + attribute->value(value); + } + return attribute; + } + + //! Allocates a char array of given size from the pool, and optionally copies a given string to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param source String to initialize the allocated memory with, or 0 to not initialize it. + //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. + //! \return Pointer to allocated char array. This pointer will never be NULL. + Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) + { + assert(source || size); // Either source or size (or both) must be specified + if (size == 0) + size = internal::measure(source) + 1; + Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); + if (source) + for (std::size_t i = 0; i < size; ++i) + result[i] = source[i]; + return result; + } + + //! Clones an xml_node and its hierarchy of child nodes and attributes. + //! Nodes and attributes are allocated from this memory pool. + //! Names and values are not cloned, they are shared between the clone and the source. + //! Result node can be optionally specified as a second parameter, + //! in which case its contents will be replaced with cloned source node. + //! This is useful when you want to clone entire document. + //! \param source Node to clone. + //! \param result Node to put results in, or 0 to automatically allocate result node + //! \return Pointer to cloned node. This pointer will never be NULL. + xml_node *clone_node(const xml_node *source, xml_node *result = 0) + { + // Prepare result node + if (result) + { + result->remove_all_attributes(); + result->remove_all_nodes(); + result->type(source->type()); + } + else + result = allocate_node(source->type()); + + // Clone name and value + result->name(source->name(), source->name_size()); + result->value(source->value(), source->value_size()); + + // Clone child nodes and attributes + for (xml_node *child = source->first_node(); child; child = child->next_sibling()) + result->append_node(clone_node(child)); + for (xml_attribute *attr = source->first_attribute(); attr; attr = attr->next_attribute()) + result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); + + return result; + } + + //! Clears the pool. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Any nodes or strings allocated from the pool will no longer be valid. + void clear() + { + while (m_begin != m_static_memory) + { + char *previous_begin = reinterpret_cast
(align(m_begin))->previous_begin; + if (m_free_func) + m_free_func(m_begin); + else + delete[] m_begin; + m_begin = previous_begin; + } + init(); + } + + //! Sets or resets the user-defined memory allocation functions for the pool. + //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. + //! Allocation function must not return invalid pointer on failure. It should either throw, + //! stop the program, or use longjmp() function to pass control to other place of program. + //! If it returns invalid pointer, results are undefined. + //!

+ //! User defined allocation functions must have the following forms: + //!
+ //!
void *allocate(std::size_t size); + //!
void free(void *pointer); + //!

+ //! \param af Allocation function, or 0 to restore default function + //! \param ff Free function, or 0 to restore default function + void set_allocator(alloc_func *af, free_func *ff) + { + assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet + m_alloc_func = af; + m_free_func = ff; + } + + private: + + struct header + { + char *previous_begin; + }; + + void init() + { + m_begin = m_static_memory; + m_ptr = align(m_begin); + m_end = m_static_memory + sizeof(m_static_memory); + } + + char *align(char *ptr) + { + std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); + return ptr + alignment; + } + + char *allocate_raw(std::size_t size) + { + // Allocate + void *memory; + if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] + { + memory = m_alloc_func(size); + assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp + } + else + { + memory = new char[size]; +#ifdef RAPIDXML_NO_EXCEPTIONS + if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc + RAPIDXML_PARSE_ERROR("out of memory", 0); +#endif + } + return static_cast(memory); + } + + void *allocate_aligned(std::size_t size) + { + // Calculate aligned pointer + char *result = align(m_ptr); + + // If not enough memory left in current pool, allocate a new pool + if (result + size > m_end) + { + // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) + std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; + if (pool_size < size) + pool_size = size; + + // Allocate + std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation + char *raw_memory = allocate_raw(alloc_size); + + // Setup new pool in allocated memory + char *pool = align(raw_memory); + header *new_header = reinterpret_cast
(pool); + new_header->previous_begin = m_begin; + m_begin = raw_memory; + m_ptr = pool + sizeof(header); + m_end = raw_memory + alloc_size; + + // Calculate aligned pointer again using new pool + result = align(m_ptr); + } + + // Update pool and return aligned pointer + m_ptr = result + size; + return result; + } + + char *m_begin; // Start of raw memory making up current pool + char *m_ptr; // First free byte in current pool + char *m_end; // One past last available byte in current pool + char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory + alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used + free_func *m_free_func; // Free function, or 0 if default is to be used + }; + + /////////////////////////////////////////////////////////////////////////// + // XML base + + //! Base class for xml_node and xml_attribute implementing common functions: + //! name(), name_size(), value(), value_size() and parent(). + //! \param Ch Character type to use + template + class xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + // Construct a base with empty name, value and parent + xml_base() + : m_name(0) + , m_value(0) + , m_parent(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets name of the node. + //! Interpretation of name depends on type of node. + //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use name_size() function to determine length of the name. + //! \return Name of node, or empty string if node has no name. + Ch *name() const + { + return m_name ? m_name : nullstr(); + } + + //! Gets size of node name, not including terminator character. + //! This function works correctly irrespective of whether name is or is not zero terminated. + //! \return Size of node name, in characters. + std::size_t name_size() const + { + return m_name ? m_name_size : 0; + } + + //! Gets value of node. + //! Interpretation of value depends on type of node. + //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use value_size() function to determine length of the value. + //! \return Value of node, or empty string if node has no value. + Ch *value() const + { + return m_value ? m_value : nullstr(); + } + + //! Gets size of node value, not including terminator character. + //! This function works correctly irrespective of whether value is or is not zero terminated. + //! \return Size of node value, in characters. + std::size_t value_size() const + { + return m_value ? m_value_size : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets name of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of name must be specified separately, because name does not have to be zero terminated. + //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! \param name Name of node to set. Does not have to be zero terminated. + //! \param size Size of name, in characters. This does not include zero terminator, if one is present. + void name(const Ch *name, std::size_t size) + { + m_name = const_cast(name); + m_name_size = size; + } + + //! Sets name of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). + //! \param name Name of node to set. Must be zero terminated. + void name(const Ch *name) + { + this->name(name, internal::measure(name)); + } + + //! Sets value of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of value must be specified separately, because it does not have to be zero terminated. + //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //!

+ //! If an element has a child node of type node_data, it will take precedence over element value when printing. + //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. + //! \param value value of node to set. Does not have to be zero terminated. + //! \param size Size of value, in characters. This does not include zero terminator, if one is present. + void value(const Ch *value, std::size_t size) + { + m_value = const_cast(value); + m_value_size = size; + } + + //! Sets value of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). + //! \param value Vame of node to set. Must be zero terminated. + void value(const Ch *value) + { + this->value(value, internal::measure(value)); + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets node parent. + //! \return Pointer to parent node, or 0 if there is no parent. + xml_node *parent() const + { + return m_parent; + } + + protected: + + // Return empty string + static Ch *nullstr() + { + static Ch zero = Ch('\0'); + return &zero; + } + + Ch *m_name; // Name of node, or 0 if no name + Ch *m_value; // Value of node, or 0 if no value + std::size_t m_name_size; // Length of node name, or undefined of no name + std::size_t m_value_size; // Length of node value, or undefined if no value + xml_node *m_parent; // Pointer to parent node, or 0 if none + + }; + + //! Class representing attribute node of XML document. + //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). + //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. + //! Thus, this text must persist in memory for the lifetime of attribute. + //! \param Ch Character type to use. + template + class xml_attribute: public xml_base + { + + friend class xml_node; + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty attribute with the specified type. + //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. + xml_attribute() + { + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which attribute is a child. + //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. + xml_document *document() const + { + if (xml_node *node = this->parent()) + { + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + else + return 0; + } + + //! Gets previous attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_prev_attribute : 0; + } + + //! Gets next attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_next_attribute : 0; + } + + private: + + xml_attribute *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero + xml_attribute *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML node + + //! Class representing a node of XML document. + //! Each node may have associated name and value strings, which are available through name() and value() functions. + //! Interpretation of name and value depends on type of the node. + //! Type of node can be determined by using type() function. + //!

+ //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. + //! Thus, this text must persist in the memory for the lifetime of node. + //! \param Ch Character type to use. + template + class xml_node: public xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty node with the specified type. + //! Consider using memory_pool of appropriate document to allocate nodes manually. + //! \param type Type of node to construct. + xml_node(node_type type) + : m_type(type) + , m_first_node(0) + , m_first_attribute(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets type of node. + //! \return Type of node. + node_type type() const + { + return m_type; + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which node is a child. + //! \return Pointer to document that contains this node, or 0 if there is no parent document. + xml_document *document() const + { + xml_node *node = const_cast *>(this); + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + + //! Gets first child node, optionally matching node name. + //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_first_node; child; child = child->next_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_first_node; + } + + //! Gets last child node, optionally matching node name. + //! Behaviour is undefined if node has no children. + //! Use first_node() to test if node has children. + //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(m_first_node); // Cannot query for last child if node has no children + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_last_node; child; child = child->previous_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_last_node; + } + + //! Gets previous sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_prev_sibling; + } + + //! Gets next sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_next_sibling; + } + + //! Gets first attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute; + } + + //! Gets last attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute ? m_last_attribute : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets type of node. + //! \param type Type of node to set. + void type(node_type type) + { + m_type = type; + } + + /////////////////////////////////////////////////////////////////////////// + // Node manipulation + + //! Prepends a new child node. + //! The prepended child becomes the first child, and all existing children are moved one position back. + //! \param child Node to prepend. + void prepend_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_next_sibling = m_first_node; + m_first_node->m_prev_sibling = child; + } + else + { + child->m_next_sibling = 0; + m_last_node = child; + } + m_first_node = child; + child->m_parent = this; + child->m_prev_sibling = 0; + } + + //! Appends a new child node. + //! The appended child becomes the last child. + //! \param child Node to append. + void append_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_prev_sibling = m_last_node; + m_last_node->m_next_sibling = child; + } + else + { + child->m_prev_sibling = 0; + m_first_node = child; + } + m_last_node = child; + child->m_parent = this; + child->m_next_sibling = 0; + } + + //! Inserts a new child node at specified place inside the node. + //! All children after and including the specified node are moved one position back. + //! \param where Place where to insert the child, or 0 to insert at the back. + //! \param child Node to insert. + void insert_node(xml_node *where, xml_node *child) + { + assert(!where || where->parent() == this); + assert(child && !child->parent() && child->type() != node_document); + if (where == m_first_node) + prepend_node(child); + else if (where == 0) + append_node(child); + else + { + child->m_prev_sibling = where->m_prev_sibling; + child->m_next_sibling = where; + where->m_prev_sibling->m_next_sibling = child; + where->m_prev_sibling = child; + child->m_parent = this; + } + } + + //! Removes first child node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_first_node() + { + assert(first_node()); + xml_node *child = m_first_node; + m_first_node = child->m_next_sibling; + if (child->m_next_sibling) + child->m_next_sibling->m_prev_sibling = 0; + else + m_last_node = 0; + child->m_parent = 0; + } + + //! Removes last child of the node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_last_node() + { + assert(first_node()); + xml_node *child = m_last_node; + if (child->m_prev_sibling) + { + m_last_node = child->m_prev_sibling; + child->m_prev_sibling->m_next_sibling = 0; + } + else + m_first_node = 0; + child->m_parent = 0; + } + + //! Removes specified child from the node + // \param where Pointer to child to be removed. + void remove_node(xml_node *where) + { + assert(where && where->parent() == this); + assert(first_node()); + if (where == m_first_node) + remove_first_node(); + else if (where == m_last_node) + remove_last_node(); + else + { + where->m_prev_sibling->m_next_sibling = where->m_next_sibling; + where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; + where->m_parent = 0; + } + } + + //! Removes all child nodes (but not attributes). + void remove_all_nodes() + { + for (xml_node *node = first_node(); node; node = node->m_next_sibling) + node->m_parent = 0; + m_first_node = 0; + } + + //! Prepends a new attribute to the node. + //! \param attribute Attribute to prepend. + void prepend_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_next_attribute = m_first_attribute; + m_first_attribute->m_prev_attribute = attribute; + } + else + { + attribute->m_next_attribute = 0; + m_last_attribute = attribute; + } + m_first_attribute = attribute; + attribute->m_parent = this; + attribute->m_prev_attribute = 0; + } + + //! Appends a new attribute to the node. + //! \param attribute Attribute to append. + void append_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_prev_attribute = m_last_attribute; + m_last_attribute->m_next_attribute = attribute; + } + else + { + attribute->m_prev_attribute = 0; + m_first_attribute = attribute; + } + m_last_attribute = attribute; + attribute->m_parent = this; + attribute->m_next_attribute = 0; + } + + //! Inserts a new attribute at specified place inside the node. + //! All attributes after and including the specified attribute are moved one position back. + //! \param where Place where to insert the attribute, or 0 to insert at the back. + //! \param attribute Attribute to insert. + void insert_attribute(xml_attribute *where, xml_attribute *attribute) + { + assert(!where || where->parent() == this); + assert(attribute && !attribute->parent()); + if (where == m_first_attribute) + prepend_attribute(attribute); + else if (where == 0) + append_attribute(attribute); + else + { + attribute->m_prev_attribute = where->m_prev_attribute; + attribute->m_next_attribute = where; + where->m_prev_attribute->m_next_attribute = attribute; + where->m_prev_attribute = attribute; + attribute->m_parent = this; + } + } + + //! Removes first attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_first_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_first_attribute; + if (attribute->m_next_attribute) + { + attribute->m_next_attribute->m_prev_attribute = 0; + } + else + m_last_attribute = 0; + attribute->m_parent = 0; + m_first_attribute = attribute->m_next_attribute; + } + + //! Removes last attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_last_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_last_attribute; + if (attribute->m_prev_attribute) + { + attribute->m_prev_attribute->m_next_attribute = 0; + m_last_attribute = attribute->m_prev_attribute; + } + else + m_first_attribute = 0; + attribute->m_parent = 0; + } + + //! Removes specified attribute from node. + //! \param where Pointer to attribute to be removed. + void remove_attribute(xml_attribute *where) + { + assert(first_attribute() && where->parent() == this); + if (where == m_first_attribute) + remove_first_attribute(); + else if (where == m_last_attribute) + remove_last_attribute(); + else + { + where->m_prev_attribute->m_next_attribute = where->m_next_attribute; + where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; + where->m_parent = 0; + } + } + + //! Removes all attributes of node. + void remove_all_attributes() + { + for (xml_attribute *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) + attribute->m_parent = 0; + m_first_attribute = 0; + } + + private: + + /////////////////////////////////////////////////////////////////////////// + // Restrictions + + // No copying + xml_node(const xml_node &); + void operator =(const xml_node &); + + /////////////////////////////////////////////////////////////////////////// + // Data members + + // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. + // This is required for maximum performance, as it allows the parser to omit initialization of + // unneded/redundant values. + // + // The rules are as follows: + // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively + // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage + // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage + + node_type m_type; // Type of node; always valid + xml_node *m_first_node; // Pointer to first child node, or 0 if none; always valid + xml_node *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero + xml_attribute *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid + xml_attribute *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero + xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML document + + //! This class represents root of the DOM hierarchy. + //! It is also an xml_node and a memory_pool through public inheritance. + //! Use parse() function to build a DOM tree from a zero-terminated XML text string. + //! parse() function allocates memory for nodes and attributes by using functions of xml_document, + //! which are inherited from memory_pool. + //! To access root node of the document, use the document itself, as if it was an xml_node. + //! \param Ch Character type to use. + template + class xml_document: public xml_node, public memory_pool + { + + public: + + //! Constructs empty XML document + xml_document() + : xml_node(node_document) + { + } + + //! Parses zero-terminated XML string according to given flags. + //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. + //! The string must persist for the lifetime of the document. + //! In case of error, rapidxml::parse_error exception will be thrown. + //!

+ //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. + //! Make sure that data is zero-terminated. + //!

+ //! Document can be parsed into multiple times. + //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. + //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. + template + void parse(Ch *text) + { + assert(text); + + // Remove current contents + this->remove_all_nodes(); + this->remove_all_attributes(); + + // Parse BOM, if any + parse_bom(text); + + // Parse children + while (1) + { + // Skip whitespace before node + skip(text); + if (*text == 0) + break; + + // Parse and append new child + if (*text == Ch('<')) + { + ++text; // Skip '<' + if (xml_node *node = parse_node(text)) + this->append_node(node); + } + else + RAPIDXML_PARSE_ERROR("expected <", text); + } + + } + + //! Clears the document by deleting all nodes and clearing the memory pool. + //! All nodes owned by document pool are destroyed. + void clear() + { + this->remove_all_nodes(); + this->remove_all_attributes(); + memory_pool::clear(); + } + + private: + + /////////////////////////////////////////////////////////////////////// + // Internal character utility functions + + // Detect whitespace character + struct whitespace_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_whitespace[static_cast(ch)]; + } + }; + + // Detect node name character + struct node_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_node_name[static_cast(ch)]; + } + }; + + // Detect attribute name character + struct attribute_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_attribute_name[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) + struct text_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_no_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_with_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast(ch)]; + } + }; + + // Detect attribute value character + template + struct attribute_value_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Detect attribute value character + template + struct attribute_value_pure_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Insert coded character, using UTF8 or 8-bit ASCII + template + static void insert_coded_character(Ch *&text, unsigned long code) + { + if (Flags & parse_no_utf8) + { + // Insert 8-bit ASCII character + // Todo: possibly verify that code is less than 256 and use replacement char otherwise? + text[0] = static_cast(code); + text += 1; + } + else + { + // Insert UTF8 sequence + if (code < 0x80) // 1 byte sequence + { + text[0] = static_cast(code); + text += 1; + } + else if (code < 0x800) // 2 byte sequence + { + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xC0); + text += 2; + } + else if (code < 0x10000) // 3 byte sequence + { + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xE0); + text += 3; + } + else if (code < 0x110000) // 4 byte sequence + { + text[3] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xF0); + text += 4; + } + else // Invalid, only codes up to 0x10FFFF are allowed in Unicode + { + RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); + } + } + } + + // Skip characters until predicate evaluates to true + template + static void skip(Ch *&text) + { + Ch *tmp = text; + while (StopPred::test(*tmp)) + ++tmp; + text = tmp; + } + + // Skip characters until predicate evaluates to true while doing the following: + // - replacing XML character entity references with proper characters (' & " < > &#...;) + // - condensing whitespace sequences to single space character + template + static Ch *skip_and_expand_character_refs(Ch *&text) + { + // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip + if (Flags & parse_no_entity_translation && + !(Flags & parse_normalize_whitespace) && + !(Flags & parse_trim_whitespace)) + { + skip(text); + return text; + } + + // Use simple skip until first modification is detected + skip(text); + + // Use translation skip + Ch *src = text; + Ch *dest = src; + while (StopPred::test(*src)) + { + // If entity translation is enabled + if (!(Flags & parse_no_entity_translation)) + { + // Test if replacement is needed + if (src[0] == Ch('&')) + { + switch (src[1]) + { + + // & ' + case Ch('a'): + if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) + { + *dest = Ch('&'); + ++dest; + src += 5; + continue; + } + if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) + { + *dest = Ch('\''); + ++dest; + src += 6; + continue; + } + break; + + // " + case Ch('q'): + if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) + { + *dest = Ch('"'); + ++dest; + src += 6; + continue; + } + break; + + // > + case Ch('g'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + case Ch('l'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('<'); + ++dest; + src += 4; + continue; + } + break; + + // &#...; - assumes ASCII + case Ch('#'): + if (src[2] == Ch('x')) + { + unsigned long code = 0; + src += 3; // Skip &#x + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 16 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + else + { + unsigned long code = 0; + src += 2; // Skip &# + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 10 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + if (*src == Ch(';')) + ++src; + else + RAPIDXML_PARSE_ERROR("expected ;", src); + continue; + + // Something else + default: + // Ignore, just copy '&' verbatim + break; + + } + } + } + + // If whitespace condensing is enabled + if (Flags & parse_normalize_whitespace) + { + // Test if condensing is needed + if (whitespace_pred::test(*src)) + { + *dest = Ch(' '); ++dest; // Put single space in dest + ++src; // Skip first whitespace char + // Skip remaining whitespace chars + while (whitespace_pred::test(*src)) + ++src; + continue; + } + } + + // No replacement, only copy character + *dest++ = *src++; + + } + + // Return new end + text = src; + return dest; + + } + + /////////////////////////////////////////////////////////////////////// + // Internal parsing functions + + // Parse BOM, if any + template + void parse_bom(Ch *&text) + { + // UTF-8? + if (static_cast(text[0]) == 0xEF && + static_cast(text[1]) == 0xBB && + static_cast(text[2]) == 0xBF) + { + text += 3; // Skup utf-8 bom + } + } + + // Parse XML declaration ( + xml_node *parse_xml_declaration(Ch *&text) + { + // If parsing of declaration is disabled + if (!(Flags & parse_declaration_node)) + { + // Skip until end of declaration + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + + // Create declaration + xml_node *declaration = this->allocate_node(node_declaration); + + // Skip whitespace before attributes or ?> + skip(text); + + // Parse declaration attributes + parse_node_attributes(text, declaration); + + // Skip ?> + if (text[0] != Ch('?') || text[1] != Ch('>')) + RAPIDXML_PARSE_ERROR("expected ?>", text); + text += 2; + + return declaration; + } + + // Parse XML comment (' + return 0; // Do not produce comment node + } + + // Remember value start + Ch *value = text; + + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create comment node + xml_node *comment = this->allocate_node(node_comment); + comment->value(value, text - value); + + // Place zero terminator after comment value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip '-->' + return comment; + } + + // Parse DOCTYPE + template + xml_node *parse_doctype(Ch *&text) + { + // Remember value start + Ch *value = text; + + // Skip to > + while (*text != Ch('>')) + { + // Determine character type + switch (*text) + { + + // If '[' encountered, scan for matching ending ']' using naive algorithm with depth + // This works for all W3C test files except for 2 most wicked + case Ch('['): + { + ++text; // Skip '[' + int depth = 1; + while (depth > 0) + { + switch (*text) + { + case Ch('['): ++depth; break; + case Ch(']'): --depth; break; + case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text); + } + ++text; + } + break; + } + + // Error on end of text + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Other character, skip it + default: + ++text; + + } + } + + // If DOCTYPE nodes enabled + if (Flags & parse_doctype_node) + { + // Create a new doctype node + xml_node *doctype = this->allocate_node(node_doctype); + doctype->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 1; // skip '>' + return doctype; + } + else + { + text += 1; // skip '>' + return 0; + } + + } + + // Parse PI + template + xml_node *parse_pi(Ch *&text) + { + // If creation of PI nodes is enabled + if (Flags & parse_pi_nodes) + { + // Create pi node + xml_node *pi = this->allocate_node(node_pi); + + // Extract PI target name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected PI target", text); + pi->name(name, text - name); + + // Skip whitespace between pi target and pi + skip(text); + + // Remember start of pi + Ch *value = text; + + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Set pi value (verbatim, no entity expansion or whitespace normalization) + pi->value(value, text - value); + + // Place zero terminator after name and value + if (!(Flags & parse_no_string_terminators)) + { + pi->name()[pi->name_size()] = Ch('\0'); + pi->value()[pi->value_size()] = Ch('\0'); + } + + text += 2; // Skip '?>' + return pi; + } + else + { + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + } + + // Parse and append data + // Return character that ends data. + // This is necessary because this character might have been overwritten by a terminating 0 + template + Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) + { + // Backup to contents start if whitespace trimming is disabled + if (!(Flags & parse_trim_whitespace)) + text = contents_start; + + // Skip until end of data + Ch *value = text, *end; + if (Flags & parse_normalize_whitespace) + end = skip_and_expand_character_refs(text); + else + end = skip_and_expand_character_refs(text); + + // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > + if (Flags & parse_trim_whitespace) + { + if (Flags & parse_normalize_whitespace) + { + // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end + if (*(end - 1) == Ch(' ')) + --end; + } + else + { + // Backup until non-whitespace character is found + while (whitespace_pred::test(*(end - 1))) + --end; + } + } + + // If characters are still left between end and value (this test is only necessary if normalization is enabled) + // Create new data node + if (!(Flags & parse_no_data_nodes)) + { + xml_node *data = this->allocate_node(node_data); + data->value(value, end - value); + node->append_node(data); + } + + // Add data to parent node if no data exists yet + if (!(Flags & parse_no_element_values)) + if (*node->value() == Ch('\0')) + node->value(value, end - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + { + Ch ch = *text; + *end = Ch('\0'); + return ch; // Return character that ends data; this is required because zero terminator overwritten it + } + + // Return character that ends data + return *text; + } + + // Parse CDATA + template + xml_node *parse_cdata(Ch *&text) + { + // If CDATA is disabled + if (Flags & parse_no_data_nodes) + { + // Skip until end of cdata + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 3; // Skip ]]> + return 0; // Do not produce CDATA node + } + + // Skip until end of cdata + Ch *value = text; + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create new cdata node + xml_node *cdata = this->allocate_node(node_cdata); + cdata->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip ]]> + return cdata; + } + + // Parse element node + template + xml_node *parse_element(Ch *&text) + { + // Create element node + xml_node *element = this->allocate_node(node_element); + + // Extract element name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected element name", text); + element->name(name, text - name); + + // Skip whitespace between element name and attributes or > + skip(text); + + // Parse attributes, if any + parse_node_attributes(text, element); + + // Determine ending type + if (*text == Ch('>')) + { + ++text; + parse_node_contents(text, element); + } + else if (*text == Ch('/')) + { + ++text; + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; + } + else + RAPIDXML_PARSE_ERROR("expected >", text); + + // Place zero terminator after name + if (!(Flags & parse_no_string_terminators)) + element->name()[element->name_size()] = Ch('\0'); + + // Return parsed element + return element; + } + + // Determine node type, and parse it + template + xml_node *parse_node(Ch *&text) + { + // Parse proper node type + switch (text[0]) + { + + // <... + default: + // Parse and append element node + return parse_element(text); + + // (text); + } + else + { + // Parse PI + return parse_pi(text); + } + + // (text); + } + break; + + // (text); + } + break; + + // (text); + } + + } // switch + + // Attempt to skip other, unrecognized node types starting with ')) + { + if (*text == 0) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + ++text; // Skip '>' + return 0; // No node recognized + + } + } + + // Parse contents of the node - children, data etc. + template + void parse_node_contents(Ch *&text, xml_node *node) + { + // For all children and text + while (1) + { + // Skip whitespace between > and node contents + Ch *contents_start = text; // Store start of node contents before whitespace is skipped + skip(text); + Ch next_char = *text; + + // After data nodes, instead of continuing the loop, control jumps here. + // This is because zero termination inside parse_and_append_data() function + // would wreak havoc with the above code. + // Also, skipping whitespace after data nodes is unnecessary. + after_data_node: + + // Determine what comes next: node closing, child node, data node, or 0? + switch (next_char) + { + + // Node closing or child node + case Ch('<'): + if (text[1] == Ch('/')) + { + // Node closing + text += 2; // Skip '(text); + if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) + RAPIDXML_PARSE_ERROR("invalid closing tag name", text); + } + else + { + // No validation, just skip name + skip(text); + } + // Skip remaining whitespace after node name + skip(text); + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; // Skip '>' + return; // Node closed, finished parsing contents + } + else + { + // Child node + ++text; // Skip '<' + if (xml_node *child = parse_node(text)) + node->append_node(child); + } + break; + + // End of data - error + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Data node + default: + next_char = parse_and_append_data(node, text, contents_start); + goto after_data_node; // Bypass regular processing after data nodes + + } + } + } + + // Parse XML attributes of the node + template + void parse_node_attributes(Ch *&text, xml_node *node) + { + // For all attributes + while (attribute_name_pred::test(*text)) + { + // Extract attribute name + Ch *name = text; + ++text; // Skip first character of attribute name + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected attribute name", name); + + // Create new attribute + xml_attribute *attribute = this->allocate_attribute(); + attribute->name(name, text - name); + node->append_attribute(attribute); + + // Skip whitespace after attribute name + skip(text); + + // Skip = + if (*text != Ch('=')) + RAPIDXML_PARSE_ERROR("expected =", text); + ++text; + + // Add terminating zero after name + if (!(Flags & parse_no_string_terminators)) + attribute->name()[attribute->name_size()] = 0; + + // Skip whitespace after = + skip(text); + + // Skip quote and remember if it was ' or " + Ch quote = *text; + if (quote != Ch('\'') && quote != Ch('"')) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; + + // Extract attribute value and expand char refs in it + Ch *value = text, *end; + const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes + if (quote == Ch('\'')) + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + else + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + + // Set attribute value + attribute->value(value, end - value); + + // Make sure that end quote is present + if (*text != quote) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; // Skip quote + + // Add terminating zero after value + if (!(Flags & parse_no_string_terminators)) + attribute->value()[attribute->value_size()] = 0; + + // Skip whitespace after attribute value + skip(text); + } + } + + }; + + //! \cond internal + namespace internal + { + + // Whitespace (space \n \r \t) + template + const unsigned char lookup_tables::lookup_whitespace[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + + // Node name (anything but space \n \r \t / > ? \0) + template + const unsigned char lookup_tables::lookup_node_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) (anything but < \0) + template + const unsigned char lookup_tables::lookup_text[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled + // (anything but < \0 &) + template + const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled + // (anything but < \0 & space \n \r \t) + template + const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute name (anything but space \n \r \t / < > = ? ! \0) + template + const unsigned char lookup_tables::lookup_attribute_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote (anything but ' \0) + template + const unsigned char lookup_tables::lookup_attribute_data_1[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote that does not require processing (anything but ' \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote (anything but " \0) + template + const unsigned char lookup_tables::lookup_attribute_data_2[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote that does not require processing (anything but " \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Digits (dec and hex, 255 denotes end of numeric character reference) + template + const unsigned char lookup_tables::lookup_digits[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F + }; + + // Upper case conversion + template + const unsigned char lookup_tables::lookup_upcase[256] = + { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F + }; + } + //! \endcond + +} + +// Undefine internal macros +#undef RAPIDXML_PARSE_ERROR + +// On MSVC, restore warnings state +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/ext/rapidxml/rapidxml/rapidxml_iterators.hpp b/ext/rapidxml/rapidxml/rapidxml_iterators.hpp new file mode 100644 index 0000000..52ebc29 --- /dev/null +++ b/ext/rapidxml/rapidxml/rapidxml_iterators.hpp @@ -0,0 +1,174 @@ +#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 node_iterator + { + + public: + + typedef typename xml_node value_type; + typedef typename xml_node &reference; + typedef typename xml_node *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + node_iterator() + : m_node(0) + { + } + + node_iterator(xml_node *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 &rhs) + { + return m_node == rhs.m_node; + } + + bool operator !=(const node_iterator &rhs) + { + return m_node != rhs.m_node; + } + + private: + + xml_node *m_node; + + }; + + //! Iterator of child attributes of xml_node + template + class attribute_iterator + { + + public: + + typedef typename xml_attribute value_type; + typedef typename xml_attribute &reference; + typedef typename xml_attribute *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + attribute_iterator() + : m_attribute(0) + { + } + + attribute_iterator(xml_node *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 &rhs) + { + return m_attribute == rhs.m_attribute; + } + + bool operator !=(const attribute_iterator &rhs) + { + return m_attribute != rhs.m_attribute; + } + + private: + + xml_attribute *m_attribute; + + }; + +} + +#endif diff --git a/ext/rapidxml/rapidxml/rapidxml_print.hpp b/ext/rapidxml/rapidxml/rapidxml_print.hpp new file mode 100644 index 0000000..0ae2b14 --- /dev/null +++ b/ext/rapidxml/rapidxml/rapidxml_print.hpp @@ -0,0 +1,421 @@ +#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 + #include +#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 + 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 (< > ' " &) + template + 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 + inline OutIt fill_chars(OutIt out, int n, Ch ch) + { + for (int i = 0; i < n; ++i) + *out++ = ch; + return out; + } + + // Find character + template + 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 + inline OutIt print_node(OutIt out, const xml_node *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 + inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent) + { + for (xml_node *child = node->first_node(); child; child = child->next_sibling()) + out = print_node(out, child, flags, indent); + return out; + } + + // Print attributes of the node + template + inline OutIt print_attributes(OutIt out, const xml_node *node, int flags) + { + for (xml_attribute *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(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 + inline OutIt print_data_node(OutIt out, const xml_node *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 + inline OutIt print_cdata_node(OutIt out, const xml_node *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 + inline OutIt print_element_node(OutIt out, const xml_node *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 *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 + inline OutIt print_declaration_node(OutIt out, const xml_node *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 + inline OutIt print_comment_node(OutIt out, const xml_node *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 + inline OutIt print_doctype_node(OutIt out, const xml_node *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 + inline OutIt print_pi_node(OutIt out, const xml_node *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 + inline OutIt print(OutIt out, const xml_node &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 + inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0) + { + print(std::ostream_iterator(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 + inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node) + { + return print(out, node); + } + +#endif + +} + +#endif diff --git a/ext/rapidxml/rapidxml/rapidxml_utils.hpp b/ext/rapidxml/rapidxml/rapidxml_utils.hpp new file mode 100644 index 0000000..37c2953 --- /dev/null +++ b/ext/rapidxml/rapidxml/rapidxml_utils.hpp @@ -0,0 +1,122 @@ +#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 +#include +#include +#include + +namespace rapidxml +{ + + //! Represents data loaded from a file + template + 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 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(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 &stream) + { + using namespace std; + + // Load data and add terminating 0 + stream.unsetf(ios::skipws); + m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); + 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 m_data; // File data + + }; + + //! Counts children of node. Time complexity is O(n). + //! \return Number of children of node + template + inline std::size_t count_children(xml_node *node) + { + xml_node *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 + inline std::size_t count_attributes(xml_node *node) + { + xml_attribute *attr = node->first_attribute(); + std::size_t count = 0; + while (attr) + { + ++count; + attr = attr->next_attribute(); + } + return count; + } + +} + +#endif diff --git a/ext/tmxlite/CMakeLists.txt b/ext/tmxlite/CMakeLists.txt deleted file mode 100644 index 8a4b03b..0000000 --- a/ext/tmxlite/CMakeLists.txt +++ /dev/null @@ -1,52 +0,0 @@ -project(tmxlite VERSION 1.3.1) - -add_library(${PROJECT_NAME} STATIC - include/tmxlite/Config.hpp - include/tmxlite/FreeFuncs.hpp - include/tmxlite/ImageLayer.hpp - include/tmxlite/Layer.hpp - include/tmxlite/LayerGroup.hpp - include/tmxlite/Map.hpp - include/tmxlite/Object.hpp - include/tmxlite/ObjectGroup.hpp - include/tmxlite/ObjectTypes.hpp - include/tmxlite/Property.hpp - include/tmxlite/TileLayer.hpp - include/tmxlite/Tileset.hpp - include/tmxlite/Types.hpp - include/tmxlite/Types.inl - include/tmxlite/detail/Log.hpp - - src/FreeFuncs.cpp - src/ImageLayer.cpp - src/Map.cpp - src/Object.cpp - src/ObjectGroup.cpp - src/Property.cpp - src/TileLayer.cpp - src/LayerGroup.cpp - src/Tileset.cpp - src/ObjectTypes.cpp) - -if (NOT USE_ZLIB) - target_sources(${PROJECT_NAME} PRIVATE - include/tmxlite/detail/gzip.hpp - src/detail/gzip.cpp) -endif() - -set_target_properties(${PROJECT_NAME} PROPERTIES - CXX_STANDARD 20 - CXX_STANDARD_REQUIRED ON) - -target_include_directories(${PROJECT_NAME} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include) - -target_compile_options(${PROJECT_NAME} PRIVATE -Wall) - -target_compile_definitions(${PROJECT_NAME} PRIVATE - $<$:_CRT_SECURE_NO_WARNINGS> # disable msvc warning - $<$:USE_ZLIB>) - -target_link_libraries(${PROJECT_NAME} base64::base64 pugixml Zstd::Zstd - $<$:ZLIB::ZLIB> - $<$:miniz::miniz>) diff --git a/ext/tmxlite/LICENSE b/ext/tmxlite/LICENSE deleted file mode 100644 index 95d80cc..0000000 --- a/ext/tmxlite/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -(c)Matt Marchant & contributors 2016 - 2021 http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or implied warranty. -In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, including commercial applications, -and to alter it and redistribute it freely, subject to the following restrictions: -The origin of this software must not be misrepresented; you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. -Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. - -This notice may not be removed or altered from any source distribution. diff --git a/ext/tmxlite/include/tmxlite/Config.hpp b/ext/tmxlite/include/tmxlite/Config.hpp deleted file mode 100644 index fe05dec..0000000 --- a/ext/tmxlite/include/tmxlite/Config.hpp +++ /dev/null @@ -1,31 +0,0 @@ -/********************************************************************* -(c) Matt Marchant 2016 - 2021 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -//static build doesn't need import/export macros -#define TMXLITE_EXPORT_API diff --git a/ext/tmxlite/include/tmxlite/FreeFuncs.hpp b/ext/tmxlite/include/tmxlite/FreeFuncs.hpp deleted file mode 100644 index c2efb0c..0000000 --- a/ext/tmxlite/include/tmxlite/FreeFuncs.hpp +++ /dev/null @@ -1,126 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2021 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/detail/Log.hpp" -#include "tmxlite/Types.hpp" - -#include -#include -#include -#include -#include - -namespace tmx -{ - //using inline here just to supress unused warnings on gcc - bool decompress(const char* source, std::vector& dest, std::size_t inSize, std::size_t expectedSize); - - static inline Colour colourFromString(std::string str) - { - //removes preceding # - auto result = str.find_last_of('#'); - if (result != std::string::npos) - { - str = str.substr(result + 1); - } - - if (str.size() == 6 || str.size() == 8) - { - unsigned int value, r, g, b; - unsigned int a = 255; - std::stringstream input(str); - input >> std::hex >> value; - - r = (value >> 16) & 0xff; - g = (value >> 8) & 0xff; - b = value & 0xff; - - if (str.size() == 8) - { - a = (value >> 24) & 0xff; - } - - return{ std::uint8_t(r), std::uint8_t(g), std::uint8_t(b), std::uint8_t(a) }; - } - Logger::log(str + ": not a valid colour string", Logger::Type::Error); - return{}; - } - - static inline std::string resolveFilePath(std::string path, const std::string& workingDir) - { - static const std::string match("../"); - std::size_t result = path.find(match); - std::size_t count = 0; - while (result != std::string::npos) - { - count++; - path = path.substr(result + match.size()); - result = path.find(match); - } - - if (workingDir.empty()) return path; - - std::string outPath = workingDir; - for (auto i = 0u; i < count; ++i) - { - result = outPath.find_last_of('/'); - if (result != std::string::npos) - { - outPath = outPath.substr(0, result); - } - } - - return outPath + '/' + path; - } - - static inline std::string getFilePath(const std::string& path) - { - //TODO this doesn't actually check that there is a file at the - //end of the path, or that it's even a valid path... - - static auto searchFunc = [](const char separator, const std::string& path)->std::string - { - std::size_t i = path.rfind(separator, path.length()); - if (i != std::string::npos) - { - return(path.substr(0, i + 1)); - } - - return ""; - }; - - -#ifdef _WIN32 //try windows formatted paths first - std::string retVal = searchFunc('\\', path); - if (!retVal.empty()) return retVal; -#endif - - return searchFunc('/', path); - } -} //namespacec tmx diff --git a/ext/tmxlite/include/tmxlite/ImageLayer.hpp b/ext/tmxlite/include/tmxlite/ImageLayer.hpp deleted file mode 100644 index 96adf52..0000000 --- a/ext/tmxlite/include/tmxlite/ImageLayer.hpp +++ /dev/null @@ -1,107 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2022 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/Config.hpp" -#include "tmxlite/Layer.hpp" -#include "tmxlite/Types.hpp" - -namespace tmx -{ - /*! - \brief Image layers contain a single image which make up that - layer. The parser contains the fully resolved path to the image - relative to the working directory. - */ - class TMXLITE_EXPORT_API ImageLayer final : public Layer - { - public: - explicit ImageLayer(const std::string&); - - Type getType() const override { return Layer::Type::Image; } - void parse(const pugi::xml_node&, Map*) override; - - /*! - \brief Returns the path, relative to the working directory, - of the image used by the image layer. - */ - const std::string& getImagePath() const { return m_filePath; } - - /*! - \brief Returns the colour used by the image to represent transparent - pixels. By default this is (0, 0, 0, 0) - */ - const Colour& getTransparencyColour() const { return m_transparencyColour; } - - /*! - \brief Returns true if the image used by this layer specifically states a - colour to use as transparency - */ - bool hasTransparency() const { return m_hasTransparency; } - - /*! - \brief Returns the size of the image of the image layer in pixels. - */ - const Vector2u& getImageSize() const { return m_imageSize; } - - /*! - \brief Returns true if the image drawn by this layer is repeated along - the X axis. - */ - bool hasRepeatX() const { return m_hasRepeatX; } - - /*! - \brief Returns true if the image drawn by this layer is repeated along - the Y axis. - */ - bool hasRepeatY() const { return m_hasRepeatY; } - - private: - std::string m_workingDir; - std::string m_filePath; - Colour m_transparencyColour; - bool m_hasTransparency; - Vector2u m_imageSize; - bool m_hasRepeatX; - bool m_hasRepeatY; - }; - - template <> - inline ImageLayer& Layer::getLayerAs() - { - assert(getType() == Type::Image); - return *static_cast(this); - } - - template <> - inline const ImageLayer& Layer::getLayerAs() const - { - assert(getType() == Type::Image); - return *static_cast(this); - } -} diff --git a/ext/tmxlite/include/tmxlite/Layer.hpp b/ext/tmxlite/include/tmxlite/Layer.hpp deleted file mode 100644 index 32c6581..0000000 --- a/ext/tmxlite/include/tmxlite/Layer.hpp +++ /dev/null @@ -1,175 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2023 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/Config.hpp" -#include "tmxlite/Property.hpp" -#include "tmxlite/Types.hpp" - -#include -#include -#include - -namespace pugi -{ - class xml_node; -} - -namespace tmx -{ - class Map; - class TileLayer; - class ObjectGroup; - class ImageLayer; - class LayerGroup; - /*! - \brief Represents a layer of a tmx format tile map. - This is an abstract base class from which all layer - types are derived. - */ - class TMXLITE_EXPORT_API Layer - { - public: - using Ptr = std::unique_ptr; - - Layer() : m_opacity(1.f), m_visible(true) {}; - virtual ~Layer() = default; - - /*! - \brief Layer type as returned by getType() - Tile: this layer is a TileLayer type - Object: This layer is an ObjectGroup type - Image: This layer is an ImageLayer type - Group: This layer is a LayerGroup type - */ - enum class Type - { - Tile, - Object, - Image, - Group - }; - - /*! - \brief Returns a Type value representing the concrete type. - Use this when deciding which conrete layer type to use when - calling the templated function getLayerAs() - */ - virtual Type getType() const = 0; - - /*! - \brief Returns the class of the Layer, as defined in the editor Tiled 1.9+ - */ - const std::string& getClass() const { return m_class; } - - /*! - \brief Use this to get a reference to the concrete layer type - which this layer points to. - Use getType() to return the type value of this layer and determine - if the concrete type is TileLayer, ObjectGroup, ImageLayer, or LayerGroup - */ - template - T& getLayerAs(); - - - template - const T& getLayerAs() const; - - /*! - \brief Attempts to parse the specific node layer type - */ - virtual void parse(const pugi::xml_node&, Map* = nullptr) = 0; - - /*! - \brief Returns the name of the layer - */ - const std::string& getName() const { return m_name; } - - /*! - \brief Returns the opacity value for the layer - */ - float getOpacity() const { return m_opacity; } - - /*! - \brief Returns whether this layer is visible or not - */ - bool getVisible() const { return m_visible; } - - /*! - \brief Returns the offset from the top left corner - of the layer, in pixels - */ - const Vector2i& getOffset() const { return m_offset; } - - /*! - \brief Returns the parallax factor - */ - const Vector2f& getParallaxFactor() const { return m_parallaxFactor; } - - /*! - \brief Returns the tint colour of the layer. - Defaults to 0xFFFFFFFF - pure white - */ - Colour getTintColour() const { return m_tintColour; } - - /*! - \brief Returns the size of the layer, in pixels. - This will be the same as the map size for fixed size maps. - */ - const Vector2u& getSize() const { return m_size; } - - /*! - \brief Returns the list of properties of this layer - */ - const std::vector& getProperties() const { return m_properties; } - - protected: - - void setName(const std::string& name) { m_name = name; } - void setClass(const std::string& cls) { m_class = cls; } - void setOpacity(float opacity) { m_opacity = opacity; } - void setVisible(bool visible) { m_visible = visible; } - void setOffset(std::int32_t x, std::int32_t y) { m_offset = Vector2i(x, y); } - void setParallaxFactor(float x, float y) { m_parallaxFactor.x = x; m_parallaxFactor.y = y; } - void setTintColour(Colour c) { m_tintColour = c; } - void setSize(std::uint32_t width, std::uint32_t height) { m_size = Vector2u(width, height); } - void addProperty(const pugi::xml_node& node) { m_properties.emplace_back(); m_properties.back().parse(node); } - - private: - std::string m_name; - std::string m_class; - float m_opacity; - bool m_visible; - Vector2i m_offset; - Vector2f m_parallaxFactor; - Colour m_tintColour = { 255,255,255,255 }; - Vector2u m_size; - - std::vector m_properties; - }; -} diff --git a/ext/tmxlite/include/tmxlite/LayerGroup.hpp b/ext/tmxlite/include/tmxlite/LayerGroup.hpp deleted file mode 100644 index a8fe910..0000000 --- a/ext/tmxlite/include/tmxlite/LayerGroup.hpp +++ /dev/null @@ -1,86 +0,0 @@ -/********************************************************************* -Grant Gangi 2019 - 2022 - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/Config.hpp" -#include "tmxlite/Layer.hpp" -#include "tmxlite/Types.hpp" - -#include - -namespace tmx -{ - /*! - \brief Layer groups are used to organize the layers of - the map in a hierarchy. They can contain all other layer - types including more layer groups to further nest layers. - */ - class TMXLITE_EXPORT_API LayerGroup final : public Layer - { - public: - - LayerGroup(const std::string& workDir, const Vector2u& tileCount); - ~LayerGroup() = default; - LayerGroup(const LayerGroup&) = delete; - const LayerGroup& operator = (const LayerGroup&) = delete; - LayerGroup(LayerGroup&&) = default; - LayerGroup& operator = (LayerGroup&&) = default; - - - Type getType() const override { return Layer::Type::Group; } - void parse(const pugi::xml_node&, Map*) override; - - /*! - \brief Returns a reference to the vector containing the layer data. - Layers are pointer-to-baseclass, the concrete type of which can be - found via Layer::getType() - \see Layer - */ - const std::vector& getLayers() const { return m_layers; } - - private: - - std::vector m_layers; - - std::string m_workingDir; - Vector2u m_tileCount; - }; - - template <> - inline LayerGroup& Layer::getLayerAs() - { - assert(getType() == Type::Group); - return *static_cast(this); - } - - template <> - inline const LayerGroup& Layer::getLayerAs() const - { - assert(getType() == Type::Group); - return *static_cast(this); - } -} diff --git a/ext/tmxlite/include/tmxlite/Map.hpp b/ext/tmxlite/include/tmxlite/Map.hpp deleted file mode 100644 index e4610e1..0000000 --- a/ext/tmxlite/include/tmxlite/Map.hpp +++ /dev/null @@ -1,282 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 -2021 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/Tileset.hpp" -#include "tmxlite/Layer.hpp" -#include "tmxlite/Property.hpp" -#include "tmxlite/Types.hpp" -#include "tmxlite/Object.hpp" - -#include -#include -#include -#include - -namespace tmx -{ - /*! - \brief Holds the xml version of the loaded map - */ - struct TMXLITE_EXPORT_API Version - { - //major/minor are apparently reserved by gcc - std::uint16_t upper; - std::uint16_t lower; - Version(std::uint16_t maj = 0, std::uint16_t min = 0) - : upper(maj), lower(min) {} - }; - - enum class Orientation - { - Orthogonal, - Isometric, - Staggered, - Hexagonal, - None - }; - - enum class RenderOrder - { - RightDown, - RightUp, - LeftDown, - LeftUp, - None - }; - - enum class StaggerAxis - { - X, Y, None - }; - - enum class StaggerIndex - { - Even, Odd, None - }; - - /*! - \brief Parser for TMX format tile maps. - This class can be used to parse the XML format tile maps created - with the Tiled map editor, providing an interface to create drawable and - physics objects. Typical usage would be to create an instance of this - class before calling load() providing a path to the *.tmx file to be - loaded. Then layers or objects can be requested from the Map class - to be interpreted as needed. - \see https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#map - */ - class TMXLITE_EXPORT_API Map final - { - public: - - Map(); - ~Map() = default; - Map(const Map&) = delete; - Map& operator = (const Map&) = delete; - Map(Map&&) = default; - Map& operator = (Map&&) = default; - - /*! - \brief Attempts to parse the tilemap at the given location. - \param std::string Path to map file to try to parse - \returns true if map was parsed successfully else returns false. - In debug mode this will attempt to log any errors to the console. - */ - bool load(const std::string&); - - /*! - \brief Loads a map from a document stored in a string - \param data A std::string containing the map data to load - \param workingDir A std::string containing the working directory - in which to find assets such as tile sets or images - \returns true if successful, else false - */ - bool loadFromString(const std::string& data, const std::string& workingDir); - - /*! - \brief Returns the version of the tile map last parsed. - If no tile map has yet been parsed the version will read 0, 0 - */ - const Version& getVersion() const { return m_version; } - - /*! - \brief Returns the orientation of the map if one is loaded, - else returns None - */ - Orientation getOrientation() const { return m_orientation; } - - /*! - \brief Returns the RenderOrder of the map if one is loaded, - else returns None - */ - RenderOrder getRenderOrder() const { return m_renderOrder; } - - /*! - \brief Returns the tile count of the map in the X and Y directions - */ - const Vector2u& getTileCount() const { return m_tileCount; } - - /*! - \brief Returns the size of the tile grid in this map. - Actual tile sizes may vary and will be extended / shrunk about - the bottom left corner of the tile. - */ - const Vector2u& getTileSize() const { return m_tileSize; } - - /*! - \brief Returns the bounds of the map - */ - FloatRect getBounds() const { return FloatRect(0.f, 0.f, static_cast(m_tileCount.x * m_tileSize.x), static_cast(m_tileCount.y * m_tileSize.y)); } - - /*! - \brief Returns the length of an edge of a tile if a Hexagonal - map is loaded. - The length returned is in pixels of the straight edge running - along the axis returned by getStaggerAxis(). If no map is loaded - or the loaded map is not of Hexagonal orientation this function - returns 0.f - */ - float getHexSideLength() const { return m_hexSideLength; } - - /*! - \brief Stagger axis of the map. - If either a Staggered or Hexagonal tile map is loaded this returns - which axis the map is staggered along, else returns None. - */ - StaggerAxis getStaggerAxis() const { return m_staggerAxis; } - - /*! - \brief Stagger Index of the loaded map. - If a Staggered or Hexagonal map is loaded this returns whether - the even or odd rows of tiles are staggered, otherwise it returns None. - */ - StaggerIndex getStaggerIndex() const { return m_staggerIndex; } - - /*! - \brief Returns the background colour of the map. - */ - const Colour& getBackgroundColour() const { return m_backgroundColour; } - - /*! - \brief Returns a reference to the vector of tile sets used by the map - */ - const std::vector& getTilesets() const { return m_tilesets; } - - /*! - \brief Returns a reference to the vector containing the layer data. - Layers are pointer-to-baseclass, the concrete type of which can be - found via Layer::getType() - \see Layer - */ - const std::vector& getLayers() const { return m_layers; } - - /*! - \brief Returns the class of the Map, as defined in the editor Tiled 1.9+ - */ - const std::string& getClass() const { return m_class; } - - /*! - \brief Returns a vector of Property objects loaded by the map - */ - const std::vector& getProperties() const { return m_properties; } - - /*! - \brief Returns a Hashmap of all animated tiles accessible by TileID - */ - const std::map& getAnimatedTiles() const { return m_animTiles; } - - /*! - \brief Returns the current working directory of the map. Images and - other resources are loaded relative to this. - */ - const std::string& getWorkingDirectory() const { return m_workingDirectory; } - - /*! - \brief Returns an unordered_map of template objects indexed by file name - */ - std::unordered_map& getTemplateObjects() { return m_templateObjects; } - const std::unordered_map& getTemplateObjects() const { return m_templateObjects; } - - /*! - \brief Returns an unordered_map of tilesets used by templated objects. - If Object::getTilesetName() is not empty it can be used to retreive a tileset - from this map. Otherwise the object's tileset can be found from in the map's - global tilesets returned by getTilesets(). - */ - std::unordered_map& getTemplateTilesets() { return m_templateTilesets; } - const std::unordered_map& getTemplateTilesets() const { return m_templateTilesets; } - - /*! - \brief Returns true if this is in infinite tile map. - Infinite maps store their tile data in for tile layers in chunks. If - this is an infinite map use TileLayer::getChunks() to get tile IDs - rather than TileLayer::getTiles(). - \see TileLayer - */ - bool isInfinite() const { return m_infinite; } - - /* - \brief Returns the origin of each layer's parallax offset value - */ - Vector2f getParallaxOrigin() const { return m_parallaxOrigin; } - - private: - Version m_version; - std::string m_class; - Orientation m_orientation; - RenderOrder m_renderOrder; - bool m_infinite; - - Vector2u m_tileCount; - Vector2u m_tileSize; - - float m_hexSideLength; - StaggerAxis m_staggerAxis; - StaggerIndex m_staggerIndex; - - Vector2f m_parallaxOrigin; - - Colour m_backgroundColour; - - std::string m_workingDirectory; - - std::vector m_tilesets; - std::vector m_layers; - std::vector m_properties; - std::map m_animTiles; - - std::unordered_map m_templateObjects; - std::unordered_map m_templateTilesets; - - bool parseMapNode(const pugi::xml_node&); - - //always returns false so we can return this - //on load failure - bool reset(); - }; -} diff --git a/ext/tmxlite/include/tmxlite/Object.hpp b/ext/tmxlite/include/tmxlite/Object.hpp deleted file mode 100644 index c7c5ac2..0000000 --- a/ext/tmxlite/include/tmxlite/Object.hpp +++ /dev/null @@ -1,221 +0,0 @@ -/********************************************************************* -(c) Matt Marchant 2016 - 2021 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/Config.hpp" -#include "tmxlite/Property.hpp" -#include "tmxlite/Types.hpp" - -#include -#include - -namespace pugi -{ - class xml_node; -} - -namespace tmx -{ - class Map; - - /*! - \brief Contains the text information stored in a Text object. - */ - struct TMXLITE_EXPORT_API Text final - { - std::string fontFamily; - std::uint32_t pixelSize = 16; //!< pixels, not points - bool wrap = false; - Colour colour; - bool bold = false; - bool italic = false; - bool underline = false; - bool strikethough = false; - bool kerning = true; - - enum class HAlign - { - Left, Centre, Right - }hAlign = HAlign::Left; - - enum class VAlign - { - Top, Centre, Bottom - }vAlign = VAlign::Top; - - std::string content; //!< actual string content - }; - - /*! - \brief Objects are stored in ObjectGroup layers. - Objects may be rectangular, elliptical, polygonal or - a polyline. Rectangular and elliptical Objects have their - size determined via the AABB, whereas polygon and polyline - shapes are defined by a list of points. Objects are - rectangular by default. Since version 1.0 Objects also - support Text nodes. - */ - class TMXLITE_EXPORT_API Object final - { - public: - enum class Shape - { - Rectangle, - Ellipse, - Point, - Polygon, - Polyline, - Text - }; - - Object(); - - /*! - \brief Attempts to parse the given xml node and - read the Object properties if it is valid. - */ - void parse(const pugi::xml_node&, Map*); - - /*! - \brief Returns the unique ID of the Object - */ - std::uint32_t getUID() const { return m_UID; } - - /*! - \brief Returns the name of the Object - */ - const std::string& getName() const { return m_name; } - - /*! - \brief Returns the type (equal to class) of the Object, as defined in the editor Tiled < 1.9 - */ - const std::string& getType() const { return m_class; } - - /*! - \brief Returns the class (equal to type) of the Object, as defined in the editor Tiled 1.9+ - */ - const std::string& getClass() const { return m_class; } - - /*! - \brief Returns the position of the Object in pixels - */ - const Vector2f& getPosition() const { return m_position; } - - /*! - \brief Returns the global Axis Aligned Bounding Box. - The AABB is positioned via the left and top properties, and - define the Object's width and height. This can be used to derive - the shape of the Object if it is rectangular or elliptical. - */ - const FloatRect& getAABB() const { return m_AABB; } - - /*! - \brief Returns the rotation of the Object in degrees clockwise - */ - float getRotation() const { return m_rotation; } - - /*! - \brief Returns the global tile ID associated with the Object - if there is one. This is used to draw the Object (and therefore - the Object must be rectangular) - */ - std::uint32_t getTileID() const { return m_tileID; } - - /*! - \brief Returns the flip flags if the objects uses a TileID to - draw it. - Returns 0 otherwise. - */ - std::uint8_t getFlipFlags() const { return m_flipFlags; } - - /*! - \brief Returns whether or not the Object is visible - */ - bool visible() const { return m_visible; } - - /*! - \brief Returns the Shape type of the Object - */ - Shape getShape() const { return m_shape; } - - /*! - \brief Returns a reference to the vector of points which - make up the Object. If the Object is rectangular or elliptical - then the vector will be empty. Point coordinates are in pixels, - relative to the object position. - */ - const std::vector& getPoints() const { return m_points; } - - /*! - \brief Returns a reference to the vector of properties belonging to - the Object. - */ - const std::vector& getProperties() const { return m_properties; } - - /*! - \brief Returns a Text struct containing information about any text - this object may have, such as font data and formatting. - If an object does not contain any text information this struct will - be populated with default values. Use getShape() to determine - if this object is in fact a text object. - */ - const Text& getText() const { return m_textData; } - Text& getText() { return m_textData; } - - /*! - \brief Returns the tileset name used by this object if it is derived - from a template, else returns an empty string. - If the string is not empty use it to index the unordered_map returned - by Map::getTemplateTilesets() - */ - const std::string& getTilesetName() const { return m_tilesetName; } - - private: - std::uint32_t m_UID; - std::string m_name; - std::string m_class; - Vector2f m_position; - FloatRect m_AABB; - float m_rotation; - std::uint32_t m_tileID; - std::uint8_t m_flipFlags; - bool m_visible; - - Shape m_shape; - std::vector m_points; - std::vector m_properties; - - Text m_textData; - - std::string m_tilesetName; - - void parsePoints(const pugi::xml_node&); - void parseText(const pugi::xml_node&); - void parseTemplate(const std::string&, Map*); - }; -} diff --git a/ext/tmxlite/include/tmxlite/ObjectGroup.hpp b/ext/tmxlite/include/tmxlite/ObjectGroup.hpp deleted file mode 100644 index 65a81ba..0000000 --- a/ext/tmxlite/include/tmxlite/ObjectGroup.hpp +++ /dev/null @@ -1,99 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2022 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/Config.hpp" -#include "tmxlite/Layer.hpp" -#include "tmxlite/Object.hpp" - -#include - -namespace tmx -{ - /*! - \brief ObjectGroup layers contain a series of Objects - which may be made up of shapes or images. - */ - class TMXLITE_EXPORT_API ObjectGroup final : public Layer - { - public: - enum class DrawOrder - { - Index, //< objects should be drawn in the order in which they appear - TopDown //< objects should be drawn sorted by their Y position - }; - - ObjectGroup(); - - Type getType() const override { return Layer::Type::Object; } - void parse(const pugi::xml_node&, Map*) override; - - /*! - \brief Returns the colour associated with this layer - */ - const Colour& getColour() const { return m_colour; } - - /*! - \brief Returns the DrawOrder for the objects in this group. - Defaults to TopDown, where Objects are drawn sorted by Y position - */ - DrawOrder getDrawOrder() const { return m_drawOrder; } - - /*! - \brief Returns a reference to the vector of properties for - the ObjectGroup - */ - const std::vector& getProperties() const { return m_properties; } - - /*! - \brief Returns a reference to the vector of Objects which belong to the group - */ - const std::vector& getObjects() const { return m_objects; } - - private: - Colour m_colour; - DrawOrder m_drawOrder; - - std::vector m_properties; - std::vector m_objects; - }; - - template <> - inline ObjectGroup& Layer::getLayerAs() - { - assert(getType() == Type::Object); - return *static_cast(this); - } - - template <> - inline const ObjectGroup& Layer::getLayerAs() const - { - assert(getType() == Type::Object); - return *static_cast(this); - } -} diff --git a/ext/tmxlite/include/tmxlite/ObjectTypes.hpp b/ext/tmxlite/include/tmxlite/ObjectTypes.hpp deleted file mode 100644 index 21f1665..0000000 --- a/ext/tmxlite/include/tmxlite/ObjectTypes.hpp +++ /dev/null @@ -1,86 +0,0 @@ -/********************************************************************* -Raphaƫl Frantz 2021 - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/Property.hpp" - -#include -#include - -namespace tmx -{ - /*! - \brief Parser for Tiled object types export format. - Link to the specification: https://doc.mapeditor.org/fr/latest/manual/custom-properties/#predefining-properties. - */ - class TMXLITE_EXPORT_API ObjectTypes final - { - public: - /*! - \brief Types that stores all predefined properties for all objects of this type. - To take less spaces, they are not exported by default into maps. - */ - struct Type - { - std::string name; - Colour colour; - std::vector properties; - }; - - /*! - \brief Attempts to parse the object types at the given location. - \param std::string Path to object types file to try to parse - \returns true if object types was parsed successfully else returns false. - In debug mode this will attempt to log any errors to the console. - */ - bool load(const std::string&); - - /*! - \brief Loads an object types from a document stored in a string - \param data A std::string containing the object types to load - \param workingDir A std::string containing the working directory - in which to find files. - \returns true if successful, else false - */ - bool loadFromString(const std::string& data, const std::string& workingDir); - - /*! - \brief Returns all predefined types and their default values. - */ - const std::vector& getTypes() const { return m_types; } - - private: - std::string m_workingDirectory; - std::vector m_types; - - bool parseObjectTypesNode(const pugi::xml_node&); - - //always returns false so we can return this - //on load failure - bool reset(); - }; -} diff --git a/ext/tmxlite/include/tmxlite/Property.hpp b/ext/tmxlite/include/tmxlite/Property.hpp deleted file mode 100644 index ddc38a3..0000000 --- a/ext/tmxlite/include/tmxlite/Property.hpp +++ /dev/null @@ -1,144 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2021 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/Config.hpp" -#include "tmxlite/Types.hpp" - -#include -#include - -namespace pugi -{ - class xml_node; -} - -namespace tmx -{ - /*! - \brief Represents a custom property. - Tiles, objects and layers of a tmx map may have custom - properties assigned to them. This class represents a - single property and provides access to its value, the - type of which can be determined with getType() - */ - class TMXLITE_EXPORT_API Property final - { - public: - - enum class Type - { - Boolean, - Float, - Int, - String, - Colour, - File, - Object, - Undef - }; - - Property(); - - static Property fromBoolean(bool value); - static Property fromFloat(float value); - static Property fromInt(int value); - static Property fromString(const std::string& value); - static Property fromColour(const Colour& value); - static Property fromFile(const std::string& value); - static Property fromObject(int value); - - /*! - \brief Attempts to parse the given node as a property - \param isObjectTypes Set to true if the parsing is done from an object types files. - */ - void parse(const pugi::xml_node&, bool isObjectTypes = false); - - /*! - \brief Returns the type of data stored in the property. - This should generally be called first before trying to - read the proprty value, as reading the incorrect type - will lead to undefined behaviour. - */ - Type getType() const { return m_type; } - - /*! - \brief Returns the name of this property - */ - const std::string& getName() const { return m_name; } - - /*! - \brief Returns the property's value as a boolean - */ - bool getBoolValue() const { assert(m_type == Type::Boolean); return m_boolValue; } - - /*! - \brief Returns the property's value as a float - */ - float getFloatValue() const { assert(m_type == Type::Float); return m_floatValue; } - - /*! - \brief Returns the property's value as an integer - */ - int getIntValue() const { assert(m_type == Type::Int || m_type == Type::Object); return m_intValue; } - - /*! - \brief Returns the property's value as a string - */ - const std::string& getStringValue() const { assert(m_type == Type::String); return m_stringValue; } - - /*! - \brief Returns the property's value as a Colour struct - */ - const Colour& getColourValue() const { assert(m_type == Type::Colour); return m_colourValue; } - - /*! - \brief Returns the file path property as a string, relative to the map file - */ - const std::string& getFileValue() const { assert(m_type == Type::File); return m_stringValue; } - - /*! - \brief Returns the property's value as an integer object handle - */ - int getObjectValue() const { assert(m_type == Type::Object); return m_intValue; } - - - private: - union - { - bool m_boolValue; - float m_floatValue; - int m_intValue; - }; - std::string m_stringValue; - std::string m_name; - Colour m_colourValue; - - Type m_type; - }; -} diff --git a/ext/tmxlite/include/tmxlite/TileLayer.hpp b/ext/tmxlite/include/tmxlite/TileLayer.hpp deleted file mode 100644 index 7231302..0000000 --- a/ext/tmxlite/include/tmxlite/TileLayer.hpp +++ /dev/null @@ -1,116 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2022 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/Layer.hpp" -#include "tmxlite/Types.hpp" - -namespace tmx -{ - /*! - \brief A layer made up from a series of tile sets - */ - class TMXLITE_EXPORT_API TileLayer final : public Layer - { - public: - /*! - \brief Tile information for a layer - */ - struct Tile final - { - std::uint32_t ID = 0; //!< Global ID of the tile - std::uint8_t flipFlags = 0; //!< Flags marking if the tile should be flipped when drawn - }; - - /*! - \brief Represents a chunk of tile data, if this is an infinite map - */ - struct Chunk final - { - Vector2i position; // tiles; - }; - - /*! - \brief Flags used to tell if a tile is flipped when drawn - */ - enum FlipFlag - { - Horizontal = 0x8, - Vertical = 0x4, - Diagonal = 0x2 - }; - - explicit TileLayer(std::size_t); - - Type getType() const override { return Layer::Type::Tile; } - void parse(const pugi::xml_node&, Map*) override; - - /*! - \brief Returns the list of tiles used to make up the layer - If this is empty then the map is most likely infinite, in - which case the tile data is stored in chunks. - \see getChunks() - */ - const std::vector& getTiles() const { return m_tiles; } - - /*! - \brief Returns a vector of chunks which make up this layer - if the map is set to infinite. This will be empty if the map - is not infinite. - \see getTiles() - */ - const std::vector& getChunks() const { return m_chunks; } - - private: - std::vector m_tiles; - std::vector m_chunks; - std::size_t m_tileCount; - - void parseBase64(const pugi::xml_node&); - void parseCSV(const pugi::xml_node&); - void parseUnencoded(const pugi::xml_node&); - - void createTiles(const std::vector&, std::vector& destination); - }; - - template <> - inline TileLayer& Layer::getLayerAs() - { - assert(getType() == Type::Tile); - return *static_cast(this); - } - - template <> - inline const TileLayer& Layer::getLayerAs() const - { - assert(getType() == Type::Tile); - return *static_cast(this); - } -} diff --git a/ext/tmxlite/include/tmxlite/Tileset.hpp b/ext/tmxlite/include/tmxlite/Tileset.hpp deleted file mode 100644 index 0a07dba..0000000 --- a/ext/tmxlite/include/tmxlite/Tileset.hpp +++ /dev/null @@ -1,296 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2023 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/Config.hpp" -#include "tmxlite/Property.hpp" -#include "tmxlite/ObjectGroup.hpp" - -#include -#include -#include - -namespace pugi -{ - class xml_node; -} - -namespace tmx -{ - class Map; - - /*! - \brief Represents a Tileset node as loaded - from a *.tmx format tile map via the tmx::Map - class. - */ - class TMXLITE_EXPORT_API Tileset final - { - public: - explicit Tileset(const std::string& workingDir); - - /*! - \brief Any tiles within a tile set which have special - data associated with them such as animation or terrain - information will have one of these stored in the tile set. - */ - struct Tile final - { - std::uint32_t ID = 0; - std::array terrainIndices{}; - std::uint32_t probability = 100; - - /*! - \brief a group of frames which make up an animation - */ - struct Animation final - { - /*! - \brief A frame within an animation - */ - struct Frame final - { - std::uint32_t tileID = 0; - std::uint32_t duration = 0; - - bool operator == (const Frame& other) const - { - return (this == &other) || - (tileID == other.tileID && duration == other.duration); - } - - bool operator != (const Frame& other) const - { - return !(*this == other); - } - }; - std::vector frames; - }animation; - std::vector properties; - ObjectGroup objectGroup; - std::string imagePath; - Vector2u imageSize; - /*! - \brief The position of the tile within the image. - */ - Vector2u imagePosition; - std::string className; - }; - - /*! - \brief Terrain information with which one - or more tiles may be associated. - */ - struct Terrain final - { - std::string name; - std::uint32_t tileID = -1; - std::vector properties; - }; - - /*! - \brief Declares the alignment of tile Objects - */ - enum class ObjectAlignment - { - Unspecified, - TopLeft, - Top, - TopRight, - Left, - Center, - Right, - BottomLeft, - Bottom, - BottomRight - }; - - /*! - \brief Attempts to parse the given xml node. - If node parsing fails an error is printed in the console - and the Tileset remains in an uninitialised state. - */ - void parse(pugi::xml_node, Map*); - - /*! - \brief Returns the first GID of this tile set. - This the ID of the first tile in the tile set, so that - each tile set guarantees a unique set of IDs - */ - std::uint32_t getFirstGID() const { return m_firstGID; } - - /*! - \brief Returns the last GID of this tile set. - This is the ID of the last tile in the tile set. - */ - std::uint32_t getLastGID() const; - - /*! - \brief Returns the name of this tile set. - */ - const std::string& getName() const { return m_name; } - - /*! - \brief Returns the class of the Tileset, as defined in the editor Tiled 1.9+ - */ - const std::string& getClass() const { return m_class; } - - /*! - \brief Returns the width and height of a tile in the - tile set, in pixels. - */ - const Vector2u& getTileSize() const { return m_tileSize; } - - /*! - \brief Returns the spacing, in pixels, between each tile in the set - */ - std::uint32_t getSpacing() const { return m_spacing; } - - /*! - \brief Returns the margin, in pixels, around each tile in the set - */ - std::uint32_t getMargin() const { return m_margin; } - - /*! - \brief Returns the number of tiles in the tile set - */ - std::uint32_t getTileCount() const { return m_tileCount; } - - /*! - \brief Returns the number of columns which make up the tile set. - This is used when rendering collection of images sets - */ - std::uint32_t getColumnCount() const { return m_columnCount; } - - /*! - \brief Returns the alignment of tile objects. - The default value is ObjectAlignment::Unspecified for compatibility. - When the alignment is Unspecified tile objects use BottomLeft in - orthogonal mode and Bottom in isometric mode. - \see ObjectAlignment - */ - ObjectAlignment getObjectAlignment() const { return m_objectAlignment; } - - /*! - \brief Returns the tile offset in pixels. - Tile will draw tiles offset from the top left using this value. - */ - const Vector2u& getTileOffset() const { return m_tileOffset; } - - /*! - \brief Returns a reference to the list of Property objects for this - tile set - */ - const std::vector& getProperties() const { return m_properties; } - - /*! - \brief Returns the file path to the tile set image, relative to the - working directory. Use this to load the texture required by whichever - method you choose to render the map. - */ - const std::string& getImagePath() const { return m_imagePath; } - - /*! - \brief Returns the size of the tile set image in pixels. - */ - const Vector2u& getImageSize() const { return m_imageSize; } - - /*! - \brief Returns the colour used by the tile map image to represent transparency. - By default this is a transparent colour (0, 0, 0, 0) - */ - const Colour& getTransparencyColour() const { return m_transparencyColour; } - - /*! - \brief Returns true if the image used by this tileset specifically requests - a colour to use as transparency. - */ - bool hasTransparency() const { return m_hasTransparency; } - - /*! - \brief Returns a vector of Terrain types associated with one - or more tiles within this tile set - */ - const std::vector& getTerrainTypes() const { return m_terrainTypes; } - - /*! - \brief Returns a reference to the vector of tile data used by - tiles which make up this tile set. - */ - const std::vector& getTiles() const { return m_tiles; } - - /*! - \brief Checks if a tiled ID is in the range of the first ID and the last ID - \param id Tile ID - \return - */ - bool hasTile(std::uint32_t id) const { return id >= m_firstGID && id <= getLastGID(); }; - - /*! - \brief queries tiles and returns a tile with the given ID. Checks if the TileID is part of the Tileset with `hasTile(id)` - \param id Tile ID. The Tile ID will be corrected internally. - \return In case of a success it returns the correct tile. In terms of failure it will return a nullptr. - */ - const Tile* getTile(std::uint32_t id) const; - - private: - - std::string m_workingDir; - - std::uint32_t m_firstGID; - std::string m_source; - std::string m_name; - std::string m_class; - Vector2u m_tileSize; - std::uint32_t m_spacing; - std::uint32_t m_margin; - std::uint32_t m_tileCount; - std::uint32_t m_columnCount; - ObjectAlignment m_objectAlignment; - Vector2u m_tileOffset; - - std::vector m_properties; - std::string m_imagePath; - Vector2u m_imageSize; - Colour m_transparencyColour; - bool m_hasTransparency; - - std::vector m_terrainTypes; - std::vector m_tileIndex; - std::vector m_tiles; - - void reset(); - - void parseOffsetNode(const pugi::xml_node&); - void parsePropertyNode(const pugi::xml_node&); - void parseTerrainNode(const pugi::xml_node&); - Tile& newTile(std::uint32_t ID); - void parseTileNode(const pugi::xml_node&, Map*); - void createMissingTile(std::uint32_t ID); - }; -} diff --git a/ext/tmxlite/include/tmxlite/Types.hpp b/ext/tmxlite/include/tmxlite/Types.hpp deleted file mode 100644 index 73fbe47..0000000 --- a/ext/tmxlite/include/tmxlite/Types.hpp +++ /dev/null @@ -1,150 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2023 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#pragma once - -#include "tmxlite/Config.hpp" - -#include -#include - - -namespace tmx -{ - /*! - \brief Two dimensional vector used to store points and positions - */ - template - struct Vector2 final - { - Vector2() : x(0), y(0) {} - Vector2(T x, T y) :x(x), y(y) {} - T x, y; - }; - - using Vector2f = Vector2; - using Vector2i = Vector2; - using Vector2u = Vector2; - - template - Vector2 operator + (const Vector2& l, const Vector2& r); - - template - Vector2& operator += (Vector2& l, const Vector2& r); - - template - Vector2 operator - (const Vector2& l, const Vector2& r); - - template - Vector2& operator -= (Vector2& l, const Vector2& r); - - template - Vector2 operator * (const Vector2& l, const Vector2& r); - - template - Vector2& operator *= (Vector2& l, const Vector2& r); - - template - Vector2 operator * (const Vector2& l, T r); - - template - Vector2& operator *= (Vector2& l, T r); - - template - Vector2 operator / (const Vector2& l, const Vector2& r); - - template - Vector2& operator /= (Vector2& l, const Vector2& r); - - template - Vector2 operator / (const Vector2& l, T r); - - template - Vector2& operator /= (Vector2& l, T r); - -#include "Types.inl" - - /*! - \brief Describes a rectangular area, such as an AABB (axis aligned bounding box) - */ - template - struct Rectangle final - { - Rectangle() : left(0), top(0), width(0), height(0) {} - Rectangle(T l, T t, T w, T h) : left(l), top(t), width(w), height(h) {} - Rectangle(Vector2 position, Vector2 size) : left(position.x), top(position.y), width(size.x), height(size.y) {} - T left, top, width, height; - }; - - using FloatRect = Rectangle; - using IntRect = Rectangle; - - /*! - \brief Contains the red, green, blue and alpha values of a colour - in the range 0 - 255. - */ - struct TMXLITE_EXPORT_API Colour final - { - Colour(std::uint8_t red = 0, std::uint8_t green = 0, std::uint8_t blue = 0, std::uint8_t alpha = 255) - : r(red), g(green), b(blue), a(alpha) {} - std::uint8_t r, g, b, a; - - bool operator == (const Colour& other) - { - return other.r == r - && other.g == g - && other.b == b - && other.a == a; - } - - bool operator != (const Colour& other) - { - return !(*this == other); - } - - explicit operator std::uint32_t() const - { - return (r << 24) | (g << 16) | (b << 8) | a; - } - }; -} - -template -std::ostream& operator << (std::ostream& os, const tmx::Vector2& t) -{ - os << "{" << t.x << ", " << t.y << "}"; - return os; -} - -template -std::ostream& operator << (std::ostream& os, const tmx::Rectangle& t) -{ - os << "{" << t.left << ", " << t.top << ", " << t.width << ", " << t.height << "}"; - return os; -} - -std::ostream& operator << (std::ostream& os, const tmx::Colour& c); diff --git a/ext/tmxlite/include/tmxlite/Types.inl b/ext/tmxlite/include/tmxlite/Types.inl deleted file mode 100644 index e129c56..0000000 --- a/ext/tmxlite/include/tmxlite/Types.inl +++ /dev/null @@ -1,110 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2023 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -template -Vector2 operator + (const Vector2& l, const Vector2& r) -{ - return { l.x + r.x, l.y + r.y }; -} - -template -Vector2& operator += (Vector2& l, const Vector2& r) -{ - l.x += r.x; - l.y += r.y; - return l; -} - -template -Vector2 operator - (const Vector2& l, const Vector2& r) -{ - return { l.x - r.x, l.y - r.y }; -} - -template -Vector2& operator -= (Vector2& l, const Vector2& r) -{ - l.x -= r.x; - l.y -= r.y; - return l; -} - -template -Vector2 operator * (const Vector2& l, const Vector2& r) -{ - return { l.x * r.x, l.y * r.y }; -} - -template -Vector2& operator *= (Vector2& l, const Vector2& r) -{ - l.x *= r.x; - l.y *= r.y; - return l; -} - -template -Vector2 operator * (const Vector2& l, T r) -{ - return { l.x * r, l.y * r }; -} - -template -Vector2& operator *= (Vector2& l, T r) -{ - l.x *= r; - l.y *= r; - return l; -} - -template -Vector2 operator / (const Vector2& l, const Vector2& r) -{ - return { l.x / r.x, l.y / r.y }; -} - -template -Vector2& operator /= (Vector2& l, const Vector2& r) -{ - l.x /= r.x; - l.y /= r.y; - return l; -} - -template -Vector2 operator / (const Vector2& l, T r) -{ - return { l.x / r, l.y / r }; -} - -template -Vector2& operator /= (Vector2& l, T r) -{ - l.x /= r; - l.y /= r; - return l; -} \ No newline at end of file diff --git a/ext/tmxlite/include/tmxlite/detail/Log.hpp b/ext/tmxlite/include/tmxlite/detail/Log.hpp deleted file mode 100644 index db1215a..0000000 --- a/ext/tmxlite/include/tmxlite/detail/Log.hpp +++ /dev/null @@ -1,163 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2021 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -//flexible logging class, based on code at https://github.com/fallahn/xygine - -#ifndef TMXLITE_LOGGER_HPP_ -#define TMXLITE_LOGGER_HPP_ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef _MSC_VER -#define NOMINMAX -#include -#endif //_MSC_VER - -namespace tmx -{ - /*! - \brief Class allowing messages to be logged to a combination - of one or more destinations such as the console, log file or - output window in Visual Studio - */ - class Logger final - { - public: - enum class Output - { - Console, - File, - All - }; - - enum class Type - { - Info, - Warning, - Error - }; - /*! - \brief Logs a message to a given destination. - \param message Message to log - \param type Whether this message gets tagged as information, a warning or an error - \param output Destination for the message. Can be the console via cout, a log file on disk, or both - */ - static void log(const std::string& message, Type type = Type::Info, Output output = Output::Console) - { - std::string outstring; - switch (type) - { - case Type::Info: - default: - outstring = "INFO: " + message; - break; - case Type::Error: - outstring = "ERROR: " + message; - break; - case Type::Warning: - outstring = "WARNING: " + message; - break; - } - - if (output == Output::Console || output == Output::All) - { - if (type == Type::Error) - { - std::cerr << outstring << std::endl; - } - else - { - std::cout << outstring << std::endl; - } - const std::size_t maxBuffer = 30; - buffer().push_back(outstring); - if (buffer().size() > maxBuffer)buffer().pop_front(); //no majick here pl0x - updateOutString(maxBuffer); - -#ifdef _MSC_VER - outstring += "\n"; - OutputDebugStringA(outstring.c_str()); -#endif //_MSC_VER - } - if (output == Output::File || output == Output::All) - { - //output to a log file - std::ofstream file("output.log", std::ios::app); - if (file.good()) - { - std::time_t time = std::time(nullptr); - auto tm = *std::localtime(&time); - //put_time isn't implemented by the ndk versions of the stl - file.imbue(std::locale()); - file << std::put_time(&tm, "%d/%m/%y-%H:%M:%S: "); - file << outstring << std::endl; - file.close(); - } - else - { - log(message, type, Output::Console); - log("Above message was intended for log file. Opening file probably failed.", Type::Warning, Output::Console); - } - } - } - - static const std::string& bufferString(){ return stringOutput(); } - - private: - static std::list& buffer(){ static std::list buffer; return buffer; } - static std::string& stringOutput() { static std::string output; return output; } - static void updateOutString(std::size_t maxBuffer) - { - static size_t count = 0; - stringOutput().append(buffer().back()); - stringOutput().append("\n"); - count++; - - if (count > maxBuffer) - { - stringOutput() = stringOutput().substr(stringOutput().find_first_of('\n') + 1, stringOutput().size()); - count--; - } - } - }; -} -#ifdef NDEBUG -#define LOG(message, type) -#else -#define LOG(message, type) {\ -std::stringstream ss; \ -ss << message << " (" << __FILE__ << ", " << __LINE__ << ")"; \ -tmx::Logger::log(ss.str(), type);} -#endif //NDEBUG - -#endif //TMXLITE_LOGGER_HPP_ diff --git a/ext/tmxlite/src/FreeFuncs.cpp b/ext/tmxlite/src/FreeFuncs.cpp deleted file mode 100644 index cdd9be8..0000000 --- a/ext/tmxlite/src/FreeFuncs.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2023 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#include "tmxlite/FreeFuncs.hpp" -#include "tmxlite/Types.hpp" -#include "tmxlite/detail/Log.hpp" -#ifndef USE_ZLIB -# include "miniz.h" -#else -# include -#endif -#include - -bool tmx::decompress(const char* source, std::vector& dest, std::size_t inSize, std::size_t expectedSize) -{ - if (!source) - { - LOG("Input string is empty, decompression failed.", Logger::Type::Error); - return false; - } - -//#ifdef USE_EXTLIBS - - -//#else - int currentSize = static_cast(expectedSize); - std::vector byteArray(expectedSize / sizeof(unsigned char)); - z_stream stream; - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - stream.next_in = (Bytef*)source; - stream.avail_in = static_cast(inSize); - stream.next_out = (Bytef*)byteArray.data(); - stream.avail_out = static_cast(expectedSize); - - //we'd prefer to use inflateInit2 but it appears - //to be incorrect in miniz. This is fine for zlib - //compressed data, but gzip compressed streams - //will fail to inflate. -#ifdef USE_ZLIB - if (inflateInit2(&stream, 15 + 32) != Z_OK) -#else - if (inflateInit(&stream) != Z_OK) -#endif - { - LOG("inflate init failed", Logger::Type::Error); - return false; - } - - int result = 0; - do - { - result = inflate(&stream, Z_SYNC_FLUSH); - - switch (result) - { - default: break; - case Z_NEED_DICT: - case Z_STREAM_ERROR: - result = Z_DATA_ERROR; - case Z_DATA_ERROR: - Logger::log("If using gzip or zstd compression try using zlib instead", Logger::Type::Info); - case Z_MEM_ERROR: - inflateEnd(&stream); - Logger::log("inflate() returned " + std::to_string(result), Logger::Type::Error); - return false; - } - - if (result != Z_STREAM_END) - { - int oldSize = currentSize; - currentSize *= 2; - std::vector newArray(currentSize / sizeof(unsigned char)); - std::memcpy(newArray.data(), byteArray.data(), currentSize / 2); - byteArray = std::move(newArray); - - stream.next_out = (Bytef*)(byteArray.data() + oldSize); - stream.avail_out = oldSize; - - } - } while (result != Z_STREAM_END); - - if (stream.avail_in != 0) - { - LOG("stream.avail_in is 0", Logger::Type::Error); - LOG("zlib decompression failed.", Logger::Type::Error); - return false; - } - - const int outSize = currentSize - stream.avail_out; - inflateEnd(&stream); - - std::vector newArray(outSize / sizeof(unsigned char)); - std::memcpy(newArray.data(), byteArray.data(), outSize); - byteArray = std::move(newArray); - - //copy bytes to vector - dest.insert(dest.begin(), byteArray.begin(), byteArray.end()); -//#endif - return true; -} - -std::ostream& operator << (std::ostream& os, const tmx::Colour& c) -{ - os << "RGBA: " << (int)c.r << ", " << (int)c.g << ", " << (int)c.b << ", " << (int)c.a; - return os; -} diff --git a/ext/tmxlite/src/ImageLayer.cpp b/ext/tmxlite/src/ImageLayer.cpp deleted file mode 100644 index cb83904..0000000 --- a/ext/tmxlite/src/ImageLayer.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2023 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#include "tmxlite/ImageLayer.hpp" -#include "tmxlite/FreeFuncs.hpp" -#include "tmxlite/detail/Log.hpp" - -#include - -using namespace tmx; - -ImageLayer::ImageLayer(const std::string& workingDir) - : m_workingDir (workingDir), - m_hasTransparency (false), - m_hasRepeatX (false), - m_hasRepeatY (false) -{ - -} - -//public -void ImageLayer::parse(const pugi::xml_node& node, Map*) -{ - std::string attribName = node.name(); - if (attribName != "imagelayer") - { - Logger::log("Node not an image layer, node skipped", Logger::Type::Error); - return; - } - - //TODO this gets repeated foreach layer type and could all be moved to base class... - setName(node.attribute("name").as_string()); - setClass(node.attribute("class").as_string()); - setOpacity(node.attribute("opacity").as_float(1.f)); - setVisible(node.attribute("visible").as_bool(true)); - setOffset(node.attribute("offsetx").as_int(0), node.attribute("offsety").as_int(0)); - setSize(node.attribute("width").as_uint(0), node.attribute("height").as_uint(0)); - setParallaxFactor(node.attribute("parallaxx").as_float(1.f), node.attribute("parallaxy").as_float(1.f)); - - std::string tintColour = node.attribute("tintcolor").as_string(); - if (!tintColour.empty()) - { - setTintColour(colourFromString(tintColour)); - } - - m_hasRepeatX = node.attribute("repeatx").as_bool(false); - m_hasRepeatY = node.attribute("repeaty").as_bool(false); - - for (const auto& child : node.children()) - { - attribName = child.name(); - if (attribName == "image") - { - attribName = child.attribute("source").as_string(); - if (attribName.empty()) - { - Logger::log("Image Layer has missing source property", Logger::Type::Warning); - return; - } - - if (child.attribute("width") && child.attribute("height")) - { - m_imageSize.x = child.attribute("width").as_uint(); - m_imageSize.y = child.attribute("height").as_uint(); - } - - m_filePath = resolveFilePath(attribName, m_workingDir); - if (child.attribute("trans")) - { - attribName = child.attribute("trans").as_string(); - m_transparencyColour = colourFromString(attribName); - m_hasTransparency = true; - } - } - else if (attribName == "properties") - { - for (const auto& p : child.children()) - { - addProperty(p); - } - } - } -} diff --git a/ext/tmxlite/src/LayerGroup.cpp b/ext/tmxlite/src/LayerGroup.cpp deleted file mode 100644 index f442378..0000000 --- a/ext/tmxlite/src/LayerGroup.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/********************************************************************* -Grant Gangi 2019 -Matt Marchant 2023 - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#include "tmxlite/LayerGroup.hpp" -#include "tmxlite/FreeFuncs.hpp" -#include "tmxlite/ObjectGroup.hpp" -#include "tmxlite/ImageLayer.hpp" -#include "tmxlite/TileLayer.hpp" -#include "tmxlite/detail/Log.hpp" - -#include - -using namespace tmx; - -LayerGroup::LayerGroup(const std::string& workingDir, const Vector2u& tileCount) - : m_workingDir(workingDir), - m_tileCount(tileCount) -{ -} - -//public -void LayerGroup::parse(const pugi::xml_node& node, Map* map) -{ - assert(map); - std::string attribString = node.name(); - if (attribString != "group") - { - Logger::log("Node was not a group layer, node will be skipped.", Logger::Type::Error); - return; - } - - setName(node.attribute("name").as_string()); - setClass(node.attribute("class").as_string()); - setOpacity(node.attribute("opacity").as_float(1.f)); - setVisible(node.attribute("visible").as_bool(true)); - setOffset(node.attribute("offsetx").as_int(0), node.attribute("offsety").as_int(0)); - setSize(node.attribute("width").as_uint(0), node.attribute("height").as_uint(0)); - setParallaxFactor(node.attribute("parallaxx").as_float(1.f), node.attribute("parallaxy").as_float(1.f)); - - std::string tintColour = node.attribute("tintcolor").as_string(); - if (!tintColour.empty()) - { - setTintColour(colourFromString(tintColour)); - } - - // parse children - for (const auto& child : node.children()) - { - attribString = child.name(); - if (attribString == "properties") - { - for (const auto& p : child.children()) - { - addProperty(p); - } - } - else if (attribString == "layer") - { - m_layers.emplace_back(std::make_unique(m_tileCount.x * m_tileCount.y)); - m_layers.back()->parse(child, map); - } - else if (attribString == "objectgroup") - { - m_layers.emplace_back(std::make_unique()); - m_layers.back()->parse(child, map); - } - else if (attribString == "imagelayer") - { - m_layers.emplace_back(std::make_unique(m_workingDir)); - m_layers.back()->parse(child, map); - } - else if (attribString == "group") - { - m_layers.emplace_back(std::make_unique(m_workingDir, m_tileCount)); - m_layers.back()->parse(child, map); - } - else - { - LOG("Unidentified name " + attribString + ": node skipped", Logger::Type::Warning); - } - } -} diff --git a/ext/tmxlite/src/Map.cpp b/ext/tmxlite/src/Map.cpp deleted file mode 100644 index 433268b..0000000 --- a/ext/tmxlite/src/Map.cpp +++ /dev/null @@ -1,362 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2023 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#include "tmxlite/Map.hpp" -#include "tmxlite/FreeFuncs.hpp" -#include "tmxlite/ObjectGroup.hpp" -#include "tmxlite/ImageLayer.hpp" -#include "tmxlite/TileLayer.hpp" -#include "tmxlite/LayerGroup.hpp" -#include "tmxlite/detail/Log.hpp" - -#include -#include - -using namespace tmx; - -Map::Map() - : m_orientation (Orientation::None), - m_renderOrder (RenderOrder::None), - m_infinite (false), - m_hexSideLength (0.f), - m_staggerAxis (StaggerAxis::None), - m_staggerIndex (StaggerIndex::None) -{ - -} - -//public -bool Map::load(const std::string& path) -{ - reset(); - - //open the doc - pugi::xml_document doc; - auto result = doc.load_file(path.c_str()); - if (!result) - { - Logger::log("Failed opening " + path, Logger::Type::Error); - Logger::log("Reason: " + std::string(result.description()), Logger::Type::Error); - return false; - } - - //make sure we have consistent path separators - m_workingDirectory = path; - std::replace(m_workingDirectory.begin(), m_workingDirectory.end(), '\\', '/'); - m_workingDirectory = getFilePath(m_workingDirectory); - - if (!m_workingDirectory.empty() && - m_workingDirectory.back() == '/') - { - m_workingDirectory.pop_back(); - } - - - //find the map node and bail if it doesn't exist - auto mapNode = doc.child("map"); - if (!mapNode) - { - Logger::log("Failed opening map: " + path + ", no map node found", Logger::Type::Error); - return reset(); - } - - return parseMapNode(mapNode); -} - -bool Map::loadFromString(const std::string& data, const std::string& workingDir) -{ - reset(); - - //open the doc - pugi::xml_document doc; - auto result = doc.load_string(data.c_str()); - if (!result) - { - Logger::log("Failed opening map", Logger::Type::Error); - Logger::log("Reason: " + std::string(result.description()), Logger::Type::Error); - return false; - } - - //make sure we have consistent path separators - m_workingDirectory = workingDir; - std::replace(m_workingDirectory.begin(), m_workingDirectory.end(), '\\', '/'); - m_workingDirectory = getFilePath(m_workingDirectory); - - if (!m_workingDirectory.empty() && - m_workingDirectory.back() == '/') - { - m_workingDirectory.pop_back(); - } - - //find the map node and bail if it doesn't exist - auto mapNode = doc.child("map"); - if (!mapNode) - { - Logger::log("Failed opening map: no map node found", Logger::Type::Error); - return reset(); - } - - return parseMapNode(mapNode); -} - -//private -bool Map::parseMapNode(const pugi::xml_node& mapNode) -{ - //parse map attributes - std::size_t pointPos = 0; - std::string attribString = mapNode.attribute("version").as_string(); - if (attribString.empty() || (pointPos = attribString.find('.')) == std::string::npos) - { - Logger::log("Invalid map version value, map not loaded.", Logger::Type::Error); - return reset(); - } - - m_version.upper = std::stoi(attribString.substr(0, pointPos)); - m_version.lower = std::stoi(attribString.substr(pointPos + 1)); - - m_class = mapNode.attribute("class").as_string(); - - attribString = mapNode.attribute("orientation").as_string(); - if (attribString.empty()) - { - Logger::log("Missing map orientation attribute, map not loaded.", Logger::Type::Error); - return reset(); - } - - if (attribString == "orthogonal") - { - m_orientation = Orientation::Orthogonal; - } - else if (attribString == "isometric") - { - m_orientation = Orientation::Isometric; - } - else if (attribString == "staggered") - { - m_orientation = Orientation::Staggered; - } - else if (attribString == "hexagonal") - { - m_orientation = Orientation::Hexagonal; - } - else - { - Logger::log(attribString + " format maps aren't supported yet, sorry! Map not loaded", Logger::Type::Error); - return reset(); - } - - attribString = mapNode.attribute("renderorder").as_string(); - //this property is optional for older version of map files - if (!attribString.empty()) - { - if (attribString == "right-down") - { - m_renderOrder = RenderOrder::RightDown; - } - else if (attribString == "right-up") - { - m_renderOrder = RenderOrder::RightUp; - } - else if (attribString == "left-down") - { - m_renderOrder = RenderOrder::LeftDown; - } - else if (attribString == "left-up") - { - m_renderOrder = RenderOrder::LeftUp; - } - else - { - Logger::log(attribString + ": invalid render order. Map not loaded.", Logger::Type::Error); - return reset(); - } - } - - if (mapNode.attribute("infinite")) - { - m_infinite = mapNode.attribute("infinite").as_int() != 0; - } - - unsigned width = mapNode.attribute("width").as_int(); - unsigned height = mapNode.attribute("height").as_int(); - if (width && height) - { - m_tileCount = { width, height }; - } - else - { - Logger::log("Invalid map tile count, map not loaded", Logger::Type::Error); - return reset(); - } - - width = mapNode.attribute("tilewidth").as_int(); - height = mapNode.attribute("tileheight").as_int(); - if (width && height) - { - m_tileSize = { width, height }; - } - else - { - Logger::log("Invalid tile size, map not loaded", Logger::Type::Error); - return reset(); - } - - m_hexSideLength = mapNode.attribute("hexsidelength").as_float(); - if (m_orientation == Orientation::Hexagonal && m_hexSideLength <= 0) - { - Logger::log("Invalid he side length found, map not loaded", Logger::Type::Error); - return reset(); - } - - attribString = mapNode.attribute("staggeraxis").as_string(); - if (attribString == "x") - { - m_staggerAxis = StaggerAxis::X; - } - else if (attribString == "y") - { - m_staggerAxis = StaggerAxis::Y; - } - if ((m_orientation == Orientation::Staggered || m_orientation == Orientation::Hexagonal) - && m_staggerAxis == StaggerAxis::None) - { - Logger::log("Map missing stagger axis property. Map not loaded.", Logger::Type::Error); - return reset(); - } - - attribString = mapNode.attribute("staggerindex").as_string(); - if (attribString == "odd") - { - m_staggerIndex = StaggerIndex::Odd; - } - else if (attribString == "even") - { - m_staggerIndex = StaggerIndex::Even; - } - if ((m_orientation == Orientation::Staggered || m_orientation == Orientation::Hexagonal) - && m_staggerIndex == StaggerIndex::None) - { - Logger::log("Map missing stagger index property. Map not loaded.", Logger::Type::Error); - return reset(); - } - - m_parallaxOrigin = - { - mapNode.attribute("parallaxoriginx").as_float(0.f), - mapNode.attribute("parallaxoriginy").as_float(0.f) - }; - - //colour property is optional - attribString = mapNode.attribute("backgroundcolor").as_string(); - if (!attribString.empty()) - { - m_backgroundColour = colourFromString(attribString); - } - - //TODO do we need next object ID - - //parse all child nodes - for (const auto& node : mapNode.children()) - { - std::string name = node.name(); - if (name == "tileset") - { - m_tilesets.emplace_back(m_workingDirectory); - m_tilesets.back().parse(node, this); - } - else if (name == "layer") - { - m_layers.emplace_back(std::make_unique(m_tileCount.x * m_tileCount.y)); - m_layers.back()->parse(node); - } - else if (name == "objectgroup") - { - m_layers.emplace_back(std::make_unique()); - m_layers.back()->parse(node, this); - } - else if (name == "imagelayer") - { - m_layers.emplace_back(std::make_unique(m_workingDirectory)); - m_layers.back()->parse(node, this); - } - else if (name == "properties") - { - const auto& children = node.children(); - for (const auto& child : children) - { - m_properties.emplace_back(); - m_properties.back().parse(child); - } - } - else if (name == "group") - { - m_layers.emplace_back(std::make_unique(m_workingDirectory, m_tileCount)); - m_layers.back()->parse(node, this); - } - else - { - LOG("Unidentified name " + name + ": node skipped", Logger::Type::Warning); - } - } - // fill animated tiles for easier lookup into map - for(const auto& ts : m_tilesets) - { - for(const auto& tile : ts.getTiles()) - { - if (!tile.animation.frames.empty()) - { - m_animTiles[tile.ID + ts.getFirstGID()] = tile; - } - } - } - - return true; -} - -bool Map::reset() -{ - m_orientation = Orientation::None; - m_renderOrder = RenderOrder::None; - m_tileCount = { 0u, 0u }; - m_tileSize = { 0u, 0u }; - m_hexSideLength = 0.f; - m_staggerAxis = StaggerAxis::None; - m_staggerIndex = StaggerIndex::None; - m_backgroundColour = {}; - m_workingDirectory = ""; - - m_tilesets.clear(); - m_layers.clear(); - m_properties.clear(); - - m_templateObjects.clear(); - m_templateTilesets.clear(); - - m_animTiles.clear(); - - return false; -} diff --git a/ext/tmxlite/src/Object.cpp b/ext/tmxlite/src/Object.cpp deleted file mode 100644 index dc63d8f..0000000 --- a/ext/tmxlite/src/Object.cpp +++ /dev/null @@ -1,399 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2021 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#include "tmxlite/Object.hpp" -#include "tmxlite/FreeFuncs.hpp" -#include "tmxlite/Map.hpp" -#include "tmxlite/Tileset.hpp" -#include "tmxlite/detail/Log.hpp" - -#include -#include - -using namespace tmx; - -Object::Object() - : m_UID (0), - m_rotation (0.f), - m_tileID (0), - m_flipFlags (0), - m_visible (true), - m_shape (Shape::Rectangle) -{ - -} - -//public -void Object::parse(const pugi::xml_node& node, Map* map) -{ - std::string attribString = node.name(); - if (attribString != "object") - { - Logger::log("This not an Object node, parsing skipped.", Logger::Type::Error); - return; - } - - m_UID = node.attribute("id").as_int(); - m_name = node.attribute("name").as_string(); - - m_class = node.attribute("type").as_string(); - if (m_class.empty()) - { - m_class = node.attribute("class").as_string(); - } - - m_position.x = node.attribute("x").as_float(); - m_AABB.left = m_position.x; - m_position.y = node.attribute("y").as_float(); - m_AABB.top = m_position.y; - m_AABB.width = node.attribute("width").as_float(); - m_AABB.height = node.attribute("height").as_float(); - m_rotation = node.attribute("rotation").as_float(); - m_visible = node.attribute("visible").as_bool(true); - - m_tileID = node.attribute("gid").as_uint(); - - static const std::uint32_t mask = 0xf0000000; - m_flipFlags = ((m_tileID & mask) >> 28); - m_tileID = m_tileID & ~mask; - - for (const auto& child : node.children()) - { - attribString = child.name(); - if (attribString == "properties") - { - for (const auto& p : child.children()) - { - m_properties.emplace_back(); - m_properties.back().parse(p); - } - } - else if (attribString == "ellipse") - { - m_shape = Shape::Ellipse; - } - else if (attribString == "point") - { - m_shape = Shape::Point; - } - else if (attribString == "polygon") - { - m_shape = Shape::Polygon; - parsePoints(child); - } - else if (attribString == "polyline") - { - m_shape = Shape::Polyline; - parsePoints(child); - } - else if (attribString == "text") - { - m_shape = Shape::Text; - parseText(child); - } - } - - //parse templates last so we know which properties - //ought to be overridden - std::string templateStr = node.attribute("template").as_string(); - if (!templateStr.empty() && map) - { - parseTemplate(templateStr, map); - } -} - -//private -void Object::parsePoints(const pugi::xml_node& node) -{ - if (node.attribute("points")) - { - std::string pointlist = node.attribute("points").as_string(); - std::stringstream stream(pointlist); - std::vector points; - std::string pointstring; - while (std::getline(stream, pointstring, ' ')) - { - points.push_back(pointstring); - } - - //parse each pair into sf::vector2f - for (unsigned int i = 0; i < points.size(); i++) - { - std::vector coords; - std::stringstream coordstream(points[i]); - - float j; - while (coordstream >> j) - { - coords.push_back(j); - //TODO this should really ignore anything non-numeric - if (coordstream.peek() == ',') - { - coordstream.ignore(); - } - } - m_points.emplace_back(coords[0], coords[1]); - } - } - else - { - Logger::log("Points for polygon or polyline object are missing", Logger::Type::Warning); - } -} - -void Object::parseText(const pugi::xml_node& node) -{ - m_textData.bold = node.attribute("bold").as_bool(false); - m_textData.colour = colourFromString(node.attribute("color").as_string("#FFFFFFFF")); - m_textData.fontFamily = node.attribute("fontfamily").as_string(); - m_textData.italic = node.attribute("italic").as_bool(false); - m_textData.kerning = node.attribute("kerning").as_bool(true); - m_textData.pixelSize = node.attribute("pixelsize").as_uint(16); - m_textData.strikethough = node.attribute("strikeout").as_bool(false); - m_textData.underline = node.attribute("underline").as_bool(false); - m_textData.wrap = node.attribute("wrap").as_bool(false); - - std::string alignment = node.attribute("halign").as_string("left"); - if (alignment == "left") - { - m_textData.hAlign = Text::HAlign::Left; - } - else if (alignment == "center") - { - m_textData.hAlign = Text::HAlign::Centre; - } - else if (alignment == "right") - { - m_textData.hAlign = Text::HAlign::Right; - } - - alignment = node.attribute("valign").as_string("top"); - if (alignment == "top") - { - m_textData.vAlign = Text::VAlign::Top; - } - else if (alignment == "center") - { - m_textData.vAlign = Text::VAlign::Centre; - } - else if (alignment == "bottom") - { - m_textData.vAlign = Text::VAlign::Bottom; - } - - m_textData.content = node.text().as_string(); -} - -void Object::parseTemplate(const std::string& path, Map* map) -{ - assert(map); - - auto& templateObjects = map->getTemplateObjects(); - auto& templateTilesets = map->getTemplateTilesets(); - - //load the template if not already loaded - if (templateObjects.count(path) == 0) - { - auto templatePath = map->getWorkingDirectory() + "/" + path; - - pugi::xml_document doc; - if (!doc.load_file(templatePath.c_str())) - { - Logger::log("Failed opening template file " + path, Logger::Type::Error); - return; - } - - auto templateNode = doc.child("template"); - if (!templateNode) - { - Logger::log("Template node missing from " + path, Logger::Type::Error); - return; - } - - //if the template has a tileset load that (if not already loaded) - std::string tilesetName; - auto tileset = templateNode.child("tileset"); - if (tileset) - { - tilesetName = tileset.attribute("source").as_string(); - if (!tilesetName.empty() && - templateTilesets.count(tilesetName) == 0) - { - templateTilesets.insert(std::make_pair(tilesetName, Tileset(map->getWorkingDirectory()))); - templateTilesets.at(tilesetName).parse(tileset, map); - } - } - - //parse the object - don't pass the map pointer here so there's - //no recursion if someone tried to get clever and put a template in a template - auto obj = templateNode.child("object"); - if (obj) - { - templateObjects.insert(std::make_pair(path, Object())); - templateObjects[path].parse(obj, nullptr); - templateObjects[path].m_tilesetName = tilesetName; - } - } - - //apply any non-overridden object properties from the template - if (templateObjects.count(path) != 0) - { - const auto& obj = templateObjects[path]; - if (m_AABB.width == 0) - { - m_AABB.width = obj.m_AABB.width; - } - - if (m_AABB.height == 0) - { - m_AABB.height = obj.m_AABB.height; - } - - m_tilesetName = obj.m_tilesetName; - - if (m_name.empty()) - { - m_name = obj.m_name; - } - - if (m_class.empty()) - { - m_class = obj.m_class; - } - - if (m_rotation == 0) - { - m_rotation = obj.m_rotation; - } - - if (m_tileID == 0) - { - m_tileID = obj.m_tileID; - } - - if (m_flipFlags == 0) - { - m_flipFlags = obj.m_flipFlags; - } - - if (m_shape == Shape::Rectangle) - { - m_shape = obj.m_shape; - } - - if (m_points.empty()) - { - m_points = obj.m_points; - } - - //compare properties and only copy ones that don't exist - for (const auto& p : obj.m_properties) - { - auto result = std::find_if(m_properties.begin(), m_properties.end(), - [&p](const Property& a) - { - return a.getName() == p.getName(); - }); - - if (result == m_properties.end()) - { - m_properties.push_back(p); - } - } - - - if (m_shape == Shape::Text) - { - //check each text property and update as necessary - //TODO this makes he assumption we prefer the template - //properties over the default ones - this might not - //actually be the case.... - const auto& otherText = obj.m_textData; - if (m_textData.fontFamily.empty()) - { - m_textData.fontFamily = otherText.fontFamily; - } - - if (m_textData.pixelSize == 16) - { - m_textData.pixelSize = otherText.pixelSize; - } - - //TODO this isn't actually right if we *want* to be false - //and the template is set to true... - if (m_textData.wrap == false) - { - m_textData.wrap = otherText.wrap; - } - - if (m_textData.colour == Colour()) - { - m_textData.colour = otherText.colour; - } - - if (m_textData.bold == false) - { - m_textData.bold = otherText.bold; - } - - if (m_textData.italic == false) - { - m_textData.italic = otherText.italic; - } - - if (m_textData.underline == false) - { - m_textData.underline = otherText.underline; - } - - if (m_textData.strikethough == false) - { - m_textData.strikethough = otherText.strikethough; - } - - if (m_textData.kerning == true) - { - m_textData.kerning = otherText.kerning; - } - - if (m_textData.hAlign == Text::HAlign::Left) - { - m_textData.hAlign = otherText.hAlign; - } - - if (m_textData.vAlign == Text::VAlign::Top) - { - m_textData.vAlign = otherText.vAlign; - } - - if (m_textData.content.empty()) - { - m_textData.content = otherText.content; - } - } - } -} diff --git a/ext/tmxlite/src/ObjectGroup.cpp b/ext/tmxlite/src/ObjectGroup.cpp deleted file mode 100644 index 9477bf9..0000000 --- a/ext/tmxlite/src/ObjectGroup.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2023 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#include "tmxlite/FreeFuncs.hpp" -#include "tmxlite/ObjectGroup.hpp" -#include "tmxlite/detail/Log.hpp" - -#include - -using namespace tmx; - -ObjectGroup::ObjectGroup() - : m_colour (127, 127, 127, 255), - m_drawOrder (DrawOrder::TopDown) -{ - -} - -//public -void ObjectGroup::parse(const pugi::xml_node& node, Map* map) -{ - assert(map); - - std::string attribString = node.name(); - if (attribString != "objectgroup") - { - Logger::log("Node was not an object group, node will be skipped.", Logger::Type::Error); - return; - } - - setName(node.attribute("name").as_string()); - setClass(node.attribute("class").as_string()); - - attribString = node.attribute("color").as_string(); - if (!attribString.empty()) - { - m_colour = colourFromString(attribString); - } - - setOpacity(node.attribute("opacity").as_float(1.f)); - setVisible(node.attribute("visible").as_bool(true)); - setOffset(node.attribute("offsetx").as_int(0), node.attribute("offsety").as_int(0)); - setSize(node.attribute("width").as_uint(0), node.attribute("height").as_uint(0)); - setParallaxFactor(node.attribute("parallaxx").as_float(1.f), node.attribute("parallaxy").as_float(1.f)); - - std::string tintColour = node.attribute("tintcolor").as_string(); - if (!tintColour.empty()) - { - setTintColour(colourFromString(tintColour)); - } - - attribString = node.attribute("draworder").as_string(); - if (attribString == "index") - { - m_drawOrder = DrawOrder::Index; - } - - for (const auto& child : node.children()) - { - attribString = child.name(); - if (attribString == "properties") - { - for (const auto& p : child) - { - m_properties.emplace_back(); - m_properties.back().parse(p); - } - } - else if (attribString == "object") - { - m_objects.emplace_back(); - m_objects.back().parse(child, map); - } - } -} diff --git a/ext/tmxlite/src/ObjectTypes.cpp b/ext/tmxlite/src/ObjectTypes.cpp deleted file mode 100644 index 6bbf519..0000000 --- a/ext/tmxlite/src/ObjectTypes.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/********************************************************************* -Raphaƫl Frantz 2021 - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#include "tmxlite/FreeFuncs.hpp" -#include "tmxlite/ObjectTypes.hpp" -#include "tmxlite/detail/Log.hpp" - -#include - -using namespace tmx; - -bool ObjectTypes::load(const std::string &path) -{ - reset(); - - //open the doc - pugi::xml_document doc; - auto result = doc.load_file(path.c_str()); - if (!result) - { - Logger::log("Failed opening " + path, Logger::Type::Error); - Logger::log("Reason: " + std::string(result.description()), Logger::Type::Error); - return false; - } - - //make sure we have consistent path separators - m_workingDirectory = path; - std::replace(m_workingDirectory.begin(), m_workingDirectory.end(), '\\', '/'); - m_workingDirectory = getFilePath(m_workingDirectory); - - if (!m_workingDirectory.empty() && - m_workingDirectory.back() == '/') - { - m_workingDirectory.pop_back(); - } - - - //find the node and bail if it doesn't exist - auto node = doc.child("objecttypes"); - if (!node) - { - Logger::log("Failed opening object types: " + path + ", no objecttype node found", Logger::Type::Error); - return reset(); - } - - return parseObjectTypesNode(node); -} - -bool ObjectTypes::loadFromString(const std::string &data, const std::string &workingDir) -{ - reset(); - - //open the doc - pugi::xml_document doc; - auto result = doc.load_string(data.c_str()); - if (!result) - { - Logger::log("Failed opening object types", Logger::Type::Error); - Logger::log("Reason: " + std::string(result.description()), Logger::Type::Error); - return false; - } - - //make sure we have consistent path separators - m_workingDirectory = workingDir; - std::replace(m_workingDirectory.begin(), m_workingDirectory.end(), '\\', '/'); - m_workingDirectory = getFilePath(m_workingDirectory); - - if (!m_workingDirectory.empty() && - m_workingDirectory.back() == '/') - { - m_workingDirectory.pop_back(); - } - - - //find the node and bail if it doesn't exist - auto node = doc.child("objecttypes"); - if (!node) - { - Logger::log("Failed object types: no objecttypes node found", Logger::Type::Error); - return reset(); - } - - return parseObjectTypesNode(node); -} - -bool ObjectTypes::parseObjectTypesNode(const pugi::xml_node &node) -{ - // <-- node - // - // ... - - //parse types - for(const auto& child : node.children()) - { - std::string attribString = child.name(); - if (attribString == "objecttype") - { - Type type; - - //parse the metadata of the type - type.name = child.attribute("name").as_string(); - type.colour = colourFromString(child.attribute("color").as_string("#FFFFFFFF"));; - - //parse the default properties of the type - for (const auto& p : child.children()) - { - Property prop; - prop.parse(p, true); - type.properties.push_back(prop); - } - - m_types.push_back(type); - } - else - { - LOG("Unidentified name " + attribString + ": node skipped", Logger::Type::Warning); - } - } - - return true; -} - -bool ObjectTypes::reset() -{ - m_workingDirectory.clear(); - m_types.clear(); - return false; -} diff --git a/ext/tmxlite/src/Property.cpp b/ext/tmxlite/src/Property.cpp deleted file mode 100644 index 4e6c376..0000000 --- a/ext/tmxlite/src/Property.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2021 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#include "tmxlite/Property.hpp" -#include "tmxlite/detail/Log.hpp" -#include "tmxlite/FreeFuncs.hpp" - -#include - -using namespace tmx; - -Property::Property() - : m_type(Type::Undef) -{ -} - -Property Property::fromBoolean(bool value) -{ - Property p; - p.m_type = Type::Boolean; - p.m_boolValue = value; - return p; -} - -Property Property::fromFloat(float value) -{ - Property p; - p.m_type = Type::Float; - p.m_floatValue = value; - return p; -} - -Property Property::fromInt(int value) -{ - Property p; - p.m_type = Type::Int; - p.m_intValue = value; - return p; -} - -Property Property::fromString(const std::string& value) -{ - Property p; - p.m_type = Type::String; - p.m_stringValue = value; - return p; -} - -Property Property::fromColour(const Colour& value) -{ - Property p; - p.m_type = Type::Colour; - p.m_colourValue = value; - return p; -} - -Property Property::fromFile(const std::string& value) -{ - Property p; - p.m_type = Type::File; - p.m_stringValue = value; - return p; -} - -Property Property::fromObject(int value) -{ - Property p; - p.m_type = Type::Object; - p.m_intValue = value; - return p; -} - -//public -void Property::parse(const pugi::xml_node& node, bool isObjectTypes) -{ - // The value attribute name is different in object types - const char *const valueAttribute = isObjectTypes ? "default" : "value"; - - std::string attribData = node.name(); - if (attribData != "property") - { - Logger::log("Node was not a valid property, node will be skipped", Logger::Type::Error); - return; - } - - m_name = node.attribute("name").as_string(); - - attribData = node.attribute("type").as_string("string"); - if (attribData == "bool") - { - attribData = node.attribute(valueAttribute).as_string("false"); - m_boolValue = (attribData == "true"); - m_type = Type::Boolean; - return; - } - else if (attribData == "int") - { - m_intValue = node.attribute(valueAttribute).as_int(0); - m_type = Type::Int; - return; - } - else if (attribData == "float") - { - m_floatValue = node.attribute(valueAttribute).as_float(0.f); - m_type = Type::Float; - return; - } - else if (attribData == "string") - { - m_stringValue = node.attribute(valueAttribute).as_string(); - - //if value is empty, try getting the child value instead - //as this is how multiline string properties are stored. - if(m_stringValue.empty()) - { - m_stringValue = node.child_value(); - } - - m_type = Type::String; - return; - } - else if (attribData == "color") - { - m_colourValue = colourFromString(node.attribute(valueAttribute).as_string("#FFFFFFFF")); - m_type = Type::Colour; - return; - } - else if (attribData == "file") - { - m_stringValue = node.attribute(valueAttribute).as_string(); - m_type = Type::File; - return; - } - else if (attribData == "object") - { - m_intValue = node.attribute(valueAttribute).as_int(0); - m_type = Type::Object; - return; - } -} diff --git a/ext/tmxlite/src/TileLayer.cpp b/ext/tmxlite/src/TileLayer.cpp deleted file mode 100644 index a08f30a..0000000 --- a/ext/tmxlite/src/TileLayer.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2023 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#include "base64.h" -#include "tmxlite/FreeFuncs.hpp" -#include "tmxlite/TileLayer.hpp" -#include "tmxlite/detail/Log.hpp" -#ifndef USE_ZLIB -# include "tmxlite/detail/gzip.hpp" -#endif - -#include -#include -#include -#include - -using namespace tmx; - -namespace -{ - struct CompressionType final - { - enum - { - Zlib, GZip, Zstd, None - }; - }; -} - -TileLayer::TileLayer(std::size_t tileCount) - : m_tileCount (tileCount) -{ - m_tiles.reserve(tileCount); -} - -//public -void TileLayer::parse(const pugi::xml_node& node, Map*) -{ - std::string attribName = node.name(); - if (attribName != "layer") - { - Logger::log("node not a layer node, skipped parsing", Logger::Type::Error); - return; - } - - setName(node.attribute("name").as_string()); - setClass(node.attribute("class").as_string()); - setOpacity(node.attribute("opacity").as_float(1.f)); - setVisible(node.attribute("visible").as_bool(true)); - setOffset(node.attribute("offsetx").as_int(0), node.attribute("offsety").as_int(0)); - setSize(node.attribute("width").as_uint(0), node.attribute("height").as_uint(0)); - setParallaxFactor(node.attribute("parallaxx").as_float(1.f), node.attribute("parallaxy").as_float(1.f)); - - std::string tintColour = node.attribute("tintcolor").as_string(); - if (!tintColour.empty()) - { - setTintColour(colourFromString(tintColour)); - } - - for (const auto& child : node.children()) - { - attribName = child.name(); - if (attribName == "data") - { - attribName = child.attribute("encoding").as_string(); - if (attribName == "base64") - { - parseBase64(child); - } - else if (attribName == "csv") - { - parseCSV(child); - } - else - { - parseUnencoded(child); - } - } - else if (attribName == "properties") - { - for (const auto& p : child.children()) - { - addProperty(p); - } - } - } - -} - -//private -void TileLayer::parseBase64(const pugi::xml_node& node) -{ - auto processDataString = [](std::string dataString, std::size_t tileCount, std::int32_t compressionType)->std::vector - { - std::stringstream ss; - ss << dataString; - ss >> dataString; - dataString = base64_decode(dataString); - - std::size_t expectedSize = tileCount * 4; //4 bytes per tile - std::vector byteData; - byteData.reserve(expectedSize); - - switch (compressionType) - { - default: - byteData.insert(byteData.end(), dataString.begin(), dataString.end()); - break; - case CompressionType::Zstd: - { - std::size_t dataSize = dataString.length() * sizeof(unsigned char); - std::size_t result = ZSTD_decompress(byteData.data(), expectedSize, &dataString[0], dataSize); - - if (ZSTD_isError(result)) - { - std::string err = ZSTD_getErrorName(result); - LOG("Failed to decompress layer data, node skipped.\nError: " + err, Logger::Type::Error); - } - } - break; - case CompressionType::GZip: -#ifndef USE_ZLIB - { - byteData.resize(expectedSize); - const auto source = std::span(reinterpret_cast(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 {}; - } - } - break; -#endif - //[[fallthrough]]; - case CompressionType::Zlib: - { - //unzip - std::size_t dataSize = dataString.length() * sizeof(unsigned char); - - if (!decompress(dataString.c_str(), byteData, dataSize, expectedSize)) - { - LOG("Failed to decompress layer data, node skipped.", Logger::Type::Error); - return {}; - } - } - break; - } - - //data stream is in bytes so we need to OR into 32 bit values - std::vector IDs; - IDs.reserve(tileCount); - for (auto i = 0u; i < expectedSize - 3u; i += 4u) - { - std::uint32_t id = byteData[i] | byteData[i + 1] << 8 | byteData[i + 2] << 16 | byteData[i + 3] << 24; - IDs.push_back(id); - } - - return IDs; - }; - - std::int32_t compressionType = CompressionType::None; - std::string compression = node.attribute("compression").as_string(); - if (compression == "gzip") - { - compressionType = CompressionType::GZip; - } - else if (compression == "zlib") - { - compressionType = CompressionType::Zlib; - } - else if (compression == "zstd") - { - compressionType = CompressionType::Zstd; - } - - std::string data = node.text().as_string(); - if (data.empty()) - { - //check for chunk nodes - auto dataCount = 0; - for (const auto& childNode : node.children()) - { - std::string childName = childNode.name(); - if (childName == "chunk") - { - std::string dataString = childNode.text().as_string(); - if (!dataString.empty()) - { - Chunk chunk; - chunk.position.x = childNode.attribute("x").as_int(); - chunk.position.y = childNode.attribute("y").as_int(); - - chunk.size.x = childNode.attribute("width").as_int(); - chunk.size.y = childNode.attribute("height").as_int(); - - auto IDs = processDataString(dataString, (chunk.size.x * chunk.size.y), compressionType); - - if (!IDs.empty()) - { - createTiles(IDs, chunk.tiles); - m_chunks.push_back(chunk); - dataCount++; - } - } - } - } - - if (dataCount == 0) - { - Logger::log("Layer " + getName() + " has no layer data. Layer skipped.", Logger::Type::Error); - return; - } - } - else - { - auto IDs = processDataString(data, m_tileCount, compressionType); - createTiles(IDs, m_tiles); - } -} - -void TileLayer::parseCSV(const pugi::xml_node& node) -{ - auto processDataString = [](const std::string dataString, std::size_t tileCount)->std::vector - { - std::vector IDs; - IDs.reserve(tileCount); - - const char* ptr = dataString.c_str(); - while (true) - { - char* end; - auto res = std::strtoul(ptr, &end, 10); - if (end == ptr) break; - ptr = end; - IDs.push_back(res); - if (*ptr == ',') ++ptr; - } - - return IDs; - }; - - std::string data = node.text().as_string(); - if (data.empty()) - { - //check for chunk nodes - auto dataCount = 0; - for (const auto& childNode : node.children()) - { - std::string childName = childNode.name(); - if (childName == "chunk") - { - std::string dataString = childNode.text().as_string(); - if (!dataString.empty()) - { - Chunk chunk; - chunk.position.x = childNode.attribute("x").as_int(); - chunk.position.y = childNode.attribute("y").as_int(); - - chunk.size.x = childNode.attribute("width").as_int(); - chunk.size.y = childNode.attribute("height").as_int(); - - auto IDs = processDataString(dataString, chunk.size.x * chunk.size.y); - - if (!IDs.empty()) - { - createTiles(IDs, chunk.tiles); - m_chunks.push_back(chunk); - dataCount++; - } - } - } - } - - if (dataCount == 0) - { - Logger::log("Layer " + getName() + " has no layer data. Layer skipped.", Logger::Type::Error); - return; - } - } - else - { - createTiles(processDataString(data, m_tileCount), m_tiles); - } -} - -void TileLayer::parseUnencoded(const pugi::xml_node& node) -{ - std::string attribName; - std::vector IDs; - IDs.reserve(m_tileCount); - - for (const auto& child : node.children()) - { - attribName = child.name(); - if (attribName == "tile") - { - IDs.push_back(child.attribute("gid").as_uint()); - } - } - - createTiles(IDs, m_tiles); -} - -void TileLayer::createTiles(const std::vector& IDs, std::vector& destination) -{ - //LOG(IDs.size() != m_tileCount, "Layer tile count does not match expected size. Found: " - // + std::to_string(IDs.size()) + ", expected: " + std::to_string(m_tileCount)); - - static const std::uint32_t mask = 0xf0000000; - for (const auto& id : IDs) - { - destination.emplace_back(); - destination.back().flipFlags = ((id & mask) >> 28); - destination.back().ID = id & ~mask; - } -} diff --git a/ext/tmxlite/src/Tileset.cpp b/ext/tmxlite/src/Tileset.cpp deleted file mode 100644 index 02db219..0000000 --- a/ext/tmxlite/src/Tileset.cpp +++ /dev/null @@ -1,456 +0,0 @@ -/********************************************************************* -Matt Marchant 2016 - 2023 -http://trederia.blogspot.com - -tmxlite - Zlib license. - -This software is provided 'as-is', without any express or -implied warranty. In no event will the authors be held -liable for any damages arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute -it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; -you must not claim that you wrote the original software. -If you use this software in a product, an acknowledgment -in the product documentation would be appreciated but -is not required. - -2. Altered source versions must be plainly marked as such, -and must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any -source distribution. -*********************************************************************/ - -#include "tmxlite/Tileset.hpp" -#include "tmxlite/FreeFuncs.hpp" -#include "tmxlite/detail/Log.hpp" - -#include -#include - -using namespace tmx; - -Tileset::Tileset(const std::string& workingDir) - : m_workingDir (workingDir), - m_firstGID (0), - m_spacing (0), - m_margin (0), - m_tileCount (0), - m_columnCount (0), - m_objectAlignment (ObjectAlignment::Unspecified), - m_transparencyColour (0, 0, 0, 0), - m_hasTransparency (false) -{ - -} - -//public -void Tileset::parse(pugi::xml_node node, Map* map) -{ - assert(map); - - std::string attribString = node.name(); - if (attribString != "tileset") - { - Logger::log(attribString + ": not a tileset node! Node will be skipped.", Logger::Type::Warning); - return; - } - - m_firstGID = node.attribute("firstgid").as_int(); - if (m_firstGID == 0) - { - Logger::log("Invalid first GID in tileset. Tileset node skipped.", Logger::Type::Warning); - return; - } - - pugi::xml_document tsxDoc; //need to keep this in scope - if (node.attribute("source")) - { - //parse TSX doc - std::string path = node.attribute("source").as_string(); - path = resolveFilePath(path, m_workingDir); - - //as the TSX file now dictates the image path, the working - //directory is now that of the tsx file - auto position = path.find_last_of('/'); - if (position != std::string::npos) - { - m_workingDir = path.substr(0, position); - } - else - { - m_workingDir = ""; - } - - //see if doc can be opened - auto result = tsxDoc.load_file(path.c_str()); - if (!result) - { - Logger::log(path + ": Failed opening tsx file for tile set, tile set will be skipped", Logger::Type::Error); - return reset(); - } - - //if it can then replace the current node with tsx node - node = tsxDoc.child("tileset"); - if (!node) - { - Logger::log("tsx file does not contain a tile set node, tile set will be skipped", Logger::Type::Error); - return reset(); - } - } - - m_name = node.attribute("name").as_string(); - LOG("found tile set " + m_name, Logger::Type::Info); - m_class = node.attribute("class").as_string(); - - m_tileSize.x = node.attribute("tilewidth").as_int(); - m_tileSize.y = node.attribute("tileheight").as_int(); - if (m_tileSize.x == 0 || m_tileSize.y == 0) - { - Logger::log("Invalid tile size found in tile set node. Node will be skipped.", Logger::Type::Error); - return reset(); - } - - m_spacing = node.attribute("spacing").as_int(); - m_margin = node.attribute("margin").as_int(); - m_tileCount = node.attribute("tilecount").as_int(); - m_columnCount = node.attribute("columns").as_int(); - - m_tileIndex.reserve(m_tileCount); - m_tiles.reserve(m_tileCount); - - std::string objectAlignment = node.attribute("objectalignment").as_string(); - if (!objectAlignment.empty()) - { - if (objectAlignment == "unspecified") - { - m_objectAlignment = ObjectAlignment::Unspecified; - } - else if (objectAlignment == "topleft") - { - m_objectAlignment = ObjectAlignment::TopLeft; - } - else if (objectAlignment == "top") - { - m_objectAlignment = ObjectAlignment::Top; - } - else if (objectAlignment == "topright") - { - m_objectAlignment = ObjectAlignment::TopRight; - } - else if (objectAlignment == "left") - { - m_objectAlignment = ObjectAlignment::Left; - } - else if (objectAlignment == "center") - { - m_objectAlignment = ObjectAlignment::Center; - } - else if (objectAlignment == "right") - { - m_objectAlignment = ObjectAlignment::Right; - } - else if (objectAlignment == "bottomleft") - { - m_objectAlignment = ObjectAlignment::BottomLeft; - } - else if (objectAlignment == "bottom") - { - m_objectAlignment = ObjectAlignment::Bottom; - } - else if (objectAlignment == "bottomright") - { - m_objectAlignment = ObjectAlignment::BottomRight; - } - } - - const auto& children = node.children(); - for (const auto& node : children) - { - std::string name = node.name(); - if (name == "image") - { - //TODO this currently doesn't cover embedded images - //mostly because I can't figure out how to export them - //from the Tiled editor... but also resource handling - //should be handled by the renderer, not the parser. - attribString = node.attribute("source").as_string(); - if (attribString.empty()) - { - Logger::log("Tileset image node has missing source property, tile set not loaded", Logger::Type::Error); - return reset(); - } - m_imagePath = resolveFilePath(attribString, m_workingDir); - if (node.attribute("trans")) - { - attribString = node.attribute("trans").as_string(); - m_transparencyColour = colourFromString(attribString); - m_hasTransparency = true; - } - if (node.attribute("width") && node.attribute("height")) - { - m_imageSize.x = node.attribute("width").as_int(); - m_imageSize.y = node.attribute("height").as_int(); - } - } - else if (name == "tileoffset") - { - parseOffsetNode(node); - } - else if (name == "properties") - { - parsePropertyNode(node); - } - else if (name == "terraintypes") - { - parseTerrainNode(node); - } - else if (name == "tile") - { - parseTileNode(node, map); - } - } - - //if the tsx file does not declare every tile, we create the missing ones - if (m_tiles.size() != getTileCount()) - { - for (std::uint32_t ID = 0; ID < getTileCount(); ID++) - { - createMissingTile(ID); - } - } -} - -std::uint32_t Tileset::getLastGID() const -{ - assert(!m_tileIndex.empty()); - return m_firstGID + static_cast(m_tileIndex.size()) - 1; -} - -const Tileset::Tile* Tileset::getTile(std::uint32_t id) const -{ - if (!hasTile(id)) - { - return nullptr; - } - - //corrects the ID. Indices and IDs are different. - id -= m_firstGID; - id = m_tileIndex[id]; - return id ? &m_tiles[id - 1] : nullptr; -} - -//private -void Tileset::reset() -{ - m_firstGID = 0; - m_source = ""; - m_name = ""; - m_class = ""; - m_tileSize = { 0,0 }; - m_spacing = 0; - m_margin = 0; - m_tileCount = 0; - m_columnCount = 0; - m_objectAlignment = ObjectAlignment::Unspecified; - m_tileOffset = { 0,0 }; - m_properties.clear(); - m_imagePath = ""; - m_transparencyColour = { 0, 0, 0, 0 }; - m_hasTransparency = false; - m_terrainTypes.clear(); - m_tileIndex.clear(); - m_tiles.clear(); -} - -void Tileset::parseOffsetNode(const pugi::xml_node& node) -{ - m_tileOffset.x = node.attribute("x").as_int(); - m_tileOffset.y = node.attribute("y").as_int(); -} - -void Tileset::parsePropertyNode(const pugi::xml_node& node) -{ - const auto& children = node.children(); - for (const auto& child : children) - { - m_properties.emplace_back(); - m_properties.back().parse(child); - } -} - -void Tileset::parseTerrainNode(const pugi::xml_node& node) -{ - const auto& children = node.children(); - for (const auto& child : children) - { - std::string name = child.name(); - if (name == "terrain") - { - m_terrainTypes.emplace_back(); - auto& terrain = m_terrainTypes.back(); - terrain.name = child.attribute("name").as_string(); - terrain.tileID = child.attribute("tile").as_int(); - auto properties = child.child("properties"); - if (properties) - { - for (const auto& p : properties) - { - name = p.name(); - if (name == "property") - { - terrain.properties.emplace_back(); - terrain.properties.back().parse(p); - } - } - } - } - } -} - -Tileset::Tile& Tileset::newTile(std::uint32_t ID) -{ - Tile& tile = (m_tiles.emplace_back(), m_tiles.back()); - if (m_tileIndex.size() <= ID) - { - m_tileIndex.resize(ID + 1, 0); - } - - m_tileIndex[ID] = static_cast(m_tiles.size()); - tile.ID = ID; - return tile; -} - -void Tileset::parseTileNode(const pugi::xml_node& node, Map* map) -{ - assert(map); - - Tile& tile = newTile(node.attribute("id").as_int()); - if (node.attribute("terrain")) - { - std::string data = node.attribute("terrain").as_string(); - bool lastWasChar = true; - std::size_t idx = 0u; - for (auto i = 0u; i < data.size() && idx < tile.terrainIndices.size(); ++i) - { - if (isdigit(data[i])) - { - tile.terrainIndices[idx++] = std::atoi(&data[i]); - lastWasChar = false; - } - else - { - if (!lastWasChar) - { - lastWasChar = true; - } - else - { - tile.terrainIndices[idx++] = -1; - lastWasChar = false; - } - } - } - if (lastWasChar) - { - tile.terrainIndices[idx] = -1; - } - } - - tile.probability = node.attribute("probability").as_int(100); - - tile.className = node.attribute("type").as_string(); - if (tile.className.empty()) - { - tile.className = node.attribute("class").as_string(); - } - - //by default we set the tile's values as in an Image tileset - tile.imagePath = m_imagePath; - tile.imageSize = m_tileSize; - - if (m_columnCount != 0) - { - std::uint32_t rowIndex = tile.ID % m_columnCount; - std::uint32_t columnIndex = tile.ID / m_columnCount; - tile.imagePosition.x = m_margin + rowIndex * (m_tileSize.x + m_spacing); - tile.imagePosition.y = m_margin + columnIndex * (m_tileSize.y + m_spacing); - } - - const auto& children = node.children(); - for (const auto& child : children) - { - std::string name = child.name(); - if (name == "properties") - { - for (const auto& prop : child.children()) - { - tile.properties.emplace_back(); - tile.properties.back().parse(prop); - } - } - else if (name == "objectgroup") - { - tile.objectGroup.parse(child, map); - } - else if (name == "image") - { - std::string attribString = child.attribute("source").as_string(); - if (attribString.empty()) - { - Logger::log("Tile image path missing", Logger::Type::Warning); - continue; - } - tile.imagePath = resolveFilePath(attribString, m_workingDir); - - tile.imagePosition = tmx::Vector2u(0, 0); - - if (child.attribute("trans")) - { - attribString = child.attribute("trans").as_string(); - m_transparencyColour = colourFromString(attribString); - m_hasTransparency = true; - } - if (child.attribute("width")) - { - tile.imageSize.x = child.attribute("width").as_uint(); - } - if (child.attribute("height")) - { - tile.imageSize.y = child.attribute("height").as_uint(); - } - } - else if (name == "animation") - { - for (const auto& frameNode : child.children()) - { - Tile::Animation::Frame frame; - frame.duration = frameNode.attribute("duration").as_int(); - frame.tileID = frameNode.attribute("tileid").as_int() + m_firstGID; - tile.animation.frames.push_back(frame); - } - } - } -} - -void Tileset::createMissingTile(std::uint32_t ID) -{ - //first, we check if the tile does not yet exist - if (m_tileIndex.size() > ID && m_tileIndex[ID]) - { - return; - } - - Tile& tile = newTile(ID); - tile.imagePath = m_imagePath; - tile.imageSize = m_tileSize; - - std::uint32_t rowIndex = ID % m_columnCount; - std::uint32_t columnIndex = ID / m_columnCount; - tile.imagePosition.x = m_margin + rowIndex * (m_tileSize.x + m_spacing); - tile.imagePosition.y = m_margin + columnIndex * (m_tileSize.y + m_spacing); -} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 53aa6e5..08895f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,8 @@ add_executable(tmx2gba argparse.hpp argparse.cpp + tmxlayer.hpp + tmxobject.hpp + tmxtileset.hpp tmxreader.hpp tmxreader.cpp convert.hpp convert.cpp headerwriter.hpp headerwriter.cpp @@ -18,7 +21,10 @@ target_compile_options(tmx2gba PRIVATE $<$:-Wall -Wextra -pedantic> $<$:-Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded>) -target_link_libraries(tmx2gba tmxlite) +target_link_libraries(${PROJECT_NAME} base64::base64 pugixml Zstd::Zstd + $<$:ZLIB::ZLIB> + $<$:miniz::miniz>) +target_link_libraries(${PROJECT_NAME} External::rapidxml) if (TMX2GBA_DKP_INSTALL) if (DEFINED ENV{DEVKITPRO}) diff --git a/ext/tmxlite/src/detail/gzip.cpp b/src/gzip.cpp similarity index 100% rename from ext/tmxlite/src/detail/gzip.cpp rename to src/gzip.cpp diff --git a/ext/tmxlite/include/tmxlite/detail/gzip.hpp b/src/gzip.hpp similarity index 100% rename from ext/tmxlite/include/tmxlite/detail/gzip.hpp rename to src/gzip.hpp diff --git a/src/headerwriter.cpp b/src/headerwriter.cpp index 0d658a9..e97f25b 100644 --- a/src/headerwriter.cpp +++ b/src/headerwriter.cpp @@ -9,7 +9,7 @@ template <> constexpr std::string_view DatType() { return "unsigned cha template <> constexpr std::string_view DatType() { return "unsigned short"; } template <> constexpr std::string_view DatType() { return "unsigned int"; } -void HeaderWriter::WriteSize(unsigned width, unsigned height) +void HeaderWriter::WriteSize(int width, int height) { stream << std::endl; WriteDefine(mName + "Width", width); diff --git a/src/headerwriter.hpp b/src/headerwriter.hpp index ddfa8c8..4ef8077 100644 --- a/src/headerwriter.hpp +++ b/src/headerwriter.hpp @@ -37,7 +37,7 @@ public: WriteDefine(name, std::to_string(value)); } - void WriteSize(unsigned width, unsigned height); + void WriteSize(int width, int height); void WriteCharacterMap(const std::span charData); void WriteCollision(const std::span collisionData); void WriteObjects(const std::span objData); diff --git a/src/tmxlayer.hpp b/src/tmxlayer.hpp new file mode 100644 index 0000000..34caf34 --- /dev/null +++ b/src/tmxlayer.hpp @@ -0,0 +1,34 @@ +/* tmxlayer.hpp - Copyright (C) 2015-2022 a dinosaur (zlib, see COPYING.txt) */ + +#ifndef TMXLAYER_HPP +#define TMXLAYER_HPP + +#include +#include +#include + +class TmxLayer +{ +public: + static constexpr uint32_t FLIP_HORZ = 0x80000000; + static constexpr uint32_t FLIP_VERT = 0x40000000; + static constexpr uint32_t FLIP_DIAG = 0x20000000; + static constexpr uint32_t FLIP_MASK = 0xE0000000; + + TmxLayer() : mWidth(0), mHeight(0), mTileDat(nullptr) {} + TmxLayer(int aWidth, int aHeight, std::string aName, uint32_t* aTileDat) + : mName(std::move(aName)), mWidth(aWidth), mHeight(aHeight), mTileDat(aTileDat) {} + inline ~TmxLayer() { delete[] mTileDat; } + + constexpr const std::string& GetName() const { return mName; } + constexpr int GetWidth() const { return mWidth; } + constexpr int GetHeight() const { return mHeight; } + constexpr const uint32_t* GetData() const { return mTileDat; } + +private: + std::string mName; + int mWidth, mHeight; + uint32_t* mTileDat; +}; + +#endif//TMXLAYER_HPP diff --git a/src/tmxobject.hpp b/src/tmxobject.hpp new file mode 100644 index 0000000..85b5b41 --- /dev/null +++ b/src/tmxobject.hpp @@ -0,0 +1,25 @@ +/* tmxobject.hpp - Copyright (C) 2015-2022 a dinosaur (zlib, see COPYING.txt) */ + +#ifndef TMXOBJECT_HPP +#define TMXOBJECT_HPP + +#include +#include + +class TmxObject +{ +public: + TmxObject() : mX(0.0f), mY(0.0f) {} + TmxObject(std::string aName, float aX, float aY) + : mName(std::move(aName)), mX(aX), mY(aY) {} + ~TmxObject() = default; + + constexpr const std::string& GetName() const { return mName; } + inline void GetPos(float& aOutX, float& aOutY) const { aOutX = mX; aOutY = mY; } + +private: + std::string mName; + float mX, mY; +}; + +#endif//TMXOBJECT_HPP diff --git a/src/tmxreader.cpp b/src/tmxreader.cpp index e597aa1..1c2b38d 100644 --- a/src/tmxreader.cpp +++ b/src/tmxreader.cpp @@ -1,12 +1,191 @@ /* tmxreader.cpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */ #include "tmxreader.hpp" -#include "tmxlite/Map.hpp" -#include "tmxlite/TileLayer.hpp" -#include "tmxlite/ObjectGroup.hpp" +#include "tmxtileset.hpp" +#include "tmxobject.hpp" +#include "tmxlayer.hpp" #include #include +bool TmxReader::DecodeMap(uint32_t* aOut, size_t aOutSize, const std::string& aBase64Dat) +{ + // Cut leading & trailing whitespace (including newlines) + auto beg = std::find_if_not(aBase64Dat.begin(), aBase64Dat.end(), ::isspace); + if (beg == std::end(aBase64Dat)) + return false; + auto end = std::find_if_not(aBase64Dat.rbegin(), aBase64Dat.rend(), ::isspace); + std::size_t begOff = std::distance(aBase64Dat.begin(), beg); + std::size_t endOff = std::distance(end, aBase64Dat.rend()) - begOff; + auto trimmed = aBase64Dat.substr(begOff, endOff); + + // Decode base64 string + std::string decoded = base64_decode(trimmed); + + // Decompress compressed data + auto dstSize = static_cast(aOutSize); + int res = uncompress( + reinterpret_cast(aOut), + &dstSize, + reinterpret_cast(decoded.data()), + static_cast(decoded.size())); + decoded.clear(); + if (res < 0) + return false; + + return true; +} + +void TmxReader::ReadTileset(rapidxml::xml_node<>* aXNode) +{ + rapidxml::xml_attribute<>* xAttrib; + + const char* name = ""; + const char* source = ""; + uint32_t firstGid = 0; + + // Read name + 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(std::stoul(xAttrib->value())); + + mTilesets.push_back(new TmxTileset(name, source, firstGid)); +} + +void TmxReader::ReadLayer(rapidxml::xml_node<>* aXNode) +{ + rapidxml::xml_attribute<>* xAttrib; + const char* name = ""; + int width = 0; + int height = 0; + uint32_t* tileDat = nullptr; + + // Read name + 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) + { + // TODO: don't assume base64 & zlib + tileDat = new uint32_t[width * height]; + if (!DecodeMap(tileDat, width * height * sizeof(uint32_t), std::string(xData->value()))) + { + delete[] tileDat; + tileDat = nullptr; + } + } + + mLayers.push_back(new TmxLayer(width, height, name, tileDat)); +} + +void TmxReader::ReadObjects(rapidxml::xml_node<>* aXNode) +{ + for (auto xNode = aXNode->first_node(); xNode != nullptr; xNode = xNode->next_sibling()) + { + if (strcmp(xNode->name(), "object") != 0) + continue; + + rapidxml::xml_attribute<>* xAttrib; + const char* name = ""; + float x = 0.0f; + float y = 0.0f; + + // Read name + 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()); + + mObjects.push_back(new TmxObject(name, x, y)); + } +} + +void TmxReader::Open(std::istream& aIn) +{ + // Delete old tilesets + for (auto tileset : mTilesets) + delete tileset; + mTilesets.clear(); + + // Delete old layers + for (auto layer : mLayers) + delete layer; + mLayers.clear(); + + mGidTable.clear(); + + // Read string into a buffer + std::stringstream buf; + buf << aIn.rdbuf(); + std::string strXml = buf.str(); + buf.clear(); + + // Parse document + rapidxml::xml_document<> xDoc; + xDoc.parse<0>(const_cast(strXml.c_str())); + + // Get map node + auto xMap = xDoc.first_node("map"); + if (xMap == nullptr) + return; + + // 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()); + + // Read nodes + for (auto xNode = xMap->first_node(); xNode != nullptr; xNode = xNode->next_sibling()) + { + // Read layer nodes + if (strcmp(xNode->name(), "layer") == 0) + ReadLayer(xNode); + else + if (strcmp(xNode->name(), "tileset") == 0) + ReadTileset(xNode); + else + if (strcmp(xNode->name(), "objectgroup") == 0) + ReadObjects(xNode); + } + + // Generate global id table + for (auto tileset : mTilesets) + mGidTable.push_back(tileset->GetFirstGid()); + std::sort(mGidTable.rbegin(), mGidTable.rend()); +} TmxReader::Error TmxReader::Open(const std::string& inPath, const std::string_view graphicsName, @@ -67,7 +246,7 @@ TmxReader::Error TmxReader::Open(const std::string& inPath, return Error::PALETTE_NOTFOUND; // Read TMX map - mSize = Size { map.getTileCount().x, map.getTileCount().y }; + mSize = Size{ map.getTileCount().x, map.getTileCount().y }; size_t numTiles = static_cast(mSize.width) * static_cast(mSize.height); // Read graphics layer diff --git a/src/tmxreader.hpp b/src/tmxreader.hpp index 2df1af9..afa6ea5 100644 --- a/src/tmxreader.hpp +++ b/src/tmxreader.hpp @@ -1,4 +1,4 @@ -/* tmxreader.hpp - Copyright (C) 2015-2024 a dinosaur (zlib, see COPYING.txt) */ +/* tmxreader.hpp - Copyright (C) 2015-2022 a dinosaur (zlib, see COPYING.txt) */ #ifndef TMXREADER_HPP #define TMXREADER_HPP @@ -10,6 +10,11 @@ #include #include #include +#include + +class TmxTileset; +class TmxLayer; +class TmxObject; class TmxReader { @@ -34,7 +39,7 @@ public: const std::string_view paletteName, const std::string_view collisionName, const std::map& objMapping); - struct Size { unsigned width, height; }; + struct Size { int width, height; }; [[nodiscard]] constexpr Size GetSize() const { return mSize; } [[nodiscard]] constexpr size_t TileCount() const { return diff --git a/src/tmxtileset.hpp b/src/tmxtileset.hpp new file mode 100644 index 0000000..bfa9817 --- /dev/null +++ b/src/tmxtileset.hpp @@ -0,0 +1,28 @@ +/* tmxtileset.hpp - Copyright (C) 2015-2022 a dinosaur (zlib, see COPYING.txt) */ + +#ifndef TMXTILESET_HPP +#define TMXTILESET_HPP + +#include +#include +#include + +class TmxTileset +{ +public: + TmxTileset() : mFirstGid(0) {} + TmxTileset(std::string aName, std::string aSource, uint32_t aFirstGid) + : mName(std::move(aName)), mSource(std::move(aSource)), mFirstGid(aFirstGid) {} + ~TmxTileset() = default; + + constexpr const std::string& GetName() const { return mName; } + constexpr const std::string& GetSource() const { return mSource; } + constexpr uint32_t GetFirstGid() const { return mFirstGid; } + +private: + std::string mName; + std::string mSource; + uint32_t mFirstGid; +}; + +#endif//TMXTILESET_HPP