Commit efdb41f2 authored by Max Kellermann's avatar Max Kellermann

db/upnp/Object: add attribute "name"

Call titleToPathElt() only once for each object.
parent 26b850c1
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include "Log.hxx" #include "Log.hxx"
#include "SongFilter.hxx" #include "SongFilter.hxx"
#include <algorithm>
#include <string> #include <string>
#include <vector> #include <vector>
#include <map> #include <map>
...@@ -210,19 +209,6 @@ UpnpDatabase::ReturnSong(Song *song) const ...@@ -210,19 +209,6 @@ UpnpDatabase::ReturnSong(Song *song) const
song->Free(); song->Free();
} }
/**
* Transform titles to turn '/' into '_' to make them acceptable path
* elements. There is a very slight risk of collision in doing
* this. Twonky returns directory names (titles) like 'Artist/Album'.
*/
gcc_pure
static std::string
titleToPathElt(std::string s)
{
std::replace(s.begin(), s.end(), '/', '_');
return s;
}
// If uri is empty, we use the object's url instead. This happens // If uri is empty, we use the object's url instead. This happens
// when the target of a Visit() is a song, which only happens when // when the target of a Visit() is a song, which only happens when
// "add"ing AFAIK. Visit() calls us with a null uri so that the url // "add"ing AFAIK. Visit() calls us with a null uri so that the url
...@@ -528,7 +514,7 @@ UpnpDatabase::BuildPath(ContentDirectoryService *server, ...@@ -528,7 +514,7 @@ UpnpDatabase::BuildPath(ContentDirectoryService *server,
if (!ReadNode(server, pid, dirent, error)) if (!ReadNode(server, pid, dirent, error))
return false; return false;
pid = dirent.m_pid.c_str(); pid = dirent.m_pid.c_str();
path = titleToPathElt(dirent.m_title) + (path.empty()? "" : "/" + path); path = dirent.name + (path.empty()? "" : "/" + path);
} }
path = std::string(server->getFriendlyName()) + "/" + path; path = std::string(server->getFriendlyName()) + "/" + path;
return true; return true;
...@@ -563,7 +549,7 @@ UpnpDatabase::Namei(ContentDirectoryService* server, ...@@ -563,7 +549,7 @@ UpnpDatabase::Namei(ContentDirectoryService* server,
// Look for the name in the sub-container list // Look for the name in the sub-container list
for (auto& dirent : dirbuf.m_containers) { for (auto& dirent : dirbuf.m_containers) {
if (!vpath[i].compare(titleToPathElt(dirent.m_title))) { if (!vpath[i].compare(dirent.name)) {
objid = dirent.m_id; // Next readdir target objid = dirent.m_id; // Next readdir target
found = true; found = true;
if (i == vpath.size() - 1) { if (i == vpath.size() - 1) {
...@@ -581,7 +567,7 @@ UpnpDatabase::Namei(ContentDirectoryService* server, ...@@ -581,7 +567,7 @@ UpnpDatabase::Namei(ContentDirectoryService* server,
// Path elt was not a container, look at the items list // Path elt was not a container, look at the items list
for (auto& dirent : dirbuf.m_items) { for (auto& dirent : dirbuf.m_items) {
if (!vpath[i].compare(titleToPathElt(dirent.m_title))) { if (!vpath[i].compare(dirent.name)) {
// If this is the last path elt, we found the target, // If this is the last path elt, we found the target,
// else it does not exist // else it does not exist
if (i == vpath.size() - 1) { if (i == vpath.size() - 1) {
...@@ -689,7 +675,7 @@ UpnpDatabase::VisitServer(ContentDirectoryService* server, ...@@ -689,7 +675,7 @@ UpnpDatabase::VisitServer(ContentDirectoryService* server,
if (visit_directory) { if (visit_directory) {
for (auto& dirent : dirbuf.m_containers) { for (auto& dirent : dirbuf.m_containers) {
Directory d((selection.uri + "/" + Directory d((selection.uri + "/" +
titleToPathElt(dirent.m_title)).c_str(), dirent.name).c_str(),
m_root); m_root);
if (!visit_directory(d, error)) if (!visit_directory(d, error))
return false; return false;
...@@ -709,7 +695,7 @@ UpnpDatabase::VisitServer(ContentDirectoryService* server, ...@@ -709,7 +695,7 @@ UpnpDatabase::VisitServer(ContentDirectoryService* server,
std::string p; std::string p;
if (!selection.recursive) if (!selection.recursive)
p = selection.uri + "/" + p = selection.uri + "/" +
titleToPathElt(dirent.m_title); dirent.name;
if (!visitSong(dirent, p.c_str(), if (!visitSong(dirent, p.c_str(),
selection, visit_song, error)) selection, visit_song, error))
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "Util.hxx" #include "Util.hxx"
#include "Expat.hxx" #include "Expat.hxx"
#include <algorithm>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -58,6 +59,19 @@ ParseDuration(const std::string &duration) ...@@ -58,6 +59,19 @@ ParseDuration(const std::string &duration)
} }
/** /**
* Transform titles to turn '/' into '_' to make them acceptable path
* elements. There is a very slight risk of collision in doing
* this. Twonky returns directory names (titles) like 'Artist/Album'.
*/
gcc_pure
static std::string
titleToPathElt(std::string s)
{
std::replace(s.begin(), s.end(), '/', '_');
return s;
}
/**
* An XML parser which builds directory contents from DIDL lite input. * An XML parser which builds directory contents from DIDL lite input.
*/ */
class UPnPDirParser final : public CommonExpatParser { class UPnPDirParser final : public CommonExpatParser {
...@@ -125,7 +139,7 @@ protected: ...@@ -125,7 +139,7 @@ protected:
bool checkobjok() { bool checkobjok() {
if (m_tobj.m_id.empty() || m_tobj.m_pid.empty() || if (m_tobj.m_id.empty() || m_tobj.m_pid.empty() ||
m_tobj.m_title.empty() || m_tobj.name.empty() ||
(m_tobj.type == UPnPDirObject::Type::ITEM && (m_tobj.type == UPnPDirObject::Type::ITEM &&
m_tobj.item_class == UPnPDirObject::ItemClass::UNKNOWN)) m_tobj.item_class == UPnPDirObject::ItemClass::UNKNOWN))
return false; return false;
...@@ -154,8 +168,11 @@ protected: ...@@ -154,8 +168,11 @@ protected:
trimstring(str); trimstring(str);
switch (m_path.back()[0]) { switch (m_path.back()[0]) {
case 'd': case 'd':
if (!m_path.back().compare("dc:title")) if (!m_path.back().compare("dc:title")) {
m_tobj.m_title += str; m_tobj.m_title = str;
m_tobj.name = titleToPathElt(str);
}
break; break;
case 'r': case 'r':
if (!m_path.back().compare("res")) { if (!m_path.back().compare("res")) {
......
...@@ -52,6 +52,12 @@ public: ...@@ -52,6 +52,12 @@ public:
std::string m_id; // ObjectId std::string m_id; // ObjectId
std::string m_pid; // Parent ObjectId std::string m_pid; // Parent ObjectId
std::string url; std::string url;
/**
* A copy of "dc:title" sanitized as a file name.
*/
std::string name;
std::string m_title; // dc:title. Directory name for a container. std::string m_title; // dc:title. Directory name for a container.
Type type; Type type;
ItemClass item_class; ItemClass item_class;
...@@ -71,8 +77,8 @@ public: ...@@ -71,8 +77,8 @@ public:
* @param[out] value * @param[out] value
* @return true if found. * @return true if found.
*/ */
const char *getprop(const char *name) const { const char *getprop(const char *_name) const {
auto it = m_props.find(name); auto it = m_props.find(_name);
if (it == m_props.end()) if (it == m_props.end())
return nullptr; return nullptr;
return it->second.c_str(); return it->second.c_str();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment