add cartridge reader

Signed-off-by: Peter Siegmund <mars3142@noreply.mars3142.dev>
This commit is contained in:
2026-02-12 11:47:02 +01:00
parent eb21513dd5
commit 669a5d8ce6
25 changed files with 984 additions and 73 deletions

2
.gitignore vendored
View File

@@ -109,3 +109,5 @@ CMakeUserPresets.json
*-prefix/
# End of https://www.toptal.com/developers/gitignore/api/cmake,clion+all
cartridges/

View File

@@ -1,14 +1,18 @@
cmake_minimum_required(VERSION 3.14)
cmake_minimum_required(VERSION 3.21)
project(wx_wherigo LANGUAGES CXX)
project(wxWherigo LANGUAGES CXX)
include(FetchContent)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_C_STANDARD 23)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(wxBUILD_SHARED OFF)
add_subdirectory(libs/lua-5.1.4)
add_subdirectory(libs/cartridge)
message(STATUS "Fetching wxWidgets...")
FetchContent_Declare(
@@ -22,16 +26,45 @@ FetchContent_MakeAvailable(wxWidgets)
message(STATUS "Configure project....")
set(SRCS
src/main.cpp
src/MyFrame.cpp
src/WxWherigo.cpp
main/src/main.cpp
main/src/cApp.cpp
main/src/ui/cFrame.cpp
)
include_directories(include)
add_executable(${PROJECT_NAME} ${SRCS})
if (APPLE)
add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${SRCS})
set_target_properties(${PROJECT_NAME} PROPERTIES
BUNDLE True
MACOSX_BUNDLE_GUI_IDENTIFIER dev.mars3142.${PROJECT_NAME}
MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME}
MACOSX_BUNDLE_BUNDLE_VERSION "0.1"
MACOSX_BUNDLE_SHORT_VERSION_STRING "0.1"
#MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/customtemplate.plist.in
INSTALL_RPATH "@executable_path"
)
else ()
add_executable(${PROJECT_NAME} ${SRCS})
endif ()
# Haupt-Includes
include_directories(main/include)
target_link_libraries(${PROJECT_NAME}
PRIVATE
wxcore
wxnet
wxbase
lua
cartridge
storage
)
# Kopiere die .dylib-Dateien ins Bundle
if (APPLE)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:lua>
$<TARGET_FILE:cartridge>
"$<TARGET_BUNDLE_DIR:${PROJECT_NAME}>/Contents/MacOS/"
)
endif ()

9
License.md Normal file
View File

@@ -0,0 +1,9 @@
# MIT License
Copyright (c) 2026 by Peter Siegmund (mars3142)
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.

31
Readme.md Normal file
View File

@@ -0,0 +1,31 @@
# Wherigo Simulator
This project is a desktop application for simulating and running Wherigo geocaches. It allows you to play Wherigo cartridges directly on your computer, making it possible to experience geocaching adventures without a GPS device or mobile app.
## Features
- Load and execute Wherigo cartridges (.gwc files)
- Simulate geocaching locations and actions
- Desktop interface for easy navigation and interaction
- Support for media and cartridge data
## Requirements
- C++23 or newer
- wxWidgets (for GUI)
- Lua 5.1.4 (for cartridge execution)
## Getting Started
1. Clone this repository.
2. Build the project using CMake and your preferred compiler.
3. Download a Wherigo cartridge (PocketPC format) from [wherigo.com](https://wherigo.com)
4. Open it in the application.
## Project Structure
- `main/` - Application entry point and UI
- `libs/cartridge/` - Cartridge parsing and media handling
- `libs/lua-5.1.4/` - Lua interpreter
## License
This project is licensed under the MIT License. See `License.md` for details.
## Author
Peter Siegmund (mars3142)

View File

@@ -0,0 +1,30 @@
set(CARTRIDGE_VERSION_MAJOR 1)
set(CARTRIDGE_VERSION_MINOR 0)
set(CARTRIDGE_VERSION_PATCH 0)
set(CARTRIDGE_VERSION "${CARTRIDGE_VERSION_MAJOR}.${CARTRIDGE_VERSION_MINOR}.${CARTRIDGE_VERSION_PATCH}")
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/version.h.in
${CMAKE_CURRENT_BINARY_DIR}/include/cartridge/version.h
@ONLY
)
set(CARTRIDGE_SRC
src/binary_reader.cpp
src/cartridge.cpp
src/lat_lng.cpp
src/media.cpp
src/parser.cpp
)
add_library(cartridge SHARED ${CARTRIDGE_SRC})
set_target_properties(cartridge PROPERTIES
VERSION ${CARTRIDGE_VERSION}
SOVERSION ${CARTRIDGE_VERSION_MAJOR}
)
target_include_directories(cartridge
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}/include
)

