mirror of https://github.com/bsnes-emu/bsnes.git
Remove icarus, merge heuristics into bsnes.
This commit is contained in:
parent
0e56b27228
commit
9e8913cea0
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include <nall/encode/bmp.hpp>
|
||||
#include <icarus/heuristics/heuristics.hpp>
|
||||
#include <icarus/heuristics/heuristics.cpp>
|
||||
#include <icarus/heuristics/super-famicom.cpp>
|
||||
#include <icarus/heuristics/game-boy.cpp>
|
||||
#include <icarus/heuristics/bs-memory.cpp>
|
||||
#include <icarus/heuristics/sufami-turbo.cpp>
|
||||
#include <heuristics/heuristics.hpp>
|
||||
#include <heuristics/heuristics.cpp>
|
||||
#include <heuristics/super-famicom.cpp>
|
||||
#include <heuristics/game-boy.cpp>
|
||||
#include <heuristics/bs-memory.cpp>
|
||||
#include <heuristics/sufami-turbo.cpp>
|
||||
|
||||
//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 {
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,38 +0,0 @@
|
|||
auto Icarus::bsMemoryManifest(string location) -> string {
|
||||
vector<uint8_t> 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<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::colecoVisionManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return colecoVisionManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::colecoVisionManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -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<string> {
|
||||
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<uint8_t>& 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());
|
||||
}
|
||||
}
|
|
@ -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<uint8_t>& 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<string>;
|
||||
auto success(string location) -> string;
|
||||
auto failure(string message) -> string;
|
||||
|
||||
auto manifest(string location) -> string;
|
||||
auto import(string location) -> string;
|
||||
|
||||
auto concatenate(vector<uint8_t>& output, string location) -> void;
|
||||
|
||||
//famicom.cpp
|
||||
auto famicomManifest(string location) -> string;
|
||||
auto famicomManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto famicomImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//super-famicom.cpp
|
||||
auto superFamicomManifest(string location) -> string;
|
||||
auto superFamicomManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto superFamicomImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//sg-1000.cpp
|
||||
auto sg1000Manifest(string location) -> string;
|
||||
auto sg1000Manifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto sg1000Import(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//sc-3000.cpp
|
||||
auto sc3000Manifest(string location) -> string;
|
||||
auto sc3000Manifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto sc3000Import(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//master-system.cpp
|
||||
auto masterSystemManifest(string location) -> string;
|
||||
auto masterSystemManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto masterSystemImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//mega-drive.cpp
|
||||
auto megaDriveManifest(string location) -> string;
|
||||
auto megaDriveManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto megaDriveImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//pc-engine.cpp
|
||||
auto pcEngineManifest(string location) -> string;
|
||||
auto pcEngineManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto pcEngineImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//supergrafx.cpp
|
||||
auto superGrafxManifest(string location) -> string;
|
||||
auto superGrafxManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto superGrafxImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//colecovision.cpp
|
||||
auto colecoVisionManifest(string location) -> string;
|
||||
auto colecoVisionManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto colecoVisionImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//msx.cpp
|
||||
auto msxManifest(string location) -> string;
|
||||
auto msxManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto msxImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//game-boy.cpp
|
||||
auto gameBoyManifest(string location) -> string;
|
||||
auto gameBoyManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto gameBoyImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//game-boy-color.cpp
|
||||
auto gameBoyColorManifest(string location) -> string;
|
||||
auto gameBoyColorManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto gameBoyColorImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//game-boy-advance.cpp
|
||||
auto gameBoyAdvanceManifest(string location) -> string;
|
||||
auto gameBoyAdvanceManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto gameBoyAdvanceImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//game-gear.cpp
|
||||
auto gameGearManifest(string location) -> string;
|
||||
auto gameGearManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto gameGearImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//wonderswan.cpp
|
||||
auto wonderSwanManifest(string location) -> string;
|
||||
auto wonderSwanManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto wonderSwanImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//wonderswan-color.cpp
|
||||
auto wonderSwanColorManifest(string location) -> string;
|
||||
auto wonderSwanColorManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto wonderSwanColorImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//pocket-challenge-v2.cpp
|
||||
auto pocketChallengeV2Manifest(string location) -> string;
|
||||
auto pocketChallengeV2Manifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto pocketChallengeV2Import(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//neo-geo-pocket.cpp
|
||||
auto neoGeoPocketManifest(string location) -> string;
|
||||
auto neoGeoPocketManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto neoGeoPocketImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//neo-geo-pocket-color.cpp
|
||||
auto neoGeoPocketColorManifest(string location) -> string;
|
||||
auto neoGeoPocketColorManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto neoGeoPocketColorImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//bs-memory.cpp
|
||||
auto bsMemoryManifest(string location) -> string;
|
||||
auto bsMemoryManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto bsMemoryImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//sufami-turbo.cpp
|
||||
auto sufamiTurboManifest(string location) -> string;
|
||||
auto sufamiTurboManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto sufamiTurboImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
private:
|
||||
string errorMessage;
|
||||
vector<string> 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;
|
||||
};
|
|
@ -1,58 +0,0 @@
|
|||
auto Icarus::famicomManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "ines.rom"});
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
concatenate(buffer, {location, "character.rom"});
|
||||
return famicomManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::famicomManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::gameBoyAdvanceManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return gameBoyAdvanceManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::gameBoyAdvanceManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
auto Icarus::gameBoyColorManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return gameBoyColorManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::gameBoyColorManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
auto Icarus::gameBoyManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return gameBoyManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::gameBoyManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::gameGearManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return gameGearManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::gameGearManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::masterSystemManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return masterSystemManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::masterSystemManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
auto Icarus::megaDriveManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
concatenate(buffer, {location, "patch.rom" });
|
||||
return megaDriveManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::megaDriveManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::msxManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return msxManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::msxManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::neoGeoPocketColorManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return neoGeoPocketColorManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::neoGeoPocketColorManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::neoGeoPocketManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return neoGeoPocketManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::neoGeoPocketManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::pcEngineManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return pcEngineManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::pcEngineManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::pocketChallengeV2Manifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return pocketChallengeV2Manifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::pocketChallengeV2Manifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::sc3000Manifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return sc3000Manifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::sc3000Manifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::sg1000Manifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return sg1000Manifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::sg1000Manifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::sufamiTurboManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return sufamiTurboManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::sufamiTurboManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
auto Icarus::superFamicomManifest(string location) -> string {
|
||||
vector<uint8_t> 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<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::superGrafxManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return superGrafxManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::superGrafxManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::wonderSwanColorManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return wonderSwanColorManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::wonderSwanColorManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
auto Icarus::wonderSwanManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return wonderSwanManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::wonderSwanManifest(vector<uint8_t>& 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<uint8_t>& 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);
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity type="win32" name="icarus" version="1.0.0.0" processorArchitecture="*"/>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
||||
<dpiAware>false</dpiAware>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
</assembly>
|
|
@ -1,8 +0,0 @@
|
|||
[Desktop Entry]
|
||||
Name=icarus
|
||||
Comment=Emulator
|
||||
Exec=icarus
|
||||
Icon=icarus
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Game;Emulator;
|
Binary file not shown.
Before Width: | Height: | Size: 33 KiB |
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.byuu.icarus</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>icarus</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>icarus</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>icarus.icns</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
Before Width: | Height: | Size: 14 KiB |
|
@ -1,2 +0,0 @@
|
|||
1 24 "icarus.Manifest"
|
||||
2 ICON DISCARDABLE "icarus.ico"
|
|
@ -1,80 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="256mm"
|
||||
height="256mm"
|
||||
viewBox="0 0 256 256"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
|
||||
sodipodi:docname="icarus.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.5"
|
||||
inkscape:cx="62.34093"
|
||||
inkscape:cy="560"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1028"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-41)">
|
||||
<circle
|
||||
id="path10"
|
||||
cx="128.0"
|
||||
cy="169.0"
|
||||
r="120.0"
|
||||
style="stroke-width:0.25;fill:#b8b8ff;fill-opacity:1" />
|
||||
<g
|
||||
aria-label="氷"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:260.07336426px;line-height:1.25;font-family:KaiTi;-inkscape-font-specification:KaiTi;letter-spacing:0px;word-spacing:0px;fill:#4050e0;fill-opacity:1;stroke:#4050e0;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="text818">
|
||||
<path
|
||||
style="fill:#4050e0;fill-opacity:1;stroke:#4050e0;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 130.80961,146.24049 q 5.07956,5.07956 14.22276,15.23868 14.22277,-13.20685 25.39779,-27.42962 12.19094,-15.23867 11.17503,-24.38187 0,-10.15912 10.15912,-4.06365 10.15911,6.09547 14.22276,12.19094 4.06364,5.07956 -2.03182,7.11138 -6.09547,1.01591 -22.35006,14.22276 -15.23867,12.19094 -32.50917,26.4137 13.20685,11.17503 23.36597,20.31823 11.17502,9.14321 24.38187,18.28641 14.22277,8.1273 27.42962,14.22276 14.22276,5.07956 21.33414,7.11139 7.11138,2.03182 -3.04773,5.07955 -9.14321,2.03183 -23.36597,3.04774 -14.22276,0 -21.33414,-2.03182 -6.09547,-3.04774 -11.17503,-8.1273 -4.06365,-5.07956 -24.38188,-27.42961 -19.30232,-23.36597 -31.49326,-39.62055 1.01591,41.65237 2.03182,64.00243 2.03183,22.35005 0,34.54099 -2.03182,12.19094 -8.12729,19.30232 -5.07956,7.11138 -8.12729,4.06365 -2.03182,-2.03183 -7.11138,-11.17503 -5.07956,-8.12729 -16.254587,-15.23867 -11.175027,-8.1273 1.015912,-5.07956 12.190935,2.03182 16.254585,2.03182 4.06365,-1.01591 6.09547,-7.11138 2.03182,-7.11138 2.03182,-46.73193 0,-40.63646 -1.01591,-77.20928 -1.01591,-37.58873 -6.09547,-45.716022 -5.07956,-9.143205 4.06365,-7.111382 10.15911,1.015912 16.25458,5.079558 7.11138,3.047735 4.06365,9.143205 -3.04774,5.079557 -4.06365,15.238673 -1.01591,10.159118 -1.01591,51.811488 z"
|
||||
id="path822" />
|
||||
<path
|
||||
style="fill:#4050e0;fill-opacity:1;stroke:#4050e0;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 88.141325,149.28823 q 5.079558,1.01591 14.222765,7.11138 9.1432,6.09547 4.06364,10.15911 -5.07955,4.06365 -12.190935,18.28641 -6.09547,14.22276 -14.222763,25.39779 -8.127292,10.15912 -19.30232,19.30232 -11.175027,8.12729 -21.334143,12.19094 -9.143204,3.04774 -16.254585,5.07956 -6.095469,1.01591 5.079558,-6.09547 11.175027,-7.11138 21.334143,-17.2705 11.175027,-10.15911 18.286408,-21.33414 8.127293,-12.19094 11.175028,-20.31823 3.047735,-9.14321 3.047735,-14.22276 1.015911,-5.07956 -3.047735,-5.07956 -4.063646,0 -15.238674,4.06364 -10.159116,4.06365 -15.238674,6.09547 -4.063646,2.03183 -13.20685,-3.04773 -8.127293,-6.09547 2.031823,-6.09547 11.175027,-1.01591 24.381878,-5.07956 14.222762,-5.07956 17.270497,-7.11138 4.063646,-3.04773 9.143204,-2.03182 z"
|
||||
id="path820" />
|
||||
<path
|
||||
style="fill:#4050e0;fill-opacity:1;stroke:#4050e0;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 63.759447,101.54038 q 9.143204,1.01591 18.286409,5.07956 9.143204,4.06365 11.175027,11.17503 2.031823,7.11138 -1.015912,11.17503 -3.047734,4.06364 -15.238673,-4.06365 -11.175028,-9.1432 -16.254586,-16.25459 -5.079557,-8.12729 3.047735,-7.11138 z"
|
||||
id="path815" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 4.9 KiB |
|
@ -1,32 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct ColecoVision {
|
||||
ColecoVision(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
ColecoVision::ColecoVision(vector<uint8_t>& 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct Famicom {
|
||||
Famicom(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
Famicom::Famicom(vector<uint8_t>& 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct GameBoyAdvance {
|
||||
GameBoyAdvance(vector<uint8_t>& buffer, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
GameBoyAdvance::GameBoyAdvance(vector<uint8_t>& data, string location) : data(data), location(location) {
|
||||
}
|
||||
|
||||
GameBoyAdvance::operator bool() const {
|
||||
return (bool)data;
|
||||
}
|
||||
|
||||
auto GameBoyAdvance::manifest() const -> string {
|
||||
if(!operator bool()) return {};
|
||||
|
||||
vector<string> identifiers = {
|
||||
"SRAM_V",
|
||||
"SRAM_F_V",
|
||||
"EEPROM_V",
|
||||
"FLASH_V",
|
||||
"FLASH512_V",
|
||||
"FLASH1M_V",
|
||||
};
|
||||
|
||||
vector<string> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct GameGear {
|
||||
GameGear(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
GameGear::GameGear(vector<uint8_t>& 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct MasterSystem {
|
||||
MasterSystem(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
MasterSystem::MasterSystem(vector<uint8_t>& 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct MegaDrive {
|
||||
MegaDrive(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
MegaDrive::MegaDrive(vector<uint8_t>& 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<string> 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct MSX {
|
||||
MSX(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
MSX::MSX(vector<uint8_t>& 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct NeoGeoPocketColor {
|
||||
NeoGeoPocketColor(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
auto title() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
NeoGeoPocketColor::NeoGeoPocketColor(vector<uint8_t>& 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct NeoGeoPocket {
|
||||
NeoGeoPocket(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
auto title() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
NeoGeoPocket::NeoGeoPocket(vector<uint8_t>& 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct PCEngine {
|
||||
PCEngine(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
PCEngine::PCEngine(vector<uint8_t>& 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct SC3000 {
|
||||
SC3000(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
SC3000::SC3000(vector<uint8_t>& 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct SG1000 {
|
||||
SG1000(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
SG1000::SG1000(vector<uint8_t>& 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct SuperGrafx {
|
||||
SuperGrafx(vector<uint8_t>& data, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
SuperGrafx::operator bool() const {
|
||||
return (bool)data;
|
||||
}
|
||||
|
||||
SuperGrafx::SuperGrafx(vector<uint8_t>& 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
namespace Heuristics {
|
||||
|
||||
struct WonderSwan {
|
||||
WonderSwan(vector<uint8_t>& buffer, string location);
|
||||
explicit operator bool() const;
|
||||
auto manifest() const -> string;
|
||||
|
||||
private:
|
||||
vector<uint8_t>& data;
|
||||
string location;
|
||||
};
|
||||
|
||||
WonderSwan::WonderSwan(vector<uint8_t>& 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
#include <nall/nall.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include <hiro/hiro.hpp>
|
||||
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 <nall/main.hpp>
|
||||
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
|
|
@ -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));
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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<string> 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();
|
||||
}
|
||||
}
|
|
@ -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<string> 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";
|
||||
}
|
|
@ -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()});
|
||||
}
|
|
@ -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<string> locations) -> void;
|
||||
|
||||
bool abort;
|
||||
vector<string> 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;
|
Loading…
Reference in New Issue