From 9e8913cea0f428e93c4c48d0084594199e4ee69f Mon Sep 17 00:00:00 2001 From: byuu <2107894+byuu@users.noreply.github.com> Date: Thu, 1 Aug 2019 09:05:01 +0900 Subject: [PATCH] Remove icarus, merge heuristics into bsnes. --- .cirrus.yml | 3 - {icarus => bsnes}/Database/BS Memory.bml | 0 {icarus => bsnes}/Database/Sufami Turbo.bml | 0 {icarus => bsnes}/Database/Super Famicom.bml | 0 {icarus => bsnes}/heuristics/bs-memory.cpp | 0 {icarus => bsnes}/heuristics/game-boy.cpp | 0 {icarus => bsnes}/heuristics/heuristics.cpp | 0 {icarus => bsnes}/heuristics/heuristics.hpp | 0 {icarus => bsnes}/heuristics/sufami-turbo.cpp | 0 .../heuristics/super-famicom.cpp | 0 bsnes/target-bsnes/GNUmakefile | 2 - bsnes/target-bsnes/program/platform.cpp | 12 +- icarus/Firmware/cx4.data.rom | Bin 3072 -> 0 bytes icarus/Firmware/sgb1.boot.rom | Bin 256 -> 0 bytes icarus/Firmware/sgb2.boot.rom | Bin 256 -> 0 bytes icarus/core/bs-memory.cpp | 38 ---- icarus/core/colecovision.cpp | 39 ---- icarus/core/core.cpp | 129 ------------- icarus/core/core.hpp | 171 ----------------- icarus/core/famicom.cpp | 58 ------ icarus/core/game-boy-advance.cpp | 39 ---- icarus/core/game-boy-color.cpp | 40 ---- icarus/core/game-boy.cpp | 40 ---- icarus/core/game-gear.cpp | 39 ---- icarus/core/master-system.cpp | 39 ---- icarus/core/mega-drive.cpp | 52 ------ icarus/core/msx.cpp | 39 ---- icarus/core/neo-geo-pocket-color.cpp | 39 ---- icarus/core/neo-geo-pocket.cpp | 39 ---- icarus/core/pc-engine.cpp | 39 ---- icarus/core/pocket-challenge-v2.cpp | 39 ---- icarus/core/sc-3000.cpp | 39 ---- icarus/core/sg-1000.cpp | 39 ---- icarus/core/sufami-turbo.cpp | 39 ---- icarus/core/super-famicom.cpp | 62 ------- icarus/core/supergrafx.cpp | 39 ---- icarus/core/wonderswan-color.cpp | 39 ---- icarus/core/wonderswan.cpp | 39 ---- icarus/data/icarus.Manifest | 14 -- icarus/data/icarus.desktop | 8 - icarus/data/icarus.ico | Bin 33644 -> 0 bytes icarus/data/icarus.plist | 18 -- icarus/data/icarus.png | Bin 14477 -> 0 bytes icarus/data/icarus.rc | 2 - icarus/data/icarus.svg | 80 -------- icarus/heuristics/colecovision.cpp | 32 ---- icarus/heuristics/famicom.cpp | 173 ------------------ icarus/heuristics/game-boy-advance.cpp | 67 ------- icarus/heuristics/game-gear.cpp | 32 ---- icarus/heuristics/master-system.cpp | 32 ---- icarus/heuristics/mega-drive.cpp | 111 ----------- icarus/heuristics/msx.cpp | 31 ---- icarus/heuristics/neo-geo-pocket-color.cpp | 55 ------ icarus/heuristics/neo-geo-pocket.cpp | 55 ------ icarus/heuristics/pc-engine.cpp | 36 ---- icarus/heuristics/sc-3000.cpp | 32 ---- icarus/heuristics/sg-1000.cpp | 32 ---- icarus/heuristics/supergrafx.cpp | 31 ---- icarus/heuristics/wonderswan.cpp | 58 ------ icarus/icarus.cpp | 159 ---------------- icarus/settings.cpp | 24 --- icarus/ui/error-dialog.cpp | 16 -- icarus/ui/import-dialog.cpp | 52 ------ icarus/ui/scan-dialog.cpp | 147 --------------- icarus/ui/settings-dialog.cpp | 24 --- icarus/ui/ui.hpp | 68 ------- 66 files changed, 6 insertions(+), 2575 deletions(-) rename {icarus => bsnes}/Database/BS Memory.bml (100%) rename {icarus => bsnes}/Database/Sufami Turbo.bml (100%) rename {icarus => bsnes}/Database/Super Famicom.bml (100%) rename {icarus => bsnes}/heuristics/bs-memory.cpp (100%) rename {icarus => bsnes}/heuristics/game-boy.cpp (100%) rename {icarus => bsnes}/heuristics/heuristics.cpp (100%) rename {icarus => bsnes}/heuristics/heuristics.hpp (100%) rename {icarus => bsnes}/heuristics/sufami-turbo.cpp (100%) rename {icarus => bsnes}/heuristics/super-famicom.cpp (100%) delete mode 100644 icarus/Firmware/cx4.data.rom delete mode 100644 icarus/Firmware/sgb1.boot.rom delete mode 100644 icarus/Firmware/sgb2.boot.rom delete mode 100644 icarus/core/bs-memory.cpp delete mode 100644 icarus/core/colecovision.cpp delete mode 100644 icarus/core/core.cpp delete mode 100644 icarus/core/core.hpp delete mode 100644 icarus/core/famicom.cpp delete mode 100644 icarus/core/game-boy-advance.cpp delete mode 100644 icarus/core/game-boy-color.cpp delete mode 100644 icarus/core/game-boy.cpp delete mode 100644 icarus/core/game-gear.cpp delete mode 100644 icarus/core/master-system.cpp delete mode 100644 icarus/core/mega-drive.cpp delete mode 100644 icarus/core/msx.cpp delete mode 100644 icarus/core/neo-geo-pocket-color.cpp delete mode 100644 icarus/core/neo-geo-pocket.cpp delete mode 100644 icarus/core/pc-engine.cpp delete mode 100644 icarus/core/pocket-challenge-v2.cpp delete mode 100644 icarus/core/sc-3000.cpp delete mode 100644 icarus/core/sg-1000.cpp delete mode 100644 icarus/core/sufami-turbo.cpp delete mode 100644 icarus/core/super-famicom.cpp delete mode 100644 icarus/core/supergrafx.cpp delete mode 100644 icarus/core/wonderswan-color.cpp delete mode 100644 icarus/core/wonderswan.cpp delete mode 100644 icarus/data/icarus.Manifest delete mode 100644 icarus/data/icarus.desktop delete mode 100644 icarus/data/icarus.ico delete mode 100644 icarus/data/icarus.plist delete mode 100644 icarus/data/icarus.png delete mode 100644 icarus/data/icarus.rc delete mode 100644 icarus/data/icarus.svg delete mode 100644 icarus/heuristics/colecovision.cpp delete mode 100644 icarus/heuristics/famicom.cpp delete mode 100644 icarus/heuristics/game-boy-advance.cpp delete mode 100644 icarus/heuristics/game-gear.cpp delete mode 100644 icarus/heuristics/master-system.cpp delete mode 100644 icarus/heuristics/mega-drive.cpp delete mode 100644 icarus/heuristics/msx.cpp delete mode 100644 icarus/heuristics/neo-geo-pocket-color.cpp delete mode 100644 icarus/heuristics/neo-geo-pocket.cpp delete mode 100644 icarus/heuristics/pc-engine.cpp delete mode 100644 icarus/heuristics/sc-3000.cpp delete mode 100644 icarus/heuristics/sg-1000.cpp delete mode 100644 icarus/heuristics/supergrafx.cpp delete mode 100644 icarus/heuristics/wonderswan.cpp delete mode 100644 icarus/icarus.cpp delete mode 100644 icarus/settings.cpp delete mode 100644 icarus/ui/error-dialog.cpp delete mode 100644 icarus/ui/import-dialog.cpp delete mode 100644 icarus/ui/scan-dialog.cpp delete mode 100644 icarus/ui/settings-dialog.cpp delete mode 100644 icarus/ui/ui.hpp diff --git a/.cirrus.yml b/.cirrus.yml index 1a5fc413..ccc267c3 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -14,7 +14,6 @@ linux-x86_64-binaries_task: - mkdir bsnes-nightly/Firmware - cp -a bsnes/out/bsnes bsnes-nightly/bsnes - cp -a bsnes/Database/* bsnes-nightly/Database - - cp -a icarus/Database/* bsnes-nightly/Database - cp -a GPLv3.txt bsnes-nightly - zip -r bsnes-nightly.zip bsnes-nightly @@ -37,7 +36,6 @@ freebsd-x86_64-binaries_task: - mkdir bsnes-nightly/Firmware - cp -a bsnes/out/bsnes bsnes-nightly/bsnes - cp -a bsnes/Database/* bsnes-nightly/Database - - cp -a icarus/Database/* bsnes-nightly/Database - cp -a GPLv3.txt bsnes-nightly - zip -r bsnes-nightly.zip bsnes-nightly @@ -60,7 +58,6 @@ windows-x86_64-binaries_task: - mkdir bsnes-nightly/Firmware - cp -a bsnes/out/bsnes bsnes-nightly/bsnes.exe - cp -a bsnes/Database/* bsnes-nightly/Database - - cp -a icarus/Database/* bsnes-nightly/Database - cp -a GPLv3.txt bsnes-nightly - zip -r bsnes-nightly.zip bsnes-nightly diff --git a/icarus/Database/BS Memory.bml b/bsnes/Database/BS Memory.bml similarity index 100% rename from icarus/Database/BS Memory.bml rename to bsnes/Database/BS Memory.bml diff --git a/icarus/Database/Sufami Turbo.bml b/bsnes/Database/Sufami Turbo.bml similarity index 100% rename from icarus/Database/Sufami Turbo.bml rename to bsnes/Database/Sufami Turbo.bml diff --git a/icarus/Database/Super Famicom.bml b/bsnes/Database/Super Famicom.bml similarity index 100% rename from icarus/Database/Super Famicom.bml rename to bsnes/Database/Super Famicom.bml diff --git a/icarus/heuristics/bs-memory.cpp b/bsnes/heuristics/bs-memory.cpp similarity index 100% rename from icarus/heuristics/bs-memory.cpp rename to bsnes/heuristics/bs-memory.cpp diff --git a/icarus/heuristics/game-boy.cpp b/bsnes/heuristics/game-boy.cpp similarity index 100% rename from icarus/heuristics/game-boy.cpp rename to bsnes/heuristics/game-boy.cpp diff --git a/icarus/heuristics/heuristics.cpp b/bsnes/heuristics/heuristics.cpp similarity index 100% rename from icarus/heuristics/heuristics.cpp rename to bsnes/heuristics/heuristics.cpp diff --git a/icarus/heuristics/heuristics.hpp b/bsnes/heuristics/heuristics.hpp similarity index 100% rename from icarus/heuristics/heuristics.hpp rename to bsnes/heuristics/heuristics.hpp diff --git a/icarus/heuristics/sufami-turbo.cpp b/bsnes/heuristics/sufami-turbo.cpp similarity index 100% rename from icarus/heuristics/sufami-turbo.cpp rename to bsnes/heuristics/sufami-turbo.cpp diff --git a/icarus/heuristics/super-famicom.cpp b/bsnes/heuristics/super-famicom.cpp similarity index 100% rename from icarus/heuristics/super-famicom.cpp rename to bsnes/heuristics/super-famicom.cpp diff --git a/bsnes/target-bsnes/GNUmakefile b/bsnes/target-bsnes/GNUmakefile index d9f219cf..79a3a705 100644 --- a/bsnes/target-bsnes/GNUmakefile +++ b/bsnes/target-bsnes/GNUmakefile @@ -30,7 +30,6 @@ ifeq ($(platform),macos) mkdir -p out/$(name).app/Contents/Resources/ mv out/$(name) out/$(name).app/Contents/MacOS/$(name) cp Database/* out/$(name).app/Contents/MacOS/Database/ - cp ../icarus/Database/* out/$(name).app/Contents/MacOS/Database/ cp $(ui)/resource/$(name).plist out/$(name).app/Contents/Info.plist sips -s format icns $(ui)/resource/$(name).png --out out/$(name).app/Contents/Resources/$(name).icns endif @@ -58,7 +57,6 @@ else ifneq ($(filter $(platform),linux bsd),) cp $(ui)/resource/$(name).desktop $(prefix)/share/applications/$(name).desktop cp $(ui)/resource/$(name).png $(prefix)/share/icons/$(name).png cp Database/* $(prefix)/share/$(name)/Database/ - cp ../icarus/Database/* $(prefix)/share/$(name)/Database/ cp Locale/* $(prefix)/share/$(name)/Locale/ endif diff --git a/bsnes/target-bsnes/program/platform.cpp b/bsnes/target-bsnes/program/platform.cpp index d1e803b4..9b7f5723 100644 --- a/bsnes/target-bsnes/program/platform.cpp +++ b/bsnes/target-bsnes/program/platform.cpp @@ -1,10 +1,10 @@ #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include //ROM data is held in memory to support compressed archives, soft-patching, and game hacks auto Program::open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file { diff --git a/icarus/Firmware/cx4.data.rom b/icarus/Firmware/cx4.data.rom deleted file mode 100644 index 31c8c44d21ba8d736bf2c2e37e4081cd0a2c0a87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3072 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 N!lU!3J(`d5{~za-LxKPR diff --git a/icarus/Firmware/sgb1.boot.rom b/icarus/Firmware/sgb1.boot.rom deleted file mode 100644 index 2bece74809a9d8ed6d3b92e021093c69c28a94fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 256 zcmXr~_utOo0mFL5|MQJb*C_l}RQt~-XxCu$h{x{pBO|-=a=Skd+!f;w@Nuj+;#K$~ z=+9{Pn~&`)8-tXzQG+|L!Vja5MtpqNnEt(2cqPcfs3_1Nb@npD*((gf)&EQsJ_|l$ zVB?SyR#IkF_-QBkN?@j<{!Bg|TMZ7NVL$cwB|h6teBhwSaDb1&j^UA=!6P;SIS#Gx z(@u5*3QTqiAd%BjvI_566<$DiXAd#d{!37}#3yWb5a>kqM-okqM-o string { - vector buffer; - //only one of these should exist - concatenate(buffer, {location, "program.rom"}); - concatenate(buffer, {location, "program.flash"}); - return bsMemoryManifest(buffer, location); -} - -auto Icarus::bsMemoryManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::BSMemory.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::BSMemory game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::bsMemoryImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "BS Memory/", name, ".bs/"}; - - auto manifest = bsMemoryManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/colecovision.cpp b/icarus/core/colecovision.cpp deleted file mode 100644 index 2931afdb..00000000 --- a/icarus/core/colecovision.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::colecoVisionManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return colecoVisionManifest(buffer, location); -} - -auto Icarus::colecoVisionManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::ColecoVision.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::ColecoVision game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::colecoVisionImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "ColecoVision/", name, ".cv/"}; - - auto manifest = colecoVisionManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/core.cpp b/icarus/core/core.cpp deleted file mode 100644 index b06d328a..00000000 --- a/icarus/core/core.cpp +++ /dev/null @@ -1,129 +0,0 @@ -Icarus::Icarus() { - Database::Famicom = BML::unserialize(string::read(locate("Database/Famicom.bml"))); - Database::SuperFamicom = BML::unserialize(string::read(locate("Database/Super Famicom.bml"))); - Database::SG1000 = BML::unserialize(string::read(locate("Database/SG-1000.bml"))); - Database::SC3000 = BML::unserialize(string::read(locate("Database/SC-3000.bml"))); - Database::MasterSystem = BML::unserialize(string::read(locate("Database/Master System.bml"))); - Database::MegaDrive = BML::unserialize(string::read(locate("Database/Mega Drive.bml"))); - Database::PCEngine = BML::unserialize(string::read(locate("Database/PC Engine.bml"))); - Database::SuperGrafx = BML::unserialize(string::read(locate("Database/SuperGrafx.bml"))); - Database::ColecoVision = BML::unserialize(string::read(locate("Database/ColecoVision.bml"))); - Database::MSX = BML::unserialize(string::read(locate("Database/MSX.bml"))); - Database::GameBoy = BML::unserialize(string::read(locate("Database/Game Boy.bml"))); - Database::GameBoyColor = BML::unserialize(string::read(locate("Database/Game Boy Color.bml"))); - Database::GameBoyAdvance = BML::unserialize(string::read(locate("Database/Game Boy Advance.bml"))); - Database::GameGear = BML::unserialize(string::read(locate("Database/Game Gear.bml"))); - Database::WonderSwan = BML::unserialize(string::read(locate("Database/WonderSwan.bml"))); - Database::WonderSwanColor = BML::unserialize(string::read(locate("Database/WonderSwan Color.bml"))); - Database::PocketChallengeV2 = BML::unserialize(string::read(locate("Database/Pocket Challenge V2.bml"))); - Database::NeoGeoPocket = BML::unserialize(string::read(locate("Database/Neo Geo Pocket.bml"))); - Database::NeoGeoPocketColor = BML::unserialize(string::read(locate("Database/Neo Geo Pocket Color.bml"))); - Database::BSMemory = BML::unserialize(string::read(locate("Database/BS Memory.bml"))); - Database::SufamiTurbo = BML::unserialize(string::read(locate("Database/Sufami Turbo.bml"))); -} - -auto Icarus::error() const -> string { - return errorMessage; -} - -auto Icarus::missing() const -> vector { - return missingFiles; -} - -auto Icarus::success(string location) -> string { - errorMessage = ""; - return location; -} - -auto Icarus::failure(string message) -> string { - errorMessage = message; - return {}; -} - -auto Icarus::manifest(string location) -> string { - location.transform("\\", "/").trimRight("/").append("/"); - if(!directory::exists(location)) return {}; - - auto type = Location::suffix(location).downcase(); - if(type == ".fc") return famicomManifest(location); - if(type == ".sfc") return superFamicomManifest(location); - if(type == ".sg1000") return sg1000Manifest(location); - if(type == ".sc3000") return sc3000Manifest(location); - if(type == ".ms") return masterSystemManifest(location); - if(type == ".md") return megaDriveManifest(location); - if(type == ".pce") return pcEngineManifest(location); - if(type == ".sgx") return superGrafxManifest(location); - if(type == ".cv") return colecoVisionManifest(location); - if(type == ".msx") return msxManifest(location); - if(type == ".gb") return gameBoyManifest(location); - if(type == ".gbc") return gameBoyColorManifest(location); - if(type == ".gba") return gameBoyAdvanceManifest(location); - if(type == ".gg") return gameGearManifest(location); - if(type == ".ws") return wonderSwanManifest(location); - if(type == ".wsc") return wonderSwanColorManifest(location); - if(type == ".pc2") return pocketChallengeV2Manifest(location); - if(type == ".ngp") return neoGeoPocketManifest(location); - if(type == ".ngpc") return neoGeoPocketColorManifest(location); - if(type == ".bs") return bsMemoryManifest(location); - if(type == ".st") return sufamiTurboManifest(location); - - return {}; -} - -auto Icarus::import(string location) -> string { - errorMessage = {}; - missingFiles = {}; - - location.transform("\\", "/").trimRight("/"); - if(!file::exists(location)) return failure("file does not exist"); - if(!file::readable(location)) return failure("file is unreadable"); - - auto name = Location::prefix(location); - auto type = Location::suffix(location).downcase(); - if(!name || !type) return failure("invalid file name"); - - auto buffer = file::read(location); - if(!buffer) return failure("file is empty"); - - if(type == ".zip") { - Decode::ZIP zip; - if(!zip.open(location)) return failure("ZIP archive is invalid"); - if(!zip.file) return failure("ZIP archive is empty"); - - name = Location::prefix(zip.file[0].name); - type = Location::suffix(zip.file[0].name).downcase(); - buffer = zip.extract(zip.file[0]); - } - - if(type == ".fc" || type == ".nes") return famicomImport(buffer, location); - if(type == ".sfc" || type == ".smc") return superFamicomImport(buffer, location); - if(type == ".sg1000" || type == ".sg") return sg1000Import(buffer, location); - if(type == ".sc3000" || type == ".sc") return sc3000Import(buffer, location); - if(type == ".ms" || type == ".sms") return masterSystemImport(buffer, location); - if(type == ".md" || type == ".smd" || type == ".gen") return megaDriveImport(buffer, location); - if(type == ".pce") return pcEngineImport(buffer, location); - if(type == ".sgx") return superGrafxImport(buffer, location); - if(type == ".cv" || type == ".col") return colecoVisionImport(buffer, location); - if(type == ".msx") return msxImport(buffer, location); - if(type == ".gb") return gameBoyImport(buffer, location); - if(type == ".gbc") return gameBoyColorImport(buffer, location); - if(type == ".gba") return gameBoyAdvanceImport(buffer, location); - if(type == ".gg") return gameGearImport(buffer, location); - if(type == ".ws") return wonderSwanImport(buffer, location); - if(type == ".wsc") return wonderSwanColorImport(buffer, location); - if(type == ".pc2") return pocketChallengeV2Import(buffer, location); - if(type == ".ngp") return neoGeoPocketImport(buffer, location); - if(type == ".ngpc" || type == ".ngc") return neoGeoPocketColorImport(buffer, location); - if(type == ".bs") return bsMemoryImport(buffer, location); - if(type == ".st") return sufamiTurboImport(buffer, location); - - return failure("unrecognized file extension"); -} - -auto Icarus::concatenate(vector& output, string location) -> void { - if(auto input = file::read(location)) { - auto size = output.size(); - output.resize(size + input.size()); - memory::copy(output.data() + size, input.data(), input.size()); - } -} diff --git a/icarus/core/core.hpp b/icarus/core/core.hpp deleted file mode 100644 index bacbc16d..00000000 --- a/icarus/core/core.hpp +++ /dev/null @@ -1,171 +0,0 @@ -struct Icarus { - virtual auto create(const string& pathname) -> bool { - return directory::create(pathname); - } - - virtual auto exists(const string& filename) -> bool { - return file::exists(filename); - } - - virtual auto copy(const string& target, const string& source) -> bool { - return file::copy(target, source); - } - - virtual auto write(const string& filename, const uint8_t* data, uint size) -> bool { - return file::write(filename, {data, size}); - } - - auto write(const string& filename, const vector& buffer) -> bool { - return write(filename, buffer.data(), buffer.size()); - } - - auto write(const string& filename, const string& text) -> bool { - return write(filename, (const uint8_t*)text.data(), text.size()); - } - - //core.cpp - Icarus(); - - auto error() const -> string; - auto missing() const -> vector; - auto success(string location) -> string; - auto failure(string message) -> string; - - auto manifest(string location) -> string; - auto import(string location) -> string; - - auto concatenate(vector& output, string location) -> void; - - //famicom.cpp - auto famicomManifest(string location) -> string; - auto famicomManifest(vector& buffer, string location) -> string; - auto famicomImport(vector& buffer, string location) -> string; - - //super-famicom.cpp - auto superFamicomManifest(string location) -> string; - auto superFamicomManifest(vector& buffer, string location) -> string; - auto superFamicomImport(vector& buffer, string location) -> string; - - //sg-1000.cpp - auto sg1000Manifest(string location) -> string; - auto sg1000Manifest(vector& buffer, string location) -> string; - auto sg1000Import(vector& buffer, string location) -> string; - - //sc-3000.cpp - auto sc3000Manifest(string location) -> string; - auto sc3000Manifest(vector& buffer, string location) -> string; - auto sc3000Import(vector& buffer, string location) -> string; - - //master-system.cpp - auto masterSystemManifest(string location) -> string; - auto masterSystemManifest(vector& buffer, string location) -> string; - auto masterSystemImport(vector& buffer, string location) -> string; - - //mega-drive.cpp - auto megaDriveManifest(string location) -> string; - auto megaDriveManifest(vector& buffer, string location) -> string; - auto megaDriveImport(vector& buffer, string location) -> string; - - //pc-engine.cpp - auto pcEngineManifest(string location) -> string; - auto pcEngineManifest(vector& buffer, string location) -> string; - auto pcEngineImport(vector& buffer, string location) -> string; - - //supergrafx.cpp - auto superGrafxManifest(string location) -> string; - auto superGrafxManifest(vector& buffer, string location) -> string; - auto superGrafxImport(vector& buffer, string location) -> string; - - //colecovision.cpp - auto colecoVisionManifest(string location) -> string; - auto colecoVisionManifest(vector& buffer, string location) -> string; - auto colecoVisionImport(vector& buffer, string location) -> string; - - //msx.cpp - auto msxManifest(string location) -> string; - auto msxManifest(vector& buffer, string location) -> string; - auto msxImport(vector& buffer, string location) -> string; - - //game-boy.cpp - auto gameBoyManifest(string location) -> string; - auto gameBoyManifest(vector& buffer, string location) -> string; - auto gameBoyImport(vector& buffer, string location) -> string; - - //game-boy-color.cpp - auto gameBoyColorManifest(string location) -> string; - auto gameBoyColorManifest(vector& buffer, string location) -> string; - auto gameBoyColorImport(vector& buffer, string location) -> string; - - //game-boy-advance.cpp - auto gameBoyAdvanceManifest(string location) -> string; - auto gameBoyAdvanceManifest(vector& buffer, string location) -> string; - auto gameBoyAdvanceImport(vector& buffer, string location) -> string; - - //game-gear.cpp - auto gameGearManifest(string location) -> string; - auto gameGearManifest(vector& buffer, string location) -> string; - auto gameGearImport(vector& buffer, string location) -> string; - - //wonderswan.cpp - auto wonderSwanManifest(string location) -> string; - auto wonderSwanManifest(vector& buffer, string location) -> string; - auto wonderSwanImport(vector& buffer, string location) -> string; - - //wonderswan-color.cpp - auto wonderSwanColorManifest(string location) -> string; - auto wonderSwanColorManifest(vector& buffer, string location) -> string; - auto wonderSwanColorImport(vector& buffer, string location) -> string; - - //pocket-challenge-v2.cpp - auto pocketChallengeV2Manifest(string location) -> string; - auto pocketChallengeV2Manifest(vector& buffer, string location) -> string; - auto pocketChallengeV2Import(vector& buffer, string location) -> string; - - //neo-geo-pocket.cpp - auto neoGeoPocketManifest(string location) -> string; - auto neoGeoPocketManifest(vector& buffer, string location) -> string; - auto neoGeoPocketImport(vector& buffer, string location) -> string; - - //neo-geo-pocket-color.cpp - auto neoGeoPocketColorManifest(string location) -> string; - auto neoGeoPocketColorManifest(vector& buffer, string location) -> string; - auto neoGeoPocketColorImport(vector& buffer, string location) -> string; - - //bs-memory.cpp - auto bsMemoryManifest(string location) -> string; - auto bsMemoryManifest(vector& buffer, string location) -> string; - auto bsMemoryImport(vector& buffer, string location) -> string; - - //sufami-turbo.cpp - auto sufamiTurboManifest(string location) -> string; - auto sufamiTurboManifest(vector& buffer, string location) -> string; - auto sufamiTurboImport(vector& buffer, string location) -> string; - -private: - string errorMessage; - vector missingFiles; -}; - -namespace Database { - Markup::Node Famicom; - Markup::Node SuperFamicom; - Markup::Node SG1000; - Markup::Node SC3000; - Markup::Node MasterSystem; - Markup::Node MegaDrive; - Markup::Node PCEngine; - Markup::Node SuperGrafx; - Markup::Node ColecoVision; - Markup::Node MSX; - Markup::Node GameBoy; - Markup::Node GameBoyColor; - Markup::Node GameBoyAdvance; - Markup::Node GameGear; - Markup::Node WonderSwan; - Markup::Node WonderSwanColor; - Markup::Node PocketChallengeV2; - Markup::Node NeoGeoPocket; - Markup::Node NeoGeoPocketColor; - Markup::Node BSMemory; - Markup::Node SufamiTurbo; -}; diff --git a/icarus/core/famicom.cpp b/icarus/core/famicom.cpp deleted file mode 100644 index 877c7c58..00000000 --- a/icarus/core/famicom.cpp +++ /dev/null @@ -1,58 +0,0 @@ -auto Icarus::famicomManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "ines.rom"}); - concatenate(buffer, {location, "program.rom"}); - concatenate(buffer, {location, "character.rom"}); - return famicomManifest(buffer, location); -} - -auto Icarus::famicomManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::Famicom.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::Famicom game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::famicomImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Famicom/", name, ".fc/"}; - - auto manifest = famicomManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - auto document = BML::unserialize(manifest); - uint offset = 0; - if(true) { - //todo: support images without iNES headers (via database lookup) - uint size = 16; - write({target, "ines.rom"}, &buffer[offset], size); - offset += size; - } - if(auto program = document["game/board/memory(type=ROM,content=Program)"]) { - uint size = program["size"].natural(); - write({target, "program.rom"}, &buffer[offset], size); - offset += size; - } - if(auto character = document["game/board/memory(type=ROM,content=Character)"]) { - uint size = character["size"].natural(); - write({target, "character.rom"}, &buffer[offset], size); - offset += size; - } - return success(target); -} diff --git a/icarus/core/game-boy-advance.cpp b/icarus/core/game-boy-advance.cpp deleted file mode 100644 index cf17d4df..00000000 --- a/icarus/core/game-boy-advance.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::gameBoyAdvanceManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return gameBoyAdvanceManifest(buffer, location); -} - -auto Icarus::gameBoyAdvanceManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::GameBoyAdvance.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::GameBoyAdvance game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::gameBoyAdvanceImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Game Boy Advance/", name, ".gba/"}; - - auto manifest = gameBoyAdvanceManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/game-boy-color.cpp b/icarus/core/game-boy-color.cpp deleted file mode 100644 index aa25f019..00000000 --- a/icarus/core/game-boy-color.cpp +++ /dev/null @@ -1,40 +0,0 @@ -auto Icarus::gameBoyColorManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return gameBoyColorManifest(buffer, location); -} - -auto Icarus::gameBoyColorManifest(vector& buffer, string location) -> string { - auto digest = Hash::SHA256(buffer).digest(); - - if(settings["icarus/UseDatabase"].boolean()) { - for(auto game : Database::GameBoyColor.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::GameBoy game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::gameBoyColorImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Game Boy Color/", name, ".gbc/"}; - - auto manifest = gameBoyColorManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/game-boy.cpp b/icarus/core/game-boy.cpp deleted file mode 100644 index d358a423..00000000 --- a/icarus/core/game-boy.cpp +++ /dev/null @@ -1,40 +0,0 @@ -auto Icarus::gameBoyManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return gameBoyManifest(buffer, location); -} - -auto Icarus::gameBoyManifest(vector& buffer, string location) -> string { - auto digest = Hash::SHA256(buffer).digest(); - - if(settings["icarus/UseDatabase"].boolean()) { - for(auto game : Database::GameBoy.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::GameBoy game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::gameBoyImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Game Boy/", name, ".gb/"}; - - auto manifest = gameBoyManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/game-gear.cpp b/icarus/core/game-gear.cpp deleted file mode 100644 index f02c40a1..00000000 --- a/icarus/core/game-gear.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::gameGearManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return gameGearManifest(buffer, location); -} - -auto Icarus::gameGearManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::GameGear.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::GameGear game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::gameGearImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Game Gear/", name, ".gg/"}; - - auto manifest = gameGearManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/master-system.cpp b/icarus/core/master-system.cpp deleted file mode 100644 index 28796adf..00000000 --- a/icarus/core/master-system.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::masterSystemManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return masterSystemManifest(buffer, location); -} - -auto Icarus::masterSystemManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::MasterSystem.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::MasterSystem game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::masterSystemImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Master System/", name, ".ms/"}; - - auto manifest = masterSystemManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/mega-drive.cpp b/icarus/core/mega-drive.cpp deleted file mode 100644 index b110c06a..00000000 --- a/icarus/core/mega-drive.cpp +++ /dev/null @@ -1,52 +0,0 @@ -auto Icarus::megaDriveManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - concatenate(buffer, {location, "patch.rom" }); - return megaDriveManifest(buffer, location); -} - -auto Icarus::megaDriveManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::MegaDrive.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::MegaDrive game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::megaDriveImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Mega Drive/", name, ".md/"}; - - auto manifest = megaDriveManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - uint offset = 0; - auto document = BML::unserialize(manifest); - for(auto rom : document.find("game/board/memory(type=ROM)")) { - auto name = string{rom["content"].text(), ".rom"}.downcase(); - auto size = rom["size"].natural(); - if(size > buffer.size() - offset) { - missingFiles.append(name); - continue; - } - write({target, name}, buffer.data() + offset, size); - offset += size; - } - if(missingFiles) return failure({"ROM image is missing data: ", missingFiles.merge("; ")}); - return success(target); -} diff --git a/icarus/core/msx.cpp b/icarus/core/msx.cpp deleted file mode 100644 index b9d00a55..00000000 --- a/icarus/core/msx.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::msxManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return msxManifest(buffer, location); -} - -auto Icarus::msxManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::MSX.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::MSX game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::msxImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "MSX/", name, ".msx/"}; - - auto manifest = msxManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/neo-geo-pocket-color.cpp b/icarus/core/neo-geo-pocket-color.cpp deleted file mode 100644 index 749a372c..00000000 --- a/icarus/core/neo-geo-pocket-color.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::neoGeoPocketColorManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return neoGeoPocketColorManifest(buffer, location); -} - -auto Icarus::neoGeoPocketColorManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::NeoGeoPocketColor.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::NeoGeoPocketColor game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::neoGeoPocketColorImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Neo Geo Pocket Color/", name, ".ngpc/"}; - - auto manifest = neoGeoPocketColorManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/neo-geo-pocket.cpp b/icarus/core/neo-geo-pocket.cpp deleted file mode 100644 index f0646e41..00000000 --- a/icarus/core/neo-geo-pocket.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::neoGeoPocketManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return neoGeoPocketManifest(buffer, location); -} - -auto Icarus::neoGeoPocketManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::NeoGeoPocket.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::NeoGeoPocket game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::neoGeoPocketImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Neo Geo Pocket/", name, ".ngp/"}; - - auto manifest = neoGeoPocketManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/pc-engine.cpp b/icarus/core/pc-engine.cpp deleted file mode 100644 index 5f9940f5..00000000 --- a/icarus/core/pc-engine.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::pcEngineManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return pcEngineManifest(buffer, location); -} - -auto Icarus::pcEngineManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::PCEngine.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::PCEngine game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::pcEngineImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "PC Engine/", name, ".pce/"}; - - auto manifest = pcEngineManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/pocket-challenge-v2.cpp b/icarus/core/pocket-challenge-v2.cpp deleted file mode 100644 index 6028166b..00000000 --- a/icarus/core/pocket-challenge-v2.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::pocketChallengeV2Manifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return pocketChallengeV2Manifest(buffer, location); -} - -auto Icarus::pocketChallengeV2Manifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::PocketChallengeV2.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::WonderSwan game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::pocketChallengeV2Import(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Pocket Challenge V2/", name, ".pc2/"}; - - auto manifest = pocketChallengeV2Manifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/sc-3000.cpp b/icarus/core/sc-3000.cpp deleted file mode 100644 index eb9d8906..00000000 --- a/icarus/core/sc-3000.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::sc3000Manifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return sc3000Manifest(buffer, location); -} - -auto Icarus::sc3000Manifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::SC3000.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::SC3000 game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::sc3000Import(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "SC-3000/", name, ".sc3000/"}; - - auto manifest = sc3000Manifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/sg-1000.cpp b/icarus/core/sg-1000.cpp deleted file mode 100644 index 73b58291..00000000 --- a/icarus/core/sg-1000.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::sg1000Manifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return sg1000Manifest(buffer, location); -} - -auto Icarus::sg1000Manifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::SG1000.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::SG1000 game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::sg1000Import(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "SG-1000/", name, ".sg1000/"}; - - auto manifest = sg1000Manifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/sufami-turbo.cpp b/icarus/core/sufami-turbo.cpp deleted file mode 100644 index 2bfce8ec..00000000 --- a/icarus/core/sufami-turbo.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::sufamiTurboManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return sufamiTurboManifest(buffer, location); -} - -auto Icarus::sufamiTurboManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::SufamiTurbo.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::SufamiTurbo game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::sufamiTurboImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Sufami Turbo/", name, ".st/"}; - - auto manifest = sufamiTurboManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/super-famicom.cpp b/icarus/core/super-famicom.cpp deleted file mode 100644 index 0aac6c7b..00000000 --- a/icarus/core/super-famicom.cpp +++ /dev/null @@ -1,62 +0,0 @@ -auto Icarus::superFamicomManifest(string location) -> string { - vector buffer; - auto files = directory::files(location, "*.rom"); - concatenate(buffer, {location, "program.rom"}); - concatenate(buffer, {location, "data.rom" }); - for(auto& file : files.match("*.program.rom")) concatenate(buffer, {location, file}); - for(auto& file : files.match("*.data.rom" )) concatenate(buffer, {location, file}); - for(auto& file : files.match("*.boot.rom" )) concatenate(buffer, {location, file}); - return superFamicomManifest(buffer, location); -} - -auto Icarus::superFamicomManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::SuperFamicom.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::SuperFamicom game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::superFamicomImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "Super Famicom/", name, ".sfc/"}; - - auto manifest = superFamicomManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".srm"}) && !exists({target, "save.ram"})) { - copy({source, name, ".srm"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - uint offset = 0; - auto document = BML::unserialize(manifest); - for(auto rom : document.find("game/board/memory(type=ROM)")) { - auto name = string{rom["architecture"].text(), ".", rom["content"].text(), ".rom"}.trimLeft(".", 1L).downcase(); - auto size = rom["size"].natural(); - if(size > buffer.size() - offset) { - auto firmware = string{rom["identifier"].text(), ".", rom["content"].text(), ".rom"}.trimLeft(".", 1L).downcase(); - auto location = locate({"Firmware/", firmware}); - if(location && file::size(location) == size) { - write({target, name}, file::read(location)); - } else { - missingFiles.append(firmware); - } - continue; - } - write({target, name}, buffer.data() + offset, size); - offset += size; - } - if(missingFiles) return failure({"ROM image is missing data: ", missingFiles.merge("; ")}); - return success(target); -} diff --git a/icarus/core/supergrafx.cpp b/icarus/core/supergrafx.cpp deleted file mode 100644 index 10969bc0..00000000 --- a/icarus/core/supergrafx.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::superGrafxManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return superGrafxManifest(buffer, location); -} - -auto Icarus::superGrafxManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::SuperGrafx.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::SuperGrafx game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::superGrafxImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "SuperGrafx/", name, ".sg/"}; - - auto manifest = superGrafxManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/wonderswan-color.cpp b/icarus/core/wonderswan-color.cpp deleted file mode 100644 index e3a48a8c..00000000 --- a/icarus/core/wonderswan-color.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::wonderSwanColorManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return wonderSwanColorManifest(buffer, location); -} - -auto Icarus::wonderSwanColorManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::WonderSwanColor.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::WonderSwan game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::wonderSwanColorImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "WonderSwan Color/", name, ".wsc/"}; - - auto manifest = wonderSwanColorManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/core/wonderswan.cpp b/icarus/core/wonderswan.cpp deleted file mode 100644 index 356c325d..00000000 --- a/icarus/core/wonderswan.cpp +++ /dev/null @@ -1,39 +0,0 @@ -auto Icarus::wonderSwanManifest(string location) -> string { - vector buffer; - concatenate(buffer, {location, "program.rom"}); - return wonderSwanManifest(buffer, location); -} - -auto Icarus::wonderSwanManifest(vector& buffer, string location) -> string { - if(settings["icarus/UseDatabase"].boolean()) { - auto digest = Hash::SHA256(buffer).digest(); - for(auto game : Database::WonderSwan.find("game")) { - if(game["sha256"].text() == digest) return BML::serialize(game); - } - } - - if(settings["icarus/UseHeuristics"].boolean()) { - Heuristics::WonderSwan game{buffer, location}; - if(auto manifest = game.manifest()) return manifest; - } - - return {}; -} - -auto Icarus::wonderSwanImport(vector& buffer, string location) -> string { - auto name = Location::prefix(location); - auto source = Location::path(location); - string target{settings["Library/Location"].text(), "WonderSwan/", name, ".ws/"}; - - auto manifest = wonderSwanManifest(buffer, location); - if(!manifest) return failure("failed to parse ROM image"); - - if(!create(target)) return failure("library path unwritable"); - if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) { - copy({source, name, ".sav"}, {target, "save.ram"}); - } - - if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); - write({target, "program.rom"}, buffer); - return success(target); -} diff --git a/icarus/data/icarus.Manifest b/icarus/data/icarus.Manifest deleted file mode 100644 index 3f6f1d8d..00000000 --- a/icarus/data/icarus.Manifest +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - false - - - diff --git a/icarus/data/icarus.desktop b/icarus/data/icarus.desktop deleted file mode 100644 index 71f0fe03..00000000 --- a/icarus/data/icarus.desktop +++ /dev/null @@ -1,8 +0,0 @@ -[Desktop Entry] -Name=icarus -Comment=Emulator -Exec=icarus -Icon=icarus -Terminal=false -Type=Application -Categories=Game;Emulator; diff --git a/icarus/data/icarus.ico b/icarus/data/icarus.ico deleted file mode 100644 index b5859acfc876a4480ca115786c8e2a2431b4f4dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33644 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%0AB$7m2UVB(Ej6T0uqnn^GSq$untg< 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 - - - - CFBundleIdentifier - org.byuu.icarus - CFBundleDisplayName - icarus - CFBundleExecutable - icarus - CFBundleIconFile - icarus.icns - NSHighResolutionCapable - - NSSupportsAutomaticGraphicsSwitching - - - diff --git a/icarus/data/icarus.png b/icarus/data/icarus.png deleted file mode 100644 index b32718b15901dc807ac1aba63a70455eb2bae8cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14477 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

UOd@u(&^ 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 diff --git a/icarus/data/icarus.rc b/icarus/data/icarus.rc deleted file mode 100644 index 3f104857..00000000 --- a/icarus/data/icarus.rc +++ /dev/null @@ -1,2 +0,0 @@ -1 24 "icarus.Manifest" -2 ICON DISCARDABLE "icarus.ico" diff --git a/icarus/data/icarus.svg b/icarus/data/icarus.svg deleted file mode 100644 index aaa7c846..00000000 --- a/icarus/data/icarus.svg +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/icarus/heuristics/colecovision.cpp b/icarus/heuristics/colecovision.cpp deleted file mode 100644 index 89baa3aa..00000000 --- a/icarus/heuristics/colecovision.cpp +++ /dev/null @@ -1,32 +0,0 @@ -namespace Heuristics { - -struct ColecoVision { - ColecoVision(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -ColecoVision::ColecoVision(vector& data, string location) : data(data), location(location) { -} - -ColecoVision::operator bool() const { - return (bool)data; -} - -auto ColecoVision::manifest() const -> string { - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - output.append(Memory{}.type("RAM").size(0x8000).content("Save").text()); - return output; -} - -} diff --git a/icarus/heuristics/famicom.cpp b/icarus/heuristics/famicom.cpp deleted file mode 100644 index 903605bb..00000000 --- a/icarus/heuristics/famicom.cpp +++ /dev/null @@ -1,173 +0,0 @@ -namespace Heuristics { - -struct Famicom { - Famicom(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -Famicom::Famicom(vector& data, string location) : data(data), location(location) { -} - -Famicom::operator bool() const { - if(data.size() < 16) return false; - if(data[0] != 'N') return false; - if(data[1] != 'E') return false; - if(data[2] != 'S') return false; - if(data[3] != 26) return false; - return true; -} - -auto Famicom::manifest() const -> string { - if(!operator bool()) return {}; - - uint mapper = ((data[7] >> 4) << 4) | (data[6] >> 4); - uint mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01); - uint prgrom = data[4] * 0x4000; - uint chrrom = data[5] * 0x2000; - uint prgram = 0u; - uint chrram = chrrom == 0u ? 8192u : 0u; - - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256({&data[16], data.size() - 16}).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - - switch(mapper) { - default: - output.append(" board: NES-NROM-256\n"); - output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); - break; - - case 1: - output.append(" board: NES-SXROM\n"); - output.append(" chip type=MMC1B2\n"); - prgram = 8192; - break; - - case 2: - output.append(" board: NES-UOROM\n"); - output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); - break; - - case 3: - output.append(" board: NES-CNROM\n"); - output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); - break; - - case 4: - //MMC3 - output.append(" board: NES-TLROM\n"); - output.append(" chip type=MMC3B\n"); - prgram = 8192; - //MMC6 - //output.append(" board: NES-HKROM\n"); - //output.append(" chip type=MMC6\n"); - //prgram = 1024; - break; - - case 5: - output.append(" board: NES-ELROM\n"); - output.append(" chip type=MMC5\n"); - prgram = 65536; - break; - - case 7: - output.append(" board: NES-AOROM\n"); - break; - - case 9: - output.append(" board: NES-PNROM\n"); - output.append(" chip type=MMC2\n"); - prgram = 8192; - break; - - case 10: - output.append(" board: NES-FKROM\n"); - output.append(" chip type=MMC4\n"); - prgram = 8192; - break; - - case 16: - output.append(" board: BANDAI-FCG\n"); - output.append(" chip type=LZ93D50\n"); - break; - - case 21: - case 23: - case 25: - //VRC4 - output.append(" board: KONAMI-VRC-4\n"); - output.append(" chip type=VRC4\n"); - output.append(" pinout a0=1 a1=0\n"); - prgram = 8192; - break; - - case 22: - //VRC2 - output.append(" board: KONAMI-VRC-2\n"); - output.append(" chip type=VRC2\n"); - output.append(" pinout a0=0 a1=1\n"); - break; - - case 24: - output.append(" board: KONAMI-VRC-6\n"); - output.append(" chip type=VRC6\n"); - break; - - case 26: - output.append(" board: KONAMI-VRC-6\n"); - output.append(" chip type=VRC6\n"); - prgram = 8192; - break; - - case 34: - output.append(" board: NES-BNROM\n"); - output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); - break; - - case 66: - output.append(" board: NES-GNROM\n"); - output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); - break; - - case 69: - output.append(" board: SUNSOFT-5B\n"); - output.append(" chip type=5B\n"); - prgram = 8192; - break; - - case 73: - output.append(" board: KONAMI-VRC-3\n"); - output.append(" chip type=VRC3\n"); - output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); - prgram = 8192; - break; - - case 75: - output.append(" board: KONAMI-VRC-1\n"); - output.append(" chip type=VRC1\n"); - break; - - case 85: - output.append(" board: KONAMI-VRC-7\n"); - output.append(" chip type=VRC7\n"); - prgram = 8192; - break; - } - - if(prgrom) output.append(Memory{}.type("ROM").size(prgrom).content("Program").text()); - if(prgram) output.append(Memory{}.type("RAM").size(prgram).content("Save").text()); - - if(chrrom) output.append(Memory{}.type("ROM").size(chrrom).content("Character").text()); - if(chrram) output.append(Memory{}.type("RAM").size(chrram).content("Character").isVolatile().text()); - - return output; -} - -} diff --git a/icarus/heuristics/game-boy-advance.cpp b/icarus/heuristics/game-boy-advance.cpp deleted file mode 100644 index 1353deb0..00000000 --- a/icarus/heuristics/game-boy-advance.cpp +++ /dev/null @@ -1,67 +0,0 @@ -namespace Heuristics { - -struct GameBoyAdvance { - GameBoyAdvance(vector& buffer, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -GameBoyAdvance::GameBoyAdvance(vector& data, string location) : data(data), location(location) { -} - -GameBoyAdvance::operator bool() const { - return (bool)data; -} - -auto GameBoyAdvance::manifest() const -> string { - if(!operator bool()) return {}; - - vector identifiers = { - "SRAM_V", - "SRAM_F_V", - "EEPROM_V", - "FLASH_V", - "FLASH512_V", - "FLASH1M_V", - }; - - vector list; - for(auto& identifier : identifiers) { - for(int n : range(data.size() - 16)) { - if(!memory::compare(&data[n], identifier.data(), identifier.size())) { - auto p = (const char*)&data[n + identifier.size()]; - if(p[0] >= '0' && p[0] <= '9' - && p[1] >= '0' && p[1] <= '9' - && p[2] >= '0' && p[2] <= '9' - ) { - char text[16]; - memory::copy(text, &data[n], identifier.size() + 3); - text[identifier.size() + 3] = 0; - if(!list.find(text)) list.append(text); - } - } - } - } - - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - if(!list); - else if(list.left().beginsWith("SRAM_V" )) output.append(Memory{}.type("RAM" ).size( 0x8000).content("Save").text()); - else if(list.left().beginsWith("SRAM_F_V" )) output.append(Memory{}.type("RAM" ).size( 0x8000).content("Save").text()); - else if(list.left().beginsWith("EEPROM_V" )) output.append(Memory{}.type("EEPROM").size( 0x0).content("Save").text()); - else if(list.left().beginsWith("FLASH_V" )) output.append(Memory{}.type("Flash" ).size(0x10000).content("Save").manufacturer("Macronix").text()); - else if(list.left().beginsWith("FLASH512_V")) output.append(Memory{}.type("Flash" ).size(0x10000).content("Save").manufacturer("Macronix").text()); - else if(list.left().beginsWith("FLASH1M_V" )) output.append(Memory{}.type("Flash" ).size(0x20000).content("Save").manufacturer("Macronix").text()); - return output; -} - -} diff --git a/icarus/heuristics/game-gear.cpp b/icarus/heuristics/game-gear.cpp deleted file mode 100644 index 5897c90f..00000000 --- a/icarus/heuristics/game-gear.cpp +++ /dev/null @@ -1,32 +0,0 @@ -namespace Heuristics { - -struct GameGear { - GameGear(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -GameGear::GameGear(vector& data, string location) : data(data), location(location) { -} - -GameGear::operator bool() const { - return (bool)data; -} - -auto GameGear::manifest() const -> string { - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - output.append(Memory{}.type("RAM").size(0x8000).content("Save").text()); - return output; -} - -} diff --git a/icarus/heuristics/master-system.cpp b/icarus/heuristics/master-system.cpp deleted file mode 100644 index 450ebaac..00000000 --- a/icarus/heuristics/master-system.cpp +++ /dev/null @@ -1,32 +0,0 @@ -namespace Heuristics { - -struct MasterSystem { - MasterSystem(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -MasterSystem::MasterSystem(vector& data, string location) : data(data), location(location) { -} - -MasterSystem::operator bool() const { - return (bool)data; -} - -auto MasterSystem::manifest() const -> string { - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - output.append(Memory{}.type("RAM").size(0x8000).content("Save").text()); - return output; -} - -} diff --git a/icarus/heuristics/mega-drive.cpp b/icarus/heuristics/mega-drive.cpp deleted file mode 100644 index 24d4d9e8..00000000 --- a/icarus/heuristics/mega-drive.cpp +++ /dev/null @@ -1,111 +0,0 @@ -namespace Heuristics { - -struct MegaDrive { - MegaDrive(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -MegaDrive::MegaDrive(vector& data, string location) : data(data), location(location) { -} - -MegaDrive::operator bool() const { - return data.size() >= 0x200; -} - -auto MegaDrive::manifest() const -> string { - if(!operator bool()) return {}; - - string ramMode = "none"; - - uint32_t ramFrom = 0; - ramFrom |= data[0x01b4] << 24; - ramFrom |= data[0x01b5] << 16; - ramFrom |= data[0x01b6] << 8; - ramFrom |= data[0x01b7] << 0; - - uint32_t ramTo = 0; - ramTo |= data[0x01b8] << 24; - ramTo |= data[0x01b9] << 16; - ramTo |= data[0x01ba] << 8; - ramTo |= data[0x01bb] << 0; - - if(!(ramFrom & 1) && !(ramTo & 1)) ramMode = "hi"; - if( (ramFrom & 1) && (ramTo & 1)) ramMode = "lo"; - if(!(ramFrom & 1) && (ramTo & 1)) ramMode = "word"; - if(data[0x01b0] != 'R' || data[0x01b1] != 'A') ramMode = "none"; - - uint32_t ramSize = ramTo - ramFrom + 1; - if(ramMode == "hi") ramSize = (ramTo >> 1) - (ramFrom >> 1) + 1; - if(ramMode == "lo") ramSize = (ramTo >> 1) - (ramFrom >> 1) + 1; - if(ramMode == "word") ramSize = ramTo - ramFrom + 1; - if(ramMode != "none") ramSize = bit::round(min(0x20000, ramSize)); - if(ramMode == "none") ramSize = 0; - - vector regions; - string region = slice((const char*)&data[0x1f0], 0, 16).trimRight(" "); - if(!regions) { - if(region == "JAPAN" ) regions.append("NTSC-J"); - if(region == "EUROPE") regions.append("PAL"); - } - if(!regions) { - if(region.find("J")) regions.append("NTSC-J"); - if(region.find("U")) regions.append("NTSC-U"); - if(region.find("E")) regions.append("PAL"); - if(region.find("W")) regions.append("NTSC-J", "NTSC-U", "PAL"); - } - if(!regions && region.size() == 1) { - uint8_t field = region.hex(); - if(field & 0x01) regions.append("NTSC-J"); - if(field & 0x04) regions.append("NTSC-U"); - if(field & 0x08) regions.append("PAL"); - } - if(!regions) { - regions.append("NTSC-J"); - } - - string domesticName; - domesticName.resize(48); - memory::copy(domesticName.get(), &data[0x0120], domesticName.size()); - for(auto& c : domesticName) if(c < 0x20 || c > 0x7e) c = ' '; - while(domesticName.find(" ")) domesticName.replace(" ", " "); - domesticName.strip(); - - string internationalName; - internationalName.resize(48); - memory::copy(internationalName.get(), &data[0x0150], internationalName.size()); - for(auto& c : internationalName) if(c < 0x20 || c > 0x7e) c = ' '; - while(internationalName.find(" ")) internationalName.replace(" ", " "); - internationalName.strip(); - - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" title: ", domesticName, "\n"); - output.append(" region: ", regions.left(), "\n"); - output.append(" board\n"); - if(domesticName == "Game Genie") { - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - output.append(Slot{}.type("MegaDrive").text()); - } else if(domesticName == "SONIC & KNUCKLES") { - output.append(Memory{}.type("ROM").size(0x200000).content("Program").text()); - output.append(Memory{}.type("ROM").size( 0x40000).content("Patch").text()); - output.append(Slot{}.type("MegaDrive").text()); - } else { - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - } - if(ramSize && ramMode != "none") { - output.append(Memory{}.type("RAM").size(ramSize).content("Save").text()); - output.append(" mode: ", ramMode, "\n"); - output.append(" offset: 0x", hex(ramFrom), "\n"); - } - return output; -} - -} diff --git a/icarus/heuristics/msx.cpp b/icarus/heuristics/msx.cpp deleted file mode 100644 index 6470cef3..00000000 --- a/icarus/heuristics/msx.cpp +++ /dev/null @@ -1,31 +0,0 @@ -namespace Heuristics { - -struct MSX { - MSX(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -MSX::MSX(vector& data, string location) : data(data), location(location) { -} - -MSX::operator bool() const { - return (bool)data; -} - -auto MSX::manifest() const -> string { - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - return output; -} - -} diff --git a/icarus/heuristics/neo-geo-pocket-color.cpp b/icarus/heuristics/neo-geo-pocket-color.cpp deleted file mode 100644 index 6390f166..00000000 --- a/icarus/heuristics/neo-geo-pocket-color.cpp +++ /dev/null @@ -1,55 +0,0 @@ -namespace Heuristics { - -struct NeoGeoPocketColor { - NeoGeoPocketColor(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - auto title() const -> string; - -private: - vector& data; - string location; -}; - -NeoGeoPocketColor::NeoGeoPocketColor(vector& data, string location) : data(data), location(location) { -} - -NeoGeoPocketColor::operator bool() const { - switch(data.size()) { - case 0x080000: return true; // 4mbit - case 0x100000: return true; // 8mbit - case 0x200000: return true; //16mbit - case 0x280000: return true; //20mbit - case 0x300000: return true; //24mbit - case 0x400000: return true; //32mbit - } - return false; -} - -auto NeoGeoPocketColor::manifest() const -> string { - if(!operator bool()) return {}; - - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" title: ", title(), "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - return output; -} - -auto NeoGeoPocketColor::title() const -> string { - if(!operator bool()) return {}; - - string title; - title.size(12); - for(uint index : range(12)) { - char letter = data[0x24 + index]; - if(letter >= 0x20 && letter <= 0x7e) title.get()[index] = letter; - } - return title.strip(); -} - -} diff --git a/icarus/heuristics/neo-geo-pocket.cpp b/icarus/heuristics/neo-geo-pocket.cpp deleted file mode 100644 index 46b014e9..00000000 --- a/icarus/heuristics/neo-geo-pocket.cpp +++ /dev/null @@ -1,55 +0,0 @@ -namespace Heuristics { - -struct NeoGeoPocket { - NeoGeoPocket(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - auto title() const -> string; - -private: - vector& data; - string location; -}; - -NeoGeoPocket::NeoGeoPocket(vector& data, string location) : data(data), location(location) { -} - -NeoGeoPocket::operator bool() const { - switch(data.size()) { - case 0x080000: return true; // 4mbit - case 0x100000: return true; // 8mbit - case 0x200000: return true; //16mbit - case 0x280000: return true; //20mbit - case 0x300000: return true; //24mbit - case 0x400000: return true; //32mbit - } - return false; -} - -auto NeoGeoPocket::manifest() const -> string { - if(!operator bool()) return {}; - - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" title: ", title(), "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - return output; -} - -auto NeoGeoPocket::title() const -> string { - if(!operator bool()) return {}; - - string title; - title.size(12); - for(uint index : range(12)) { - char letter = data[0x24 + index]; - if(letter >= 0x20 && letter <= 0x7e) title.get()[index] = letter; - } - return title.strip(); -} - -} diff --git a/icarus/heuristics/pc-engine.cpp b/icarus/heuristics/pc-engine.cpp deleted file mode 100644 index 2106bc50..00000000 --- a/icarus/heuristics/pc-engine.cpp +++ /dev/null @@ -1,36 +0,0 @@ -namespace Heuristics { - -struct PCEngine { - PCEngine(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -PCEngine::PCEngine(vector& data, string location) : data(data), location(location) { - if((data.size() & 0x1fff) == 512) { - //remove header if present - memory::move(&data[0], &data[512], data.size() - 512); - data.resize(data.size() - 512); - } -} - -PCEngine::operator bool() const { - return (bool)data; -} - -auto PCEngine::manifest() const -> string { - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - return output; -} - -} diff --git a/icarus/heuristics/sc-3000.cpp b/icarus/heuristics/sc-3000.cpp deleted file mode 100644 index 6f24f26c..00000000 --- a/icarus/heuristics/sc-3000.cpp +++ /dev/null @@ -1,32 +0,0 @@ -namespace Heuristics { - -struct SC3000 { - SC3000(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -SC3000::SC3000(vector& data, string location) : data(data), location(location) { -} - -SC3000::operator bool() const { - return (bool)data; -} - -auto SC3000::manifest() const -> string { - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - output.append(Memory{}.type("RAM").size(0x8000).content("Save").text()); - return output; -} - -} diff --git a/icarus/heuristics/sg-1000.cpp b/icarus/heuristics/sg-1000.cpp deleted file mode 100644 index 1a5f24ed..00000000 --- a/icarus/heuristics/sg-1000.cpp +++ /dev/null @@ -1,32 +0,0 @@ -namespace Heuristics { - -struct SG1000 { - SG1000(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -SG1000::SG1000(vector& data, string location) : data(data), location(location) { -} - -SG1000::operator bool() const { - return (bool)data; -} - -auto SG1000::manifest() const -> string { - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - output.append(Memory{}.type("RAM").size(0x8000).content("Save").text()); - return output; -} - -} diff --git a/icarus/heuristics/supergrafx.cpp b/icarus/heuristics/supergrafx.cpp deleted file mode 100644 index 9ceab33c..00000000 --- a/icarus/heuristics/supergrafx.cpp +++ /dev/null @@ -1,31 +0,0 @@ -namespace Heuristics { - -struct SuperGrafx { - SuperGrafx(vector& data, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -SuperGrafx::operator bool() const { - return (bool)data; -} - -SuperGrafx::SuperGrafx(vector& data, string location) : data(data), location(location) { -} - -auto SuperGrafx::manifest() const -> string { - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); - return output; -} - -} diff --git a/icarus/heuristics/wonderswan.cpp b/icarus/heuristics/wonderswan.cpp deleted file mode 100644 index fd14007e..00000000 --- a/icarus/heuristics/wonderswan.cpp +++ /dev/null @@ -1,58 +0,0 @@ -namespace Heuristics { - -struct WonderSwan { - WonderSwan(vector& buffer, string location); - explicit operator bool() const; - auto manifest() const -> string; - -private: - vector& data; - string location; -}; - -WonderSwan::WonderSwan(vector& data, string location) : data(data), location(location) { -} - -WonderSwan::operator bool() const { - return data.size() >= 0x10000; -} - -auto WonderSwan::manifest() const -> string { - if(!operator bool()) return {}; - - auto metadata = &data[data.size() - 16]; - - bool color = metadata[7]; - - string ramType; - uint ramSize = 0; - switch(metadata[11]) { - case 0x01: ramType = "RAM"; ramSize = 8 * 1024; break; - case 0x02: ramType = "RAM"; ramSize = 32 * 1024; break; - case 0x03: ramType = "RAM"; ramSize = 128 * 1024; break; - case 0x04: ramType = "RAM"; ramSize = 256 * 1024; break; - case 0x05: ramType = "RAM"; ramSize = 512 * 1024; break; - case 0x10: ramType = "EEPROM"; ramSize = 128; break; - case 0x20: ramType = "EEPROM"; ramSize = 2048; break; - case 0x50: ramType = "EEPROM"; ramSize = 1024; break; - } - - bool orientation = metadata[12] & 1; //0 = horizontal; 1 = vertical - bool hasRTC = metadata[13] & 1; - - string output; - output.append("game\n"); - output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" orientation: ", !orientation ? "horizontal" : "vertical", "\n"); - output.append(" board\n"); - output.append(Memory{}.type("ROM").size(data.size()).content("Program").text()); -if(ramType && ramSize) - output.append(Memory{}.type(ramType).size(ramSize).content("Save").text()); -if(hasRTC) - output.append(Memory{}.type("RTC").size(0x10).content("Time").text()); - return output; -} - -} diff --git a/icarus/icarus.cpp b/icarus/icarus.cpp deleted file mode 100644 index b7548bfc..00000000 --- a/icarus/icarus.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include -using namespace nall; - -#include -using namespace hiro; - -auto locate(string name) -> string { - string location = {Path::program(), name}; - if(inode::exists(location)) return location; - - location = {Path::userData(), "bsnes/"}; - if(inode::exists(location)) return location; - - directory::create({Path::userSettings(), "bsnes/"}); - return {Path::userSettings(), "bsnes/", name}; -} - -#include "settings.cpp" -Settings settings; - -#include "heuristics/heuristics.hpp" -#include "heuristics/heuristics.cpp" -#include "heuristics/famicom.cpp" -#include "heuristics/super-famicom.cpp" -#include "heuristics/sg-1000.cpp" -#include "heuristics/sc-3000.cpp" -#include "heuristics/master-system.cpp" -#include "heuristics/mega-drive.cpp" -#include "heuristics/pc-engine.cpp" -#include "heuristics/supergrafx.cpp" -#include "heuristics/colecovision.cpp" -#include "heuristics/msx.cpp" -#include "heuristics/game-boy.cpp" -#include "heuristics/game-boy-advance.cpp" -#include "heuristics/game-gear.cpp" -#include "heuristics/wonderswan.cpp" -#include "heuristics/neo-geo-pocket.cpp" -#include "heuristics/neo-geo-pocket-color.cpp" -#include "heuristics/bs-memory.cpp" -#include "heuristics/sufami-turbo.cpp" - -#include "core/core.hpp" -#include "core/core.cpp" -#include "core/famicom.cpp" -#include "core/super-famicom.cpp" -#include "core/sg-1000.cpp" -#include "core/sc-3000.cpp" -#include "core/master-system.cpp" -#include "core/mega-drive.cpp" -#include "core/pc-engine.cpp" -#include "core/supergrafx.cpp" -#include "core/colecovision.cpp" -#include "core/msx.cpp" -#include "core/game-boy.cpp" -#include "core/game-boy-color.cpp" -#include "core/game-boy-advance.cpp" -#include "core/game-gear.cpp" -#include "core/wonderswan.cpp" -#include "core/wonderswan-color.cpp" -#include "core/neo-geo-pocket.cpp" -#include "core/neo-geo-pocket-color.cpp" -#include "core/pocket-challenge-v2.cpp" -#include "core/bs-memory.cpp" -#include "core/sufami-turbo.cpp" - -#if !defined(ICARUS_LIBRARY) - -Icarus icarus; -#include "ui/ui.hpp" -#include "ui/scan-dialog.cpp" -#include "ui/settings-dialog.cpp" -#include "ui/import-dialog.cpp" -#include "ui/error-dialog.cpp" - -auto hiro::initialize() -> void { - Application::setName("icarus"); -} - -#include -auto nall::main(Arguments arguments) -> void { - if(arguments.size() == 1 && arguments[0] == "--name") { - return print("icarus"); - } - - if(arguments.size() == 2 && arguments[0] == "--manifest" && directory::exists(arguments[1])) { - return print(icarus.manifest(arguments[1])); - } - - if(arguments.size() == 2 && arguments[0] == "--import" && file::exists(arguments[1])) { - if(string target = icarus.import(arguments[1])) { - return print(target, "\n"); - } - return; - } - - if(arguments.size() == 1 && arguments[0] == "--import") { - if(string source = BrowserDialog() - .setTitle("Load ROM File") - .setPath(settings["icarus/Path"].text()) - .setFilters("ROM Files|" - "*.fc:*.nes:" - "*.sfc:*.smc:" - "*.sg1000:*.sg:" - "*.sc3000:*.sc:" - "*.ms:*.sms:" - "*.md:*.smd:*.gen:" - "*.pce:" - "*.sgx:" - "*.cv:*.col:" - "*.msx:" - "*.gb:" - "*.gbc:" - "*.gba:" - "*.gg:" - "*.ws:" - "*.wsc:" - "*.pc2:" - "*.ngp:" - "*.ngpc:*.ngc:" - "*.bs:" - "*.st:" - "*.zip" - ).openFile()) { - if(string target = icarus.import(source)) { - settings["icarus/Path"].setValue(Location::path(source)); - return print(target, "\n"); - } - } - return; - } - - new ScanDialog; - new SettingsDialog; - new ImportDialog; - new ErrorDialog; - - #if defined(PLATFORM_MACOS) - Application::Cocoa::onAbout([&] { - MessageDialog().setTitle("About icarus").setText({ - "icarus\n\n" - "Author: byuu\n" - "License: GPLv3\n" - "Website: https://byuu.org/\n" - }).information(); - }); - Application::Cocoa::onPreferences([&] { - scanDialog->settingsButton.doActivate(); - }); - Application::Cocoa::onQuit([&] { - Application::quit(); - }); - #endif - - scanDialog->show(); - Application::run(); - settings.save(); -} - -#endif diff --git a/icarus/settings.cpp b/icarus/settings.cpp deleted file mode 100644 index 462d9cb2..00000000 --- a/icarus/settings.cpp +++ /dev/null @@ -1,24 +0,0 @@ -struct Settings : Markup::Node { - Settings(); - auto save() -> void; -}; - -Settings::Settings() { - Markup::Node::operator=(BML::unserialize(string::read(locate("settings.bml")))); - - auto set = [&](const string& name, const string& value) { - //create node and set to default value only if it does not already exist - if(!operator[](name)) operator()(name).setValue(value); - }; - - set("Library/Location", {Path::user(), "Emulation/"}); - - set("icarus/Path", Path::user()); - set("icarus/CreateManifests", false); - set("icarus/UseDatabase", true); - set("icarus/UseHeuristics", true); -} - -auto Settings::save() -> void { - file::write(locate("settings.bml"), BML::serialize(*this)); -} diff --git a/icarus/ui/error-dialog.cpp b/icarus/ui/error-dialog.cpp deleted file mode 100644 index 847efb08..00000000 --- a/icarus/ui/error-dialog.cpp +++ /dev/null @@ -1,16 +0,0 @@ -ErrorDialog::ErrorDialog() { - errorDialog = this; - - onClose([&] { setVisible(false); scanDialog->show(); }); - layout.setPadding(5); - errorLog.setEditable(false); - closeButton.setText("Close").onActivate([&] { doClose(); }); - - setSize({800, 360}); - setCentered(); -} - -auto ErrorDialog::show(const string& text) -> void { - errorLog.setText(text); - setVisible(); -} diff --git a/icarus/ui/import-dialog.cpp b/icarus/ui/import-dialog.cpp deleted file mode 100644 index 959e773e..00000000 --- a/icarus/ui/import-dialog.cpp +++ /dev/null @@ -1,52 +0,0 @@ -ImportDialog::ImportDialog() { - importDialog = this; - - onClose([&] { - stopButton.setEnabled(false).setText("Stopping ..."); - abort = true; - }); - layout.setPadding(5); - stopButton.setText("Stop").onActivate([&] { doClose(); }); - - setTitle("icarus - Importing ..."); - setSize({480, layout.minimumSize().height()}); - setCentered(); -} - -auto ImportDialog::run(vector locations) -> void { - abort = false; - errors.reset(); - unsigned position = 0; - - setVisible(true); - for(auto& location : locations) { - auto name = Location::base(location); - - if(abort) { - errors.append(string{"[", name, "] aborted"}); - continue; - } - - statusLabel.setText(name); - double progress = 100.0 * (double)position++ / (double)locations.size() + 0.5; - progressBar.setPosition((unsigned)progress); - Application::processEvents(); - - if(!icarus.import(location)) { - errors.append(string{"[", name, "] ", icarus.error()}); - } - } - setVisible(false); - - if(errors) { - string message{"Import completed, but with ", errors.size(), " error", errors.size() ? "s" : "", ". View log?"}; - if(MessageDialog().setTitle("icarus").setText(message).question() == "Yes") { - errorDialog->show(errors.merge("\n")); - } else { - scanDialog->show(); - } - } else { - MessageDialog().setTitle("icarus").setText("Import completed successfully.").information(); - scanDialog->show(); - } -} diff --git a/icarus/ui/scan-dialog.cpp b/icarus/ui/scan-dialog.cpp deleted file mode 100644 index fb80bdac..00000000 --- a/icarus/ui/scan-dialog.cpp +++ /dev/null @@ -1,147 +0,0 @@ -ScanDialog::ScanDialog() { - scanDialog = this; - - onClose(&Application::quit); - layout.setPadding(5); - pathEdit.onActivate([&] { refresh(); }); - refreshButton.setIcon(Icon::Action::Refresh).setBordered(false).onActivate([&] { - pathEdit.setText(settings["icarus/Path"].text()); - refresh(); - }); - homeButton.setIcon(Icon::Go::Home).setBordered(false).onActivate([&] { - pathEdit.setText(Path::user()); - refresh(); - }); - upButton.setIcon(Icon::Go::Up).setBordered(false).onActivate([&] { - pathEdit.setText(Location::dir(settings["icarus/Path"].text())); - refresh(); - }); - scanList.onActivate([&] { activate(); }); - selectAllButton.setText("Select All").onActivate([&] { - for(auto& item : scanList.items()) { - if(item.checkable()) item.setChecked(true); - } - }); - unselectAllButton.setText("Unselect All").onActivate([&] { - for(auto& item : scanList.items()) { - if(item.checkable()) item.setChecked(false); - } - }); - settingsButton.setText("Settings ...").onActivate([&] { - settingsDialog->setCentered(*this); - settingsDialog->setVisible(); - settingsDialog->setFocused(); - }); - importButton.setText("Import ...").onActivate([&] { import(); }); - - setTitle("icarus"); - setSize({800, 480}); - setCentered(); -} - -auto ScanDialog::show() -> void { - setVisible(); - pathEdit.setText(settings["icarus/Path"].text()); - refresh(); -} - -auto ScanDialog::refresh() -> void { - scanList.reset(); - - auto pathname = pathEdit.text().transform("\\", "/"); - if((pathname || Path::root() == "/") && !pathname.endsWith("/")) pathname.append("/"); - - settings["icarus/Path"].setValue(pathname); - pathEdit.setText(pathname); - auto contents = directory::icontents(pathname); - - for(auto& name : contents) { - if(!name.endsWith("/")) continue; - if(gamePakType(Location::suffix(name))) continue; - scanList.append(ListViewItem().setIcon(Icon::Emblem::Folder).setText(name.trimRight("/"))); - } - - for(auto& name : contents) { - if(name.endsWith("/")) continue; - if(!gameRomType(Location::suffix(name).downcase())) continue; - scanList.append(ListViewItem().setCheckable().setIcon(Icon::Emblem::File).setText(name)); - } - - Application::processEvents(); - scanList.setFocused(); -} - -auto ScanDialog::activate() -> void { - if(auto item = scanList.selected()) { - string location{settings["icarus/Path"].text(), item.text()}; - if(!gamePakType(Location::suffix(location))) { - pathEdit.setText(location); - refresh(); - } - } -} - -auto ScanDialog::import() -> void { - vector filenames; - for(auto& item : scanList.items()) { - if(item.checked()) { - filenames.append(string{settings["icarus/Path"].text(), item.text()}); - } - } - - if(!filenames) { - MessageDialog().setParent(*this).setText("Nothing selected to import.").error(); - return; - } - - setVisible(false); - importDialog->run(filenames); -} - -auto ScanDialog::gamePakType(const string& type) -> bool { - return type == ".sys" - || type == ".fc" - || type == ".sfc" - || type == ".sg1000" - || type == ".sc3000" - || type == ".ms" - || type == ".md" - || type == ".pce" - || type == ".sgx" - || type == ".msx" - || type == ".gb" - || type == ".gbc" - || type == ".gba" - || type == ".gg" - || type == ".ws" - || type == ".wsc" - || type == ".pc2" - || type == ".ngp" - || type == ".ngpc" - || type == ".bs" - || type == ".st"; -} - -auto ScanDialog::gameRomType(const string& type) -> bool { - return type == ".zip" - || type == ".fc" || type == ".nes" - || type == ".sfc" || type == ".smc" - || type == ".sg1000" || type == ".sg" - || type == ".sc3000" || type == ".sc" - || type == ".ms" || type == ".sms" - || type == ".md" || type == ".smd" || type == ".gen" - || type == ".pce" - || type == ".sgx" - || type == ".msx" - || type == ".gb" - || type == ".gbc" - || type == ".gba" - || type == ".gg" - || type == ".ws" - || type == ".wsc" - || type == ".pc2" - || type == ".ngp" - || type == ".ngpc" || type == ".ngc" - || type == ".bs" - || type == ".st"; -} diff --git a/icarus/ui/settings-dialog.cpp b/icarus/ui/settings-dialog.cpp deleted file mode 100644 index 5dfabaef..00000000 --- a/icarus/ui/settings-dialog.cpp +++ /dev/null @@ -1,24 +0,0 @@ -SettingsDialog::SettingsDialog() { - settingsDialog = this; - - layout.setPadding(5); - locationLabel.setText("Library Location:"); - locationEdit.setEditable(false).setText(settings["Library/Location"].text()); - changeLocationButton.setText("Change ...").onActivate([&] { - if(auto location = BrowserDialog().setParent(*this).setTitle("Select Library Location").selectFolder()) { - settings["Library/Location"].setValue(location); - locationEdit.setText(location); - } - }); - createManifestsOption.setText("Create Manifests (not recommended; breaks backward-compatibility)") - .setChecked(settings["icarus/CreateManifests"].boolean()).onToggle([&] { - settings["icarus/CreateManifests"].setValue(createManifestsOption.checked()); - }); - useDatabaseOption.setText("Use Database (highly recommended; provides bit-perfect memory mapping)") - .setChecked(settings["icarus/UseDatabase"].boolean()).onToggle([&] { - settings["icarus/UseDatabase"].setValue(useDatabaseOption.checked()); - }); - - setTitle("Settings"); - setSize({480, layout.minimumSize().height()}); -} diff --git a/icarus/ui/ui.hpp b/icarus/ui/ui.hpp deleted file mode 100644 index 4cadd8b0..00000000 --- a/icarus/ui/ui.hpp +++ /dev/null @@ -1,68 +0,0 @@ -struct ScanDialog : Window { - ScanDialog(); - - auto show() -> void; - auto refresh() -> void; - auto activate() -> void; - auto import() -> void; - - auto gamePakType(const string& type) -> bool; - auto gameRomType(const string& type) -> bool; - - VerticalLayout layout{this}; - HorizontalLayout pathLayout{&layout, Size{~0, 0}}; - LineEdit pathEdit{&pathLayout, Size{~0, 0}, 0}; - Button refreshButton{&pathLayout, Size{0, 0}, 0}; - Button homeButton{&pathLayout, Size{0, 0}, 0}; - Button upButton{&pathLayout, Size{0, 0}, 0}; - ListView scanList{&layout, Size{~0, ~0}}; - HorizontalLayout controlLayout{&layout, Size{~0, 0}}; - Button selectAllButton{&controlLayout, Size{100, 0}}; - Button unselectAllButton{&controlLayout, Size{100, 0}}; - Widget controlSpacer{&controlLayout, Size{~0, 0}}; - Button settingsButton{&controlLayout, Size{100, 0}}; - Button importButton{&controlLayout, Size{100, 0}}; -}; - -struct SettingsDialog : Window { - SettingsDialog(); - - VerticalLayout layout{this}; - HorizontalLayout locationLayout{&layout, Size{~0, 0}}; - Label locationLabel{&locationLayout, Size{0, 0}}; - LineEdit locationEdit{&locationLayout, Size{~0, 0}}; - Button changeLocationButton{&locationLayout, Size{80, 0}}; - CheckLabel createManifestsOption{&layout, Size{~0, 0}, 2}; - CheckLabel useDatabaseOption{&layout, Size{~0, 0}}; -}; - -struct ImportDialog : Window { - ImportDialog(); - auto run(vector locations) -> void; - - bool abort; - vector errors; - - VerticalLayout layout{this}; - Label statusLabel{&layout, Size{~0, 0}}; - ProgressBar progressBar{&layout, Size{~0, 0}}; - HorizontalLayout controlLayout{&layout, Size{~0, 0}}; - Widget spacer{&controlLayout, Size{~0, 0}}; - Button stopButton{&controlLayout, Size{80, 0}}; -}; - -struct ErrorDialog : Window { - ErrorDialog(); - auto show(const string& text) -> void; - - VerticalLayout layout{this}; - TextEdit errorLog{&layout, Size{~0, ~0}}; - HorizontalLayout controlLayout{&layout, Size{~0, 0}}; - Widget spacer{&controlLayout, Size{~0, 0}}; - Button closeButton{&controlLayout, Size{80, 0}}; -}; - -ScanDialog* scanDialog = nullptr; -SettingsDialog* settingsDialog = nullptr; -ImportDialog* importDialog = nullptr; -ErrorDialog* errorDialog = nullptr;