1
0
mirror of https://github.com/ScrelliCopter/tmx2gba.git synced 2025-02-21 03:29:25 +11:00

14 Commits

45 changed files with 956 additions and 535 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.c linguist-vendored

View File

@@ -23,7 +23,7 @@ jobs:
- { name: "Windows MSVC x86", os: windows-latest, artifact: windows-x86, arch: x86 }
- { name: "Windows MSVC x64", os: windows-latest, artifact: windows-x64 }
- { name: "Windows MSVC ARM64", os: windows-latest, artifact: windows-arm64, arch: amd64_arm64 }
- { name: "Ubuntu", artifact: "linux", os: ubuntu-latest, extra: "-DUSE_BUNDLED_ZSTD:BOOL=OFF" }
- { name: "Ubuntu", artifact: "linux", os: ubuntu-latest, extra: "-DUSE_BUNDLED_ZSTD:BOOL=OFF -DUSE_BUNDLED_PUGIXML:BOOL=OFF" }
runs-on: ${{matrix.config.os}}
steps:
@@ -38,7 +38,7 @@ jobs:
- uses: awalsh128/cache-apt-pkgs-action@latest
if: ${{matrix.config.artifact == 'linux'}}
with:
packages: libzstd-dev
packages: libzstd-dev libpugixml-dev
version: 1.0
- name: Configure CMake

View File

@@ -19,13 +19,13 @@ if (ENABLE_ASAN)
add_link_options(-fsanitize=address -shared-libasan)
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules/")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
# Libraries
if (USE_BUNDLED_PUGIXML)
add_subdirectory(ext/pugixml)
else()
find_package(PUGIXML REQUIRED)
find_package(pugixml REQUIRED CONFIG)
endif()
if (USE_ZLIB)
@@ -37,14 +37,12 @@ endif()
if (USE_BUNDLED_ZSTD)
add_subdirectory(ext/zstd)
else()
find_package(ZSTD REQUIRED)
find_package(Zstd REQUIRED)
endif()
if (USE_BUNDLED_TMXLITE)
add_subdirectory(ext/tmxlite)
else()
find_package(TMXLITE REQUIRED)
endif()
add_subdirectory(ext/base64)
add_subdirectory(ext/tmxlite)
# Main tmx2gba sources
add_subdirectory(src)

View File

