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 "Log.h"
#include "Settings.h"
#include "Util.h"
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)
{
// first, verify that path is within the system's root folder
@ -157,6 +102,8 @@ void parseGamelist(SystemData* system)
return;
}
fs::path relativeTo = system->getStartPath();
const char* tagList[2] = { "game", "folder" };
FileType typeList[2] = { GAME, FOLDER };
for(int i = 0; i < 2; i++)
@ -165,7 +112,7 @@ void parseGamelist(SystemData* system)
FileType type = typeList[i];
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))
{
@ -182,7 +129,7 @@ void parseGamelist(SystemData* system)
//load the metadata
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
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);
//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
&& ++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
// 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();
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());
newNode.prepend_child("path").text().set(makeRelativePath(file->getPath(), system->getStartPath(), false).generic_string().c_str());
}
}
@ -284,7 +221,7 @@ void updateGamelist(SystemData* system)
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());
if(nodePath == gamePath || (fs::exists(nodePath) && fs::exists(gamePath) && fs::equivalent(nodePath, gamePath)))
{

View file

@ -1,6 +1,9 @@
#include "MetaData.h"
#include "components/TextComponent.h"
#include "Log.h"
#include "Util.h"
namespace fs = boost::filesystem;
MetaDataDecl gameDecls[] = {
// 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);
@ -63,7 +66,12 @@ MetaDataList MetaDataList::createFromXML(MetaDataListType type, pugi::xml_node n
pugi::xml_node md = node.child(iter->key.c_str());
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{
mdl.set(iter->key, iter->defaultValue);
}
@ -72,30 +80,27 @@ MetaDataList MetaDataList::createFromXML(MetaDataListType type, pugi::xml_node n
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();
for(auto iter = mMap.begin(); iter != mMap.end(); iter++)
{
bool write = true;
if(ignoreDefaults)
{
for(auto mddIter = mdd.begin(); mddIter != mdd.end(); mddIter++)
{
if(mddIter->key == iter->first)
auto mapIter = mMap.find(mddIter->key);
if(mapIter != mMap.end())
{
if(iter->second == mddIter->defaultValue)
write = false;
// we have this value!
// if it's just the default (and we ignore defaults), don't write it
if(ignoreDefaults && mapIter->second == mddIter->defaultValue)
continue;
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();
if(write)
parent.append_child(iter->first.c_str()).text().set(iter->second.c_str());
parent.append_child(mapIter->first.c_str()).text().set(value.c_str());
}
}
}

View file

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

View file

@ -1,6 +1,8 @@
#include "Util.h"
#include <boost/filesystem.hpp>
#include "resources/ResourceManager.h"
#include "platform.h"
namespace fs = boost::filesystem;
std::string strToUpper(const char* from)
{
@ -70,3 +72,102 @@ std::string getCanonicalPath(const std::string& path)
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 <Eigen/Dense>
#include <boost/filesystem.hpp>
std::string strToUpper(const char* from);
std::string& strToUpper(std::string& str);
@ -14,3 +15,14 @@ Eigen::Vector2f roundVector(const Eigen::Vector2f& vec);
float round(float num);
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);