View File

@@ -0,0 +1,72 @@
// MIT License
// Copyright (c) 2026 by Peter Siegmund (mars3142)
// 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.
#pragma once
#include <stdexcept>
#include <string>
#include <vector>
namespace cartridge {
enum class SeekOrigin { Begin, Current, End };
enum class Endian { Little, Big };
class BinaryReader {
public:
explicit BinaryReader(const std::vector<uint8_t> &data,
Endian endian = Endian::Little);
void seek(int offset, SeekOrigin origin);
uint8_t getByte();
int16_t getShort();
uint16_t getUShort();
int32_t getLong();
uint32_t getULong();
double getDouble();
std::string getASCIIZ();
[[nodiscard]] const std::vector<uint8_t>& data() const { return _data; }
private:
template <typename T> T readInt(size_t size);
static bool isSystemLittleEndian();
static void swapBytes(uint8_t *data, size_t size);
const std::vector<uint8_t> &_data;
Endian _endian;
size_t _index;
};
template <typename T> T BinaryReader::readInt(const size_t size) {
if (_index + size > _data.size())
throw std::out_of_range("readInt out of range");
T value = 0;
if (_endian == Endian::Little) {
for (size_t i = 0; i < size; ++i) {
value |= static_cast<T>(_data[_index + i]) << (8 * i);
}
} else {
for (size_t i = 0; i < size; ++i) {
value = (value << 8) | _data[_index + i];
}
}
_index += size;
return value;
}
} // namespace cartridge

View File

@@ -0,0 +1,94 @@
// MIT License
// Copyright (c) 2026 by Peter Siegmund (mars3142)
// 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.
#pragma once
#include "cartridge/binary_reader.h"
#include "cartridge/lat_lng.h"
#include "cartridge/media.h"
#include <map>
#include <memory>
#include <string>
#include <vector>
namespace cartridge {
class Cartridge {
public:
// Factory method to create Cartridge from BinaryReader
static std::unique_ptr<Cartridge> create(BinaryReader &reader);
// Getters
[[nodiscard]] double altitude() const;
[[nodiscard]] const std::string &author() const;
[[nodiscard]] const LatLng &latLng() const;
[[nodiscard]] const std::string &cartridgeName() const;
[[nodiscard]] const std::string &cartridgeDesc() const;
[[nodiscard]] const std::string &cartridgeGuid() const;
[[nodiscard]] const std::string &typeOfCartridge() const;
[[nodiscard]] const std::string &playerName() const;
[[nodiscard]] const std::string &startLocationDesc() const;
[[nodiscard]] const std::string &version() const;
[[nodiscard]] const std::string &company() const;
[[nodiscard]] const std::string &recommendDevice() const;
[[nodiscard]] const std::string &completionCode() const;
// Media methods
std::unique_ptr<Media> getMedia(int objectId);
[[nodiscard]] int mediaCount() const;
std::unique_ptr<Media> splashScreen();
std::unique_ptr<Media> smallIcon();
std::unique_ptr<Media> luac();
// Comparison operators
bool operator==(const Cartridge &other) const;
bool operator!=(const Cartridge &other) const;
Cartridge(std::string cartridgeGuid, double altitude, std::string author,
std::string cartridgeDesc, std::string cartridgeName,
std::string company, std::string completionCode, LatLng latLng,
std::string playerName, std::string recommendDevice,
int smallIconId, int splashScreenId, std::string startLocationDesc,
std::string typeOfCartridge, std::string version,
std::map<int, int> references, std::vector<uint8_t> bytes);
private:
// Fields
std::string m_cartridgeGuid;
double m_altitude;
std::string m_author;
std::string m_cartridgeDesc;
std::string m_cartridgeName;
std::string m_company;
std::string m_completionCode;
LatLng m_latLng;
std::string m_playerName;
std::string m_recommendDevice;
int m_smallIconId;
int m_splashScreenId;
std::string m_startLocationDesc;
std::string m_typeOfCartridge;
std::string m_version;
std::map<int, int> m_references;
std::vector<uint8_t> m_bytes;
int m_lastObject = -1;
std::unique_ptr<Media> m_lastMedia;
};
} // namespace cartridge

