2020-06-06 11:10:33 +00:00
|
|
|
//
|
2020-06-21 12:25:28 +00:00
|
|
|
// MameNames.cpp
|
2020-06-06 11:10:33 +00:00
|
|
|
//
|
2020-06-21 12:25:28 +00:00
|
|
|
// Provides expanded game names based on short MAME name arguments. Also contains
|
|
|
|
// functions to check whether a passed argument is a MAME BIOS or a MAME device.
|
|
|
|
// The data sources are stored in the .emulationstation/resources directory
|
|
|
|
// as the files mamebioses.xml, mamedevices.xml and mamenames.xml.
|
2020-06-06 11:10:33 +00:00
|
|
|
//
|
|
|
|
|
2018-02-09 17:23:58 +00:00
|
|
|
#include "MameNames.h"
|
|
|
|
|
|
|
|
#include "resources/ResourceManager.h"
|
|
|
|
#include "utils/FileSystemUtil.h"
|
2020-06-06 11:10:33 +00:00
|
|
|
#include "utils/StringUtil.h"
|
2018-02-09 17:23:58 +00:00
|
|
|
#include "Log.h"
|
2020-06-24 15:38:41 +00:00
|
|
|
#include <pugixml.hpp>
|
2018-02-09 17:23:58 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
MameNames* MameNames::sInstance = nullptr;
|
|
|
|
|
|
|
|
void MameNames::init()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!sInstance)
|
|
|
|
sInstance = new MameNames();
|
2020-06-06 11:10:33 +00:00
|
|
|
}
|
2018-02-09 17:23:58 +00:00
|
|
|
|
|
|
|
void MameNames::deinit()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (sInstance) {
|
|
|
|
delete sInstance;
|
|
|
|
sInstance = nullptr;
|
|
|
|
}
|
2020-06-06 11:10:33 +00:00
|
|
|
}
|
2018-02-09 17:23:58 +00:00
|
|
|
|
|
|
|
MameNames* MameNames::getInstance()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!sInstance)
|
|
|
|
sInstance = new MameNames();
|
2018-02-09 17:23:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
return sInstance;
|
2020-06-06 11:10:33 +00:00
|
|
|
}
|
2018-02-09 17:23:58 +00:00
|
|
|
|
|
|
|
MameNames::MameNames()
|
|
|
|
{
|
2020-06-21 17:35:43 +00:00
|
|
|
std::string xmlpath = ResourceManager::getInstance()->getResourcePath(":/MAME/mamenames.xml");
|
2018-02-09 17:23:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!Utils::FileSystem::exists(xmlpath))
|
|
|
|
return;
|
2018-02-09 17:23:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"...";
|
2018-02-09 17:23:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
pugi::xml_document doc;
|
2020-07-10 16:32:23 +00:00
|
|
|
#ifdef _WIN64
|
|
|
|
pugi::xml_parse_result result =
|
|
|
|
doc.load_file(Utils::String::stringToWideString(xmlpath).c_str());
|
|
|
|
#else
|
2020-06-21 12:25:28 +00:00
|
|
|
pugi::xml_parse_result result = doc.load_file(xmlpath.c_str());
|
2020-07-10 16:32:23 +00:00
|
|
|
#endif
|
2018-02-09 17:23:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!result) {
|
|
|
|
LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n "
|
|
|
|
<< result.description();
|
|
|
|
return;
|
|
|
|
}
|
2018-02-09 17:23:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
for (pugi::xml_node gameNode = doc.child("game");
|
|
|
|
gameNode; gameNode = gameNode.next_sibling("game")) {
|
|
|
|
NamePair namePair = {
|
|
|
|
gameNode.child("mamename").text().get(),
|
|
|
|
gameNode.child("realname").text().get()
|
|
|
|
};
|
|
|
|
mNamePairs.push_back(namePair);
|
|
|
|
}
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Read BIOS file.
|
2020-06-21 17:35:43 +00:00
|
|
|
xmlpath = ResourceManager::getInstance()->getResourcePath(":/MAME/mamebioses.xml");
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!Utils::FileSystem::exists(xmlpath))
|
|
|
|
return;
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"...";
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-07-10 16:32:23 +00:00
|
|
|
#ifdef _WIN64
|
|
|
|
result = doc.load_file(Utils::String::stringToWideString(xmlpath).c_str());
|
|
|
|
#else
|
2020-06-21 12:25:28 +00:00
|
|
|
result = doc.load_file(xmlpath.c_str());
|
2020-07-10 16:32:23 +00:00
|
|
|
#endif
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!result) {
|
|
|
|
LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n "
|
|
|
|
<< result.description();
|
|
|
|
return;
|
|
|
|
}
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
for (pugi::xml_node biosNode = doc.child("bios");
|
|
|
|
biosNode; biosNode = biosNode.next_sibling("bios")) {
|
|
|
|
std::string bios = biosNode.text().get();
|
|
|
|
mMameBioses.push_back(bios);
|
|
|
|
}
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-06-26 15:17:35 +00:00
|
|
|
// Read device file.
|
2020-06-21 17:35:43 +00:00
|
|
|
xmlpath = ResourceManager::getInstance()->getResourcePath(":/MAME/mamedevices.xml");
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!Utils::FileSystem::exists(xmlpath))
|
|
|
|
return;
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"...";
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-07-10 16:32:23 +00:00
|
|
|
#ifdef _WIN64
|
|
|
|
result = doc.load_file(Utils::String::stringToWideString(xmlpath).c_str());
|
|
|
|
#else
|
2020-06-21 12:25:28 +00:00
|
|
|
result = doc.load_file(xmlpath.c_str());
|
2020-07-10 16:32:23 +00:00
|
|
|
#endif
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!result) {
|
|
|
|
LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n "
|
|
|
|
<< result.description();
|
|
|
|
return;
|
|
|
|
}
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
for (pugi::xml_node deviceNode = doc.child("device");
|
|
|
|
deviceNode; deviceNode = deviceNode.next_sibling("device")) {
|
|
|
|
std::string device = deviceNode.text().get();
|
|
|
|
mMameDevices.push_back(device);
|
|
|
|
}
|
2020-06-26 15:17:35 +00:00
|
|
|
}
|
2018-02-09 17:23:58 +00:00
|
|
|
|
|
|
|
MameNames::~MameNames()
|
|
|
|
{
|
2020-06-06 11:10:33 +00:00
|
|
|
}
|
2018-02-09 17:23:58 +00:00
|
|
|
|
|
|
|
std::string MameNames::getRealName(const std::string& _mameName)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
size_t start = 0;
|
|
|
|
size_t end = mNamePairs.size();
|
|
|
|
|
|
|
|
while (start < end) {
|
|
|
|
const size_t index = (start + end) / 2;
|
|
|
|
const int compare = strcmp(mNamePairs[index].mameName.c_str(), _mameName.c_str());
|
|
|
|
|
|
|
|
if (compare < 0)
|
|
|
|
start = index + 1;
|
|
|
|
else if (compare > 0)
|
|
|
|
end = index;
|
|
|
|
else
|
|
|
|
return mNamePairs[index].realName;
|
|
|
|
}
|
|
|
|
|
|
|
|
return _mameName;
|
2020-06-06 11:10:33 +00:00
|
|
|
}
|
2018-02-09 17:23:58 +00:00
|
|
|
|
2020-06-06 11:10:33 +00:00
|
|
|
std::string MameNames::getCleanName(const std::string& _mameName)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
std::string cleanName = Utils::String::removeParenthesis(getRealName(_mameName));
|
|
|
|
return cleanName;
|
2020-06-06 11:10:33 +00:00
|
|
|
}
|
2018-05-10 01:29:46 +00:00
|
|
|
|
|
|
|
const bool MameNames::isBios(const std::string& _biosName)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
return MameNames::find(mMameBioses, _biosName);
|
2020-06-06 11:10:33 +00:00
|
|
|
}
|
2018-05-10 01:29:46 +00:00
|
|
|
|
|
|
|
const bool MameNames::isDevice(const std::string& _deviceName)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
return MameNames::find(mMameDevices, _deviceName);
|
2019-08-25 15:23:02 +00:00
|
|
|
|
2020-06-06 11:10:33 +00:00
|
|
|
}
|
2018-05-10 01:29:46 +00:00
|
|
|
|
|
|
|
const bool MameNames::find(std::vector<std::string> devices, const std::string& name)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
size_t start = 0;
|
|
|
|
size_t end = devices.size();
|
|
|
|
|
|
|
|
while (start < end) {
|
|
|
|
const size_t index = (start + end) / 2;
|
|
|
|
const int compare = strcmp(devices[index].c_str(), name.c_str());
|
|
|
|
|
|
|
|
if (compare < 0)
|
|
|
|
start = index + 1;
|
|
|
|
else if (compare > 0)
|
|
|
|
end = index;
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2018-05-10 01:29:46 +00:00
|
|
|
}
|