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.
This commit is contained in:
Max Kellermann 2014-01-14 12:36:15 +01:00
parent dafd0bc49a
commit ddc75cc46b
3 changed files with 76 additions and 66 deletions

View File

@ -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,
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,46 +547,41 @@ 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;
if (i == vpath.size() - 1) {
// The last element in the path was found and it's
// a container, we're done
oobjid = objid;
odirent = dirent;
return true;
}
break;
}
}
if (found)
continue;
// Path elt was not a container, look at the items list
for (auto& dirent : dirbuf.m_items) {
if (!vpath[i].compare(dirent.name)) {
// If this is the last path elt, we found the target,
// else it does not exist
if (i == vpath.size() - 1) {
oobjid = objid;
odirent = dirent;
return true;
} else {
error.Format(db_domain, DB_NOT_FOUND,
"No such object");
return false;
}
}
}
// Neither container nor item, we're done.
if (!found)
break; 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) {
// The last element in the path was found and it's
// a container, we're done
oobjid = objid;
odirent = *child;
return true;
}
break;
case UPnPDirObject::Type::ITEM:
// If this is the last path elt, we found the target,
// else it does not exist
if (i == vpath.size() - 1) {
oobjid = objid;
odirent = *child;
return true;
} else {
error.Format(db_domain, DB_NOT_FOUND,
"No such object");
return false;
}
}
} }
error.Format(db_domain, DB_NOT_FOUND, "No such object"); error.Format(db_domain, DB_NOT_FOUND, "No such object");
@ -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;
if (visit_directory) { for (const auto &dirent : dirbuf.objects) {
for (auto& dirent : dirbuf.m_containers) { switch (dirent.type) {
Directory d((selection.uri + "/" + case UPnPDirObject::Type::UNKNOWN:
dirent.name).c_str(), assert(false);
m_root); gcc_unreachable();
if (!visit_directory(d, error))
return false;
}
}
if (visit_song || visit_playlist) { case UPnPDirObject::Type::CONTAINER:
for (const auto &dirent : dirbuf.m_items) { if (visit_directory) {
Directory d((selection.uri + "/" +
dirent.name).c_str(),
m_root);
if (!visit_directory(d, error))
return false;
}
break;
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,
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)

View File

@ -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();
} }

View File

@ -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;
*/ */
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.