View File

@@ -0,0 +1,36 @@
// MIT License
// Copyright (c) 2026 by Peter Siegmund (mars3142)
// 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.
#pragma once
#include <string>
namespace cartridge {
class LatLng {
double m_latitude;
double m_longitude;
static std::string _format(double value, const std::string& suffix);
public:
LatLng(double latitude, double longitude);
[[nodiscard]] std::string latitude() const;
[[nodiscard]] std::string longitude() const;
[[nodiscard]] std::string toString() const;
};
}

View File

@@ -0,0 +1,66 @@
// MIT License
// Copyright (c) 2026 by Peter Siegmund (mars3142)
// 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.
#pragma once
#include "cartridge/binary_reader.h"
#include <memory>
#include <string>
#include <vector>
namespace cartridge {
enum class ObjectType {
Deleted = -1,
Luac = 0,
Bmp = 1,
Png = 2,
Jpg = 3,
Gif = 4,
Wav = 17,
Mp3 = 18,
Fdl = 19,
Snd = 20,
Ogg = 21,
Swf = 33,
Txt = 49,
Invalid = -9999
};
class Media {
public:
Media(std::string objectType, const std::vector<uint8_t> &data);
static std::unique_ptr<Media> create(BinaryReader &reader, int objectId,
int address);
bool operator==(const Media &other) const;
[[nodiscard]] std::size_t hash() const;
[[nodiscard]] const std::vector<uint8_t> &getData() const { return data; }
[[nodiscard]] const std::string &getObjectType() const { return objectType; }
private:
static std::vector<uint8_t> readMediaData(BinaryReader &reader);
static std::string getObjectTypeString(int objectType);
std::string objectType;
std::vector<uint8_t> data;
};
} // namespace cartridge

View File

@@ -0,0 +1,24 @@
// MIT License
// Copyright (c) 2026 by Peter Siegmund (mars3142)
// 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.
#pragma once
#include <memory>
#include <string>
#include <vector>
#include "cartridge/cartridge.h"
namespace cartridge {
std::unique_ptr<Cartridge> parseData(const std::vector<uint8_t>& bytes);
} // namespace cartridge

View File

@@ -0,0 +1,91 @@
// MIT License
// Copyright (c) 2026 by Peter Siegmund (mars3142)
// 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.
#include "cartridge/binary_reader.h"
#include <algorithm>
namespace cartridge {
BinaryReader::BinaryReader(const std::vector<uint8_t> &data,
const Endian endian)
: _data(data), _endian(endian), _index(0) {}
void BinaryReader::seek(const int offset, const SeekOrigin origin) {
switch (origin) {
case SeekOrigin::Begin:
_index = offset;
break;
case SeekOrigin::Current:
_index += offset;
break;
case SeekOrigin::End:
_index = _data.size() - offset;
break;
}
}
uint8_t BinaryReader::getByte() {
if (_index >= _data.size())
throw std::out_of_range("getByte out of range");
return _data[_index++];
}
int16_t BinaryReader::getShort() { return readInt<int16_t>(2); }
uint16_t BinaryReader::getUShort() { return readInt<uint16_t>(2); }
int32_t BinaryReader::getLong() { return readInt<int32_t>(4); }
uint32_t BinaryReader::getULong() { return readInt<uint32_t>(4); }
double BinaryReader::getDouble() {
if (_index + 8 > _data.size())
throw std::out_of_range("getDouble out of range");
double value;
std::memcpy(&value, &_data[_index], 8);
if ((_endian == Endian::Little) != isSystemLittleEndian()) {
swapBytes(reinterpret_cast<uint8_t *>(&value), 8);
}
_index += 8;
return value;
}
std::string BinaryReader::getASCIIZ() {
std::string result;
uint8_t byte = 0;
do {
byte = getByte();
if (byte != 0)
result += static_cast<char>(byte);
} while (byte != 0);
return result;
}
bool BinaryReader::isSystemLittleEndian() {
uint16_t num = 1;
return *reinterpret_cast<uint8_t *>(&num) == 1;
}
void BinaryReader::swapBytes(uint8_t *data, size_t size) {
for (size_t i = 0; i < size / 2; ++i) {
std::swap(data[i], data[size - 1 - i]);
}
}
} // namespace cartridge

