From c49d3b2006e9fa1f22378750fd51b844aec9cda7 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Wed, 21 Feb 2018 11:12:09 +1100 Subject: [PATCH] Update to v106r07 release. byuu says: Changelog: - Super Game Boy: for the 50th time, higan won't segfault if you cancel the Game Boy cartridge load request - icarus: moved to new manifest syntax for all remaining systems - Game Boy: moved to new manifest syntax Errata: - Game Boy: save RAM does not appear to be working for some reason - Famicom: higan won't even start to run this system; it just acts like a cartridge was never loaded ... - cores outside of the Super Famicom and Game Boy/Color will not run due to icarus/higan manifest syntax differences --- higan/emulator/emulator.hpp | 2 +- higan/gb/cartridge/cartridge.cpp | 68 +++--- higan/sfc/cartridge/load.cpp | 14 +- icarus/Database/BS Memory.bml | 2 +- icarus/Database/Sufami Turbo.bml | 2 +- icarus/Database/Super Famicom.bml | 309 ++++++++++++++++++++++++- icarus/core/bs-memory.cpp | 5 +- icarus/core/core.cpp | 32 +-- icarus/core/core.hpp | 36 +-- icarus/core/famicom.cpp | 51 ++-- icarus/core/game-boy-advance.cpp | 33 +-- icarus/core/game-boy-color.cpp | 32 +-- icarus/core/game-boy.cpp | 32 +-- icarus/core/game-gear.cpp | 21 +- icarus/core/master-system.cpp | 21 +- icarus/core/mega-drive.cpp | 21 +- icarus/core/pc-engine.cpp | 21 +- icarus/core/sufami-turbo.cpp | 5 +- icarus/core/super-famicom.cpp | 5 +- icarus/core/supergrafx.cpp | 21 +- icarus/core/wonderswan-color.cpp | 21 +- icarus/core/wonderswan.cpp | 21 +- icarus/heuristics/bs-memory.cpp | 10 +- icarus/heuristics/famicom.cpp | 158 +++++++------ icarus/heuristics/game-boy-advance.cpp | 80 ++++--- icarus/heuristics/game-boy.cpp | 83 ++++--- icarus/heuristics/game-gear.cpp | 40 ++-- icarus/heuristics/heuristics.cpp | 12 + icarus/heuristics/heuristics.hpp | 7 + icarus/heuristics/master-system.cpp | 42 ++-- icarus/heuristics/mega-drive.cpp | 69 +++--- icarus/heuristics/pc-engine.cpp | 48 ++-- icarus/heuristics/sufami-turbo.cpp | 23 +- icarus/heuristics/super-famicom.cpp | 12 +- icarus/heuristics/supergrafx.cpp | 40 ++-- icarus/heuristics/wonderswan.cpp | 84 +++---- icarus/icarus.cpp | 2 + 37 files changed, 915 insertions(+), 570 deletions(-) create mode 100644 icarus/heuristics/heuristics.cpp create mode 100644 icarus/heuristics/heuristics.hpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 73444915..feefb40f 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "106.06"; + static const string Version = "106.07"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org/"; diff --git a/higan/gb/cartridge/cartridge.cpp b/higan/gb/cartridge/cartridge.cpp index 37dbcab5..831e469d 100644 --- a/higan/gb/cartridge/cartridge.cpp +++ b/higan/gb/cartridge/cartridge.cpp @@ -19,6 +19,12 @@ Cartridge cartridge; auto Cartridge::load() -> bool { information = {}; + rom = {}; + ram = {}; + rtc = {}; + mapper = &mbc0; + accelerometer = false; + rumble = false; if(Model::GameBoy()) { if(auto loaded = platform->load(ID::GameBoy, "Game Boy", "gb")) { @@ -43,10 +49,9 @@ auto Cartridge::load() -> bool { } else return false; auto document = BML::unserialize(information.manifest); - auto board = document["board"]; - information.title = document["information/title"].text(); + information.title = document["game/label"].text(); - auto mapperID = document["board/mapper"].text(); + auto mapperID = document["game/board"].text(); if(mapperID == "MBC0" ) mapper = &mbc0; if(mapperID == "MBC1" ) mapper = &mbc1; if(mapperID == "MBC1M") mapper = &mbc1m; @@ -59,32 +64,37 @@ auto Cartridge::load() -> bool { if(mapperID == "HuC1" ) mapper = &huc1; if(mapperID == "HuC3" ) mapper = &huc3; if(mapperID == "TAMA" ) mapper = &tama; - if(!mapper) mapper = &mbc0; - accelerometer = (bool)document["board/accelerometer"]; - rumble = (bool)document["board/rumble"]; + accelerometer = (bool)document["game/board/accelerometer"]; + rumble = (bool)document["game/board/rumble"]; - rom.size = max(0x4000, document["board/rom/size"].natural()); - rom.data = (uint8*)memory::allocate(rom.size, 0xff); - if(auto name = document["board/rom/name"].text()) { - if(auto fp = platform->open(pathID(), name, File::Read, File::Required)) { - fp->read(rom.data, min(rom.size, fp->size())); + if(auto node = document["game/memory[type=ROM]"]) { + rom.size = max(0x4000, node["size"].natural()); + rom.data = (uint8*)memory::allocate(rom.size, 0xff); + if(auto name = node["name"].text()) { + if(auto fp = platform->open(pathID(), name, File::Read, File::Required)) { + fp->read(rom.data, min(rom.size, fp->size())); + } } } - ram.size = document["board/ram/size"].natural(); - ram.data = (uint8*)memory::allocate(ram.size, 0xff); - if(auto name = document["board/ram/name"].text()) { - if(auto fp = platform->open(pathID(), name, File::Read, File::Optional)) { - fp->read(ram.data, min(ram.size, fp->size())); + if(auto node = document["game/memory[type=NVRAM]"]) { + ram.size = node["size"].natural(); + ram.data = (uint8*)memory::allocate(ram.size, 0xff); + if(auto name = node["name"].text()) { + if(auto fp = platform->open(pathID(), name, File::Read, File::Optional)) { + fp->read(ram.data, min(ram.size, fp->size())); + } } } - rtc.size = document["board/rtc/size"].natural(); - rtc.data = (uint8*)memory::allocate(rtc.size, 0xff); - if(auto name = document["board/rtc/name"].text()) { - if(auto fp = platform->open(pathID(), name, File::Read, File::Optional)) { - fp->read(rtc.data, min(rtc.size, fp->size())); + if(auto node = document["game/memory[type=RTC]"]) { + rtc.size = node["size"].natural(); + rtc.data = (uint8*)memory::allocate(rtc.size, 0xff); + if(auto name = node["name"].text()) { + if(auto fp = platform->open(pathID(), name, File::Read, File::Optional)) { + fp->read(rtc.data, min(rtc.size, fp->size())); + } } } @@ -95,15 +105,19 @@ auto Cartridge::load() -> bool { auto Cartridge::save() -> void { auto document = BML::unserialize(information.manifest); - if(auto name = document["board/ram/name"].text()) { - if(auto fp = platform->open(pathID(), name, File::Write)) { - fp->write(ram.data, ram.size); + if(auto node = document["game/memory[type=NVRAM]"]) { + if(auto name = node["name"].text()) { + if(auto fp = platform->open(pathID(), name, File::Write)) { + fp->write(ram.data, ram.size); + } } } - if(auto name = document["board/rtc/name"].text()) { - if(auto fp = platform->open(pathID(), name, File::Write)) { - fp->write(rtc.data, rtc.size); + if(auto node = document["game/memory[type=RTC]"]) { + if(auto name = node["name"].text()) { + if(auto fp = platform->open(pathID(), name, File::Write)) { + fp->write(rtc.data, rtc.size); + } } } } diff --git a/higan/sfc/cartridge/load.cpp b/higan/sfc/cartridge/load.cpp index fb4326bc..d4e7fb0a 100644 --- a/higan/sfc/cartridge/load.cpp +++ b/higan/sfc/cartridge/load.cpp @@ -22,10 +22,15 @@ auto Cartridge::loadBoard(Markup::Node node) -> Markup::Node { } if(!matched) continue; - if(region.endsWith("-USA") - || region.endsWith("-CAN") - || region.endsWith("-JPN") - || region.endsWith("-KOR") + if(region.endsWith("BRA") + || region.endsWith("CAN") + || region.endsWith("HKG") + || region.endsWith("JPN") + || region.endsWith("KOR") + || region.endsWith("LTN") + || region.endsWith("ROC") + || region.endsWith("USA") + || region.beginsWith("SHVC-") || region == "NTSC") { output.append("region=ntsc\n"); } else { @@ -62,7 +67,6 @@ auto Cartridge::loadBoard(Markup::Node node) -> Markup::Node { } } - print(output, "\n"); return BML::unserialize(output); } diff --git a/icarus/Database/BS Memory.bml b/icarus/Database/BS Memory.bml index 7acfd945..535df0e1 100644 --- a/icarus/Database/BS Memory.bml +++ b/icarus/Database/BS Memory.bml @@ -1,5 +1,5 @@ database - revision: 2018-02-14 + revision: 2018-02-16 //BS Memory (JPN) diff --git a/icarus/Database/Sufami Turbo.bml b/icarus/Database/Sufami Turbo.bml index 878bde13..f807e1b7 100644 --- a/icarus/Database/Sufami Turbo.bml +++ b/icarus/Database/Sufami Turbo.bml @@ -1,5 +1,5 @@ database - revision: 2018-02-14 + revision: 2018-02-16 //Sufami Turbo (JPN) diff --git a/icarus/Database/Super Famicom.bml b/icarus/Database/Super Famicom.bml index 7b6c22c9..6fbf45d6 100644 --- a/icarus/Database/Super Famicom.bml +++ b/icarus/Database/Super Famicom.bml @@ -1,5 +1,34 @@ database - revision: 2018-02-14 + revision: 2018-02-16 + +//Prototypes (JPN) + +database + revision: 2018-02-16 + +game + sha256: 182cd72c2ef57119b56bef1f7c18660498422a912f1bb652771d465cd183b04e + region: JPN + revision: 1.0 + board: SHVC-4PV5B-01 + name: From TV Animation - Slam Dunk - Shuueisha Limited + label: From TV Animation - Slam Dunk - 集英社Limited + memory + type: EPROM + size: 0x180000 + name: program.rom + +game + sha256: bcba4ca39f0279f7a52657bccbffa84564eaea455e2565597b93942ec245fdb1 + region: JPN + revision: 1.0 + board: SHVC-2P3B-01 + name: Kunio-kun no Dodgeball da yo - Zen'in Shuugou! - Tournament Special + label: くにおくんのドッジボールだよ 全員集合! トーナメントスペシャル + memory + type: EPROM + size: 0x80000 + name: program.rom //Super Comboy (KOR) @@ -82,7 +111,55 @@ game //Super Famicom (JPN) database - revision: 2018-02-14 + revision: 2018-02-16 + +game + sha256: 6f6bacdd73aef29ff6a015c25db4a5cd8ba31142b2cc3fe56261d23bbf8329ea + region: SHVC-AAZJ-JPN + revision: SHVC-AAZJ-0 + board: SHVC-1J5M-01 + name: Angelique - Premium Box + label: アンジェリーク プレミアムBox + memory + type: ROM + size: 0x200000 + name: program.rom + memory + type: NVRAM + size: 0x8000 + name: save.ram + +game + sha256: 1f7619ea0d02f16e2b2dcbb36013bb3405eb791885f23884b583eb63768614c4 + region: SHVC-AQLJ-JPN + revision: SHVC-AQLJ-0 + board: SHVC-1J5M-01 + name: Angelique - Voice Fantasy + label: アンジェリーク ヴォイス・ファンタジー + memory + type: ROM + size: 0x300000 + name: program.rom + memory + type: NVRAM + size: 0x8000 + name: save.ram + +game + sha256: ecd772c4a21101d079a795e47abbe00052bef69cc1c854a328f0077016c53311 + region: SHVC-AH9J-JPN + revision: SHVC-AH9J-0 + board: SHVC-1J3M-20 + name: Bomberman B-Daman + label: ボンバーマン ビーダマン + memory + type: ROM + size: 0x100000 + name: program.rom + memory + type: NVRAM + size: 0x2000 + name: save.ram game sha256: 3ce321496edc5d77038de2034eb3fb354d7724afd0bc7fd0319f3eb5d57b984d @@ -104,6 +181,22 @@ game size: 0x80000 name: download.ram +game + sha256: c195641a1b472590cb3d0be0c48d682b9fee94d7b700dd7bd3297bb995b49307 + region: SHVC-B5 + revision: SHVC-B5-0 + board: SHVC-1J3B-01 + name: Conveni Wars - Barcode Battler Senki - Super Senshi Shutsugeki seyo! + label: Conveni Wars Barcode Battler 戦記 スーパー戦士 出撃せよ! + memory + type: ROM + size: 0x80000 + name: program.rom + memory + type: NVRAM + size: 0x2000 + name: save.ram + game sha256: 38a855229eab468c3ede7573db73082c66b157adfc7af787ccac50559b747f5f region: SHVC-ZDBJ-JPN @@ -120,6 +213,54 @@ game size: 0x8000 name: save.ram +game + sha256: dcb14c95f058a32f40cc329793f5d95fd6cf1755cffe02c0594d1c583a06d356 + region: SHVC-AEMJ-JPN + revision: SHVC-AEMJ-0 + board: SHVC-1J3M-20 + name: Emit Vol. 1 - Toki no Maigo + label: エミット Vol. 1 時の迷子 + memory + type: ROM + size: 0x300000 + name: program.rom + memory + type: NVRAM + size: 0x2000 + name: save.ram + +game + sha256: dc1ecf27d9ce4fdf674c9405339016f5a812f7c4687e588cc6404e2b3b92541a + region: SHVC-AEIJ-JPN + revision: SHVC-AEIJ-0 + board: SHVC-1J3M-20 + name: Emit Vol. 2 - Inochigake no Tabi + label: エミット Vol. 2 命がけの旅 + memory + type: ROM + size: 0x300000 + name: program.rom + memory + type: NVRAM + size: 0x2000 + name: save.ram + +game + sha256: f49417cb8759a30e12439e846f7d581afd1519c625e6a0522876666098521fcc + region: SHVC-AETJ-JPN + revision: SHVC-AETJ-0 + board: SHVC-1J3M-20 + name: Emit Vol. 3 - Watashi ni Sayonara o + label: エミット Vol. 3 私にさよならを + memory + type: ROM + size: 0x300000 + name: program.rom + memory + type: NVRAM + size: 0x2000 + name: save.ram + game sha256: 74aa3a26b66f34819fbbdcdb2475cf9161cc2590fb1ec89fb24940ef10e44332 region: SHVC-F4 @@ -136,6 +277,22 @@ game size: 0x2000 name: save.ram +game + sha256: db337a2e8cf6de653d092ba3489cabc658f91c63ec8a9db4e1866400aadf913f + region: SHVC-AGHJ-JPN + revision: SHVC-AGHJ-0 + board: SHVC-2J3M-20 + name: Get in the Hole + label: ゲットインザホール + memory + type: ROM + size: 0x180000 + name: program.rom + memory + type: NVRAM + size: 0x2000 + name: save.ram + game sha256: 4dfba33201de6b5dec952d0f327aeb44ed784c025a72c982356dd41b52efc219 region: SHVC-ZBPJ-JPN @@ -172,6 +329,66 @@ game size: 0x2000 name: save.ram +game + sha256: fe44f9d0db9f04f704764577b94e5bf2e18bc7a1c4ff1e6bdaca06d49ed6813c + region: SHVC-LK + revision: SHVC-LK-0 + board: SHVC-1A0N-20 + name: Lethal Enforcers + label: リーサルエンフォーサーズ + memory + type: ROM + size: 0x200000 + name: program.rom + +game + sha256: c51c5930b344f553415d54c3c964c050e1eb6355b10f5966deabb686e70e1750 + region: SHVC-WE + revision: SHVC-WE-0 + board: SHVC-YA0N-01 + name: Mario & Wario + label: マリオとワリオ + memory + type: ROM + size: 0x100000 + name: program.rom + +game + sha256: e842cac1a4301be196f1e137fbd1a16866d5c913f24dbca313f4dd8bd7472f45 + region: SHVC-MP + revision: SHVC-MP-0 + board: SHVC-1A5B-04 + name: Mario Paint + label: マリオペイント + memory + type: ROM + size: 0x100000 + name: program.rom + memory + type: NVRAM + size: 0x8000 + name: save.ram + +game + sha256: 2298d92acdfecc7270a6c9a57a6ddc55d7fa841fe9c0e7c0d64e33682fffa429 + region: SHVC-A4WJ-JPN + revision: SHVC-A4WJ-0 + board: SHVC-1L5B-20 + name: Mini Yonku Shining Scorpion - Let's & Go!! + label: ミニ四駆シャイニングスコーピオン レッツ&ゴー!! + memory + type: ROM + size: 0x400000 + name: program.rom + memory + type: NVRAM + size: 0x8000 + name: save.ram + memory + type: RAM + size: 0x800 + name: internal.ram + game sha256: d712adecbde70a74c4a580fe90a45d0d19f2641d1b4e091d507bddeec9601de1 region: SHVC-ZMCJ-JPN @@ -268,6 +485,34 @@ game size: 0x40000 name: program.rom +game + sha256: 442397be57b3740ca236cfb37633b95f88a2c80dafc94b56a805229793563ce1 + region: SHVC-9B + revision: SHVC-9B-0 + board: SHVC-1J0N-10 + name: Super Bomberman 2 - Taikenban + label: スーパーボンバーマン2 体験版 + memory + type: ROM + size: 0x100000 + name: program.rom + +game + sha256: 5f8e6894f71c62bc5e70485715dbd2e2d8f3c0383ec54211dc5fe180098d0e3f + region: SHVC-AK8J-JPN + revision: SHVC-AK8J-0 + board: SHVC-1J3M-20 + name: Super Bomberman 5 - CoroCoro Comic + label: スーパーボンバーマン5 コロコロコミック + memory + type: ROM + size: 0x200000 + name: program.rom + memory + type: NVRAM + size: 0x2000 + name: save.ram + game sha256: 4d7fc331a811b8dc630b469262fd6f45e289243cef83101f32038158967d1b28 region: SHVC-SGB @@ -348,6 +593,66 @@ game size: 0x2000 name: save.ram +game + sha256: ecd462c64516169cc83dd266af354fe676fcf53811863a361d78cc918619da0d + region: SHVC-XL + revision: SHVC-XL-1 + board: SHVC-1A5M-20 + name: Super Sangokushi II + label: スーパー三国志II 復刻版 + memory + type: ROM + size: 0x100000 + name: program.rom + memory + type: NVRAM + size: 0x8000 + name: save.ram + +game + sha256: fde83367c1caf6edfb41a0c609bacc90084e9808b32ba52b13d204eb59535ab5 + region: SHVC-LR + revision: SHVC-LR-0 + board: SHVC-1A0N-20 + name: Super Scope 6 + label: スーパースコープ6 + memory + type: ROM + size: 0x100000 + name: program.rom + +game + sha256: 8dda3b0888a32005041f2feb9be4e14807d40291f951a4612461cf41dac9cb78 + region: SHVC-T2 + revision: SHVC-T2-0 + board: SHVC-1A1B-06 + name: Super Tetris 2 + Bombliss + label: Super Tetris 2 + Bombliss + memory + type: ROM + size: 0x100000 + name: program.rom + memory + type: NVRAM + size: 0x800 + name: save.ram + +game + sha256: b66da2a23f249e525b1dd444596a3f10559cb3c30fa3c0bca83ed8f4405fcfcf + region: SHVC-ANZJ-JPN + revision: SHVC-ANZJ-0 + board: SHVC-1J3M-20 + name: Undake 30 - Same Game Daisakusen - Mario Version + label: Undake 30 鮫亀大作戦 マリオバージョン + memory + type: ROM + size: 0x60000 + name: program.rom + memory + type: NVRAM + size: 0x2000 + name: save.ram + //Super Famicom (ROC) database diff --git a/icarus/core/bs-memory.cpp b/icarus/core/bs-memory.cpp index 25a5b016..9e7c6da9 100644 --- a/icarus/core/bs-memory.cpp +++ b/icarus/core/bs-memory.cpp @@ -5,10 +5,9 @@ auto Icarus::bsMemoryManifest(string location) -> string { } auto Icarus::bsMemoryManifest(vector& buffer, string location) -> string { - auto digest = Hash::SHA256(buffer).digest(); - if(settings["icarus/UseDatabase"].boolean()) { - for(auto game : database.bsMemory.find("game")) { + auto digest = Hash::SHA256(buffer).digest(); + for(auto game : Database::BSMemory.find("game")) { if(game["sha256"].text() == digest) return BML::serialize(game); } } diff --git a/icarus/core/core.cpp b/icarus/core/core.cpp index 4e3ae15b..a6358034 100644 --- a/icarus/core/core.cpp +++ b/icarus/core/core.cpp @@ -1,18 +1,18 @@ Icarus::Icarus() { - database.famicom = BML::unserialize(string::read(locate("Database/Famicom.bml"))); - database.superFamicom = BML::unserialize(string::read(locate("Database/Super Famicom.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.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.bsMemory = BML::unserialize(string::read(locate("Database/BS Memory.bml"))); - database.sufamiTurbo = BML::unserialize(string::read(locate("Database/Sufami Turbo.bml"))); + Database::Famicom = BML::unserialize(string::read(locate("Database/Famicom.bml"))); + Database::SuperFamicom = BML::unserialize(string::read(locate("Database/Super Famicom.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::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::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 { @@ -35,7 +35,7 @@ auto Icarus::failure(string message) -> string { auto Icarus::manifest(string location) -> string { location.transform("\\", "/").trimRight("/").append("/"); - if(!directory::exists(location)) return ""; + if(!directory::exists(location)) return {}; auto type = Location::suffix(location).downcase(); if(type == ".fc") return famicomManifest(location); @@ -53,7 +53,7 @@ auto Icarus::manifest(string location) -> string { if(type == ".bs") return bsMemoryManifest(location); if(type == ".st") return sufamiTurboManifest(location); - return ""; + return {}; } auto Icarus::import(string location) -> string { diff --git a/icarus/core/core.hpp b/icarus/core/core.hpp index f48de576..4686420d 100644 --- a/icarus/core/core.hpp +++ b/icarus/core/core.hpp @@ -38,7 +38,7 @@ struct Icarus { //famicom.cpp auto famicomManifest(string location) -> string; - auto famicomManifest(vector& buffer, string location, uint* prgrom = nullptr, uint* chrrom = nullptr) -> string; + auto famicomManifest(vector& buffer, string location) -> string; auto famicomImport(vector& buffer, string location) -> string; //super-famicom.cpp @@ -109,21 +109,21 @@ struct Icarus { private: string errorMessage; string_vector missingFiles; - - struct { - Markup::Node famicom; - Markup::Node superFamicom; - Markup::Node masterSystem; - Markup::Node megaDrive; - Markup::Node pcEngine; - Markup::Node superGrafx; - Markup::Node gameBoy; - Markup::Node gameBoyColor; - Markup::Node gameBoyAdvance; - Markup::Node gameGear; - Markup::Node wonderSwan; - Markup::Node wonderSwanColor; - Markup::Node bsMemory; - Markup::Node sufamiTurbo; - } database; +}; + +namespace Database { + Markup::Node Famicom; + Markup::Node SuperFamicom; + Markup::Node MasterSystem; + Markup::Node MegaDrive; + Markup::Node PCEngine; + Markup::Node SuperGrafx; + Markup::Node GameBoy; + Markup::Node GameBoyColor; + Markup::Node GameBoyAdvance; + Markup::Node GameGear; + Markup::Node WonderSwan; + Markup::Node WonderSwanColor; + Markup::Node BSMemory; + Markup::Node SufamiTurbo; }; diff --git a/icarus/core/famicom.cpp b/icarus/core/famicom.cpp index c8f07f56..e9e44b7d 100644 --- a/icarus/core/famicom.cpp +++ b/icarus/core/famicom.cpp @@ -6,35 +6,20 @@ auto Icarus::famicomManifest(string location) -> string { return famicomManifest(buffer, location); } -auto Icarus::famicomManifest(vector& buffer, string location, uint* prgrom, uint* chrrom) -> string { - string markup; - string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); - - if(settings["icarus/UseDatabase"].boolean() && !markup) { - for(auto node : database.famicom) { - if(node["sha256"].text() == digest) { - markup.append(node.text(), "\n sha256: ", digest, "\n"); - break; - } +auto Icarus::famicomManifest(vector& buffer, string location) -> string { + if(settings["icarus/UseDatabase"].boolean()) { + auto digest = Hash::SHA256(buffer).digest(); + for(auto game : Database::Famicom.find("game")) { + if(game["sha256"].text() == digest) return BML::serialize(game); } } - if(settings["icarus/UseHeuristics"].boolean() && !markup) { - FamicomCartridge cartridge{buffer.data(), buffer.size()}; - if(markup = cartridge.markup) { - markup.append("\n"); - markup.append("information\n"); - markup.append(" title: ", Location::prefix(location), "\n"); - markup.append(" sha256: ", digest, "\n"); - markup.append(" note: ", "heuristically generated by icarus\n"); - } + if(settings["icarus/UseHeuristics"].boolean()) { + Heuristics::Famicom game{buffer, location}; + if(auto manifest = game.manifest()) return manifest; } - auto document = BML::unserialize(markup); - if(prgrom) *prgrom = document["board/prg/rom/size"].natural(); //0 if node does not exist - if(chrrom) *chrrom = document["board/chr/rom/size"].natural(); //0 if node does not exist - - return markup; + return {}; } auto Icarus::famicomImport(vector& buffer, string location) -> string { @@ -42,20 +27,22 @@ auto Icarus::famicomImport(vector& buffer, string location) -> string { auto source = Location::path(location); string target{settings["Library/Location"].text(), "Famicom/", name, ".fc/"}; - uint prgrom = 0; - uint chrrom = 0; - auto markup = famicomManifest(buffer, location, &prgrom, &chrrom); - if(!markup) return failure("failed to parse ROM image"); + auto manifest = famicomManifest(buffer, location); + if(!manifest) return failure("failed to parse ROM image"); + + auto document = BML::unserialize(manifest); + uint prgrom = document["game/memory[name=program.rom]"]["size"].natural(); + uint chrrom = document["game/memory[name=character.rom]"]["size"].natural(); 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"}, markup); - write({target, "ines.rom"}, buffer.data(), 16); - write({target, "program.rom"}, buffer.data() + 16, prgrom); + if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); + write({target, "ines.rom"}, &buffer[0], 16); + write({target, "program.rom"}, &buffer[16], prgrom); if(!chrrom) return success(target); - write({target, "character.rom"}, buffer.data() + 16 + prgrom, chrrom); + write({target, "character.rom"}, &buffer[16 + prgrom], chrrom); return success(target); } diff --git a/icarus/core/game-boy-advance.cpp b/icarus/core/game-boy-advance.cpp index 9e347ff4..cf17d4df 100644 --- a/icarus/core/game-boy-advance.cpp +++ b/icarus/core/game-boy-advance.cpp @@ -5,30 +5,19 @@ auto Icarus::gameBoyAdvanceManifest(string location) -> string { } auto Icarus::gameBoyAdvanceManifest(vector& buffer, string location) -> string { - string markup; - string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); - - if(settings["icarus/UseDatabase"].boolean() && !markup) { - for(auto node : database.gameBoyAdvance) { - if(node["sha256"].text() == digest) { - markup.append(node.text(), "\n sha256: ", digest, "\n"); - break; - } + 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() && !markup) { - GameBoyAdvanceCartridge cartridge{buffer.data(), buffer.size()}; - if(markup = cartridge.markup) { - markup.append("\n"); - markup.append("information\n"); - markup.append(" title: ", Location::prefix(location), "\n"); - markup.append(" sha256: ", digest, "\n"); - markup.append(" note: ", "heuristically generated by icarus\n"); - } + if(settings["icarus/UseHeuristics"].boolean()) { + Heuristics::GameBoyAdvance game{buffer, location}; + if(auto manifest = game.manifest()) return manifest; } - return markup; + return {}; } auto Icarus::gameBoyAdvanceImport(vector& buffer, string location) -> string { @@ -36,15 +25,15 @@ auto Icarus::gameBoyAdvanceImport(vector& buffer, string location) -> s auto source = Location::path(location); string target{settings["Library/Location"].text(), "Game Boy Advance/", name, ".gba/"}; - auto markup = gameBoyAdvanceManifest(buffer, location); - if(!markup) return failure("failed to parse ROM image"); + 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"}, markup); + if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); write({target, "program.rom"}, buffer); return success(target); } diff --git a/icarus/core/game-boy-color.cpp b/icarus/core/game-boy-color.cpp index 62858768..aa25f019 100644 --- a/icarus/core/game-boy-color.cpp +++ b/icarus/core/game-boy-color.cpp @@ -5,30 +5,20 @@ auto Icarus::gameBoyColorManifest(string location) -> string { } auto Icarus::gameBoyColorManifest(vector& buffer, string location) -> string { - string markup; - string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); + auto digest = Hash::SHA256(buffer).digest(); - if(settings["icarus/UseDatabase"].boolean() && !markup) { - for(auto node : database.gameBoyColor) { - if(node["sha256"].text() == digest) { - markup.append(node.text(), "\n sha256: ", digest, "\n"); - break; - } + 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() && !markup) { - GameBoyCartridge cartridge{buffer.data(), buffer.size()}; - if(markup = cartridge.markup) { - markup.append("\n"); - markup.append("information\n"); - markup.append(" title: ", Location::prefix(location), "\n"); - markup.append(" sha256: ", digest, "\n"); - markup.append(" note: ", "heuristically generated by icarus\n"); - } + if(settings["icarus/UseHeuristics"].boolean()) { + Heuristics::GameBoy game{buffer, location}; + if(auto manifest = game.manifest()) return manifest; } - return markup; + return {}; } auto Icarus::gameBoyColorImport(vector& buffer, string location) -> string { @@ -36,15 +26,15 @@ auto Icarus::gameBoyColorImport(vector& buffer, string location) -> str auto source = Location::path(location); string target{settings["Library/Location"].text(), "Game Boy Color/", name, ".gbc/"}; - auto markup = gameBoyColorManifest(buffer, location); - if(!markup) return failure("failed to parse ROM image"); + 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"}, markup); + if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); write({target, "program.rom"}, buffer); return success(target); } diff --git a/icarus/core/game-boy.cpp b/icarus/core/game-boy.cpp index 34d6038e..d358a423 100644 --- a/icarus/core/game-boy.cpp +++ b/icarus/core/game-boy.cpp @@ -5,30 +5,20 @@ auto Icarus::gameBoyManifest(string location) -> string { } auto Icarus::gameBoyManifest(vector& buffer, string location) -> string { - string markup; - string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); + auto digest = Hash::SHA256(buffer).digest(); - if(settings["icarus/UseDatabase"].boolean() && !markup) { - for(auto node : database.gameBoy) { - if(node["sha256"].text() == digest) { - markup.append(node.text(), "\n sha256: ", digest, "\n"); - break; - } + 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() && !markup) { - GameBoyCartridge cartridge{buffer.data(), buffer.size()}; - if(markup = cartridge.markup) { - markup.append("\n"); - markup.append("information\n"); - markup.append(" title: ", Location::prefix(location), "\n"); - markup.append(" sha256: ", digest, "\n"); - markup.append(" note: ", "heuristically generated by icarus\n"); - } + if(settings["icarus/UseHeuristics"].boolean()) { + Heuristics::GameBoy game{buffer, location}; + if(auto manifest = game.manifest()) return manifest; } - return markup; + return {}; } auto Icarus::gameBoyImport(vector& buffer, string location) -> string { @@ -36,15 +26,15 @@ auto Icarus::gameBoyImport(vector& buffer, string location) -> string { auto source = Location::path(location); string target{settings["Library/Location"].text(), "Game Boy/", name, ".gb/"}; - auto markup = gameBoyManifest(buffer, location); - if(!markup) return failure("failed to parse ROM image"); + 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"}, markup); + if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest); write({target, "program.rom"}, buffer); return success(target); } diff --git a/icarus/core/game-gear.cpp b/icarus/core/game-gear.cpp index 476c1f78..f02c40a1 100644 --- a/icarus/core/game-gear.cpp +++ b/icarus/core/game-gear.cpp @@ -5,24 +5,19 @@ auto Icarus::gameGearManifest(string location) -> string { } auto Icarus::gameGearManifest(vector& buffer, string location) -> string { - string manifest; - - if(settings["icarus/UseDatabase"].boolean() && !manifest) { - string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); - for(auto node : database.gameGear) { - if(node["sha256"].text() == digest) { - manifest.append(node.text(), "\n sha256: ", digest, "\n"); - break; - } + 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() && !manifest) { - GameGearCartridge cartridge{location, buffer.data(), buffer.size()}; - manifest = cartridge.manifest; + if(settings["icarus/UseHeuristics"].boolean()) { + Heuristics::GameGear game{buffer, location}; + if(auto manifest = game.manifest()) return manifest; } - return manifest; + return {}; } auto Icarus::gameGearImport(vector& buffer, string location) -> string { diff --git a/icarus/core/master-system.cpp b/icarus/core/master-system.cpp index 8da283f0..28796adf 100644 --- a/icarus/core/master-system.cpp +++ b/icarus/core/master-system.cpp @@ -5,24 +5,19 @@ auto Icarus::masterSystemManifest(string location) -> string { } auto Icarus::masterSystemManifest(vector& buffer, string location) -> string { - string manifest; - - if(settings["icarus/UseDatabase"].boolean() && !manifest) { - string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); - for(auto node : database.masterSystem) { - if(node["sha256"].text() == digest) { - manifest.append(node.text(), "\n sha256: ", digest, "\n"); - break; - } + 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() && !manifest) { - MasterSystemCartridge cartridge{location, buffer.data(), buffer.size()}; - manifest = cartridge.manifest; + if(settings["icarus/UseHeuristics"].boolean()) { + Heuristics::MasterSystem game{buffer, location}; + if(auto manifest = game.manifest()) return manifest; } - return manifest; + return {}; } auto Icarus::masterSystemImport(vector& buffer, string location) -> string { diff --git a/icarus/core/mega-drive.cpp b/icarus/core/mega-drive.cpp index 266a5f21..7e85b259 100644 --- a/icarus/core/mega-drive.cpp +++ b/icarus/core/mega-drive.cpp @@ -5,24 +5,19 @@ auto Icarus::megaDriveManifest(string location) -> string { } auto Icarus::megaDriveManifest(vector& buffer, string location) -> string { - string manifest; - - if(settings["icarus/UseDatabase"].boolean() && !manifest) { - string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); - for(auto node : database.megaDrive) { - if(node["sha256"].text() == digest) { - manifest.append(node.text(), "\n sha256: ", digest, "\n"); - break; - } + 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() && !manifest) { - MegaDriveCartridge cartridge{location, buffer.data(), buffer.size()}; - manifest = cartridge.manifest; + if(settings["icarus/UseHeuristics"].boolean()) { + Heuristics::MegaDrive game{buffer, location}; + if(auto manifest = game.manifest()) return manifest; } - return manifest; + return {}; } auto Icarus::megaDriveImport(vector& buffer, string location) -> string { diff --git a/icarus/core/pc-engine.cpp b/icarus/core/pc-engine.cpp index cb86eda4..5f9940f5 100644 --- a/icarus/core/pc-engine.cpp +++ b/icarus/core/pc-engine.cpp @@ -5,24 +5,19 @@ auto Icarus::pcEngineManifest(string location) -> string { } auto Icarus::pcEngineManifest(vector& buffer, string location) -> string { - string manifest; - - if(settings["icarus/UseDatabase"].boolean() && !manifest) { - string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); - for(auto node : database.pcEngine) { - if(node["sha256"].text() == digest) { - manifest.append(node.text(), "\n sha256: ", digest, "\n"); - break; - } + 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() && !manifest) { - PCEngineCartridge cartridge{location, buffer.data(), buffer.size()}; - manifest = cartridge.manifest; + if(settings["icarus/UseHeuristics"].boolean()) { + Heuristics::PCEngine game{buffer, location}; + if(auto manifest = game.manifest()) return manifest; } - return manifest; + return {}; } auto Icarus::pcEngineImport(vector& buffer, string location) -> string { diff --git a/icarus/core/sufami-turbo.cpp b/icarus/core/sufami-turbo.cpp index 5bd381ad..2bfce8ec 100644 --- a/icarus/core/sufami-turbo.cpp +++ b/icarus/core/sufami-turbo.cpp @@ -5,10 +5,9 @@ auto Icarus::sufamiTurboManifest(string location) -> string { } auto Icarus::sufamiTurboManifest(vector& buffer, string location) -> string { - auto digest = Hash::SHA256(buffer).digest(); - if(settings["icarus/UseDatabase"].boolean()) { - for(auto game : database.sufamiTurbo.find("game")) { + auto digest = Hash::SHA256(buffer).digest(); + for(auto game : Database::SufamiTurbo.find("game")) { if(game["sha256"].text() == digest) return BML::serialize(game); } } diff --git a/icarus/core/super-famicom.cpp b/icarus/core/super-famicom.cpp index 1d15fb39..f6895515 100644 --- a/icarus/core/super-famicom.cpp +++ b/icarus/core/super-famicom.cpp @@ -10,10 +10,9 @@ auto Icarus::superFamicomManifest(string location) -> string { } auto Icarus::superFamicomManifest(vector& buffer, string location) -> string { - auto digest = Hash::SHA256(buffer).digest(); - if(settings["icarus/UseDatabase"].boolean()) { - for(auto game : database.superFamicom.find("game")) { + auto digest = Hash::SHA256(buffer).digest(); + for(auto game : Database::SuperFamicom.find("game")) { if(game["sha256"].text() == digest) return BML::serialize(game); } } diff --git a/icarus/core/supergrafx.cpp b/icarus/core/supergrafx.cpp index ef748bea..10969bc0 100644 --- a/icarus/core/supergrafx.cpp +++ b/icarus/core/supergrafx.cpp @@ -5,24 +5,19 @@ auto Icarus::superGrafxManifest(string location) -> string { } auto Icarus::superGrafxManifest(vector& buffer, string location) -> string { - string manifest; - - if(settings["icarus/UseDatabase"].boolean() && !manifest) { - string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); - for(auto node : database.superGrafx) { - if(node["sha256"].text() == digest) { - manifest.append(node.text(), "\n sha256: ", digest, "\n"); - break; - } + 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() && !manifest) { - SuperGrafxCartridge cartridge{location, buffer.data(), buffer.size()}; - manifest = cartridge.manifest; + if(settings["icarus/UseHeuristics"].boolean()) { + Heuristics::SuperGrafx game{buffer, location}; + if(auto manifest = game.manifest()) return manifest; } - return manifest; + return {}; } auto Icarus::superGrafxImport(vector& buffer, string location) -> string { diff --git a/icarus/core/wonderswan-color.cpp b/icarus/core/wonderswan-color.cpp index f0111f63..e3a48a8c 100644 --- a/icarus/core/wonderswan-color.cpp +++ b/icarus/core/wonderswan-color.cpp @@ -5,24 +5,19 @@ auto Icarus::wonderSwanColorManifest(string location) -> string { } auto Icarus::wonderSwanColorManifest(vector& buffer, string location) -> string { - string manifest; - - if(settings["icarus/UseDatabase"].boolean() && !manifest) { - string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); - for(auto node : database.wonderSwanColor) { - if(node["sha256"].text() == digest) { - manifest.append(node.text(), "\n sha256: ", digest, "\n"); - break; - } + 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() && !manifest) { - WonderSwanCartridge cartridge{location, buffer.data(), buffer.size()}; - manifest = cartridge.manifest; + if(settings["icarus/UseHeuristics"].boolean()) { + Heuristics::WonderSwan game{buffer, location}; + if(auto manifest = game.manifest()) return manifest; } - return manifest; + return {}; } auto Icarus::wonderSwanColorImport(vector& buffer, string location) -> string { diff --git a/icarus/core/wonderswan.cpp b/icarus/core/wonderswan.cpp index 860f7972..356c325d 100644 --- a/icarus/core/wonderswan.cpp +++ b/icarus/core/wonderswan.cpp @@ -5,24 +5,19 @@ auto Icarus::wonderSwanManifest(string location) -> string { } auto Icarus::wonderSwanManifest(vector& buffer, string location) -> string { - string manifest; - - if(settings["icarus/UseDatabase"].boolean() && !manifest) { - string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); - for(auto node : database.wonderSwan) { - if(node["sha256"].text() == digest) { - manifest.append(node.text(), "\n sha256: ", digest, "\n"); - break; - } + 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() && !manifest) { - WonderSwanCartridge cartridge{location, buffer.data(), buffer.size()}; - manifest = cartridge.manifest; + if(settings["icarus/UseHeuristics"].boolean()) { + Heuristics::WonderSwan game{buffer, location}; + if(auto manifest = game.manifest()) return manifest; } - return manifest; + return {}; } auto Icarus::wonderSwanImport(vector& buffer, string location) -> string { diff --git a/icarus/heuristics/bs-memory.cpp b/icarus/heuristics/bs-memory.cpp index c06f4ca1..0c8c35ae 100644 --- a/icarus/heuristics/bs-memory.cpp +++ b/icarus/heuristics/bs-memory.cpp @@ -1,9 +1,8 @@ namespace Heuristics { -struct BSMemory { +struct BSMemory : Heuristics { BSMemory(vector& data, string location); explicit operator bool() const; - auto manifest() const -> string; private: @@ -19,17 +18,14 @@ BSMemory::operator bool() const { } auto BSMemory::manifest() const -> string { - if(!operator bool()) return ""; + if(!operator bool()) return {}; string output; output.append("game\n"); output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); output.append(" name: ", Location::prefix(location), "\n"); output.append(" label: ", Location::prefix(location), "\n"); - output.append(" memory\n"); - output.append(" type: NAND\n"); - output.append(" size: 0x", hex(data.size()), "\n"); - output.append(" name: program.rom\n"); + output.append(memory("NAND", data.size(), "program.rom")); return output; } diff --git a/icarus/heuristics/famicom.cpp b/icarus/heuristics/famicom.cpp index e7517f69..c51df04e 100644 --- a/icarus/heuristics/famicom.cpp +++ b/icarus/heuristics/famicom.cpp @@ -1,161 +1,173 @@ -struct FamicomCartridge { - FamicomCartridge(const uint8_t* data, uint size); +namespace Heuristics { - string markup; +struct Famicom : Heuristics { + Famicom(vector& data, string location); + explicit operator bool() const; + auto manifest() const -> string; -//private: - uint mapper; - uint mirror; - uint prgrom; - uint prgram; - uint chrrom; - uint chrram; +private: + vector& data; + string location; }; -FamicomCartridge::FamicomCartridge(const uint8_t* data, uint size) { - if(size < 16) return; - if(data[0] != 'N') return; - if(data[1] != 'E') return; - if(data[2] != 'S') return; - if(data[3] != 26) return; +Famicom::Famicom(vector& data, string location) : data(data), location(location) { +} - mapper = ((data[7] >> 4) << 4) | (data[6] >> 4); - mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01); - prgrom = data[4] * 0x4000; - chrrom = data[5] * 0x2000; - prgram = 0u; - chrram = chrrom == 0u ? 8192u : 0u; +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; +} - markup.append("board "); +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(" name: ", Location::prefix(location), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); switch(mapper) { default: - markup.append("id:NES-NROM-256\n"); - markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); + output.append(" board: NES-NROM-256\n"); + output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; case 1: - markup.append("id:NES-SXROM\n"); - markup.append(" chip type=MMC1B2\n"); + output.append(" board: NES-SXROM\n"); + output.append(" chip type=MMC1B2\n"); prgram = 8192; break; case 2: - markup.append("id:NES-UOROM\n"); - markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); + output.append(" board: NES-UOROM\n"); + output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; case 3: - markup.append("id:NES-CNROM\n"); - markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); + output.append(" board: NES-CNROM\n"); + output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; case 4: //MMC3 - markup.append("id:NES-TLROM\n"); - markup.append(" chip type=MMC3B\n"); + output.append(" board: NES-TLROM\n"); + output.append(" chip type=MMC3B\n"); prgram = 8192; //MMC6 - //markup.append("id:NES-HKROM\n"); - //markup.append(" chip type=MMC6n"); + //output.append(" board: NES-HKROM\n"); + //output.append(" chip type=MMC6\n"); //prgram = 1024; break; case 5: - markup.append("id:NES-ELROM\n"); - markup.append(" chip type=MMC5\n"); + output.append(" board: NES-ELROM\n"); + output.append(" chip type=MMC5\n"); prgram = 65536; break; case 7: - markup.append("id:NES-AOROM\n"); + output.append(" board: NES-AOROM\n"); break; case 9: - markup.append("id:NES-PNROM\n"); - markup.append(" chip type=MMC2\n"); + output.append(" board: NES-PNROM\n"); + output.append(" chip type=MMC2\n"); prgram = 8192; break; case 10: - markup.append("id:NES-FKROM\n"); - markup.append(" chip type=MMC4\n"); + output.append(" board: NES-FKROM\n"); + output.append(" chip type=MMC4\n"); prgram = 8192; break; case 16: - markup.append("id:BANDAI-FCG\n"); - markup.append(" chip type=LZ93D50\n"); + output.append(" board: BANDAI-FCG\n"); + output.append(" chip type=LZ93D50\n"); break; case 21: case 23: case 25: //VRC4 - markup.append("id:KONAMI-VRC-4\n"); - markup.append(" chip type=VRC4\n"); - markup.append(" pinout a0=1 a1=0\n"); + 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 - markup.append("id:KONAMI-VRC-2\n"); - markup.append(" chip type=VRC2\n"); - markup.append(" pinout a0=0 a1=1\n"); + output.append(" board: KONAMI-VRC-2\n"); + output.append(" chip type=VRC2\n"); + output.append(" pinout a0=0 a1=1\n"); break; case 24: - markup.append("id:KONAMI-VRC-6\n"); - markup.append(" chip type=VRC6\n"); + output.append(" board: KONAMI-VRC-6\n"); + output.append(" chip type=VRC6\n"); break; case 26: - markup.append("id:KONAMI-VRC-6\n"); - markup.append(" chip type=VRC6\n"); + output.append(" board: KONAMI-VRC-6\n"); + output.append(" chip type=VRC6\n"); prgram = 8192; break; case 34: - markup.append("id:NES-BNROM\n"); - markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); + output.append(" board: NES-BNROM\n"); + output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; case 66: - markup.append("id:NES-GNROM\n"); - markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); + output.append(" board: NES-GNROM\n"); + output.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; case 69: - markup.append("id:SUNSOFT-5B\n"); - markup.append(" chip type=5B\n"); + output.append(" board: SUNSOFT-5B\n"); + output.append(" chip type=5B\n"); prgram = 8192; break; case 73: - markup.append("id:KONAMI-VRC-3\n"); - markup.append(" chip type=VRC3\n"); - markup.append(" mirror mode=", mirror == 0 ? "horizontal" : "vertical", "\n"); + 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: - markup.append("id:KONAMI-VRC-1\n"); - markup.append(" chip type=VRC1\n"); + output.append(" board: KONAMI-VRC-1\n"); + output.append(" chip type=VRC1\n"); break; case 85: - markup.append("id:KONAMI-VRC-7\n"); - markup.append(" chip type=VRC7\n"); + output.append(" board: KONAMI-VRC-7\n"); + output.append(" chip type=VRC7\n"); prgram = 8192; break; } - markup.append(" prg\n"); - if(prgrom) markup.append(" rom name=program.rom size=0x", hex(prgrom), "\n"); - if(prgram) markup.append(" ram name=save.ram size=0x", hex(prgram), "\n"); + if(prgrom) output.append(memory("ROM", prgrom, "program.rom")); + if(prgram) output.append(memory("NVRAM", prgram, "save.ram")); + + if(chrrom) output.append(memory("ROM", chrrom, "character.rom")); + if(chrram) output.append(memory("RAM", chrram, "character.ram")); + + return output; +} - markup.append(" chr\n"); - if(chrrom) markup.append(" rom name=character.rom size=0x", hex(chrrom), "\n"); - if(chrram) markup.append(" ram size=0x", hex(chrram), "\n"); } diff --git a/icarus/heuristics/game-boy-advance.cpp b/icarus/heuristics/game-boy-advance.cpp index 5ee2cadc..ae0f9191 100644 --- a/icarus/heuristics/game-boy-advance.cpp +++ b/icarus/heuristics/game-boy-advance.cpp @@ -1,50 +1,66 @@ -struct GameBoyAdvanceCartridge { - GameBoyAdvanceCartridge(const uint8_t* data, unsigned size); +namespace Heuristics { - string markup; - string identifiers; +struct GameBoyAdvance : Heuristics { + GameBoyAdvance(vector& buffer, string location); + explicit operator bool() const; + auto manifest() const -> string; + +private: + vector& data; + string location; }; -GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t* data, unsigned size) { - struct Identifier { - string name; - unsigned size; +GameBoyAdvance::GameBoyAdvance(vector& data, string location) : data(data), location(location) { +} + +GameBoyAdvance::operator bool() const { + return (bool)data; +} + +auto GameBoyAdvance::manifest() const -> string { + if(!operator bool()) return {}; + + string_vector identifiers = { + "SRAM_V", + "SRAM_F_V", + "EEPROM_V", + "FLASH_V", + "FLASH512_V", + "FLASH1M_V", }; - vector idlist; - idlist.append({"SRAM_V", 6}); - idlist.append({"SRAM_F_V", 8}); - idlist.append({"EEPROM_V", 8}); - idlist.append({"FLASH_V", 7}); - idlist.append({"FLASH512_V", 10}); - idlist.append({"FLASH1M_V", 9}); string_vector list; - for(auto& id : idlist) { - for(signed n = 0; n < size - 16; n++) { - if(!memcmp(data + n, (const char*)id.name, id.size)) { - const char* p = (const char*)data + n + id.size; + 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]; - memcpy(text, data + n, id.size + 3); - text[id.size + 3] = 0; + memory::copy(text, &data[n], identifier.size() + 3); + text[identifier.size() + 3] = 0; if(!list.find(text)) list.append(text); } } } } - identifiers = list.merge(","); - markup.append("board\n"); - markup.append(" rom type=mrom name=program.rom size=0x", hex(size), "\n"); - if(0); - else if(identifiers.beginsWith("SRAM_V" )) markup.append(" ram type=sram name=save.ram size=0x8000\n"); - else if(identifiers.beginsWith("SRAM_F_V" )) markup.append(" ram type=sram name=save.ram size=0x8000\n"); - else if(identifiers.beginsWith("EEPROM_V" )) markup.append(" ram type=eeprom name=save.ram size=0x0\n"); - else if(identifiers.beginsWith("FLASH_V" )) markup.append(" ram type=flash name=save.ram size=0x10000\n"); - else if(identifiers.beginsWith("FLASH512_V")) markup.append(" ram type=flash name=save.ram size=0x10000\n"); - else if(identifiers.beginsWith("FLASH1M_V" )) markup.append(" ram type=flash name=save.ram size=0x20000\n"); -//if(identifiers) markup.append(" #detected: ", identifiers, "\n"); + string output; + output.append("game\n"); + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(memory("ROM", data.size(), "program.rom")); + if(!list); + else if(list.left().beginsWith("SRAM_V" )) output.append(memory("NVRAM", 0x8000, "save.ram")); + else if(list.left().beginsWith("SRAM_F_V" )) output.append(memory("NVRAM", 0x8000, "save.ram")); + else if(list.left().beginsWith("EEPROM_V" )) output.append(memory("EEPROM", 0x0, "save.ram")); + else if(list.left().beginsWith("FLASH_V" )) output.append(memory("NAND", 0x10000, "save.ram")); + else if(list.left().beginsWith("FLASH512_V")) output.append(memory("NAND", 0x10000, "save.ram")); + else if(list.left().beginsWith("FLASH1M_V" )) output.append(memory("NAND", 0x20000, "save.ram")); + return output; +} + } diff --git a/icarus/heuristics/game-boy.cpp b/icarus/heuristics/game-boy.cpp index 7e579a56..79544c04 100644 --- a/icarus/heuristics/game-boy.cpp +++ b/icarus/heuristics/game-boy.cpp @@ -1,12 +1,38 @@ -struct GameBoyCartridge { - GameBoyCartridge(uint8_t* data, uint size); +namespace Heuristics { - string markup; +struct GameBoy : Heuristics { + GameBoy(vector& data, string location); + explicit operator bool() const; + auto manifest() const -> string; - bool black = false; //cartridge works in DMG+CGB mode - bool clear = false; //cartridge works in CGB mode only +private: + auto read(uint offset) const -> uint8_t { return data[headerAddress + offset]; } + + vector& data; + string location; + uint headerAddress = 0; +}; + +GameBoy::GameBoy(vector& data, string location) : data(data), location(location) { + headerAddress = data.size() < 0x8000 ? data.size() : data.size() - 0x8000; + if(read(0x0104) == 0xce && read(0x0105) == 0xed && read(0x0106) == 0x66 && read(0x0107) == 0x66 + && read(0x0108) == 0xcc && read(0x0109) == 0x0d && read(0x0147) >= 0x0b && read(0x0147) <= 0x0d + ) { //MMM01 stores header at bottom of data[] + } else { //all other mappers store header at top of data[] + headerAddress = 0; + } +} + +GameBoy::operator bool() const { + return data.size() >= 0x4000; +} + +auto GameBoy::manifest() const -> string { + if(!operator bool()) return {}; + + bool black = (read(0x0143) & 0xc0) == 0x80; //cartridge works in DMG+CGB mode + bool clear = (read(0x0143) & 0xc0) == 0xc0; //cartridge works in CGB mode only - string mapper = "MBC0"; bool flash = false; bool battery = false; bool ram = false; @@ -18,27 +44,10 @@ struct GameBoyCartridge { uint romSize = 0; uint ramSize = 0; uint rtcSize = 0; -}; -GameBoyCartridge::GameBoyCartridge(uint8_t* data, uint size) { - if(size < 0x4000) return; + string mapper = "MBC0"; - uint index = size < 0x8000 ? size : size - 0x8000; - if(data[index + 0x0104] == 0xce && data[index + 0x0105] == 0xed - && data[index + 0x0106] == 0x66 && data[index + 0x0107] == 0x66 - && data[index + 0x0108] == 0xcc && data[index + 0x0109] == 0x0d - && data[index + 0x0147] >= 0x0b && data[index + 0x0147] <= 0x0d - ) { - //MMM01 stores header at bottom of data[] - } else { - //all other mappers store header at top of data[] - index = 0; - } - - black = (data[index + 0x0143] & 0xc0) == 0x80; - clear = (data[index + 0x0143] & 0xc0) == 0xc0; - - switch(data[index + 0x0147]) { + switch(read(0x0147)) { case 0x00: mapper = "MBC0"; @@ -195,7 +204,7 @@ GameBoyCartridge::GameBoyCartridge(uint8_t* data, uint size) { } - switch(data[index + 0x0148]) { default: + switch(read(0x0148)) { default: case 0x00: romSize = 2 * 16 * 1024; break; case 0x01: romSize = 4 * 16 * 1024; break; case 0x02: romSize = 8 * 16 * 1024; break; @@ -211,7 +220,7 @@ GameBoyCartridge::GameBoyCartridge(uint8_t* data, uint size) { if(mapper == "MBC6" && flash) flashSize = 1024 * 1024; - switch(data[index + 0x0149]) { default: + switch(read(0x0149)) { default: case 0x00: ramSize = 0 * 1024; break; case 0x01: ramSize = 2 * 1024; break; case 0x02: ramSize = 8 * 1024; break; @@ -226,9 +235,19 @@ GameBoyCartridge::GameBoyCartridge(uint8_t* data, uint size) { if(mapper == "MBC3" && rtc) rtcSize = 13; if(mapper == "TAMA" && rtc) rtcSize = 21; - markup.append("board mapper=", mapper, accelerometer ? " accelerometer" : "", rumble ? " rumble" : "", "\n"); - markup.append(" rom name=program.rom size=0x", hex(romSize), "\n"); - if(flash && flashSize) markup.append(" flash name=download.rom size=0x", hex(flashSize), "\n"); - if(ram && ramSize) markup.append(" ram ", battery ? "name=save.ram " : "", "size=0x", hex(ramSize), "\n"); - if(rtc && rtcSize) markup.append(" rtc ", battery ? "name=rtc.ram " : "", "size=0x", hex(rtcSize), "\n"); + string output; + output.append("game\n"); + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" board: ", mapper, "\n"); + if(accelerometer) output.append(" accelerometer\n"); + if(rumble) output.append(" rumble\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(memory("ROM", data.size(), "program.rom")); + if(flash && flashSize) output.append(memory("NAND", flashSize, "download.rom")); + if(ram && ramSize) output.append(memory(battery ? "NVRAM" : "RAM", ramSize, "save.ram")); + if(rtc && rtcSize) output.append(memory("RTC", rtcSize, "rtc.ram")); + return output; +} + } diff --git a/icarus/heuristics/game-gear.cpp b/icarus/heuristics/game-gear.cpp index 3667f226..c2376c1e 100644 --- a/icarus/heuristics/game-gear.cpp +++ b/icarus/heuristics/game-gear.cpp @@ -1,20 +1,30 @@ -struct GameGearCartridge { - GameGearCartridge(string location, uint8_t* data, uint size); +namespace Heuristics { - string manifest; +struct GameGear : Heuristics { + GameGear(vector& data, string location); + explicit operator bool() const; + auto manifest() const -> string; -//private: - struct Information { - } information; +private: + vector& data; + string location; }; -GameGearCartridge::GameGearCartridge(string location, uint8_t* data, uint size) { - manifest.append("board\n"); - manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); - manifest.append("\n"); - manifest.append("information\n"); - manifest.append(" title: ", Location::prefix(location), "\n"); - manifest.append(" sha256: ", Hash::SHA256(data, size).digest(), "\n"); - manifest.append("\n"); - manifest.append("note: heuristically generated by icarus\n"); +GameGear::GameGear(vector& data, string location) : data(data), location(location) { +} + +GameGear::operator bool() const { + return (bool)data; +} + +auto GameGear::manifest() const -> string { + string output; + output.append("game\n"); + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(memory("ROM", data.size(), "program.rom")); + return output; +} + } diff --git a/icarus/heuristics/heuristics.cpp b/icarus/heuristics/heuristics.cpp new file mode 100644 index 00000000..dfef71d5 --- /dev/null +++ b/icarus/heuristics/heuristics.cpp @@ -0,0 +1,12 @@ +namespace Heuristics { + +auto Heuristics::memory(string type, uint size, string name) const -> string { + string output; + output.append(" memory\n"); + output.append(" type: ", type, "\n"); + output.append(" size: 0x", hex(size), "\n"); + output.append(" name: ", name, "\n"); + return output; +} + +} diff --git a/icarus/heuristics/heuristics.hpp b/icarus/heuristics/heuristics.hpp new file mode 100644 index 00000000..79fcd627 --- /dev/null +++ b/icarus/heuristics/heuristics.hpp @@ -0,0 +1,7 @@ +namespace Heuristics { + +struct Heuristics { + auto memory(string type, uint size, string name) const -> string; +}; + +} diff --git a/icarus/heuristics/master-system.cpp b/icarus/heuristics/master-system.cpp index a0e034ed..e8107cd9 100644 --- a/icarus/heuristics/master-system.cpp +++ b/icarus/heuristics/master-system.cpp @@ -1,21 +1,31 @@ -struct MasterSystemCartridge { - MasterSystemCartridge(string location, uint8_t* data, uint size); +namespace Heuristics { - string manifest; +struct MasterSystem : Heuristics { + MasterSystem(vector& data, string location); + explicit operator bool() const; + auto manifest() const -> string; -//private: - struct Information { - } information; +private: + vector& data; + string location; }; -MasterSystemCartridge::MasterSystemCartridge(string location, uint8_t* data, uint size) { - manifest.append("board\n"); - manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); - manifest.append(" ram name=save.ram size=0x8000\n"); - manifest.append("\n"); - manifest.append("information\n"); - manifest.append(" title: ", Location::prefix(location), "\n"); - manifest.append(" sha256: ", Hash::SHA256(data, size).digest(), "\n"); - manifest.append("\n"); - manifest.append("note: heuristically generated by icarus\n"); +MasterSystem::MasterSystem(vector& data, string location) : data(data), location(location) { +} + +MasterSystem::operator bool() const { + return (bool)data; +} + +auto MasterSystem::manifest() const -> string { + string output; + output.append("game\n"); + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(memory("ROM", data.size(), "program.rom")); + output.append(memory("NVRAM", 0x8000, "save.ram")); + return output; +} + } diff --git a/icarus/heuristics/mega-drive.cpp b/icarus/heuristics/mega-drive.cpp index 2ebf87bf..40e02d53 100644 --- a/icarus/heuristics/mega-drive.cpp +++ b/icarus/heuristics/mega-drive.cpp @@ -1,15 +1,24 @@ -struct MegaDriveCartridge { - MegaDriveCartridge(string location, uint8_t* data, uint size); +namespace Heuristics { - string manifest; +struct MegaDrive : Heuristics { + MegaDrive(vector& data, string location); + explicit operator bool() const; + auto manifest() const -> string; -//private: - struct Information { - } information; +private: + vector& data; + string location; }; -MegaDriveCartridge::MegaDriveCartridge(string location, uint8_t* data, uint size) { - if(size < 0x200) return; +MegaDrive::MegaDrive(vector& data, string location) : data(data), location(location) { +} + +MegaDrive::operator bool() const { + return data.size() >= 0x200; +} + +auto MegaDrive::manifest() const -> string { + if(!operator bool()) return {}; string ramMode = "none"; @@ -40,32 +49,38 @@ MegaDriveCartridge::MegaDriveCartridge(string location, uint8_t* data, uint size string_vector regions; string region = slice((const char*)&data[0x1f0], 0, 16).trimRight(" "); if(!regions) { - if(region == "JAPAN" ) regions.append("ntsc-j"); - if(region == "EUROPE") regions.append("pal"); + if(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(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(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"); + regions.append("NTSC-J"); } - manifest.append("board region=", regions.left(), "\n"); - manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); - if(ramSize && ramMode != "none") - manifest.append(" ram name=save.ram size=0x", hex(ramSize), " offset=0x", hex(ramFrom), " mode=", ramMode, "\n"); - manifest.append("\n"); - manifest.append("information\n"); - manifest.append(" title: ", Location::prefix(location), "\n"); - manifest.append("\n"); - manifest.append("note: heuristically generated by icarus\n"); + string output; + output.append("game\n"); + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(" region: ", regions.left(), "\n"); + output.append(memory("ROM", data.size(), "program.rom")); + if(ramSize && ramMode != "none") { + output.append(memory("NVRAM", ramSize, "save.ram")); + output.append(" mode: ", ramMode, "\n"); + output.append(" offset: 0x", hex(ramFrom), "\n"); + } + return output; +} + } diff --git a/icarus/heuristics/pc-engine.cpp b/icarus/heuristics/pc-engine.cpp index b20156fd..43ead635 100644 --- a/icarus/heuristics/pc-engine.cpp +++ b/icarus/heuristics/pc-engine.cpp @@ -1,23 +1,35 @@ -struct PCEngineCartridge { - PCEngineCartridge(string location, uint8_t* data, uint size); +namespace Heuristics { - string manifest; +struct PCEngine : Heuristics { + PCEngine(vector& data, string location); + explicit operator bool() const; + auto manifest() const -> string; -//private: - struct Information { - } information; +private: + vector& data; + string location; }; -PCEngineCartridge::PCEngineCartridge(string location, uint8_t* data, uint size) { - //skip header - if((size & 0x1fff) == 512) data += 512, size -= 512; - - manifest.append("board\n"); - manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); - manifest.append("\n"); - manifest.append("information\n"); - manifest.append(" title: ", Location::prefix(location), "\n"); - manifest.append(" sha256: ", Hash::SHA256(data, size).digest(), "\n"); - manifest.append("\n"); - manifest.append("note: heuristically generated by icarus\n"); +PCEngine::PCEngine(vector& data, string location) : data(data), location(location) { + if((data.size() & 0x1fff) == 512) { + //remove header if present + memory::move(&data[0], &data[512], data.size() - 512); + data.resize(data.size() - 512); + } +} + +PCEngine::operator bool() const { + return (bool)data; +} + +auto PCEngine::manifest() const -> string { + string output; + output.append("game\n"); + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(memory("ROM", data.size(), "program.rom")); + return output; +} + } diff --git a/icarus/heuristics/sufami-turbo.cpp b/icarus/heuristics/sufami-turbo.cpp index 95852225..819f158d 100644 --- a/icarus/heuristics/sufami-turbo.cpp +++ b/icarus/heuristics/sufami-turbo.cpp @@ -1,6 +1,6 @@ namespace Heuristics { -struct SufamiTurbo { +struct SufamiTurbo : Heuristics { SufamiTurbo(vector& data, string location); explicit operator bool() const; @@ -19,27 +19,18 @@ SufamiTurbo::operator bool() const { } auto SufamiTurbo::manifest() const -> string { - if(!operator bool()) return ""; + if(!operator bool()) return {}; uint romSize = data[0x36] * 0x20000; //128KB uint ramSize = data[0x37] * 0x800; // 2KB string output; output.append("game\n"); - output.append(" name: ", Location::prefix(location), "\n"); - output.append(" label: ", Location::prefix(location), "\n"); - if(romSize) { - output.append(" memory\n"); - output.append(" type: ROM\n"); - output.append(" size: 0x", hex(data.size()), "\n"); - output.append(" name: program.rom\n"); - } - if(ramSize) { - output.append(" memory\n"); - output.append(" type: NVRAM\n"); - output.append(" size: 0x", hex(ramSize), "\n"); - output.append(" name: save.ram\n"); - } + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(memory("ROM", data.size(), "program.rom")); + if(ramSize) output.append(memory("NVRAM", ramSize, "save.ram")); return output; } diff --git a/icarus/heuristics/super-famicom.cpp b/icarus/heuristics/super-famicom.cpp index 7214ab10..acb115ac 100644 --- a/icarus/heuristics/super-famicom.cpp +++ b/icarus/heuristics/super-famicom.cpp @@ -1,6 +1,6 @@ namespace Heuristics { -struct SuperFamicom { +struct SuperFamicom : Heuristics { SuperFamicom(vector& data, string location); explicit operator bool() const; @@ -17,7 +17,6 @@ struct SuperFamicom { private: auto size() const -> uint { return data.size(); } - auto memory(string type, uint size, string name) const -> string; auto scoreHeader(uint address) -> uint; auto firmwareARM() const -> string; auto firmwareHITACHI() const -> string; @@ -123,15 +122,6 @@ auto SuperFamicom::manifest() const -> string { return output; } -auto SuperFamicom::memory(string type, uint size, string name) const -> string { - string output; - output.append(" memory\n"); - output.append(" type: ", type, "\n"); - output.append(" size: 0x", hex(size), "\n"); - output.append(" name: ", name, "\n"); - return output; -} - auto SuperFamicom::region() const -> string { string region; diff --git a/icarus/heuristics/supergrafx.cpp b/icarus/heuristics/supergrafx.cpp index 1b6f81ae..ad657e16 100644 --- a/icarus/heuristics/supergrafx.cpp +++ b/icarus/heuristics/supergrafx.cpp @@ -1,20 +1,30 @@ -struct SuperGrafxCartridge { - SuperGrafxCartridge(string location, uint8_t* data, uint size); +namespace Heuristics { - string manifest; +struct SuperGrafx : Heuristics { + SuperGrafx(vector& data, string location); + explicit operator bool() const; + auto manifest() const -> string; -//private: - struct Information { - } information; +private: + vector& data; + string location; }; -SuperGrafxCartridge::SuperGrafxCartridge(string location, uint8_t* data, uint size) { - manifest.append("board\n"); - manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); - manifest.append("\n"); - manifest.append("information\n"); - manifest.append(" title: ", Location::prefix(location), "\n"); - manifest.append(" sha256: ", Hash::SHA256(data, size).digest(), "\n"); - manifest.append("\n"); - manifest.append("note: heuristically generated by icarus\n"); +SuperGrafx::operator bool() const { + return (bool)data; +} + +SuperGrafx::SuperGrafx(vector& data, string location) : data(data), location(location) { +} + +auto SuperGrafx::manifest() const -> string { + string output; + output.append("game\n"); + output.append(" sha256: ", Hash::SHA256(data).digest(), "\n"); + output.append(" name: ", Location::prefix(location), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(memory("ROM", data.size(), "program.rom")); + return output; +} + } diff --git a/icarus/heuristics/wonderswan.cpp b/icarus/heuristics/wonderswan.cpp index 7491909b..90c5b5e7 100644 --- a/icarus/heuristics/wonderswan.cpp +++ b/icarus/heuristics/wonderswan.cpp @@ -1,53 +1,55 @@ -struct WonderSwanCartridge { - WonderSwanCartridge(string location, uint8_t* data, uint size); +namespace Heuristics { - string manifest; +struct WonderSwan : Heuristics { + WonderSwan(vector& buffer, string location); + explicit operator bool() const; + auto manifest() const -> string; -//private: - struct Information { - bool color; - - string ramType; - uint ramSize; - bool orientation; //0 = horizontal; 1 = vertical - bool hasRTC; - } information; +private: + vector& data; + string location; }; -WonderSwanCartridge::WonderSwanCartridge(string location, uint8_t* data, uint size) { - if(size < 0x10000) return; +WonderSwan::WonderSwan(vector& data, string location) : data(data), location(location) { +} - auto metadata = data + size - 16; +WonderSwan::operator bool() const { + return data.size() >= 0x10000; +} - information.color = metadata[7]; +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]) { - default: information.ramType = ""; information.ramSize = 0; break; - case 0x01: information.ramType = "sram"; information.ramSize = 8 * 1024; break; - case 0x02: information.ramType = "sram"; information.ramSize = 32 * 1024; break; - case 0x03: information.ramType = "sram"; information.ramSize = 128 * 1024; break; - case 0x04: information.ramType = "sram"; information.ramSize = 256 * 1024; break; - case 0x05: information.ramType = "sram"; information.ramSize = 512 * 1024; break; - case 0x10: information.ramType = "eeprom"; information.ramSize = 128; break; - case 0x20: information.ramType = "eeprom"; information.ramSize = 2048; break; - case 0x50: information.ramType = "eeprom"; information.ramSize = 1024; break; + case 0x01: ramType = "NVRAM"; ramSize = 8 * 1024; break; + case 0x02: ramType = "NVRAM"; ramSize = 32 * 1024; break; + case 0x03: ramType = "NVRAM"; ramSize = 128 * 1024; break; + case 0x04: ramType = "NVRAM"; ramSize = 256 * 1024; break; + case 0x05: ramType = "NVRAM"; 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; } - information.orientation = metadata[12] & 1; + 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(" name: ", Location::prefix(location), "\n"); + output.append(" label: ", Location::prefix(location), "\n"); + output.append(" orientation: ", !orientation ? "horizontal" : "vertical", "\n"); + output.append(memory("ROM", data.size(), "program.rom")); + if(ramType && ramSize) output.append(memory(ramType, ramSize, "save.ram")); + if(hasRTC) output.append(memory("NVRAM", 16, "rtc.ram")); + return output; +} - information.hasRTC = metadata[13] & 1; - - manifest.append("board\n"); - manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); - if(information.ramType && information.ramSize) - manifest.append(" ram name=save.ram type=", information.ramType, " size=0x", hex(information.ramSize), "\n"); - if(information.hasRTC) - manifest.append(" rtc name=rtc.ram size=16\n"); - manifest.append("\n"); - manifest.append("information\n"); - manifest.append(" title: ", Location::prefix(location), "\n"); - manifest.append(" orientation: ", !information.orientation ? "horizontal" : "vertical", "\n"); - manifest.append(" sha256: ", Hash::SHA256(data, size).digest(), "\n"); - manifest.append("\n"); - manifest.append("note: heuristically generated by icarus\n"); } diff --git a/icarus/icarus.cpp b/icarus/icarus.cpp index f8075763..db2e032e 100644 --- a/icarus/icarus.cpp +++ b/icarus/icarus.cpp @@ -15,6 +15,8 @@ auto locate(string name) -> string { #include "settings.cpp" Settings settings; +#include "heuristics/heuristics.hpp" +#include "heuristics/heuristics.cpp" #include "heuristics/famicom.cpp" #include "heuristics/super-famicom.cpp" #include "heuristics/master-system.cpp"