/* * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include "media.hpp" #ifndef OX_BARE_METAL #include #include namespace keel { ox::Result loadRom(ox::CRStringView 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 { const auto size = file.tellg(); file.seekg(0, std::ios::beg); auto buff = new char[static_cast(size)]; file.read(buff, size); return buff; } catch (const std::ios_base::failure &e) { oxErrorf("Could not read ROM file due to file IO failure: {}", e.what()); return OxError(2, "Could not read ROM file"); } catch (const std::bad_alloc &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::CRStringView path) noexcept { oxRequire(files, ctx.rom->ls(path)); for (const auto &f : files) { oxRequireM(filePath, ox::join("/", ox::Array{path, f})); oxRequire(stat, ctx.rom->stat(filePath)); if (stat.fileType == ox::FileType::NormalFile) { oxRequire(data, ctx.rom->read(filePath)); const auto [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 pathToUuid(Context &ctx, ox::CRStringView 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 uuidToPath(Context &ctx, ox::CRStringView uuid) noexcept { #ifndef OX_BARE_METAL oxRequire(out, ctx.uuidToPath.at(uuid)); return *out; #else return OxError(1, "UUID to path conversion not supported on this platform"); #endif } ox::Result uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept { #ifndef OX_BARE_METAL oxRequire(out, ctx.uuidToPath.at(uuid.toString())); return *out; #else return OxError(1, "UUID to path conversion not supported on this platform"); #endif } ox::Error performPackTransforms(Context &ctx, ox::Buffer &clawData) noexcept { #ifndef OX_BARE_METAL for (auto tr : ctx.packTransforms) { oxReturnError(tr(ctx, clawData)); } return {}; #else return OxError(1, "Transformations not supported on this platform"); #endif } } #else #include "context.hpp" #define MEM_ROM reinterpret_cast(0x0800'0000) namespace keel { static void clearUuidMap(Context&) noexcept { } ox::Error buildUuidMap(Context&) noexcept { return {}; } ox::Result loadRom(ox::CRStringView) 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(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 getPreloadAddr(keel::Context &ctx, ox::CRStringView path) noexcept { oxRequire(stat, ctx.rom->stat(path)); oxRequire(buff, static_cast(ctx.rom.get())->directAccess(path)); PreloadPtr p; oxReturnError(ox::readMC(buff, static_cast(stat.size), &p)); return static_cast(p.preloadAddr) + ctx.preloadSectionOffset; } ox::Result getPreloadAddr(keel::Context &ctx, const ox::FileAddress &file) noexcept { oxRequire(stat, ctx.rom->stat(file)); oxRequire(buff, static_cast(ctx.rom.get())->directAccess(file)); PreloadPtr p; oxReturnError(ox::readMC(buff, static_cast(stat.size), &p)); return static_cast(p.preloadAddr) + ctx.preloadSectionOffset; } } #endif namespace keel { ox::Error setRomFs(Context &ctx, ox::UPtr fs) noexcept { ctx.rom = std::move(fs); clearUuidMap(ctx); return buildUuidMap(ctx); } ox::Result> loadRomFs(ox::CRStringView path) noexcept { auto const lastDot = ox::lastIndexOf(path, '.'); if (!lastDot.error && substr(path, lastDot.value) == ".oxfs") { oxRequire(rom, loadRom(path)); return {ox::make_unique(rom, 32 * ox::units::MB, unloadRom)}; } else { #ifdef OX_HAS_PASSTHROUGHFS return {ox::make_unique(path)}; #else return OxError(2); #endif } } }