View File

@@ -0,0 +1,148 @@
// MIT License
// Copyright (c) 2026 by Peter Siegmund (mars3142)
// 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.
#include "cartridge/cartridge.h"
#include "cartridge/binary_reader.h"
#include "cartridge/lat_lng.h"
#include "cartridge/media.h"
namespace cartridge {
Cartridge::Cartridge(std::string cartridgeGuid, double altitude,
std::string author, std::string cartridgeDesc,
std::string cartridgeName, std::string company,
std::string completionCode, LatLng latLng,
std::string playerName, std::string recommendDevice,
int smallIconId, int splashScreenId,
std::string startLocationDesc, std::string typeOfCartridge,
std::string version, std::map<int, int> references,
std::vector<uint8_t> bytes)
: m_cartridgeGuid(std::move(cartridgeGuid)), m_altitude(altitude),
m_author(std::move(author)), m_cartridgeDesc(std::move(cartridgeDesc)),
m_cartridgeName(std::move(cartridgeName)), m_company(std::move(company)),
m_completionCode(std::move(completionCode)), m_latLng(latLng),
m_playerName(std::move(playerName)),
m_recommendDevice(std::move(recommendDevice)), m_smallIconId(smallIconId),
m_splashScreenId(splashScreenId),
m_startLocationDesc(std::move(startLocationDesc)),
m_typeOfCartridge(std::move(typeOfCartridge)),
m_version(std::move(version)), m_references(std::move(references)),
m_bytes(std::move(bytes)) {}
std::unique_ptr<Cartridge> Cartridge::create(BinaryReader &reader) {
try {
uint16_t count = reader.getUShort();
std::map<int, int> references;
for (uint16_t index = 0; index < count; ++index) {
int objectId = reader.getShort();
int address = reader.getLong();
references.emplace(objectId, address);
}
reader.getLong(); // header length
double latitude = reader.getDouble();
double longitude = reader.getDouble();
double altitude = reader.getDouble();
reader.getLong(); // unknown 0
reader.getLong(); // unknown 1
int splashScreenId = reader.getShort();
int smallIconId = reader.getShort();
std::string typeOfCartridge = reader.getASCIIZ();
std::string playerName = reader.getASCIIZ();
reader.getLong(); // unknown 2
reader.getLong(); // unknown 3
std::string cartridgeName = reader.getASCIIZ();
std::string cartridgeGuid = reader.getASCIIZ();
std::string cartridgeDesc = reader.getASCIIZ();
std::string startLocationDesc = reader.getASCIIZ();
std::string version = reader.getASCIIZ();
std::string author = reader.getASCIIZ();
std::string company = reader.getASCIIZ();
std::string recommendedDevice = reader.getASCIIZ();
reader.getLong(); // unknown 4
std::string completionCode = reader.getASCIIZ();
// Rohdaten aus dem Reader extrahieren
const std::vector<uint8_t> &bytes = reader.data();
return std::make_unique<Cartridge>(
cartridgeGuid, altitude, author, cartridgeDesc, cartridgeName, company,
completionCode, LatLng(latitude, longitude), playerName,
recommendedDevice, smallIconId, splashScreenId, startLocationDesc,
typeOfCartridge, version, references, bytes);
} catch (const std::exception &) {
return nullptr;
}
}
double Cartridge::altitude() const { return m_altitude; }
const std::string &Cartridge::author() const { return m_author; }
const LatLng &Cartridge::latLng() const { return m_latLng; }
const std::string &Cartridge::cartridgeName() const { return m_cartridgeName; }
const std::string &Cartridge::cartridgeDesc() const { return m_cartridgeDesc; }
const std::string &Cartridge::cartridgeGuid() const { return m_cartridgeGuid; }
const std::string &Cartridge::typeOfCartridge() const {
return m_typeOfCartridge;
}
const std::string &Cartridge::playerName() const { return m_playerName; }
const std::string &Cartridge::startLocationDesc() const {
return m_startLocationDesc;
}
const std::string &Cartridge::version() const { return m_version; }
const std::string &Cartridge::company() const { return m_company; }
const std::string &Cartridge::recommendDevice() const {
return m_recommendDevice;
}
const std::string &Cartridge::completionCode() const { return m_completionCode; }
std::unique_ptr<Media> Cartridge::getMedia(const int objectId) {
if (m_lastObject == objectId && m_lastMedia) {
return std::make_unique<Media>(*m_lastMedia);
}
auto it = m_references.find(objectId);
if (it != m_references.end()) {
int address = it->second;
BinaryReader reader(m_bytes, Endian::Little);
auto media = Media::create(reader, objectId, address);
if (media && media->getData().size() < 128000) {
m_lastObject = objectId;
m_lastMedia = std::make_unique<Media>(*media);
}
return media;
}
return nullptr;
}
int Cartridge::mediaCount() const {
return static_cast<int>(m_references.size());
}
std::unique_ptr<Media> Cartridge::splashScreen() {
return getMedia(m_splashScreenId);
}
std::unique_ptr<Media> Cartridge::smallIcon() { return getMedia(m_smallIconId); }
std::unique_ptr<Media> Cartridge::luac() { return getMedia(0); }
bool Cartridge::operator==(const Cartridge &other) const {
return m_cartridgeGuid == other.m_cartridgeGuid;
}
bool Cartridge::operator!=(const Cartridge &other) const {
return !(*this == other);
}
} // namespace cartridge

