Files
jasper/src/olympic/keel/src/media.cpp
Gary Talent 511548a2ee Squashed 'deps/nostalgia/' changes from 5f10edd3..0daf938f
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
2024-09-28 23:44:24 -05:00

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
}
}
}