Trust the gamelist by not checking whether files exist and also improve the algorithm for parsing the gamelist.

This commit is contained in:
Alex Jones 2016-08-09 21:26:30 +01:00
parent 0ab75f8996
commit 454a18f9ec
6 changed files with 51 additions and 23 deletions

View file

@ -56,8 +56,7 @@ FileData::~FileData()
if(mParent) if(mParent)
mParent->removeChild(this); mParent->removeChild(this);
while(mChildren.size()) mChildren.clear();
delete mChildren.back();
} }
std::string FileData::getDisplayName() const std::string FileData::getDisplayName() const
@ -107,15 +106,20 @@ void FileData::addChild(FileData* file)
assert(mType == FOLDER); assert(mType == FOLDER);
assert(file->getParent() == NULL); assert(file->getParent() == NULL);
const std::string key = file->getPath().filename().string();
if (mChildrenByFilename.find(key) == mChildrenByFilename.end())
{
mChildrenByFilename[key] = file;
mChildren.push_back(file); mChildren.push_back(file);
file->mParent = this; file->mParent = this;
}
} }
void FileData::removeChild(FileData* file) void FileData::removeChild(FileData* file)
{ {
assert(mType == FOLDER); assert(mType == FOLDER);
assert(file->getParent() == this); assert(file->getParent() == this);
mChildrenByFilename.erase(file->getPath().filename().string());
for(auto it = mChildren.begin(); it != mChildren.end(); it++) for(auto it = mChildren.begin(); it != mChildren.end(); it++)
{ {
if(*it == file) if(*it == file)
@ -127,6 +131,7 @@ void FileData::removeChild(FileData* file)
// File somehow wasn't in our children. // File somehow wasn't in our children.
assert(false); assert(false);
} }
void FileData::sort(ComparisonFunction& comparator, bool ascending) void FileData::sort(ComparisonFunction& comparator, bool ascending)

View file

@ -1,7 +1,8 @@
#pragma once #pragma once
#include <vector> #include <unordered_map>
#include <string> #include <string>
#include <vector>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include "MetaData.h" #include "MetaData.h"
@ -39,6 +40,7 @@ public:
inline FileType getType() const { return mType; } inline FileType getType() const { return mType; }
inline const boost::filesystem::path& getPath() const { return mPath; } inline const boost::filesystem::path& getPath() const { return mPath; }
inline FileData* getParent() const { return mParent; } inline FileData* getParent() const { return mParent; }
inline const std::unordered_map<std::string, FileData*>& getChildrenByFilename() const { return mChildrenByFilename; }
inline const std::vector<FileData*>& getChildren() const { return mChildren; } inline const std::vector<FileData*>& getChildren() const { return mChildren; }
inline SystemData* getSystem() const { return mSystem; } inline SystemData* getSystem() const { return mSystem; }
@ -76,5 +78,6 @@ private:
boost::filesystem::path mPath; boost::filesystem::path mPath;
SystemData* mSystem; SystemData* mSystem;
FileData* mParent; FileData* mParent;
std::unordered_map<std::string,FileData*> mChildrenByFilename;
std::vector<FileData*> mChildren; std::vector<FileData*> mChildren;
}; };

View file