View File

@@ -0,0 +1,56 @@
// MIT License
// Copyright (c) 2026 by Peter Siegmund (mars3142)
// 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.
#include "cartridge/lat_lng.h"
#include <cmath>
#include <iomanip>
#include <sstream>
namespace cartridge {
LatLng::LatLng(const double latitude, const double longitude)
: m_latitude(latitude), m_longitude(longitude) {}
std::string LatLng::latitude() const { return _format(m_latitude, "NS"); }
std::string LatLng::longitude() const { return _format(m_longitude, "EW"); }
std::string LatLng::toString() const {
const std::string lat = latitude();
const std::string lon = longitude();
if (!lat.empty() && !lon.empty()) {
return lat + " " + lon;
}
return lat + lon;
}
std::string LatLng::_format(double value, const std::string &suffix) {
const bool isNegative = value < 0;
value = std::abs(value);
const int degrees = static_cast<int>(std::floor(value));
if (degrees == 360) {
return "";
}
const double minutes = (value - degrees) * 60.0;
std::ostringstream oss;
oss << (isNegative ? suffix.substr(1, 1) : suffix.substr(0, 1)) << " "
<< degrees << "\u00B0 " << std::fixed << std::setprecision(3) << minutes;
return oss.str();
}
} // namespace cartridge

View File

@@ -0,0 +1,107 @@
// MIT License
// Copyright (c) 2026 by Peter Siegmund (mars3142)
// 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.
#include "cartridge/media.h"
#include <utility>
namespace cartridge {
Media::Media(std::string objectType, const std::vector<uint8_t> &data)
: objectType(std::move(objectType)), data(data) {}
std::unique_ptr<Media> Media::create(BinaryReader &reader, const int objectId,
const int address) {
try {
std::vector<uint8_t> data;
int objectType = 0;
reader.seek(address, SeekOrigin::Begin);
if (objectId == 0) {
data = readMediaData(reader);
} else {
if (reader.getByte() != 0) {
objectType = reader.getLong();
data = readMediaData(reader);
}
}
if (!data.empty()) {
return std::make_unique<Media>(getObjectTypeString(objectType), data);
}
return nullptr;
} catch ([[maybe_unused]] const std::exception &ex) {
// Logging analog zu Dart: print('Exception: $ex');
return nullptr;
}
}
std::vector<uint8_t> Media::readMediaData(BinaryReader &reader) {
const int32_t length = reader.getLong();
std::vector<uint8_t> data;
data.reserve(length);
for (int32_t i = 0; i < length; ++i) {
data.push_back(reader.getByte());
}
return data;
}
std::string Media::getObjectTypeString(int objectType) {
switch (objectType) {
case -1:
return "deleted";
case 0:
return "luac";
case 1:
return "bmp";
case 2:
return "png";
case 3:
return "jpg";
case 4:
return "gif";
case 17:
return "wav";
case 18:
return "mp3";
case 19:
return "fdl";
case 20:
return "snd";
case 21:
return "ogg";
case 33:
return "swf";
case 49:
return "txt";
default:
return "invalid (" + std::to_string(objectType) + ")";
}
}
bool Media::operator==(const Media &other) const {
return objectType == other.objectType && data == other.data;
}
std::size_t Media::hash() const {
const std::size_t h1 = std::hash<std::string>{}(objectType);
std::size_t h2 = 0;
for (const auto b : data)
h2 ^= std::hash<uint8_t>{}(b) + 0x9e3779b9 + (h2 << 6) + (h2 >> 2);
return h1 ^ (h2 << 1);
}
} // namespace cartridge

