mirror of https://github.com/PCSX2/pcsx2.git
GameDB: Hopefully resolve possible unicode filepath issues
GameDB: Big cleanup as a result of review feedback
This commit is contained in:
parent
e90046d8a2
commit
4b975efa23
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "fmt/core.h"
|
||||
#include "yaml-cpp/yaml.h"
|
||||
#include <fstream>
|
||||
|
||||
std::string GameDatabaseSchema::GameEntry::memcardFiltersAsString()
|
||||
{
|
||||
|
@ -36,59 +37,35 @@ std::string GameDatabaseSchema::GameEntry::memcardFiltersAsString()
|
|||
return filters;
|
||||
}
|
||||
|
||||
std::string YamlGameDatabaseImpl::safeGetString(const YAML::Node& n, std::string key, std::string def)
|
||||
std::vector<std::string> YamlGameDatabaseImpl::convertMultiLineStringToVector(const std::string multiLineString)
|
||||
{
|
||||
if (!n[key])
|
||||
return def;
|
||||
return n[key].as<std::string>();
|
||||
}
|
||||
|
||||
int YamlGameDatabaseImpl::safeGetInt(const YAML::Node& n, std::string key, int def)
|
||||
{
|
||||
if (!n[key])
|
||||
return def;
|
||||
return n[key].as<int>();
|
||||
}
|
||||
|
||||
std::vector<std::string> YamlGameDatabaseImpl::safeGetMultilineString(const YAML::Node& n, std::string key, std::vector<std::string> def)
|
||||
{
|
||||
if (!n[key])
|
||||
return def;
|
||||
|
||||
std::vector<std::string> lines;
|
||||
|
||||
std::istringstream stream(safeGetString(n, key));
|
||||
std::istringstream stream(multiLineString);
|
||||
std::string line;
|
||||
|
||||
while(std::getline(stream, line)) {
|
||||
while (std::getline(stream, line))
|
||||
{
|
||||
lines.push_back(line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
std::vector<std::string> YamlGameDatabaseImpl::safeGetStringList(const YAML::Node& n, std::string key, std::vector<std::string> def)
|
||||
{
|
||||
if (!n[key])
|
||||
return def;
|
||||
return n[key].as<std::vector<std::string>>();
|
||||
}
|
||||
|
||||
GameDatabaseSchema::GameEntry YamlGameDatabaseImpl::entryFromYaml(const std::string serial, const YAML::Node& node)
|
||||
{
|
||||
GameDatabaseSchema::GameEntry gameEntry;
|
||||
try
|
||||
{
|
||||
gameEntry.name = safeGetString(node, "name");
|
||||
gameEntry.region = safeGetString(node, "region");
|
||||
gameEntry.compat = static_cast<GameDatabaseSchema::Compatibility>(safeGetInt(node, "compat", enum_cast(gameEntry.compat)));
|
||||
gameEntry.eeRoundMode = static_cast<GameDatabaseSchema::RoundMode>(safeGetInt(node, "eeRoundMode", enum_cast(gameEntry.eeRoundMode)));
|
||||
gameEntry.vuRoundMode = static_cast<GameDatabaseSchema::RoundMode>(safeGetInt(node, "vuRoundMode", enum_cast(gameEntry.vuRoundMode)));
|
||||
gameEntry.eeClampMode = static_cast<GameDatabaseSchema::ClampMode>(safeGetInt(node, "eeClampMode", enum_cast(gameEntry.eeClampMode)));
|
||||
gameEntry.vuClampMode = static_cast<GameDatabaseSchema::ClampMode>(safeGetInt(node, "vuClampMode", enum_cast(gameEntry.vuClampMode)));
|
||||
gameEntry.name = node["name"].as<std::string>("");
|
||||
gameEntry.region = node["region"].as<std::string>("");
|
||||
gameEntry.compat = static_cast<GameDatabaseSchema::Compatibility>(node["compat"].as<int>(enum_cast(gameEntry.compat)));
|
||||
gameEntry.eeRoundMode = static_cast<GameDatabaseSchema::RoundMode>(node["eeRoundMode"].as<int>(enum_cast(gameEntry.eeRoundMode)));
|
||||
gameEntry.vuRoundMode = static_cast<GameDatabaseSchema::RoundMode>(node["vuRoundMode"].as<int>(enum_cast(gameEntry.vuRoundMode)));
|
||||
gameEntry.eeClampMode = static_cast<GameDatabaseSchema::ClampMode>(node["eeClampMode"].as<int>(enum_cast(gameEntry.eeClampMode)));
|
||||
gameEntry.vuClampMode = static_cast<GameDatabaseSchema::ClampMode>(node["vuClampMode"].as<int>(enum_cast(gameEntry.vuClampMode)));
|
||||
|
||||
// Validate game fixes, invalid ones will be dropped!
|
||||
for (std::string fix : safeGetStringList(node, "gameFixes"))
|
||||
for (std::string& fix : node["gameFixes"].as<std::vector<std::string>>(std::vector<std::string>()))
|
||||
{
|
||||
bool fixValidated = false;
|
||||
for (GamefixId id = GamefixId_FIRST; id < pxEnumEnd; ++id)
|
||||
|
@ -112,10 +89,10 @@ GameDatabaseSchema::GameEntry YamlGameDatabaseImpl::entryFromYaml(const std::str
|
|||
|
||||
if (YAML::Node speedHacksNode = node["speedHacks"])
|
||||
{
|
||||
for (YAML::const_iterator entry = speedHacksNode.begin(); entry != speedHacksNode.end(); entry++)
|
||||
for (const auto& entry : speedHacksNode)
|
||||
{
|
||||
// Validate speedhacks, invalid ones will be skipped!
|
||||
std::string speedHack = entry->first.as<std::string>();
|
||||
std::string speedHack = entry.first.as<std::string>();
|
||||
|
||||
// NOTE - currently only 1 speedhack!
|
||||
if (speedHack != "mvuFlagSpeedHack")
|
||||
|
@ -124,32 +101,37 @@ GameDatabaseSchema::GameEntry YamlGameDatabaseImpl::entryFromYaml(const std::str
|
|||
continue;
|
||||
}
|
||||
|
||||
gameEntry.speedHacks[speedHack] = entry->second.as<int>();
|
||||
gameEntry.speedHacks[speedHack] = entry.second.as<int>();
|
||||
}
|
||||
}
|
||||
|
||||
gameEntry.memcardFilters = safeGetStringList(node, "memcardFilters");
|
||||
gameEntry.memcardFilters = node["memcardFilters"].as<std::vector<std::string>>(std::vector<std::string>());
|
||||
|
||||
if (YAML::Node patches = node["patches"])
|
||||
{
|
||||
for (YAML::const_iterator entry = patches.begin(); entry != patches.end(); entry++)
|
||||
for (const auto& entry : patches)
|
||||
{
|
||||
std::string crc = entry->first.as<std::string>();
|
||||
YAML::Node patchNode = entry->second;
|
||||
std::string crc = entry.first.as<std::string>();
|
||||
YAML::Node patchNode = entry.second;
|
||||
|
||||
GameDatabaseSchema::Patch patchCol;
|
||||
|
||||
patchCol.author = safeGetString(patchNode, "author");
|
||||
patchCol.patchLines = safeGetMultilineString(patchNode, "content");
|
||||
patchCol.author = patchNode["author"].as<std::string>("");
|
||||
patchCol.patchLines = convertMultiLineStringToVector(patchNode["content"].as<std::string>(""));
|
||||
gameEntry.patches[crc] = patchCol;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (YAML::RepresentationException e)
|
||||
catch (const YAML::RepresentationException& e)
|
||||
{
|
||||
Console.Error(fmt::format("[GameDB] Invalid GameDB syntax detected on serial: '{}'. Error Details - {}", serial, e.msg));
|
||||
gameEntry.isValid = false;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Console.Error(fmt::format("[GameDB] Unexpected error occurred when reading serial: '{}'. Error Details - {}", serial, e.what()));
|
||||
gameEntry.isValid = false;
|
||||
}
|
||||
return gameEntry;
|
||||
}
|
||||
|
||||
|
@ -168,23 +150,28 @@ int YamlGameDatabaseImpl::numGames()
|
|||
return gameDb.size();
|
||||
}
|
||||
|
||||
bool YamlGameDatabaseImpl::initDatabase(const std::string filePath)
|
||||
bool YamlGameDatabaseImpl::initDatabase(std::ifstream& stream)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!stream)
|
||||
{
|
||||
Console.Error("[GameDB] Unable to open GameDB file.");
|
||||
return false;
|
||||
}
|
||||
// yaml-cpp has memory leak issues if you persist and modify a YAML::Node
|
||||
// convert to a map and throw it away instead!
|
||||
YAML::Node data = YAML::LoadFile(filePath);
|
||||
for (YAML::const_iterator entry = data.begin(); entry != data.end(); entry++)
|
||||
YAML::Node data = YAML::Load(stream);
|
||||
for (const auto& entry : data)
|
||||
{
|
||||
// we don't want to throw away the entire GameDB file if a single entry is made, but we do
|
||||
// want to yell about it so it can be corrected
|
||||
// we don't want to throw away the entire GameDB file if a single entry is made incorrectly,
|
||||
// but we do want to yell about it so it can be corrected
|
||||
try
|
||||
{
|
||||
std::string serial = entry->first.as<std::string>();
|
||||
gameDb[serial] = entryFromYaml(serial, entry->second);
|
||||
std::string serial = entry.first.as<std::string>();
|
||||
gameDb[serial] = entryFromYaml(serial, entry.second);
|
||||
}
|
||||
catch (YAML::RepresentationException e)
|
||||
catch (const YAML::RepresentationException& e)
|
||||
{
|
||||
Console.Error(fmt::format("[GameDB] Invalid GameDB syntax detected. Error Details - {}", e.msg));
|
||||
}
|
||||
|
@ -192,7 +179,7 @@ bool YamlGameDatabaseImpl::initDatabase(const std::string filePath)
|
|||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Console.Error(fmt::format("Error occured when initializing GameDB: {}", e.what()));
|
||||
Console.Error(fmt::format("[GameDB] Error occured when initializing GameDB: {}", e.what()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ public:
|
|||
class IGameDatabase
|
||||
{
|
||||
public:
|
||||
virtual bool initDatabase(const std::string filePath) = 0;
|
||||
virtual bool initDatabase(std::ifstream& stream) = 0;
|
||||
virtual GameDatabaseSchema::GameEntry findGame(const std::string serial) = 0;
|
||||
virtual int numGames() = 0;
|
||||
};
|
||||
|
@ -92,7 +92,7 @@ public:
|
|||
class YamlGameDatabaseImpl : public IGameDatabase
|
||||
{
|
||||
public:
|
||||
bool initDatabase(const std::string filePath) override;
|
||||
bool initDatabase(std::ifstream& stream) override;
|
||||
GameDatabaseSchema::GameEntry findGame(const std::string serial) override;
|
||||
int numGames() override;
|
||||
|
||||
|
@ -100,11 +100,7 @@ private:
|
|||
std::unordered_map<std::string, GameDatabaseSchema::GameEntry> gameDb;
|
||||
GameDatabaseSchema::GameEntry entryFromYaml(const std::string serial, const YAML::Node& node);
|
||||
|
||||
// TODO - config - move these into a generic library
|
||||
std::string safeGetString(const YAML::Node& n, std::string key, std::string def = "");
|
||||
int safeGetInt(const YAML::Node& n, std::string key, int def = 0);
|
||||
std::vector<std::string> safeGetMultilineString(const YAML::Node& n, std::string key, std::vector<std::string> def = {});
|
||||
std::vector<std::string> safeGetStringList(const YAML::Node& n, std::string key, std::vector<std::string> def = {});
|
||||
std::vector<std::string> convertMultiLineStringToVector(const std::string multiLineString);
|
||||
};
|
||||
|
||||
extern IGameDatabase* AppHost_GetGameDatabase();
|
||||
|
|
|
@ -20,10 +20,21 @@
|
|||
|
||||
#include <wx/stdpaths.h>
|
||||
#include "fmt/core.h"
|
||||
#include <fstream>
|
||||
|
||||
std::ifstream AppGameDatabase::getFileAsStream(const wxString& file)
|
||||
{
|
||||
// TODO - config - refactor with std::filesystem/ghc::filesystem
|
||||
#ifdef _WIN32
|
||||
return std::ifstream(file.wc_str());
|
||||
#else
|
||||
return std::ifstream(file.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
AppGameDatabase& AppGameDatabase::LoadFromFile(const wxString& _file)
|
||||
{
|
||||
// TODO - config - kill this with fire with std::filesystem
|
||||
// TODO - config - refactor with std::filesystem/ghc::filesystem
|
||||
|
||||
wxString file(_file);
|
||||
if (wxFileName(file).IsRelative())
|
||||
|
@ -45,21 +56,22 @@ AppGameDatabase& AppGameDatabase::LoadFromFile(const wxString& _file)
|
|||
|
||||
if (!wxFileExists(file))
|
||||
{
|
||||
Console.Error(L"(GameDB) Database Not Found! [%s]", WX_STR(file));
|
||||
Console.Error(L"[GameDB] Database Not Found! [%s]", WX_STR(file));
|
||||
return *this;
|
||||
}
|
||||
|
||||
u64 qpc_Start = GetCPUTicks();
|
||||
const u64 qpc_Start = GetCPUTicks();
|
||||
|
||||
if (!this->initDatabase(std::string(file)))
|
||||
std::ifstream fileStream = getFileAsStream(file);
|
||||
if (!this->initDatabase(fileStream))
|
||||
{
|
||||
Console.Error(L"(GameDB) Database could not be loaded successfully");
|
||||
Console.Error(L"[GameDB] Database could not be loaded successfully");
|
||||
return *this;
|
||||
}
|
||||
|
||||
u64 qpc_end = GetCPUTicks();
|
||||
const u64 qpc_end = GetCPUTicks();
|
||||
|
||||
Console.WriteLn(fmt::format("(GameDB) {} games on record (loaded in {}ms)", this->numGames(),
|
||||
Console.WriteLn(fmt::format("[GameDB] {} games on record (loaded in {}ms)", this->numGames(),
|
||||
(u32)(((qpc_end - qpc_Start) * 1000) / GetTickFrequency())));
|
||||
|
||||
return *this;
|
||||
|
|
|
@ -33,6 +33,9 @@ public:
|
|||
}
|
||||
|
||||
AppGameDatabase& LoadFromFile(const wxString& file = Path::Combine(PathDefs::GetProgramDataDir(), wxFileName(L"GameIndex.yaml")));
|
||||
|
||||
private:
|
||||
std::ifstream getFileAsStream(const wxString& file);
|
||||
};
|
||||
|
||||
static wxString compatToStringWX(GameDatabaseSchema::Compatibility compat)
|
||||
|
|
Loading…
Reference in New Issue