@@ -1,43 +1,39 @@
# tmx2gba #
tmx2gba is a simple command line utility that converts [Tiled](http://www.mapeditor.org/) .tmx maps to Game Boy Advance formatted charmaps.
Originally developed for my own personal use, I've thrown it up in case this is of use to anyone else.
If you find a bug, please open an issue.
Enjoy!
### Features ###
* Exports to raw binary that can be easily memcpy'd into VRAM.
* Export raw charmaps that can be easily memcpy'd into VRAM.
* Preserves tile flipping.
* Supports per-tile palette specification.
* Custom collision layer support.
* Support for objects with id mapping.
### How do I use it? ###
## Usage ##
```
tmx2gba [-h] [-r offset] [-lyc name] [-p 0-15] <-i inpath> <-o outpath>
tmx2gba [-hv] [-r offset] [-lyc name] [-p 0-15] [-m name;id] <-i inpath> <-o outpath>
```
| Command | Required | Notes |
|--------------|----------|-----------------------------------------------------------------------|
| -h | N/A | Display help & command info. |
| -v | No | Display version & quit. |
| -l (name) | No | Name of layer to use (default first layer in TMX). |
| -y (name) | No | Layer for palette mappings. |
| -c (name) | No | Output a separate 8bit collision map of the specified layer. |
| -r (offset) | No | Offset tile indices (default 0). |
| -p (0-15) | No | Select which palette to use for 4-bit tilesets. |
| -m (name;id) | No | Map an object name to an ID, will enable object exports. |
| -i (path) | *Yes* | Path to input TMX file. |
| -o (path) | *Yes* | Path to output files. |
| -f <file> | No | Command line instructions list for easy integration with buildscripts |
| Command | Required | Notes |
|--------------|----------|------------------------------------------------------------------------------------|
| -h | N/A | Display help & command info |
| -v | No | Display version & quit |
| -l (name) | No | Name of layer to use (default first layer in TMX) |
| -y (name) | No | Layer for palette mappings |
| -c (name) | No | Output a separate 8bit collision map of the specified layer |
| -r (offset) | No | Offset tile indices (default 0) |
| -p (0-15) | No | Select which palette to use for 4-bit tilesets |
| -m (name;id) | No | Map an object name to an ID, will enable object exports |
| -i (path) | *Yes* | Path to input TMX file |
| -o (path) | *Yes* | Path to output files |
| -f <file> | No | Flag file containing command-line arguments for easy integration with buildscripts |
### How do I build it? ###
## Building ##
Dependencies for building are CMake 3.x and a C++11 compliant compiler,
Dependencies for building are CMake 3.15 and a C++20 compliant compiler,
all other dependencies are in-tree so you should be able to build with:
```bash
cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
make -C build -j$(nproc --all)
cmake --build build
```
Optionally, you may install it to use it system wide:
@@ -45,10 +41,8 @@ Optionally, you may install it to use it system wide:
sudo cmake --install build
```
Which will copy the tmx2gba executable to /usr/local/bin/tmx2gba by default,
if you prefer to use /usr for some reason you may specify a prefix like so:
```bash
sudo cmake --install build --prefix /usr
```
`--prefix /usr` can be used to override install location.
If you're a devkitPro user and would prefer to keep all your development tools compartmentalised
you may optionally install to the tools directory with the `TMX2GBA_DKP_INSTALL` option (OFF by default).
The build scripts will respect your `DEVKITPRO` environment variable but if not set will install to
@@ -63,32 +57,11 @@ sudo cmake --install build
* Add support for multi-SBB prepared charmaps.
* Check if this works for NDS as well.
* Compression support.
* Support for less common TMX formats.
### License ###
[tmx2gba](https://github.com/ScrelliCopter/tmx2gba) is licensed under the zlib license.
[RapidXML](http://rapidxml.sourceforge.net/) is licensed under the Boost & MIT licenses.
[René Nyffenegger's base64.cpp](https://github.com/ReneNyffenegger/cpp-base64) is licensed under the zlib license.
[miniz](https://github.com/richgel999/miniz) is public domain software.
[ultragetopt](https://github.com/kevinoid/ultragetopt) is licensed under the MIT license.
```
Copyright (C) 2015-2023 a dinosaur
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.
```
## License ##
[tmx2gba](https://github.com/ScrelliCopter/tmx2gba) is licensed under the [Zlib license](COPYING.txt).
- A modified [tmxlite](https://github.com/fallahn/tmxlite) is licensed under the [Zlib license](ext/tmxlite/LICENSE).
- [pugixml](https://pugixml.org/) is licensed under the [MIT license](ext/pugixml/LICENSE.md).
- [René Nyffenegger's base64.cpp](https://github.com/ReneNyffenegger/cpp-base64) is licensed under the [Zlib license](ext/base64/LICENSE).
- [miniz](https://github.com/richgel999/miniz) is licensed under the [MIT license](ext/miniz/LICENSE).
- [ZStandard](https://facebook.github.io/zstd/) is licensed under the [BSD 3-clause license](ext/zstd/LICENSE).

View File

@@ -1,10 +0,0 @@
find_path(PUGIXML_INCLUDE_DIR NAMES pugixml.hpp)
find_library(PUGIXML_LIBRARY NAMES pugixml)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PUGIXML DEFAULT_MSG
PUGIXML_LIBRARY PUGIXML_INCLUDE_DIR)
mark_as_advanced(PUGIXML_INCLUDE_DIR
PUGIXML_LIBRARY)

View File

@@ -1,10 +0,0 @@
include(FindPackageHandleStandardArgs)
# Search for the header file
find_path(TMXLITE_INCLUDE_DIR NAMES tmxlite/Config.hpp PATH_SUFFIXES include)
# Search for the library
find_library(TMXLITE_LIBRARIES NAMES tmxlite PATH_SUFFIXES lib)
# Did we find everything we need?
FIND_PACKAGE_HANDLE_STANDARD_ARGS(tmxlite DEFAULT_MSG TMXLITE_LIBRARIES TMXLITE_INCLUDE_DIR)

View File

@@ -1,41 +0,0 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# - Try to find Facebook zstd library
# This will define
# ZSTD_FOUND
# ZSTD_INCLUDE_DIR
# ZSTD_LIBRARY
#
find_path(ZSTD_INCLUDE_DIR NAMES zstd.h)
find_library(ZSTD_LIBRARY_DEBUG NAMES zstdd zstd_staticd)
find_library(ZSTD_LIBRARY_RELEASE NAMES zstd zstd_static)
include(SelectLibraryConfigurations)
SELECT_LIBRARY_CONFIGURATIONS(ZSTD)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(
ZSTD DEFAULT_MSG
ZSTD_LIBRARY ZSTD_INCLUDE_DIR
)
if (ZSTD_FOUND)
message(STATUS "Found Zstd: ${ZSTD_LIBRARY}")
endif()
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)

View File

@@ -0,0 +1,171 @@
# SPDX-License-Identifier: Zlib
# SPDX-FileCopyrightText: 2024 a dinosaur
#[=======================================================================[.rst:
FindZstd
--------
Find the Facebook Zstd library.
Imported Targets
^^^^^^^^^^^^^^^^
.. variable:: Zstd::Zstd
:prop_tgt:`IMPORTED` target for using Zstd, if Zstd is found.
Result Variables
^^^^^^^^^^^^^^^^
This module defines the following variables:
.. variable:: Zstd_FOUND
True if Zstd was found.
.. variable:: Zstd_INCLUDE_DIRS
Path to the directory containing the Zstd headers (zstd.h, etc.)
.. variable:: Zstd_LIBRARIES
Location of the Zstd library.
.. variable:: Zstd_VERSION
The version of Zstd found.
Legacy Variables
^^^^^^^^^^^^^^^^
The following variables are defined by the official Zstd CMakeLists.txt:
.. variable:: zstd_VERSION_MAJOR
The major version of Zstd.
.. variable:: zstd_VERSION_MINOR
The minor version of Zstd.
.. variable:: zstd_VERSION_PATCH
The patch/release version of Zstd.
The following variables are provided for compatibility with old find modules:
.. variable:: ZSTD_INCLUDE_DIR
Directory containing the Zstd header. (use ``Zstd_INCLUDE_DIRS`` instead)
.. variable:: ZSTD_LIBRARY
The Zstd library. (use ``Zstd_LIBRARIES`` instead)
Hints
^^^^^
.. variable:: Zstd_PREFER_STATIC_LIBS
Set to ``ON`` to prefer static libraries. Defaults to ``OFF``
Cache Variables
^^^^^^^^^^^^^^^
The following cache variables may also be set,
these are transitory and should not be relied upon:
.. variable:: Zstd_INCLUDE_DIR
Directory containing the Zstd header.
.. variable:: Zstd_LIBRARY_DEBUG
The Zstd debug library if found.
.. variable:: Zstd_LIBRARY_RELEASE
The Zstd release library if found.
.. variable:: Zstd_LIBRARY
The Zstd library.
#]=======================================================================]
#TODO: define Zstd::static & Zstd::shared and alias Zstd::Zstd based on preference
find_path(Zstd_INCLUDE_DIR NAMES zstd.h)
mark_as_advanced(Zstd_INCLUDE_DIR)
if (Zstd_PREFER_STATIC_LIBS)
find_library(Zstd_LIBRARY_DEBUG NAMES zstd_staticd zstdd)
find_library(Zstd_LIBRARY_RELEASE NAMES zstd_static zstd)
else()
find_library(Zstd_LIBRARY_DEBUG NAMES zstdd zstd_staticd)
find_library(Zstd_LIBRARY_RELEASE NAMES zstd zstd_static)
endif()
include(SelectLibraryConfigurations)
select_library_configurations(Zstd)
mark_as_advanced(Zstd_LIBRARY Zstd_LIBRARY_DEBUG Zstd_LIBRARY_RELEASE)
if (Zstd_INCLUDE_DIR AND EXISTS "${Zstd_INCLUDE_DIR}/zstd.h")
function (_zstd_read_define _variable _define)
set(_file "${Zstd_INCLUDE_DIR}/zstd.h")
set(_regex "#define[ \t]+${_define}[ \t]+([0-9]+)")
file(STRINGS "${_file}" _line LIMIT_COUNT 1 REGEX "${_regex}")
if (CMAKE_VERSION VERSION_LESS "3.29")
string(REGEX MATCH "${_regex}" _line "${_line}")
endif()
set(${_variable} ${CMAKE_MATCH_1} PARENT_SCOPE)
endfunction()
_zstd_read_define(zstd_VERSION_MAJOR "ZSTD_VERSION_MAJOR")
_zstd_read_define(zstd_VERSION_MINOR "ZSTD_VERSION_MINOR")
_zstd_read_define(zstd_VERSION_PATCH "ZSTD_VERSION_RELEASE")
set(Zstd_VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}")
mark_as_advanced(zstd_VERSION_MAJOR zstd_VERSION_MINOR zstd_VERSION_PATCH Zstd_VERSION)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Zstd
REQUIRED_VARS Zstd_LIBRARY Zstd_INCLUDE_DIR
VERSION_VAR Zstd_VERSION)
mark_as_advanced(Zstd_FOUND)
if (Zstd_FOUND)
set(Zstd_INCLUDE_DIRS ${Zstd_INCLUDE_DIR})
set(Zstd_LIBRARIES ${Zstd_LIBRARY})
# Legacy variables
set(ZSTD_INCLUDE_DIR ${Zstd_INCLUDE_DIR})
set(ZSTD_LIBRARY ${Zstd_LIBRARY})
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
if (NOT TARGET Zstd::Zstd)
add_library(Zstd::Zstd UNKNOWN IMPORTED)
set_property(TARGET Zstd::Zstd PROPERTY
INTERFACE_INCLUDE_DIRECTORIES "${Zstd_INCLUDE_DIR}")
endif()
if (NOT Zstd_LIBRARY_DEBUG AND NOT Zstd_LIBRARY_RELEASE)
set_property(TARGET Zstd::Zstd PROPERTY
IMPORTED_LOCATION "${Zstd_LIBRARY}")
endif()
if (Zstd_LIBRARY_DEBUG)
set_property(TARGET Zstd::Zstd APPEND PROPERTY
IMPORTED_CONFIGURATIONS DEBUG)
set_property(TARGET Zstd::Zstd PROPERTY
IMPORTED_LOCATION_DEBUG "${Zstd_LIBRARY_DEBUG}")
endif()
if (Zstd_LIBRARY_RELEASE)
set_property(TARGET Zstd::Zstd APPEND PROPERTY
IMPORTED_CONFIGURATIONS RELEASE)
set_property(TARGET Zstd::Zstd PROPERTY
IMPORTED_LOCATION_RELEASE "${Zstd_LIBRARY_RELEASE}")
endif()
endif()

View File

@@ -0,0 +1,5 @@
add_library(base64
base64.cpp base64.h)
add_library(base64::base64 ALIAS base64)
target_include_directories(base64
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

19
ext/base64/LICENSE Normal file
View File

@@ -0,0 +1,19 @@
Copyright © 2004-2017 by René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author 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 source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
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 source code.
3. This notice may not be removed or altered from any source distribution.

305
ext/base64/base64.cpp Normal file
View File

@@ -0,0 +1,305 @@
/*
base64.cpp and base64.h
base64 encoding and decoding with C++.
More information at
https://renenyffenegger.ch/notes/development/Base64/Encoding-and-decoding-base-64-with-cpp
Version: 2.rc.09 (release candidate)
Copyright (C) 2004-2017, 2020-2022 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author 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 source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
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 source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#include "base64.h"
#include <algorithm>
#if defined(__cpp_exceptions)
#include <stdexcept>
#else
#include <cassert>
#endif
//
// Depending on the url parameter in base64_chars, one of
// two sets of base64 characters needs to be chosen.
// They differ in their last two characters.
//
static const char* to_base64_chars[2] = {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"+/",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"-_"};
static const unsigned char from_base64_chars[256] = {
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 62, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 63,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
static unsigned int pos_of_char(const unsigned char chr) {
//
// Return the position of chr within base64_encode()
//
if (from_base64_chars[chr] != 64) return from_base64_chars[chr];
//
// 2020-10-23: Throw std::exception rather than const char*
//(Pablo Martin-Gomez, https://github.com/Bouska)
//
#if defined(__cpp_exceptions)
throw std::runtime_error("Input is not valid base64-encoded data.");
#else
assert(!"Input is not valid base64-encoded data.");
#endif
}
static std::string insert_linebreaks(std::string str, size_t distance) {
//
// Provided by https://github.com/JomaCorpFX, adapted by me.
//
if (!str.length()) {
return "";
}
size_t pos = distance;
while (pos < str.size()) {
str.insert(pos, "\n");
pos += distance + 1;
}
return str;
}
template <typename String, unsigned int line_length>
static std::string encode_with_line_breaks(String s) {
return insert_linebreaks(base64_encode(s, false), line_length);
}
template <typename String>
static std::string encode_pem(String s) {
return encode_with_line_breaks<String, 64>(s);
}
template <typename String>
static std::string encode_mime(String s) {
return encode_with_line_breaks<String, 76>(s);
}
template <typename String>
static std::string encode(String s, bool url) {
return base64_encode(reinterpret_cast<const unsigned char*>(s.data()), s.length(), url);
}
std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, bool url) {
size_t len_encoded = (in_len +2) / 3 * 4;
unsigned char trailing_char = url ? '.' : '=';
//
// Choose set of base64 characters. They differ
// for the last two positions, depending on the url
// parameter.
// A bool (as is the parameter url) is guaranteed
// to evaluate to either 0 or 1 in C++ therefore,
// the correct character set is chosen by subscripting
// base64_chars with url.
//
const char* base64_chars_ = to_base64_chars[url];
std::string ret;
ret.reserve(len_encoded);
unsigned int pos = 0;
while (pos < in_len) {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0xfc) >> 2]);
if (pos+1 < in_len) {
ret.push_back(base64_chars_[((bytes_to_encode[pos + 0] & 0x03) << 4) + ((bytes_to_encode[pos + 1] & 0xf0) >> 4)]);
if (pos+2 < in_len) {
ret.push_back(base64_chars_[((bytes_to_encode[pos + 1] & 0x0f) << 2) + ((bytes_to_encode[pos + 2] & 0xc0) >> 6)]);
ret.push_back(base64_chars_[ bytes_to_encode[pos + 2] & 0x3f]);
}
else {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 1] & 0x0f) << 2]);
ret.push_back(trailing_char);
}
}
else {
ret.push_back(base64_chars_[(bytes_to_encode[pos + 0] & 0x03) << 4]);
ret.push_back(trailing_char);
ret.push_back(trailing_char);
}
pos += 3;
}
return ret;
}
template <typename String>
static std::string decode(String const& encoded_string, bool remove_linebreaks) {
//
// decode(…) is templated so that it can be used with String = const std::string&
// or std::string_view (requires at least C++17)
//
if (encoded_string.empty()) return std::string();
if (remove_linebreaks) {
std::string copy(encoded_string);
copy.erase(std::remove(copy.begin(), copy.end(), '\n'), copy.end());
return base64_decode(copy, false);
}
size_t length_of_string = encoded_string.length();
size_t pos = 0;
//
// The approximate length (bytes) of the decoded string might be one or
// two bytes smaller, depending on the amount of trailing equal signs
// in the encoded string. This approximation is needed to reserve
// enough space in the string to be returned.
//
size_t approx_length_of_decoded_string = length_of_string / 4 * 3;
std::string ret;
ret.reserve(approx_length_of_decoded_string);
while (pos < length_of_string) {
//
// Iterate over encoded input string in chunks. The size of all
// chunks except the last one is 4 bytes.
//
// The last chunk might be padded with equal signs or dots
// in order to make it 4 bytes in size as well, but this
// is not required as per RFC 2045.
//
// All chunks except the last one produce three output bytes.
//
// The last chunk produces at least one and up to three bytes.
//
size_t pos_of_char_1 = pos_of_char(encoded_string.at(pos+1) );
//
// Emit the first output byte that is produced in each chunk:
//
ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char(encoded_string.at(pos+0)) ) << 2 ) + ( (pos_of_char_1 & 0x30 ) >> 4)));
if ( ( pos + 2 < length_of_string ) && // Check for data that is not padded with equal signs (which is allowed by RFC 2045)
encoded_string.at(pos+2) != '=' &&
encoded_string.at(pos+2) != '.' // accept URL-safe base 64 strings, too, so check for '.' also.
)
{
//
// Emit a chunk's second byte (which might not be produced in the last chunk).
//
unsigned int pos_of_char_2 = pos_of_char(encoded_string.at(pos+2) );
ret.push_back(static_cast<std::string::value_type>( (( pos_of_char_1 & 0x0f) << 4) + (( pos_of_char_2 & 0x3c) >> 2)));
if ( ( pos + 3 < length_of_string ) &&
encoded_string.at(pos+3) != '=' &&
encoded_string.at(pos+3) != '.'
)
{
//
// Emit a chunk's third byte (which might not be produced in the last chunk).
//
ret.push_back(static_cast<std::string::value_type>( ( (pos_of_char_2 & 0x03 ) << 6 ) + pos_of_char(encoded_string.at(pos+3)) ));
}
}
pos += 4;
}
return ret;
}
std::string base64_decode(std::string const& s, bool remove_linebreaks) {
return decode(s, remove_linebreaks);
}
std::string base64_encode(std::string const& s, bool url) {
return encode(s, url);
}
std::string base64_encode_pem (std::string const& s) {
return encode_pem(s);
}
std::string base64_encode_mime(std::string const& s) {
return encode_mime(s);
}
#if __cplusplus >= 201703L
//
// Interface with std::string_view rather than const std::string&
// Requires C++17
// Provided by Yannic Bonenberger (https://github.com/Yannic)
//
std::string base64_encode(std::string_view s, bool url) {
return encode(s, url);
}
std::string base64_encode_pem(std::string_view s) {
return encode_pem(s);
}
std::string base64_encode_mime(std::string_view s) {
return encode_mime(s);
}
std::string base64_decode(std::string_view s, bool remove_linebreaks) {
return decode(s, remove_linebreaks);
}
#endif // __cplusplus >= 201703L

35
ext/base64/base64.h Normal file
View File

@@ -0,0 +1,35 @@
//
// base64 encoding and decoding with C++.
// Version: 2.rc.09 (release candidate)
//
#ifndef BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
#define BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A
#include <string>
#if __cplusplus >= 201703L
#include <string_view>
#endif // __cplusplus >= 201703L
std::string base64_encode (std::string const& s, bool url = false);
std::string base64_encode_pem (std::string const& s);
std::string base64_encode_mime(std::string const& s);
std::string base64_decode(std::string const& s, bool remove_linebreaks = false);
std::string base64_encode(unsigned char const*, size_t len, bool url = false);
#if __cplusplus >= 201703L
//
// Interface with std::string_view rather than const std::string&
// Requires C++17
// Provided by Yannic Bonenberger (https://github.com/Yannic)
//
std::string base64_encode (std::string_view s, bool url = false);
std::string base64_encode_pem (std::string_view s);
std::string base64_encode_mime(std::string_view s);
std::string base64_decode(std::string_view s, bool remove_linebreaks = false);
#endif // __cplusplus >= 201703L
#endif /* BASE64_H_C0CE2A47_D10E_42C9_A27C_C883944E704A */

View File

@@ -1,52 +1,52 @@
project(tmxlite VERSION 1.3.1)
set(USE_RTTI TRUE CACHE BOOL "Use run time type information?")
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
# includes the list of source files in the src directory
set(PROJECT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
file(GLOB PROJECT_SRC ${PROJECT_DIR}/*.cpp)
file(GLOB PROJECT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp)
file(GLOB PROJECT_HEADERS_INL ${CMAKE_CURRENT_SOURCE_DIR}/include/*.inl)
file(GLOB PROJECT_HEADERS_DETAIL ${CMAKE_CURRENT_SOURCE_DIR}/include/detail/*.hpp)
set(PROJECT_SRC ${PROJECT_SRC} ${PROJECT_HEADERS} ${PROJECT_HEADERS_INL} ${PROJECT_HEADERS_DETAIL})
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)
add_library(tmxlite STATIC ${PROJECT_SRC})
if (NOT USE_ZLIB)
target_sources(${PROJECT_NAME} PRIVATE
include/tmxlite/detail/gzip.hpp
src/detail/gzip.cpp)
endif()
set_target_properties(tmxlite PROPERTIES
CXX_STANDARD 14
set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON)
target_compile_definitions(tmxlite PRIVATE $<$<CONFIG:Debug>:_DEBUG_> TMXLITE_STATIC)
target_compile_options(tmxlite PRIVATE -Wall)
if (NOT USE_RTTI AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
target_compile_options(tmxlite PRIVATE -fno-rtti)
endif()
target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include)
# disable msvc warning
if (MSVC)
target_compile_definitions(tmxlite PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
target_compile_options(${PROJECT_NAME} PRIVATE -Wall)
if (USE_BUNDLED_PUGIXML)
target_link_libraries(tmxlite pugixml::static)
else()
target_include_directories(tmxlite PRIVATE ${PUGIXML_INCLUDE_DIR})
target_link_libraries(tmxlite ZLIB::ZLIB ${PUGIXML_LIBRARY})
endif()
target_compile_definitions(${PROJECT_NAME} PRIVATE
$<$<BOOL:${MSVC}>:_CRT_SECURE_NO_WARNINGS> # disable msvc warning
$<$<TARGET_EXISTS:ZLIB::ZLIB>:USE_ZLIB>)
if (USE_ZLIB)
target_compile_definitions(tmxlite PRIVATE USE_ZLIB)
target_link_libraries(tmxlite ZLIB::ZLIB)
else()
target_link_libraries(tmxlite miniz::miniz)
endif()
target_compile_definitions(tmxlite PRIVATE USE_ZSTD)
if (USE_BUNDLED_ZSTD)
target_link_libraries(tmxlite zstd::static)
else()
target_include_directories(tmxlite PRIVATE ${ZSTD_INCLUDE_DIR})
target_link_libraries(tmxlite ZLIB::ZLIB ${ZSTD_LIBRARY})
endif()
target_include_directories(tmxlite PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(${PROJECT_NAME} base64::base64 pugixml Zstd::Zstd
$<$<TARGET_EXISTS:ZLIB::ZLIB>:ZLIB::ZLIB>
$<$<TARGET_EXISTS:miniz::miniz>:miniz::miniz>)

13
ext/tmxlite/LICENSE Normal file
View File

@@ -0,0 +1,13 @@
(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.

View File

@@ -27,38 +27,5 @@ source distribution.
#pragma once
//check which platform we're on and create export macros as necessary
#if !defined(TMXLITE_STATIC)
#if defined(_WIN32)
//windows compilers need specific (and different) keywords for export
#define TMXLITE_EXPORT_API __declspec(dllexport)
//for vc compilers we also need to turn off this annoying C4251 warning
#ifdef _MSC_VER
#pragma warning(disable: 4251)
#endif //_MSC_VER
#else //linux, FreeBSD, Mac OS X
#if __GNUC__ >= 4
//gcc 4 has special keywords for showing/hiding symbols,
//the same keyword is used for both importing and exporting
#define TMXLITE_EXPORT_API __attribute__ ((__visibility__ ("default")))
#else
//gcc < 4 has no mechanism to explicitly hide symbols, everything's exported
#define TMXLITE_EXPORT_API
#endif //__GNUC__
#endif //_WIN32
#else
//static build doesn't need import/export macros
#define TMXLITE_EXPORT_API
#endif //TMXLITE_STATIC

View File

@@ -25,35 +25,10 @@ and must not be misrepresented as being the original software.
source distribution.
*********************************************************************/
/*********************************************************************
base64_decode
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author 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 source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
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 source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*********************************************************************/
#pragma once
#include <tmxlite/detail/Android.hpp>
#include <tmxlite/detail/Log.hpp>
#include <tmxlite/Types.hpp>
#include "tmxlite/detail/Log.hpp"
#include "tmxlite/Types.hpp"
#include <string>
#include <sstream>
@@ -66,72 +41,6 @@ namespace tmx
//using inline here just to supress unused warnings on gcc
bool decompress(const char* source, std::vector<unsigned char>& dest, std::size_t inSize, std::size_t expectedSize);
static inline std::string base64_decode(std::string const& encoded_string)
{
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
std::function<bool(unsigned char)> is_base64 =
[](unsigned char c)->bool
{
return (isalnum(c) || (c == '+') || (c == '/'));
};
auto in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_]))
{
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4)
{
for (i = 0; i < 4; i++)
{
char_array_4[i] = static_cast<unsigned char>(base64_chars.find(char_array_4[i]));
}
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
{
ret += char_array_3[i];
}
i = 0;
}
}
if (i)
{
for (j = i; j < 4; j++)
{
char_array_4[j] = 0;
}
for (j = 0; j < 4; j++)
{
char_array_4[j] = static_cast<unsigned char>(base64_chars.find(char_array_4[j]));
}
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++)
{
ret += char_array_3[j];
}
}
return ret;
}
static inline Colour colourFromString(std::string str)
{
//removes preceding #
@@ -164,7 +73,7 @@ namespace tmx
}
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;
@@ -186,17 +95,8 @@ namespace tmx
outPath = outPath.substr(0, result);
}
}
// this does only work on windows
#ifndef __ANDROID__
return outPath + '/' + path;
#endif
// todo: make resolveFilePath work with subfolders on
// android - currently only the root folder is working
#ifdef __ANDROID__
return path;
#endif
}
static inline std::string getFilePath(const std::string& path)
@@ -223,4 +123,4 @@ namespace tmx
return searchFunc('/', path);
}
} //namespacec tmx
} //namespacec tmx

View File

@@ -27,9 +27,9 @@ source distribution.
#pragma once
#include <tmxlite/Config.hpp>
#include <tmxlite/Layer.hpp>
#include <tmxlite/Types.hpp>
#include "tmxlite/Config.hpp"
#include "tmxlite/Layer.hpp"
#include "tmxlite/Types.hpp"
namespace tmx
{
@@ -59,7 +59,7 @@ namespace tmx
const Colour& getTransparencyColour() const { return m_transparencyColour; }
/*!
\brief Returns true if the image used by this layer specifically states a
\brief Returns true if the image used by this layer specifically states a
colour to use as transparency
*/
bool hasTransparency() const { return m_hasTransparency; }
@@ -70,13 +70,13 @@ namespace tmx
const Vector2u& getImageSize() const { return m_imageSize; }
/*!
\brief Returns true if the image drawn by this layer is repeated along
\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
\brief Returns true if the image drawn by this layer is repeated along
the Y axis.
*/
bool hasRepeatY() const { return m_hasRepeatY; }

View File

@@ -27,9 +27,9 @@ source distribution.
#pragma once
#include <tmxlite/Config.hpp>
#include <tmxlite/Property.hpp>
#include <tmxlite/Types.hpp>
#include "tmxlite/Config.hpp"
#include "tmxlite/Property.hpp"
#include "tmxlite/Types.hpp"
#include <string>
#include <memory>

View File

@@ -26,9 +26,9 @@ source distribution.
#pragma once
#include <tmxlite/Config.hpp>
#include <tmxlite/Layer.hpp>
#include <tmxlite/Types.hpp>
#include "tmxlite/Config.hpp"
#include "tmxlite/Layer.hpp"
#include "tmxlite/Types.hpp"
#include <vector>
@@ -83,4 +83,4 @@ namespace tmx
assert(getType() == Type::Group);
return *static_cast<const LayerGroup*>(this);
}
}
}

View File

@@ -27,11 +27,11 @@ 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 "tmxlite/Tileset.hpp"
#include "tmxlite/Layer.hpp"
#include "tmxlite/Property.hpp"
#include "tmxlite/Types.hpp"
#include "tmxlite/Object.hpp"
#include <string>
#include <vector>
@@ -45,13 +45,13 @@ namespace tmx
*/
struct TMXLITE_EXPORT_API Version
{
//major/minor are apparently reserved by gcc
//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,
@@ -93,7 +93,7 @@ namespace tmx
class TMXLITE_EXPORT_API Map final
{
public:
Map();
~Map() = default;
Map(const Map&) = delete;
@@ -203,7 +203,7 @@ namespace tmx
/*!
\brief Returns a vector of Property objects loaded by the map
*/
const std::vector<Property>& getProperties() const { return m_properties; }
const std::vector<Property>& getProperties() const { return m_properties; }
/*!
\brief Returns a Hashmap of all animated tiles accessible by TileID
@@ -279,4 +279,4 @@ namespace tmx
//on load failure
bool reset();
};
}
}

View File

@@ -27,9 +27,9 @@ source distribution.
#pragma once
#include <tmxlite/Config.hpp>
#include <tmxlite/Property.hpp>
#include <tmxlite/Types.hpp>
#include "tmxlite/Config.hpp"
#include "tmxlite/Property.hpp"
#include "tmxlite/Types.hpp"
#include <string>
#include <vector>
@@ -70,13 +70,13 @@ namespace tmx
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
shapes are defined by a list of points. Objects are
rectangular by default. Since version 1.0 Objects also
support Text nodes.
*/
@@ -105,12 +105,12 @@ namespace tmx
\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
*/
@@ -125,7 +125,7 @@ namespace tmx
\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
@@ -133,19 +133,19 @@ namespace tmx
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.
@@ -157,12 +157,12 @@ namespace tmx
\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
@@ -170,7 +170,7 @@ namespace tmx
relative to the object position.
*/
const std::vector<Vector2f>& getPoints() const { return m_points; }
/*!
\brief Returns a reference to the vector of properties belonging to
the Object.
@@ -188,7 +188,7 @@ namespace tmx
Text& getText() { return m_textData; }
/*!
\brief Returns the tileset name used by this object if it is derived
\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()
@@ -218,4 +218,4 @@ namespace tmx
void parseText(const pugi::xml_node&);
void parseTemplate(const std::string&, Map*);
};
}
}

View File

@@ -27,9 +27,9 @@ source distribution.
#pragma once
#include <tmxlite/Config.hpp>
#include <tmxlite/Layer.hpp>
#include <tmxlite/Object.hpp>
#include "tmxlite/Config.hpp"
#include "tmxlite/Layer.hpp"
#include "tmxlite/Object.hpp"
#include <vector>
@@ -96,4 +96,4 @@ namespace tmx
assert(getType() == Type::Object);
return *static_cast<const ObjectGroup*>(this);
}
}
}

View File

@@ -26,7 +26,7 @@ source distribution.
#pragma once
#include <tmxlite/Property.hpp>
#include "tmxlite/Property.hpp"
#include <string>
#include <vector>
@@ -83,4 +83,4 @@ namespace tmx
//on load failure
bool reset();
};
}
}

View File

@@ -27,8 +27,8 @@ source distribution.
#pragma once
#include <tmxlite/Config.hpp>
#include <tmxlite/Types.hpp>
#include "tmxlite/Config.hpp"
#include "tmxlite/Types.hpp"
#include <string>
#include <cassert>
@@ -43,14 +43,14 @@ 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
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,
@@ -62,7 +62,7 @@ namespace tmx
Object,
Undef
};
Property();
static Property fromBoolean(bool value);

View File

@@ -27,8 +27,8 @@ source distribution.
#pragma once
#include <tmxlite/Layer.hpp>
#include <tmxlite/Types.hpp>
#include "tmxlite/Layer.hpp"
#include "tmxlite/Types.hpp"
namespace tmx
{
@@ -66,7 +66,7 @@ namespace tmx
Vertical = 0x4,
Diagonal = 0x2
};
explicit TileLayer(std::size_t);
Type getType() const override { return Layer::Type::Tile; }
@@ -113,4 +113,4 @@ namespace tmx
assert(getType() == Type::Tile);
return *static_cast<const TileLayer*>(this);
}
}
}

View File

@@ -27,9 +27,9 @@ source distribution.
#pragma once
#include <tmxlite/Config.hpp>
#include <tmxlite/Property.hpp>
#include <tmxlite/ObjectGroup.hpp>
#include "tmxlite/Config.hpp"
#include "tmxlite/Property.hpp"
#include "tmxlite/ObjectGroup.hpp"
#include <string>
#include <vector>
@@ -101,7 +101,7 @@ namespace tmx
Vector2u imagePosition;
std::string className;
};
/*!
\brief Terrain information with which one
or more tiles may be associated.
@@ -247,7 +247,7 @@ namespace tmx
/*!
\brief Checks if a tiled ID is in the range of the first ID and the last ID
\param id Tile ID
\return
\return
*/
bool hasTile(std::uint32_t id) const { return id >= m_firstGID && id <= getLastGID(); };

View File

@@ -27,7 +27,7 @@ source distribution.
#pragma once
#include <tmxlite/Config.hpp>
#include "tmxlite/Config.hpp"
#include <cstdint>
#include <ostream>
@@ -147,4 +147,4 @@ std::ostream& operator << (std::ostream& os, const tmx::Rectangle<T>& t)
return os;
}
std::ostream& operator << (std::ostream& os, const tmx::Colour& c);
std::ostream& operator << (std::ostream& os, const tmx::Colour& c);

View File

@@ -1,53 +0,0 @@
/*********************************************************************
Matt Marchant 2016
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.
*********************************************************************/
#ifndef ANDROID_INC_HPP_
#define ANDROID_INC_HPP_
#ifdef __ANDROID__
#include <string>
#include <sstream>
#include <cstdlib>
namespace std
{
template <typename T>
std::string to_string(T value)
{
std::ostringstream os;
os << value;
return os.str();
}
}
#define STOI(str) std::strtol(str.c_str(), 0, 10)
#else
#define STOI(str) std::stoi(str)
#endif // __ANDROID__
#endif // ANDROID_INC_HPP_

View File

@@ -43,18 +43,6 @@ source distribution.
#include <windows.h>
#endif //_MSC_VER
#ifdef __ANDROID__
#include <android/log.h>
#include <cstring>
#define LOG_TAG "TMXlite-Debug"
//#define ALOG(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#endif // __ANDROID__
namespace tmx
{
/*!
@@ -105,23 +93,10 @@ namespace tmx
{
if (type == Type::Error)
{
#ifdef __ANDROID__
int outstringLength = outstring.length();
char outstring_chararray[outstringLength+1];
std::strcpy(outstring_chararray, outstring.c_str());
LOGE("%s",outstring_chararray);
#endif
std::cerr << outstring << std::endl;
}
else
{
#ifdef __ANDROID__
int outstringLength = outstring.length();
char outstring_chararray[outstringLength+1];
std::strcpy(outstring_chararray, outstring.c_str());
LOGI("%s", outstring_chararray);
#endif
std::cout << outstring << std::endl;
}
const std::size_t maxBuffer = 30;
@@ -140,13 +115,11 @@ namespace tmx
std::ofstream file("output.log", std::ios::app);
if (file.good())
{
#ifndef __ANDROID__
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: ");
#endif //__ANDROID__
file << outstring << std::endl;
file.close();
}
@@ -178,13 +151,13 @@ namespace tmx
}
};
}
#ifndef _DEBUG_
#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 //_DEBUG_
#endif //NDEBUG
#endif //TMXLITE_LOGGER_HPP_
#endif //TMXLITE_LOGGER_HPP_

View File

@@ -0,0 +1,39 @@
// gzip.hpp - portable memory miniz based gzip reader
// SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2024 a dinosaur
#ifndef GZIP_HPP
#define GZIP_HPP
#include "miniz.h"
#include <cstdint>
#include <span>
class GZipReader
{
static constexpr uint8_t
FTEXT = 1, FHCRC = 1<<1, FEXTRA = 1<<2, FNAME = 1<<3, FCOMMENT = 1<<4;
static constexpr uint8_t XFL_BEST = 2, XFL_FASTEST = 4;
tinfl_decompressor mState;
std::span<const uint8_t>::iterator mIt;
size_t mSourceLen, mBytesRead;
uint32_t mModificationTime, mCrc, mInputSize, mComputedCrc;
uint16_t crc16;
uint8_t mFlags, mXflags, mOsId;
public:
GZipReader() noexcept;
constexpr size_t SourceLength() const noexcept { return mSourceLen; }
constexpr uint32_t OutputLength() const noexcept { return mInputSize; }
bool OpenMemory(const std::span<const uint8_t> source) noexcept;
bool Read(std::span<uint8_t> out) noexcept;
bool Check() const noexcept;
};
#endif//GZIP_HPP

View File

@@ -25,15 +25,14 @@ and must not be misrepresented as being the original software.
source distribution.
*********************************************************************/
#include "tmxlite/FreeFuncs.hpp"
#include "tmxlite/Types.hpp"
#include "tmxlite/detail/Log.hpp"
#ifndef USE_ZLIB
#include "miniz.h"
# include "miniz.h"
#else
#include <zlib.h>
# include <zlib.h>
#endif
#include <tmxlite/FreeFuncs.hpp>
#include <tmxlite/Types.hpp>
#include <tmxlite/detail/Log.hpp>
#include <cstring>
bool tmx::decompress(const char* source, std::vector<unsigned char>& dest, std::size_t inSize, std::size_t expectedSize)
@@ -59,7 +58,7 @@ bool tmx::decompress(const char* source, std::vector<unsigned char>& dest, std::
stream.next_out = (Bytef*)byteArray.data();
stream.avail_out = static_cast<unsigned int>(expectedSize);
//we'd prefer to use inflateInit2 but it appears
//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.

View File

@@ -25,10 +25,11 @@ and must not be misrepresented as being the original software.
source distribution.
*********************************************************************/
#include "tmxlite/ImageLayer.hpp"
#include "tmxlite/FreeFuncs.hpp"
#include "tmxlite/detail/Log.hpp"
#include <pugixml.hpp>
#include <tmxlite/ImageLayer.hpp>
#include <tmxlite/FreeFuncs.hpp>
#include <tmxlite/detail/Log.hpp>
using namespace tmx;

View File

@@ -25,13 +25,14 @@ and must not be misrepresented as being the original software.
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 <pugixml.hpp>
#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>
using namespace tmx;

View File

@@ -25,16 +25,15 @@ and must not be misrepresented as being the original software.
source distribution.
*********************************************************************/
#include <pugixml.hpp>
#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 <tmxlite/detail/Android.hpp>
#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 <pugixml.hpp>
#include <queue>
using namespace tmx;
@@ -136,8 +135,8 @@ bool Map::parseMapNode(const pugi::xml_node& mapNode)
return reset();
}
m_version.upper = STOI(attribString.substr(0, pointPos));
m_version.lower = STOI(attribString.substr(pointPos + 1));
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();

View File

@@ -25,13 +25,13 @@ and must not be misrepresented as being the original software.
source distribution.
*********************************************************************/
#include <pugixml.hpp>
#include <tmxlite/Object.hpp>
#include <tmxlite/FreeFuncs.hpp>
#include <tmxlite/Map.hpp>
#include <tmxlite/Tileset.hpp>
#include <tmxlite/detail/Log.hpp>
#include "tmxlite/Object.hpp"
#include "tmxlite/FreeFuncs.hpp"
#include "tmxlite/Map.hpp"
#include "tmxlite/Tileset.hpp"
#include "tmxlite/detail/Log.hpp"
#include <pugixml.hpp>
#include <sstream>
using namespace tmx;
@@ -65,7 +65,7 @@ void Object::parse(const pugi::xml_node& node, Map* map)
{
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();
@@ -272,7 +272,7 @@ void Object::parseTemplate(const std::string& path, Map* map)
{
m_AABB.height = obj.m_AABB.height;
}
m_tilesetName = obj.m_tilesetName;
if (m_name.empty())
@@ -313,7 +313,7 @@ void Object::parseTemplate(const std::string& path, Map* map)
//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(),
auto result = std::find_if(m_properties.begin(), m_properties.end(),
[&p](const Property& a)
{
return a.getName() == p.getName();

View File

@@ -25,10 +25,11 @@ and must not be misrepresented as being the original software.
source distribution.
*********************************************************************/
#include "tmxlite/FreeFuncs.hpp"
#include "tmxlite/ObjectGroup.hpp"
#include "tmxlite/detail/Log.hpp"
#include <pugixml.hpp>
#include <tmxlite/FreeFuncs.hpp>
#include <tmxlite/ObjectGroup.hpp>
#include <tmxlite/detail/Log.hpp>
using namespace tmx;

View File

@@ -24,10 +24,11 @@ and must not be misrepresented as being the original software.
source distribution.
*********************************************************************/
#include "tmxlite/FreeFuncs.hpp"
#include "tmxlite/ObjectTypes.hpp"
#include "tmxlite/detail/Log.hpp"
#include <pugixml.hpp>
#include <tmxlite/FreeFuncs.hpp>
#include <tmxlite/ObjectTypes.hpp>
#include <tmxlite/detail/Log.hpp>
using namespace tmx;

View File

@@ -25,10 +25,11 @@ and must not be misrepresented as being the original software.
source distribution.
*********************************************************************/
#include "tmxlite/Property.hpp"
#include "tmxlite/detail/Log.hpp"
#include "tmxlite/FreeFuncs.hpp"
#include <pugixml.hpp>
#include <tmxlite/Property.hpp>
#include <tmxlite/detail/Log.hpp>
#include <tmxlite/FreeFuncs.hpp>
using namespace tmx;

View File

@@ -25,17 +25,18 @@ and must not be misrepresented as being the original software.
source distribution.
*********************************************************************/
#include <pugixml.hpp>
#ifdef USE_ZSTD
#include <zstd.h>
#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 <tmxlite/FreeFuncs.hpp>
#include <tmxlite/TileLayer.hpp>
#include <tmxlite/detail/Log.hpp>
#include <pugixml.hpp>
#include <zstd.h>
#include <sstream>
#include <span>
using namespace tmx;
@@ -130,11 +131,10 @@ void TileLayer::parseBase64(const pugi::xml_node& node)
byteData.insert(byteData.end(), dataString.begin(), dataString.end());
break;
case CompressionType::Zstd:
#if defined USE_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);
@@ -142,14 +142,20 @@ void TileLayer::parseBase64(const pugi::xml_node& node)
}
}
break;
#else
Logger::log("Library must be built with USE_ZSTD for Zstd compression", Logger::Type::Error);
return {};
#endif
case CompressionType::GZip:
#ifndef USE_ZLIB
Logger::log("Library must be built with USE_ZLIB for GZip compression", Logger::Type::Error);
return {};
{
byteData.resize(expectedSize);
const auto source = std::span(reinterpret_cast<const uint8_t*>(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:
@@ -220,7 +226,7 @@ void TileLayer::parseBase64(const pugi::xml_node& node)
createTiles(IDs, chunk.tiles);
m_chunks.push_back(chunk);
dataCount++;
}
}
}
}
}
@@ -325,7 +331,7 @@ void TileLayer::createTiles(const std::vector<std::uint32_t>& IDs, std::vector<T
{
//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)
{

View File

@@ -25,11 +25,11 @@ and must not be misrepresented as being the original software.
source distribution.
*********************************************************************/
#include <pugixml.hpp>
#include <tmxlite/Tileset.hpp>
#include <tmxlite/FreeFuncs.hpp>
#include <tmxlite/detail/Log.hpp>
#include "tmxlite/Tileset.hpp"
#include "tmxlite/FreeFuncs.hpp"
#include "tmxlite/detail/Log.hpp"
#include <pugixml.hpp>
#include <ctype.h>
using namespace tmx;
@@ -59,7 +59,7 @@ void Tileset::parse(pugi::xml_node node, Map* map)
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)
{
@@ -237,7 +237,7 @@ const Tileset::Tile* Tileset::getTile(std::uint32_t id) const
{
return nullptr;
}
//corrects the ID. Indices and IDs are different.
id -= m_firstGID;
id = m_tileIndex[id];
@@ -368,12 +368,12 @@ void Tileset::parseTileNode(const pugi::xml_node& node, Map* map)
{
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)
if (m_columnCount != 0)
{
std::uint32_t rowIndex = tile.ID % m_columnCount;
std::uint32_t columnIndex = tile.ID / m_columnCount;

View File

@@ -0,0 +1,125 @@
// gzip.cpp - portable memory miniz based gzip reader
// SPDX-License-Identifier: Zlib
// SPDX-FileCopyrightText: (c) 2024 a dinosaur
#include "tmxlite/detail/gzip.hpp"
#include <string_view>
GZipReader::GZipReader() noexcept :
mSourceLen(0), mBytesRead(0),
mModificationTime(0), mCrc(0), mInputSize(0), mComputedCrc(0),
crc16(0), mFlags(0), mXflags(0), mOsId(0)
{
tinfl_init(&mState);
mComputedCrc = static_cast<uint32_t>(mz_crc32(0, nullptr, 0));
}
bool GZipReader::OpenMemory(const std::span<const uint8_t> source) noexcept
{
if (source.size() < 20)
return false;
auto it = std::cbegin(source), end = std::cend(source);
constexpr uint8_t magic[2] = { 0x1F, 0x8B };
if (*it++ != magic[0] || *it++ != magic[1])
return false;
constexpr uint8_t CM_DEFLATE = 8;
uint8_t compression = *it++;
if (compression != CM_DEFLATE)
return false;
mFlags = *it++;
mModificationTime = *it++;
mModificationTime |= *it++ << 8;
mModificationTime |= *it++ << 16;
mModificationTime |= *it++ << 24;
mXflags = *it++;
mOsId = *it++;
if (mFlags & FEXTRA)
{
// Skip "extra" field
if (it + 2 >= end)
return false;
uint16_t extraLen = *it++;
extraLen = *it++ << 8;
if (it + extraLen >= end)
return false;
it += extraLen;
}
if (mFlags & FNAME)
{
// Skip null-terminated name string
do
{
if (++it == end)
return false;
} while (*it != '\0');
if (++it == end)
return false;
}
if (mFlags & FCOMMENT)
{
// Skip null-terminated comment string
do
{
if (++it == end)
return false;
} while (*it != '\0');
if (++it == end)
return false;
}
if (mFlags & FHCRC)
{
if (it + 2 >= end)
return false;
crc16 = *it++;
crc16 |= *it++;
}
mIt = it;
mSourceLen = end - it - 8;
it += mSourceLen;
mCrc = *it++;
mCrc |= *it++ << 8;
mCrc |= *it++ << 16;
mCrc |= *it++ << 24;
mInputSize = *it++;
mInputSize |= *it++ << 8;
mInputSize |= *it++ << 16;
mInputSize |= *it++ << 24;
return true;
}
bool GZipReader::Read(std::span<uint8_t> out) noexcept
{
size_t outLen = out.size();
auto res = tinfl_decompress(&mState,
static_cast<const mz_uint8*>(&*mIt), &mSourceLen,
static_cast<mz_uint8*>(out.data()), static_cast<mz_uint8*>(out.data()), &outLen,
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
if (res != TINFL_STATUS_DONE)
return false;
mIt += outLen;
mBytesRead += outLen;
mComputedCrc = static_cast<uint32_t>(mz_crc32(static_cast<mz_ulong>(mComputedCrc), out.data(), outLen));
return true;
}
bool GZipReader::Check() const noexcept
{
if (mComputedCrc != mCrc)
return false;
if (static_cast<uint32_t>(mBytesRead & UINT32_MAX) != mInputSize)
return false;
return true;
}

View File

@@ -108,7 +108,8 @@ endif()
set_source_files_properties(${Sources} PROPERTIES LANGUAGE C)
add_library(zstd STATIC ${Sources} ${Headers})
add_library(zstd::static ALIAS zstd)
add_library(Zstd::static ALIAS zstd)
add_library(Zstd::Zstd ALIAS zstd)
add_zstd_compilation_flags(zstd)

View File

@@ -23,7 +23,7 @@ void ArgParse::Options::ShowShortUsage(const std::string_view name, std::ostream
out << "Usage: " << name;
for (const auto& it : options)
{
if (it.argumentName)
if (!it.argumentName.empty())
{
// Option with argument
it.required
@@ -55,8 +55,8 @@ void ArgParse::Options::ShowHelpUsage(const std::string_view name, std::ostream&
out << ">" << std::endl;
// Determine the alignment width from the longest argument
auto paramLength = [](const Option& p) -> int { return p.argumentName
? static_cast<int>(std::strlen(p.argumentName) + 3)
auto paramLength = [](const Option& p) -> int { return !p.argumentName.empty()
? static_cast<int>(p.argumentName.length() + 3)
: 1; };
auto longestParam = std::max_element(options.begin(), options.end(),
[=](auto a, auto b) -> bool { return paramLength(a) < paramLength(b); });
@@ -67,7 +67,8 @@ void ArgParse::Options::ShowHelpUsage(const std::string_view name, std::ostream&
{
auto decorateArgument = [=] { return " <" + std::string(it.argumentName) + "> "; };
out << " -" << it.flag
<< std::left << std::setw(alignWidth) << std::setfill('-') << (it.argumentName ? decorateArgument() : " ")
<< std::left << std::setw(alignWidth) << std::setfill('-')
<< (!it.argumentName.empty() ? decorateArgument() : " ")
<< " " << it.helpString << std::endl;
}
out << std::flush;
@@ -99,7 +100,7 @@ ArgParse::ParseCtrl ArgParse::ParserState::Next(const std::string_view token)
const auto opt = getOption(flagChar);
if (opt.has_value())
{
bool expect = opt.value().get().argumentName != nullptr;
bool expect = !opt.value().get().argumentName.empty();
if (token.length() <= 2)
{
expectArg = expect;

View File

@@ -16,18 +16,18 @@ namespace ArgParse
{
struct Option
{
const char* argumentName;
const char* helpString;
std::string_view argumentName;
std::string_view helpString;
char flag;
bool required;
static constexpr Option Optional(char flag, const char* name, const char* help)
static constexpr Option Optional(char flag, const std::string_view name, const std::string_view help)
{
return { name, help, flag, false };
}
static constexpr Option Required(char flag, const char* name, const char* help)
static constexpr Option Required(char flag, const std::string_view name, const std::string_view help)
{
return { name, help, flag, false };
return { name, help, flag, true };
}
};

View File

@@ -26,8 +26,8 @@ using ArgParse::Option;
static const ArgParse::Options options =
{
Option::Optional('h', nullptr, "Display this help & command info"),
Option::Optional('v', nullptr, "Display version & quit"),
Option::Optional('h', {}, "Display this help & command info"),
Option::Optional('v', {}, "Display version & quit"),
Option::Optional('l', "name", "Name of layer to use (default first layer in TMX)"),
Option::Optional('y', "name", "Layer for palette mappings"),
Option::Optional('c', "name", "Output a separate 8bit collision map of the specified layer"),