View File

@@ -0,0 +1,44 @@
// MIT License
// Copyright (c) 2026 by Peter Siegmund (mars3142)
// 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.
#include "cartridge/parser.h"
#include <array>
#include <filesystem>
#include <fstream>
#include <iostream>
namespace cartridge {
std::unique_ptr<Cartridge> parseData(const std::vector<uint8_t> &bytes) {
try {
constexpr std::array<uint8_t, 7> header = {0x02, 0x0a, 0x43, 0x41,
0x52, 0x54, 0x00};
BinaryReader reader(bytes, Endian::Little);
for (const unsigned char i : header) {
if (reader.getByte() != i) {
return nullptr;
}
}
return Cartridge::create(reader);
} catch (...) {
return nullptr;
}
}
} // namespace cartridge

View File

@@ -0,0 +1,7 @@
#pragma once
#define CARTRIDGE_VERSION_MAJOR @CARTRIDGE_VERSION_MAJOR@
#define CARTRIDGE_VERSION_MINOR @CARTRIDGE_VERSION_MINOR@
#define CARTRIDGE_VERSION_PATCH @CARTRIDGE_VERSION_PATCH@
#define CARTRIDGE_VERSION "@CARTRIDGE_VERSION@"

View File

@@ -0,0 +1,72 @@
# CMake build for Lua 5.1.4
cmake_minimum_required(VERSION 3.21)
project(lua LANGUAGES C)
set(LUA_SOURCES
src/lapi.c
src/lcode.c
src/ldebug.c
src/ldo.c
src/ldump.c
src/lfunc.c
src/lgc.c
src/llex.c
src/lmem.c
src/loadlib.c
src/lobject.c
src/lopcodes.c
src/lparser.c
src/lstate.c
src/lstring.c
src/ltable.c
src/ltm.c
src/lundump.c
src/lvm.c
src/lzio.c
src/lauxlib.c
src/lbaselib.c
src/ldblib.c
src/liolib.c
src/lmathlib.c
src/loslib.c
src/ltablib.c
src/lstrlib.c
src/linit.c
)
set(LUA_VERSION_MAJOR 5)
set(LUA_VERSION_MINOR 1)
set(LUA_VERSION_PATCH 4)
set(LUA_VERSION "${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}.${LUA_VERSION_PATCH}")
add_library(lua SHARED ${LUA_SOURCES})
set_target_properties(lua PROPERTIES
VERSION ${LUA_VERSION}
SOVERSION ${LUA_VERSION_MAJOR}
)
add_executable(lua_bin
src/lua.c
)
target_link_libraries(lua_bin PRIVATE lua)
target_include_directories(lua_bin PRIVATE src)
add_executable(luac_bin
src/luac.c
src/print.c
)
target_link_libraries(luac_bin PRIVATE lua)
target_include_directories(luac_bin PRIVATE src)
# Header files
set(LUA_HEADERS
${LUA_SRC_DIR}/lua.h
${LUA_SRC_DIR}/luaconf.h
${LUA_SRC_DIR}/lualib.h
${LUA_SRC_DIR}/lauxlib.h
)
target_include_directories(lua
PUBLIC
${LUA_SRC_DIR}
)

