Commit ddc75cc4 authored by Max Kellermann's avatar Max Kellermann

db/upnp/Directory: merge m_containers and m_items

There is no use in duplicating these containers. It only means that we have to search both, duplicating the code.
parent dafd0bc4
...@@ -452,7 +452,11 @@ UpnpDatabase::SearchSongs(ContentDirectoryService* server, ...@@ -452,7 +452,11 @@ UpnpDatabase::SearchSongs(ContentDirectoryService* server,
if (!SearchSongs(server, objid, selection, dirbuf, error)) if (!SearchSongs(server, objid, selection, dirbuf, error))
return false; return false;
for (const auto &dirent : dirbuf.m_items) { for (const auto &dirent : dirbuf.objects) {
if (dirent.type != UPnPDirObject::Type::ITEM ||
dirent.item_class != UPnPDirObject::ItemClass::MUSIC)
continue;
// We get song ids as the result of the UPnP search. But our // We get song ids as the result of the UPnP search. But our
// client expects paths (e.g. we get 1$4$3788 from minidlna, // client expects paths (e.g. we get 1$4$3788 from minidlna,
// but we need to translate to /Music/All_Music/Satisfaction). // but we need to translate to /Music/All_Music/Satisfaction).
...@@ -489,10 +493,8 @@ UpnpDatabase::ReadNode(ContentDirectoryService *server, ...@@ -489,10 +493,8 @@ UpnpDatabase::ReadNode(ContentDirectoryService *server,
if (!server->getMetadata(objid, dirbuf, error)) if (!server->getMetadata(objid, dirbuf, error))
return false; return false;
if (dirbuf.m_containers.size() == 1) { if (dirbuf.objects.size() == 1) {
dirent = dirbuf.m_containers[0]; dirent = dirbuf.objects[0];
} else if (dirbuf.m_items.size() == 1) {
dirent = dirbuf.m_items[0];
} else { } else {
error.Format(upnp_domain, "Bad resource"); error.Format(upnp_domain, "Bad resource");
return false; return false;
...@@ -545,34 +547,34 @@ UpnpDatabase::Namei(ContentDirectoryService* server, ...@@ -545,34 +547,34 @@ UpnpDatabase::Namei(ContentDirectoryService* server,
if (!server->readDir(objid.c_str(), dirbuf, error)) if (!server->readDir(objid.c_str(), dirbuf, error))
return false; return false;
bool found = false;
// Look for the name in the sub-container list // Look for the name in the sub-container list
for (auto& dirent : dirbuf.m_containers) { const UPnPDirObject *child =
if (!vpath[i].compare(dirent.name)) { dirbuf.FindObject(vpath[i].c_str());
objid = dirent.m_id; // Next readdir target if (child == nullptr)
found = true; break;
switch (child->type) {
case UPnPDirObject::Type::UNKNOWN:
assert(false);
gcc_unreachable();
case UPnPDirObject::Type::CONTAINER:
objid = child->m_id; // Next readdir target
if (i == vpath.size() - 1) { if (i == vpath.size() - 1) {
// The last element in the path was found and it's // The last element in the path was found and it's
// a container, we're done // a container, we're done
oobjid = objid; oobjid = objid;
odirent = dirent; odirent = *child;
return true; return true;
} }
break; break;
}
}
if (found)
continue;
// Path elt was not a container, look at the items list case UPnPDirObject::Type::ITEM:
for (auto& dirent : dirbuf.m_items) {
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) {
oobjid = objid; oobjid = objid;
odirent = dirent; odirent = *child;
return true; return true;
} else { } else {
error.Format(db_domain, DB_NOT_FOUND, error.Format(db_domain, DB_NOT_FOUND,
...@@ -582,11 +584,6 @@ UpnpDatabase::Namei(ContentDirectoryService* server, ...@@ -582,11 +584,6 @@ UpnpDatabase::Namei(ContentDirectoryService* server,
} }
} }
// Neither container nor item, we're done.
if (!found)
break;
}
error.Format(db_domain, DB_NOT_FOUND, "No such object"); error.Format(db_domain, DB_NOT_FOUND, "No such object");
return false; return false;
} }
...@@ -675,18 +672,24 @@ UpnpDatabase::VisitServer(ContentDirectoryService* server, ...@@ -675,18 +672,24 @@ UpnpDatabase::VisitServer(ContentDirectoryService* server,
if (!server->readDir(objid.c_str(), dirbuf, error)) if (!server->readDir(objid.c_str(), dirbuf, error))
return false; return false;
for (const auto &dirent : dirbuf.objects) {
switch (dirent.type) {
case UPnPDirObject::Type::UNKNOWN:
assert(false);
gcc_unreachable();
case UPnPDirObject::Type::CONTAINER:
if (visit_directory) { if (visit_directory) {
for (auto& dirent : dirbuf.m_containers) {
Directory d((selection.uri + "/" + Directory d((selection.uri + "/" +
dirent.name).c_str(), dirent.name).c_str(),
m_root); m_root);
if (!visit_directory(d, error)) if (!visit_directory(d, error))
return false; return false;
} }
}
if (visit_song || visit_playlist) { break;
for (const auto &dirent : dirbuf.m_items) {
case UPnPDirObject::Type::ITEM:
switch (dirent.item_class) { switch (dirent.item_class) {
case UPnPDirObject::ItemClass::MUSIC: case UPnPDirObject::ItemClass::MUSIC:
if (visit_song) { if (visit_song) {
...@@ -810,7 +813,11 @@ UpnpDatabase::VisitUniqueTags(const DatabaseSelection &selection, ...@@ -810,7 +813,11 @@ UpnpDatabase::VisitUniqueTags(const DatabaseSelection &selection,
if (!SearchSongs(&server, rootid, selection, dirbuf, error)) if (!SearchSongs(&server, rootid, selection, dirbuf, error))
return false; return false;
for (auto &dirent : dirbuf.m_items) { for (const auto &dirent : dirbuf.objects) {
if (dirent.type != UPnPDirObject::Type::ITEM ||
dirent.item_class != UPnPDirObject::ItemClass::MUSIC)
continue;
std::string tagvalue; std::string tagvalue;
if (getTagValue(dirent, tag, tagvalue)) { if (getTagValue(dirent, tag, tagvalue)) {
#if defined(__clang__) || GCC_CHECK_VERSION(4,8) #if defined(__clang__) || GCC_CHECK_VERSION(4,8)
......
...@@ -149,15 +149,9 @@ protected: ...@@ -149,15 +149,9 @@ protected:
virtual void EndElement(const XML_Char *name) virtual void EndElement(const XML_Char *name)
{ {
if (!strcmp(name, "container")) { if ((!strcmp(name, "container") || !strcmp(name, "item")) &&
if (checkobjok()) { checkobjok())
m_dir.m_containers.push_back(m_tobj); m_dir.objects.push_back(m_tobj);
}
} else if (!strcmp(name, "item")) {
if (checkobjok()) {
m_dir.m_items.push_back(m_tobj);
}
}
m_path.pop_back(); m_path.pop_back();
} }
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define MPD_UPNP_DIRECTORY_HXX #define MPD_UPNP_DIRECTORY_HXX
#include "Object.hxx" #include "Object.hxx"
#include "Compiler.h"
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -33,8 +34,16 @@ class Error; ...@@ -33,8 +34,16 @@ class Error;
*/ */
class UPnPDirContent { class UPnPDirContent {
public: public:
std::vector<UPnPDirObject> m_containers; std::vector<UPnPDirObject> objects;
std::vector<UPnPDirObject> m_items;
gcc_pure
const UPnPDirObject *FindObject(const char *name) const {
for (const auto &o : objects)
if (o.name == name)
return &o;
return nullptr;
}
/** /**
* Parse from DIDL-Lite XML data. * Parse from DIDL-Lite XML data.
......
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