@ -8,13 +8,21 @@
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& path, FileType type) FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& path, FileType type, bool trustGamelist)
{ {
// first, verify that path is within the system's root folder // first, verify that path is within the system's root folder
FileData* root = system->getRootFolder(); FileData* root = system->getRootFolder();
fs::path relative;
bool contains = false; bool contains = false;
fs::path relative = removeCommonPath(path, root->getPath(), contains); if (trustGamelist)
{
relative = removeCommonPathUsingStrings(path, root->getPath(), contains);
}
else
{
relative = removeCommonPath(path, root->getPath(), contains);
}
if(!contains) if(!contains)
{ {
LOG(LogError) << "File path \"" << path << "\" is outside system path \"" << system->getStartPath() << "\""; LOG(LogError) << "File path \"" << path << "\" is outside system path \"" << system->getStartPath() << "\"";
@ -26,16 +34,12 @@ FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& pa
bool found = false; bool found = false;
while(path_it != relative.end()) while(path_it != relative.end())
{ {
const std::vector<FileData*>& children = treeNode->getChildren(); const std::unordered_map<std::string, FileData*>& children = treeNode->getChildrenByFilename();
found = false;
for(auto child_it = children.begin(); child_it != children.end(); child_it++) std::string key = path_it->string();
{ found = children.find(key) != children.end();
if((*child_it)->getPath().filename() == *path_it) if (found) {
{ treeNode = children.at(key);
treeNode = *child_it;
found = true;
break;
}
} }
// this is the end // this is the end
@ -79,6 +83,7 @@ FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& pa
void parseGamelist(SystemData* system) void parseGamelist(SystemData* system)
{ {
bool trustGamelist = Settings::getInstance()->getBool("ParseGamelistOnly");
std::string xmlpath = system->getGamelistPath(false); std::string xmlpath = system->getGamelistPath(false);
if(!boost::filesystem::exists(xmlpath)) if(!boost::filesystem::exists(xmlpath))
@ -114,13 +119,13 @@ void parseGamelist(SystemData* system)
{ {
fs::path path = resolvePath(fileNode.child("path").text().get(), relativeTo, false); fs::path path = resolvePath(fileNode.child("path").text().get(), relativeTo, false);
if(!boost::filesystem::exists(path)) if(!trustGamelist && !boost::filesystem::exists(path))
{ {
LOG(LogWarning) << "File \"" << path << "\" does not exist! Ignoring."; LOG(LogWarning) << "File \"" << path << "\" does not exist! Ignoring.";
continue; continue;
} }
FileData* file = findOrCreateFile(system, path, type); FileData* file = findOrCreateFile(system, path, type, trustGamelist);
if(!file) if(!file)
{ {
LOG(LogError) << "Error finding/creating FileData for \"" << path << "\", skipping."; LOG(LogError) << "Error finding/creating FileData for \"" << path << "\", skipping.";

View file

@ -198,7 +198,7 @@ void SystemData::populateFolder(FileData* folder)
populateFolder(newFolder); populateFolder(newFolder);
//ignore folders that do not contain games //ignore folders that do not contain games
if(newFolder->getChildren().size() == 0) if(newFolder->getChildrenByFilename().size() == 0)
delete newFolder; delete newFolder;
else else
folder->addChild(newFolder); folder->addChild(newFolder);
@ -311,7 +311,7 @@ bool SystemData::loadConfig()
path = genericPath.generic_string(); path = genericPath.generic_string();
SystemData* newSys = new SystemData(name, fullname, path, extensions, cmd, platformIds, themeFolder); SystemData* newSys = new SystemData(name, fullname, path, extensions, cmd, platformIds, themeFolder);
if(newSys->getRootFolder()->getChildren().size() == 0) if(newSys->getRootFolder()->getChildrenByFilename().size() == 0)
{ {
LOG(LogWarning) << "System \"" << name << "\" has no games! Ignoring it."; LOG(LogWarning) << "System \"" << name << "\" has no games! Ignoring it.";
delete newSys; delete newSys;

View file

@ -100,6 +100,20 @@ fs::path resolvePath(const fs::path& path, const fs::path& relativeTo, bool allo
return path; return path;
} }
fs::path removeCommonPathUsingStrings(const fs::path& path, const fs::path& relativeTo, bool& contains)
{
std::string pathStr = path.c_str();
std::string relativeToStr = relativeTo.c_str();
if (pathStr.find_first_of(relativeToStr) == 0) {
contains = true;
return pathStr.substr(relativeToStr.size() + 1);
}
else {
contains = false;
return path;
}
}
// example: removeCommonPath("/home/pi/roms/nes/foo/bar.nes", "/home/pi/roms/nes/") returns "foo/bar.nes" // example: removeCommonPath("/home/pi/roms/nes/foo/bar.nes", "/home/pi/roms/nes/") returns "foo/bar.nes"
fs::path removeCommonPath(const fs::path& path, const fs::path& relativeTo, bool& contains) fs::path removeCommonPath(const fs::path& path, const fs::path& relativeTo, bool& contains)
{ {

View file

@ -19,6 +19,7 @@ float round(float num);
std::string getCanonicalPath(const std::string& str); std::string getCanonicalPath(const std::string& str);
boost::filesystem::path removeCommonPathUsingStrings(const boost::filesystem::path& path, const boost::filesystem::path& relativeTo, bool& contains);
// example: removeCommonPath("/home/pi/roms/nes/foo/bar.nes", "/home/pi/roms/nes/") returns "foo/bar.nes" // example: removeCommonPath("/home/pi/roms/nes/foo/bar.nes", "/home/pi/roms/nes/") returns "foo/bar.nes"
boost::filesystem::path removeCommonPath(const boost::filesystem::path& path, const boost::filesystem::path& relativeTo, bool& contains); boost::filesystem::path removeCommonPath(const boost::filesystem::path& path, const boost::filesystem::path& relativeTo, bool& contains);