View File

@@ -2,7 +2,7 @@
#include <wx/wx.h>
class WxWherigo : public wxApp
class cApp : public wxApp
{
public:
bool OnInit() override;

View File

@@ -2,10 +2,10 @@
#include <wx/wx.h>
class MyFrame : public wxFrame
class cFrame : public wxMDIParentFrame
{
public:
MyFrame();
cFrame();
private:
void OnHello(wxCommandEvent& event);

8
main/src/cApp.cpp Normal file
View File

@@ -0,0 +1,8 @@
#include "cApp.h"
#include "ui/cFrame.h"
bool cApp::OnInit()
{
auto *frame = new cFrame();
return frame->Show(true);
}

4
main/src/main.cpp Normal file
View File

@@ -0,0 +1,4 @@
#include "cApp.h"
#include <wx/wx.h>
wxIMPLEMENT_APP(cApp);

38
main/src/ui/cFrame.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include "ui/cFrame.h"
enum { ID_Hello = 1 };
cFrame::cFrame() : wxMDIParentFrame(nullptr, wxID_ANY, "Hello World") {
auto *menuFile = new wxMenu;
menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
"Help string shown in status bar for this menu item");
menuFile->AppendSeparator();
menuFile->Append(wxID_EXIT);
auto *menuHelp = new wxMenu;
menuHelp->Append(wxID_ABOUT);
auto *menuBar = new wxMenuBar;
menuBar->Append(menuFile, "&File");
menuBar->Append(menuHelp, "&Help");
SetMenuBar(menuBar);
CreateStatusBar();
SetStatusText("Welcome to wxWidgets!");
Bind(wxEVT_MENU, &cFrame::OnHello, this, ID_Hello);
Bind(wxEVT_MENU, &cFrame::OnAbout, this, wxID_ABOUT);
Bind(wxEVT_MENU, &cFrame::OnExit, this, wxID_EXIT);
}
void cFrame::OnExit(wxCommandEvent &event) { Close(true); }
void cFrame::OnAbout(wxCommandEvent &event) {
wxMessageBox("This is a wxWidgets Hello World example", "About Hello World",
wxOK | wxICON_INFORMATION);
}
void cFrame::OnHello(wxCommandEvent &event) {
wxLogMessage("Hello world from wxWidgets!");
}

View File

@@ -1,48 +0,0 @@
#include "MyFrame.h"
enum
{
ID_Hello = 1
};
MyFrame::MyFrame()
: wxFrame(nullptr, wxID_ANY, "Hello World")
{
auto *menuFile = new wxMenu;
menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
"Help string shown in status bar for this menu item");
menuFile->AppendSeparator();
menuFile->Append(wxID_EXIT);
auto *menuHelp = new wxMenu;
menuHelp->Append(wxID_ABOUT);
auto *menuBar = new wxMenuBar;
menuBar->Append(menuFile, "&File");
menuBar->Append(menuHelp, "&Help");
SetMenuBar( menuBar );
CreateStatusBar();
SetStatusText("Welcome to wxWidgets!");
Bind(wxEVT_MENU, &MyFrame::OnHello, this, ID_Hello);
Bind(wxEVT_MENU, &MyFrame::OnAbout, this, wxID_ABOUT);
Bind(wxEVT_MENU, &MyFrame::OnExit, this, wxID_EXIT);
}
void MyFrame::OnExit(wxCommandEvent& event)
{
Close(true);
}
void MyFrame::OnAbout(wxCommandEvent& event)
{
wxMessageBox("This is a wxWidgets Hello World example",
"About Hello World", wxOK | wxICON_INFORMATION);
}
void MyFrame::OnHello(wxCommandEvent& event)
{
wxLogMessage("Hello world from wxWidgets!");
}

View File

@@ -1,9 +0,0 @@
#include "WxWherigo.h"
#include "MyFrame.h"
bool WxWherigo::OnInit()
{
auto *frame = new MyFrame();
frame->Show(true);
return true;
}

View File

@@ -1,4 +0,0 @@
#include <wx/wx.h>
#include "WxWherigo.h"
wxIMPLEMENT_APP(WxWherigo);