Made metadata image paths relative too.

Moved some path functions into Util.h/.cpp.
This commit is contained in:
Aloshi 2014-06-02 13:55:00 -05:00
parent 37db651ffa
commit fac09b6fac
5 changed files with 150 additions and 94 deletions

View file

@ -4,65 +4,10 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include "Log.h" #include "Log.h"
#include "Settings.h" #include "Settings.h"
#include "Util.h"
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
// expands "./my/path.sfc" to "[relativeTo]/my/path.sfc"
fs::path resolvePath(const fs::path& path, const fs::path& relativeTo)
{
if(path.begin() != path.end() && *path.begin() == fs::path("."))
{
fs::path ret = relativeTo;
for(auto it = ++path.begin(); it != path.end(); ++it)
ret /= *it;
return ret;
}
return path;
}
// 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 p = fs::canonical(path);
fs::path r = fs::canonical(relativeTo);
if(p.root_path() != r.root_path())
{
contains = false;
return p;
}
fs::path result;
// find point of divergence
auto itr_path = p.begin();
auto itr_relative_to = r.begin();
while(*itr_path == *itr_relative_to && itr_path != p.end() && itr_relative_to != r.end())
{
++itr_path;
++itr_relative_to;
}
if(itr_relative_to != r.end())
{
contains = false;
return p;
}
while(itr_path != p.end())
{
if(*itr_path != fs::path("."))
result = result / *itr_path;
++itr_path;
}
contains = true;
return result;
}
FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& path, FileType type) FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& path, FileType type)
{ {
// first, verify that path is within the system's root folder // first, verify that path is within the system's root folder
@ -157,6 +102,8 @@ void parseGamelist(SystemData* system)
return; return;
} }
fs::path relativeTo = system->getStartPath();
const char* tagList[2] = { "game", "folder" }; const char* tagList[2] = { "game", "folder" };
FileType typeList[2] = { GAME, FOLDER }; FileType typeList[2] = { GAME, FOLDER };
for(int i = 0; i < 2; i++) for(int i = 0; i < 2; i++)
@ -165,7 +112,7 @@ void parseGamelist(SystemData* system)
FileType type = typeList[i]; FileType type = typeList[i];
for(pugi::xml_node fileNode = root.child(tag); fileNode; fileNode = fileNode.next_sibling(tag)) for(pugi::xml_node fileNode = root.child(tag); fileNode; fileNode = fileNode.next_sibling(tag))
{ {
fs::path path = resolvePath(fileNode.child("path").text().get(), system->getStartPath()); fs::path path = resolvePath(fileNode.child("path").text().get(), relativeTo, false);
if(!boost::filesystem::exists(path)) if(!boost::filesystem::exists(path))
{ {
@ -182,7 +129,7 @@ void parseGamelist(SystemData* system)
//load the metadata //load the metadata
std::string defaultName = file->metadata.get("name"); std::string defaultName = file->metadata.get("name");
file->metadata = MetaDataList::createFromXML(GAME_METADATA, fileNode); file->metadata = MetaDataList::createFromXML(GAME_METADATA, fileNode, relativeTo);
//make sure name gets set if one didn't exist //make sure name gets set if one didn't exist
if(file->metadata.get("name").empty()) if(file->metadata.get("name").empty())
@ -197,7 +144,7 @@ void addFileDataNode(pugi::xml_node& parent, const FileData* file, const char* t
pugi::xml_node newNode = parent.append_child(tag); pugi::xml_node newNode = parent.append_child(tag);
//write metadata //write metadata
file->metadata.appendToXML(newNode, true); file->metadata.appendToXML(newNode, true, system->getStartPath());
if(newNode.children().begin() == newNode.child("name") //first element is name if(newNode.children().begin() == newNode.child("name") //first element is name
&& ++newNode.children().begin() == newNode.children().end() //theres only one element && ++newNode.children().begin() == newNode.children().end() //theres only one element
@ -210,17 +157,7 @@ void addFileDataNode(pugi::xml_node& parent, const FileData* file, const char* t
//there's something useful in there so we'll keep the node, add the path //there's something useful in there so we'll keep the node, add the path
// try and make the path relative if we can so things still work if we change the rom folder location in the future // try and make the path relative if we can so things still work if we change the rom folder location in the future
fs::path relPath = file->getPath(); newNode.prepend_child("path").text().set(makeRelativePath(file->getPath(), system->getStartPath(), false).generic_string().c_str());
bool contains = false;
relPath = removeCommonPath(relPath, system->getStartPath(), contains);
if(contains)
{
// it's in the start path (which we just stripped off), so add a "./"
relPath = "." / relPath;
}
newNode.prepend_child("path").text().set(relPath.generic_string().c_str());
} }
} }
@ -284,7 +221,7 @@ void updateGamelist(SystemData* system)
continue; continue;
} }
fs::path nodePath = resolvePath(pathNode.text().get(), system->getStartPath()); fs::path nodePath = resolvePath(pathNode.text().get(), system->getStartPath(), true);
fs::path gamePath((*fit)->getPath()); fs::path gamePath((*fit)->getPath());
if(nodePath == gamePath || (fs::exists(nodePath) && fs::exists(gamePath) && fs::equivalent(nodePath, gamePath))) if(nodePath == gamePath || (fs::exists(nodePath) && fs::exists(gamePath) && fs::equivalent(nodePath, gamePath)))
{ {

View file

@ -1,6 +1,9 @@
#include "MetaData.h" #include "MetaData.h"
#include "components/TextComponent.h" #include "components/TextComponent.h"
#include "Log.h" #include "Log.h"
#include "Util.h"
namespace fs = boost::filesystem;
MetaDataDecl gameDecls[] = { MetaDataDecl gameDecls[] = {
// key, type, default, statistic, name in GuiMetaDataEd, prompt in GuiMetaDataEd // key, type, default, statistic, name in GuiMetaDataEd, prompt in GuiMetaDataEd
@ -52,7 +55,7 @@ MetaDataList::MetaDataList(MetaDataListType type)
} }
MetaDataList MetaDataList::createFromXML(MetaDataListType type, pugi::xml_node node) MetaDataList MetaDataList::createFromXML(MetaDataListType type, pugi::xml_node node, const fs::path& relativeTo)
{ {
MetaDataList mdl(type); MetaDataList mdl(type);
@ -63,7 +66,12 @@ MetaDataList MetaDataList::createFromXML(MetaDataListType type, pugi::xml_node n
pugi::xml_node md = node.child(iter->key.c_str()); pugi::xml_node md = node.child(iter->key.c_str());
if(md) if(md)
{ {
mdl.set(iter->key, md.text().get()); // if it's a path, resolve relative paths
std::string value = md.text().get();
if(iter->type == MD_IMAGE_PATH)
value = resolvePath(value, relativeTo, true).generic_string();
mdl.set(iter->key, value);
}else{ }else{
mdl.set(iter->key, iter->defaultValue); mdl.set(iter->key, iter->defaultValue);
} }
@ -72,30 +80,27 @@ MetaDataList MetaDataList::createFromXML(MetaDataListType type, pugi::xml_node n
return mdl; return mdl;
} }
void MetaDataList::appendToXML(pugi::xml_node parent, bool ignoreDefaults) const void MetaDataList::appendToXML(pugi::xml_node parent, bool ignoreDefaults, const fs::path& relativeTo) const
{ {
const std::vector<MetaDataDecl>& mdd = getMDD(); const std::vector<MetaDataDecl>& mdd = getMDD();
for(auto iter = mMap.begin(); iter != mMap.end(); iter++) for(auto mddIter = mdd.begin(); mddIter != mdd.end(); mddIter++)
{ {
bool write = true; auto mapIter = mMap.find(mddIter->key);
if(mapIter != mMap.end())
if(ignoreDefaults)
{ {
for(auto mddIter = mdd.begin(); mddIter != mdd.end(); mddIter++) // we have this value!
{ // if it's just the default (and we ignore defaults), don't write it
if(mddIter->key == iter->first) if(ignoreDefaults && mapIter->second == mddIter->defaultValue)
{ continue;
if(iter->second == mddIter->defaultValue)
write = false;
break; // try and make paths relative if we can
} std::string value = mapIter->second;
} if(mddIter->type == MD_IMAGE_PATH)
value = makeRelativePath(value, relativeTo, true).generic_string();
parent.append_child(mapIter->first.c_str()).text().set(value.c_str());
} }
if(write)
parent.append_child(iter->first.c_str()).text().set(iter->second.c_str());
} }
} }

View file

@ -5,6 +5,7 @@
#include <map> #include <map>
#include "GuiComponent.h" #include "GuiComponent.h"
#include <boost/date_time.hpp> #include <boost/date_time.hpp>
#include <boost/filesystem.hpp>
enum MetaDataType enum MetaDataType
{ {
@ -44,8 +45,8 @@ const std::vector<MetaDataDecl>& getMDDByType(MetaDataListType type);
class MetaDataList class MetaDataList
{ {
public: public:
static MetaDataList createFromXML(MetaDataListType type, pugi::xml_node node); static MetaDataList createFromXML(MetaDataListType type, pugi::xml_node node, const boost::filesystem::path& relativeTo);
void appendToXML(pugi::xml_node parent, bool ignoreDefaults = false) const; void appendToXML(pugi::xml_node parent, bool ignoreDefaults, const boost::filesystem::path& relativeTo) const;
MetaDataList(MetaDataListType type); MetaDataList(MetaDataListType type);

View file

@ -1,6 +1,8 @@
#include "Util.h" #include "Util.h"
#include <boost/filesystem.hpp>
#include "resources/ResourceManager.h" #include "resources/ResourceManager.h"
#include "platform.h"
namespace fs = boost::filesystem;
std::string strToUpper(const char* from) std::string strToUpper(const char* from)
{ {
@ -70,3 +72,102 @@ std::string getCanonicalPath(const std::string& path)
return boost::filesystem::canonical(path).generic_string(); return boost::filesystem::canonical(path).generic_string();
} }
// expands "./my/path.sfc" to "[relativeTo]/my/path.sfc"
// if allowHome is true, also expands "~/my/path.sfc" to "/home/pi/my/path.sfc"
fs::path resolvePath(const fs::path& path, const fs::path& relativeTo, bool allowHome)
{
// nothing here
if(path.begin() == path.end())
return path;
if(*path.begin() == ".")
{
fs::path ret = relativeTo;
for(auto it = ++path.begin(); it != path.end(); ++it)
ret /= *it;
return ret;
}
if(allowHome && *path.begin() == "~")
{
fs::path ret = getHomePath();
for(auto it = ++path.begin(); it != path.end(); ++it)
ret /= *it;
return ret;
}
return path;
}
// 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 p = fs::canonical(path);
fs::path r = fs::canonical(relativeTo);
if(p.root_path() != r.root_path())
{
contains = false;
return p;
}
fs::path result;
// find point of divergence
auto itr_path = p.begin();
auto itr_relative_to = r.begin();
while(*itr_path == *itr_relative_to && itr_path != p.end() && itr_relative_to != r.end())
{
++itr_path;
++itr_relative_to;
}
if(itr_relative_to != r.end())
{
contains = false;
return p;
}
while(itr_path != p.end())
{
if(*itr_path != fs::path("."))
result = result / *itr_path;
++itr_path;
}
contains = true;
return result;
}
// usage: makeRelativePath("/path/to/my/thing.sfc", "/path/to") -> "./my/thing.sfc"
// usage: makeRelativePath("/home/pi/my/thing.sfc", "/path/to", true) -> "~/my/thing.sfc"
fs::path makeRelativePath(const fs::path& path, const fs::path& relativeTo, bool allowHome)
{
bool contains = false;
fs::path ret = removeCommonPath(path, relativeTo, contains);
if(contains)
{
// success
ret = "." / ret;
return ret;
}
if(allowHome)
{
contains = false;
std::string homePath = getHomePath();
ret = removeCommonPath(path, homePath, contains);
if(contains)
{
// success
ret = "~" / ret;
return ret;
}
}
// nothing could be resolved
return path;
}

View file

@ -1,5 +1,6 @@
#include <string> #include <string>
#include <Eigen/Dense> #include <Eigen/Dense>
#include <boost/filesystem.hpp>
std::string strToUpper(const char* from); std::string strToUpper(const char* from);
std::string& strToUpper(std::string& str); std::string& strToUpper(std::string& str);
@ -14,3 +15,14 @@ Eigen::Vector2f roundVector(const Eigen::Vector2f& vec);
float round(float num); float round(float num);
std::string getCanonicalPath(const std::string& str); std::string getCanonicalPath(const std::string& str);
// 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);
// usage: makeRelativePath("/path/to/my/thing.sfc", "/path/to") -> "./my/thing.sfc"
// usage: makeRelativePath("/home/pi/my/thing.sfc", "/path/to", true) -> "~/my/thing.sfc"
boost::filesystem::path makeRelativePath(const boost::filesystem::path& path, const boost::filesystem::path& relativeTo, bool allowHome);
// expands "./my/path.sfc" to "[relativeTo]/my/path.sfc"
// if allowHome is true, also expands "~/my/path.sfc" to "/home/pi/my/path.sfc"
boost::filesystem::path resolvePath(const boost::filesystem::path& path, const boost::filesystem::path& relativeTo, bool allowHome);