0daf938f [nostalgia/core/studio] Cleanup, make all number keys after num colors jump to last b90ab27a [nostalgia/core/studio] Fix Palette Color Name input to properly take focus c711f435 [nostalgia/core/studio] Fix PaletteEditor 0 key shortcut 84cb03d8 [nostalgia/core/studio] Cleanup 945a55f9 [studio] Fix Project to cut off correct end of OC data 2173b12c [nostalgia/core/studio] Give PaletteEditor keyboard shortcuts aa970b1f [keel,studio] Cleanup 6ad79b30 [ox] Cleanup a7cf2673 [studio] Remove null terminator from OC output 1a9f0d49 [ox] Rename CRString to StringCR a1b5b565 [olympic,nostalgia] Rename CRStringView to StringViewCR 256be6da [glutils] Rename CRStringView to StringViewCR cc10631b [ox] Rename CRStringView to StringViewCR 829dc029 [keel] Fix Linux build e8a1ff06 [ox/oc] Fix Linux build bdfb5e97 [nostalgia/core] Cleanup 396fecab [ox/oc] Add option for writeOC to return a string 5373b63c [keel,studio] Removing null terminator from JSON file output 8b655c40 [ox/std] Add HashMap::values 92d85d11 Merge commit '9f5f3e26efed6cd27f2a8ff0746f018d75986934' 118fef61 [buildcore] Remove python -m prefix from mypy command 8769305d [nostalgia] Allow disabling of BUILD_SHARED_LIBS c5999050 [nostalgia] Add support for partial tilesheet loading da23c930 [ox/std] Add oxModelFwdDecl macro for broken Apple Clang 3ae1d6c8 [ox/std] Make operator[] in Array and Vector nodiscard a7af6c66 [keel] Cleanup 0cc6757c [keel] Add manifest to pack output 3b8eaef3 [keel] Move vald and repair funcs to their own file, make conversion to validation b7990ed2 [keel] Make pack file copy logging nest for dir level 71313ed8 [ox/std] Cleanup 10531b6e [keel] Cleanup dfbc298d [keel] Add pack file copy status to logging 76760daf [ox/std] Cleanup Defer 5834b9c9 [ox/std] Cleanup logging output 2a584905 [ox/fs] More cleanup and bug fix from previous cleanup 702b166b [ox/fs] Cleanup 8dd837b3 [nostalgia/core] Add a valid function for CompactTileSheet 1d262597 [keel] Make default repair return a no repair error 712299fa [studio] Cleanup c45efa60 [ox/std] Make Result copyTo and moveTo able to convert git-subtree-dir: deps/nostalgia git-subtree-split: 0daf938f765b3a3ce8ba7fb292572a6a5a004634
256 lines
7.2 KiB
C++
256 lines
7.2 KiB
C++
/*
|
|
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
|
*/
|
|
|
|
#include <keel/media.hpp>
|
|
|
|
#ifndef OX_BARE_METAL
|
|
|
|
#include <fstream>
|
|
|
|
#include <ox/std/trace.hpp>
|
|
|
|
namespace keel {
|
|
|
|
ox::Result<char*> loadRom(ox::StringViewCR path) noexcept {
|
|
std::ifstream file(std::string(toStdStringView(path)), std::ios::binary | std::ios::ate);
|
|
if (!file.good()) {
|
|
oxErrorf("Could not find ROM file: {}", path);
|
|
return OxError(1, "Could not find ROM file");
|
|
}
|
|
try {
|
|
auto const size = file.tellg();
|
|
file.seekg(0, std::ios::beg);
|
|
auto buff = new char[static_cast<std::size_t>(size)];
|
|
file.read(buff, size);
|
|
return buff;
|
|
} catch (std::ios_base::failure const&e) {
|
|
oxErrorf("Could not read ROM file due to file IO failure: {}", e.what());
|
|
return OxError(2, "Could not read ROM file");
|
|
} catch (std::bad_alloc const&e) {
|
|
oxErrorf("Could not read ROM file due to new failure: {}", e.what());
|
|
return OxError(2, "Could not allocate memory for ROM file");
|
|
}
|
|
}
|
|
|
|
void unloadRom(char *rom) noexcept {
|
|
ox::safeDelete(rom);
|
|
}
|
|
|
|
static void clearUuidMap(Context &ctx) noexcept {
|
|
ctx.uuidToPath.clear();
|
|
ctx.pathToUuid.clear();
|
|
}
|
|
|
|
void createUuidMapping(Context &ctx, ox::StringView filePath, ox::UUID const&uuid) noexcept {
|
|
ctx.pathToUuid[filePath] = uuid;
|
|
ctx.uuidToPath[uuid.toString()] = filePath;
|
|
}
|
|
|
|
static ox::Error buildUuidMap(Context &ctx, ox::StringViewCR path) noexcept {
|
|
oxRequire(files, ctx.rom->ls(path));
|
|
for (auto const&f : files) {
|
|
oxRequireM(filePath, ox::join("/", ox::Array<ox::StringView, 2>{path, f}));
|
|
oxRequire(stat, ctx.rom->stat(filePath));
|
|
if (stat.fileType == ox::FileType::NormalFile) {
|
|
oxRequire(data, ctx.rom->read(filePath));
|
|
auto const [hdr, err] = readAssetHeader(data);
|
|
if (!err) {
|
|
createUuidMapping(ctx, filePath, hdr.uuid);
|
|
}
|
|
} else if (stat.fileType == ox::FileType::Directory) {
|
|
if (!beginsWith(f, ".")) {
|
|
oxReturnError(buildUuidMap(ctx, filePath));
|
|
}
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
ox::Error buildUuidMap(Context &ctx) noexcept {
|
|
if (!ctx.rom) {
|
|
return OxError(1, "No ROM FS");
|
|
}
|
|
return buildUuidMap(ctx, "");
|
|
}
|
|
|
|
ox::Result<ox::UUID> pathToUuid(Context &ctx, ox::StringViewCR path) noexcept {
|
|
#ifndef OX_BARE_METAL
|
|
oxRequire(out, ctx.pathToUuid.at(path));
|
|
return *out;
|
|
#else
|
|
return OxError(1, "UUID to path conversion not supported on this platform");
|
|
#endif
|
|
}
|
|
|
|
ox::Result<ox::UUID> getUuid(Context &ctx, ox::FileAddress const&fileAddr) noexcept {
|
|
oxRequire(path, fileAddr.getPath());
|
|
return getUuid(ctx, path);
|
|
}
|
|
|
|
ox::Result<ox::UUID> getUuid(Context &ctx, ox::StringView path) noexcept {
|
|
if (beginsWith(path, "uuid://")) {
|
|
auto const uuid = substr(path, 7);
|
|
return ox::UUID::fromString(uuid);
|
|
} else {
|
|
return pathToUuid(ctx, path);
|
|
}
|
|
}
|
|
|
|
ox::Result<ox::CStringView> getPath(Context &ctx, ox::FileAddress const&fileAddr) noexcept {
|
|
oxRequire(path, fileAddr.getPath());
|
|
if (beginsWith(path, "uuid://")) {
|
|
auto const uuid = substr(path, 7);
|
|
#ifndef OX_BARE_METAL
|
|
oxRequireM(out, ctx.uuidToPath.at(uuid));
|
|
return ox::CStringView{*out};
|
|
#else
|
|
return OxError(1, "UUID to path conversion not supported on this platform");
|
|
#endif
|
|
} else {
|
|
return ox::CStringView{path};
|
|
}
|
|
}
|
|
|
|
ox::Result<ox::CStringView> getPath(Context &ctx, ox::CStringView fileId) noexcept {
|
|
if (beginsWith(fileId, "uuid://")) {
|
|
auto const uuid = substr(fileId, 7);
|
|
#ifndef OX_BARE_METAL
|
|
oxRequireM(out, ctx.uuidToPath.at(uuid));
|
|
return ox::CStringView{*out};
|
|
#else
|
|
return OxError(1, "UUID to path conversion not supported on this platform");
|
|
#endif
|
|
} else {
|
|
return ox::CStringView{fileId};
|
|
}
|
|
}
|
|
|
|
ox::Result<ox::CStringView> uuidUrlToPath(Context &ctx, ox::StringView uuid) noexcept {
|
|
uuid = substr(uuid, 7);
|
|
#ifndef OX_BARE_METAL
|
|
oxRequireM(out, ctx.uuidToPath.at(uuid));
|
|
return ox::CStringView(*out);
|
|
#else
|
|
return OxError(1, "UUID to path conversion not supported on this platform");
|
|
#endif
|
|
}
|
|
|
|
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::StringViewCR uuid) noexcept {
|
|
#ifndef OX_BARE_METAL
|
|
oxRequireM(out, ctx.uuidToPath.at(uuid));
|
|
return ox::CStringView(*out);
|
|
#else
|
|
return OxError(1, "UUID to path conversion not supported on this platform");
|
|
#endif
|
|
}
|
|
|
|
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept {
|
|
#ifndef OX_BARE_METAL
|
|
oxRequireM(out, ctx.uuidToPath.at(uuid.toString()));
|
|
return ox::CStringView(*out);
|
|
#else
|
|
return OxError(1, "UUID to path conversion not supported on this platform");
|
|
#endif
|
|
}
|
|
|
|
ox::Error reloadAsset(keel::Context &ctx, ox::StringView assetId) noexcept {
|
|
ox::UUIDStr uuidStr;
|
|
if (beginsWith(assetId, "uuid://")) {
|
|
assetId = substr(assetId, 7);
|
|
oxRequire(p, keel::uuidToPath(ctx, assetId));
|
|
} else {
|
|
auto const [uuid, uuidErr] = getUuid(ctx, assetId);
|
|
if (!uuidErr) {
|
|
uuidStr = uuid.toString();
|
|
assetId = uuidStr;
|
|
}
|
|
}
|
|
return ctx.assetManager.reloadAsset(assetId);
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
#include <keel/context.hpp>
|
|
|
|
#define MEM_ROM reinterpret_cast<char*>(0x0800'0000)
|
|
|
|
namespace keel {
|
|
|
|
static void clearUuidMap(Context&) noexcept {
|
|
}
|
|
|
|
ox::Error buildUuidMap(Context&) noexcept {
|
|
return {};
|
|
}
|
|
|
|
ox::Result<char*> loadRom(ox::StringViewCR) noexcept {
|
|
// put the header in the wrong order to prevent mistaking this code for the
|
|
// media section
|
|
constexpr auto headerP2 = "R_______________";
|
|
constexpr auto headerP1 = "KEEL_MEDIA_HEADE";
|
|
constexpr auto headerP1Len = ox::strlen(headerP2);
|
|
constexpr auto headerP2Len = ox::strlen(headerP1);
|
|
constexpr auto headerLen = headerP1Len + headerP2Len;
|
|
for (auto current = MEM_ROM; current < reinterpret_cast<char*>(0x0a000000); current += headerLen) {
|
|
if (ox::memcmp(current, headerP1, headerP1Len) == 0 &&
|
|
ox::memcmp(current + headerP1Len, headerP2, headerP2Len) == 0) {
|
|
return current + headerLen;
|
|
}
|
|
}
|
|
return OxError(1);
|
|
}
|
|
|
|
void unloadRom(char*) noexcept {
|
|
}
|
|
|
|
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::StringViewCR path) noexcept {
|
|
oxRequire(stat, ctx.rom->stat(path));
|
|
oxRequire(buff, static_cast<ox::MemFS*>(ctx.rom.get())->directAccess(path));
|
|
PreloadPtr p;
|
|
oxReturnError(ox::readMC({buff, static_cast<std::size_t>(stat.size)}, p));
|
|
return static_cast<std::size_t>(p.preloadAddr) + ctx.preloadSectionOffset;
|
|
}
|
|
|
|
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::FileAddress const&file) noexcept {
|
|
oxRequire(stat, ctx.rom->stat(file));
|
|
oxRequire(buff, static_cast<ox::MemFS*>(ctx.rom.get())->directAccess(file));
|
|
PreloadPtr p;
|
|
oxReturnError(ox::readMC({buff, static_cast<std::size_t>(stat.size)}, p));
|
|
return static_cast<std::size_t>(p.preloadAddr) + ctx.preloadSectionOffset;
|
|
}
|
|
|
|
ox::Error reloadAsset(keel::Context&, ox::StringView) noexcept {
|
|
return OxError(1, "reloadAsset is unsupported on this platform");
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
namespace keel {
|
|
|
|
ox::Error setRomFs(Context &ctx, ox::UPtr<ox::FileSystem> &&fs) noexcept {
|
|
ctx.rom = std::move(fs);
|
|
clearUuidMap(ctx);
|
|
return buildUuidMap(ctx);
|
|
}
|
|
|
|
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(ox::StringViewCR path) noexcept {
|
|
auto const lastDot = ox::lastIndexOf(path, '.');
|
|
if (!lastDot.error && substr(path, lastDot.value) == ".oxfs") {
|
|
oxRequire(rom, loadRom(path));
|
|
return {ox::make_unique<ox::FileSystem32>(rom, 32 * ox::units::MB, unloadRom)};
|
|
} else {
|
|
#ifdef OX_HAS_PASSTHROUGHFS
|
|
return {ox::make_unique<ox::PassThroughFS>(path)};
|
|
#else
|
|
return OxError(2);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
}
|