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 7e42808552
commit 7b414bf398
25 changed files with 984 additions and 73 deletions

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