improve built in extraction detection (#2865)

This commit is contained in:
Adam Bird 2023-05-09 23:39:57 -04:00 committed by GitHub
parent 72358eb4d7
commit c70bdb7700
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 118 additions and 43 deletions

View File

@ -54,10 +54,10 @@ static constexpr uint32_t OOT_PAL_GC_DBG2 = 0x87121EFE; // 03-13-2002 build
static constexpr uint32_t OOT_PAL_GC_MQ_DBG = 0x917D18F6;
static const std::unordered_map<uint32_t, const char*> verMap = {
{ OOT_PAL_GC, "Pal Gamecube" },
{ OOT_PAL_GC_DBG1, "PAL Debug 1" },
{ OOT_PAL_GC_DBG2, "PAL Debug 2" },
{ OOT_PAL_GC_MQ_DBG, "PAL MQ Debug" },
{ OOT_PAL_GC, "PAL GameCube" },
{ OOT_PAL_GC_DBG1, "PAL GameCube Debug 1" },
{ OOT_PAL_GC_DBG2, "PAL GameCube Debug 2" },
{ OOT_PAL_GC_MQ_DBG, "PAL GameCube MQ Debug" },
};
// TODO only check the first 54MB of the rom.
@ -156,6 +156,40 @@ void Extractor::SetRomInfo(const std::string& path) {
mCurRomSize = GetCurRomSize();
}
void Extractor::FilterRoms(std::vector<std::string>& roms, RomSearchMode searchMode) {
std::ifstream inFile;
std::vector<std::string>::iterator it = roms.begin();
while (it != roms.end()) {
std::string rom = *it;
SetRomInfo(rom);
// Skip. We will handle rom size errors later on after filtering
if (!ValidateRomSize()) {
it++;
continue;
}
inFile.open(rom, std::ios::in | std::ios::binary);
inFile.read((char*)mRomData.get(), mCurRomSize);
inFile.clear();
inFile.close();
RomToBigEndian(mRomData.get(), mCurRomSize);
// Rom doesn't claim to be valid
// Game type doesn't match search mode
if (!verMap.contains(GetRomVerCrc()) ||
(searchMode == RomSearchMode::Vanilla && IsMasterQuest()) ||
(searchMode == RomSearchMode::MQ && !IsMasterQuest())) {
it = roms.erase(it);
continue;
}
it++;
}
}
void Extractor::GetRoms(std::vector<std::string>& roms) {
#ifdef _WIN32
WIN32_FIND_DATAA ffd;
@ -258,6 +292,7 @@ bool Extractor::GetRomPathFromBox() {
mCurRomSize = GetCurRomSize();
return true;
}
uint32_t Extractor::GetRomVerCrc() const {
return BSWAP32(((uint32_t*)mRomData.get())[4]);
}
@ -303,28 +338,73 @@ bool Extractor::ValidateRom(bool skipCrcTextBox) {
return true;
}
bool Extractor::Run() {
bool Extractor::ManuallySearchForRom() {
std::ifstream inFile;
if (!GetRomPathFromBox()) {
ShowErrorBox("No rom selected", "No Rom selected. Exiting");
return false;
}
inFile.open(mCurrentRomPath, std::ios::in | std::ios::binary);
if (!inFile.is_open()) {
return false; // TODO Handle error
}
inFile.read((char*)mRomData.get(), mCurRomSize);
inFile.close();
RomToBigEndian(mRomData.get(), mCurRomSize);
if (!ValidateRom()) {
return false;
}
return true;
}
bool Extractor::ManuallySearchForRomMatchingType(RomSearchMode searchMode) {
if (!ManuallySearchForRom()) {
return false;
}
char msgBuf[150];
snprintf(msgBuf, 150, "The selected rom does not match the expected game type\nExpected type: %s.\n\nDo you want to search again?",
searchMode == RomSearchMode::MQ ? "Master Quest" : "Vanilla");
while ((searchMode == RomSearchMode::Vanilla && IsMasterQuest()) ||
(searchMode == RomSearchMode::MQ && !IsMasterQuest())) {
int ret = ShowYesNoBox("Wrong Game Type", msgBuf);
switch (ret) {
case IDYES:
if (!ManuallySearchForRom()) {
return false;
}
continue;
case IDNO:
return false;
default:
UNREACHABLE;
break;
}
}
return true;
}
bool Extractor::Run(RomSearchMode searchMode) {
std::vector<std::string> roms;
std::ifstream inFile;
uint32_t verCrc;
GetRoms(roms);
FilterRoms(roms, searchMode);
if (roms.empty()) {
int ret = ShowYesNoBox("No roms found", "No roms found. Look for one?");
switch (ret) {
case IDYES:
if (!GetRomPathFromBox()) {
ShowErrorBox("No rom selected", "No rom selected. Exiting");
return false;
}
inFile.open(mCurrentRomPath, std::ios::in | std::ios::binary);
if (!inFile.is_open()) {
return false; // TODO Handle error
}
inFile.read((char*)mRomData.get(), mCurRomSize);
if (!ValidateRom()) {
if (!ManuallySearchForRomMatchingType(searchMode)) {
return false;
}
break;
@ -338,27 +418,21 @@ bool Extractor::Run() {
}
for (const auto& rom : roms) {
int option;
SetRomInfo(rom);
if (inFile.is_open()) {
inFile.close();
}
inFile.open(rom, std::ios::in | std::ios::binary);
if (!ValidateRomSize()) {
ShowSizeErrorBox();
continue;
}
inFile.open(rom, std::ios::in | std::ios::binary);
inFile.read((char*)mRomData.get(), mCurRomSize);
inFile.clear();
inFile.close();
RomToBigEndian(mRomData.get(), mCurRomSize);
verCrc = GetRomVerCrc();
// Rom doesn't claim to be valid
if (!verMap.contains(verCrc)) {
continue;
}
int option = ShowRomPickBox(GetRomVerCrc());
option = ShowRomPickBox(verCrc);
if (option == (int)ButtonId::YES) {
if (!ValidateRom(true)) {
if (rom == roms.back()) {
@ -371,21 +445,11 @@ bool Extractor::Run() {
}
break;
} else if (option == (int)ButtonId::FIND) {
if (!GetRomPathFromBox()) {
ShowErrorBox("No rom selected", "No Rom selected. Exiting");
return false;
}
inFile.open(mCurrentRomPath, std::ios::in | std::ios::binary);
if (!inFile.is_open()) {
return false; // TODO Handle error
}
inFile.read((char*)mRomData.get(), mCurRomSize);
if (!ValidateRom()) {
if (!ManuallySearchForRomMatchingType(searchMode)) {
return false;
}
break;
} else if (option == (int)ButtonId::NO) {
inFile.close();
if (rom == roms.back()) {
ShowErrorBox("No rom provided", "No rom provided. Exiting");
return false;

View File

@ -19,6 +19,12 @@ static constexpr size_t MB32 = 32 * MB_BASE;
static constexpr size_t MB54 = 54 * MB_BASE;
static constexpr size_t MB64 = 64 * MB_BASE;
enum class RomSearchMode {
Both = 0,
Vanilla = 1,
MQ = 2,
};
class Extractor {
std::unique_ptr<unsigned char[]> mRomData = std::make_unique<unsigned char[]>(MB64);
std::string mCurrentRomPath;
@ -33,21 +39,24 @@ class Extractor {
bool ValidateRom(bool skipCrcBox = false);
const char* GetZapdVerStr() const;
bool IsMasterQuest() const;
void SetRomInfo(const std::string& path);
void FilterRoms(std::vector<std::string>& roms, RomSearchMode searchMode);
void GetRoms(std::vector<std::string>& roms);
void ShowSizeErrorBox() const;
void ShowCrcErrorBox() const;
int ShowRomPickBox(uint32_t verCrc) const;
bool ManuallySearchForRom();
bool ManuallySearchForRomMatchingType(RomSearchMode searchMode);
public:
//TODO create some kind of abstraction for message boxes.
static int ShowYesNoBox(const char* title, const char* text);
static void ShowErrorBox(const char* title, const char* text);
bool IsMasterQuest() const;
bool Run();
bool Run(RomSearchMode searchMode = RomSearchMode::Both);
bool CallZapd();
const char* GetZapdStr();
};

View File

@ -710,6 +710,7 @@ extern "C" void InitOTR() {
#if not defined (__SWITCH__) && not defined(__WIIU__)
if (!std::filesystem::exists(LUS::Context::GetPathRelativeToAppDirectory("oot-mq.otr")) &&
!std::filesystem::exists(LUS::Context::GetPathRelativeToAppDirectory("oot.otr"))){
bool generatedOtrIsMQ = false;
if (Extractor::ShowYesNoBox("No OTR Files", "No OTR files found. Generate one now?") == IDYES) {
Extractor extract;
if (!extract.Run()) {
@ -717,12 +718,13 @@ extern "C" void InitOTR() {
exit(1);
}
extract.CallZapd();
generatedOtrIsMQ = extract.IsMasterQuest();
} else {
exit(1);
}
if (Extractor::ShowYesNoBox("Extraction Complete", "ROM Extracted. Extract another?") == IDYES) {
Extractor extract;
if (!extract.Run()) {
if (!extract.Run(generatedOtrIsMQ ? RomSearchMode::Vanilla : RomSearchMode::MQ)) {
Extractor::ShowErrorBox("Error", "An error occured, an OTR file may have been generated by a different step. Continuing...");
} else {
extract.CallZapd();