db/upnp: use SplitString() instead of stringToTokens()

This commit is contained in:
Max Kellermann 2018-01-02 13:21:40 +01:00
parent 8c7d7dfa5b
commit 0a4b866d8a

View File

@ -24,7 +24,6 @@
#include "lib/upnp/ClientInit.hxx" #include "lib/upnp/ClientInit.hxx"
#include "lib/upnp/Discovery.hxx" #include "lib/upnp/Discovery.hxx"
#include "lib/upnp/ContentDirectoryService.hxx" #include "lib/upnp/ContentDirectoryService.hxx"
#include "lib/upnp/Util.hxx"
#include "db/Interface.hxx" #include "db/Interface.hxx"
#include "db/DatabasePlugin.hxx" #include "db/DatabasePlugin.hxx"
#include "db/Selection.hxx" #include "db/Selection.hxx"
@ -39,9 +38,9 @@
#include "fs/Traits.hxx" #include "fs/Traits.hxx"
#include "Log.hxx" #include "Log.hxx"
#include "SongFilter.hxx" #include "SongFilter.hxx"
#include "util/SplitString.hxx"
#include <string> #include <string>
#include <vector>
#include <set> #include <set>
#include <assert.h> #include <assert.h>
@ -105,7 +104,7 @@ public:
private: private:
void VisitServer(const ContentDirectoryService &server, void VisitServer(const ContentDirectoryService &server,
const std::list<std::string> &vpath, std::forward_list<std::string> &&vpath,
const DatabaseSelection &selection, const DatabaseSelection &selection,
VisitDirectory visit_directory, VisitDirectory visit_directory,
VisitSong visit_song, VisitSong visit_song,
@ -125,7 +124,7 @@ private:
const DatabaseSelection &selection) const; const DatabaseSelection &selection) const;
UPnPDirObject Namei(const ContentDirectoryService &server, UPnPDirObject Namei(const ContentDirectoryService &server,
const std::list<std::string> &vpath) const; std::forward_list<std::string> &&vpath) const;
/** /**
* Take server and objid, return metadata. * Take server and objid, return metadata.
@ -186,20 +185,28 @@ UpnpDatabase::ReturnSong(const LightSong *_song) const
const LightSong * const LightSong *
UpnpDatabase::GetSong(const char *uri) const UpnpDatabase::GetSong(const char *uri) const
{ {
auto vpath = stringToTokens(uri, '/'); auto vpath = SplitString(uri, '/');
if (vpath.size() < 2) if (vpath.empty())
throw DatabaseError(DatabaseErrorCode::NOT_FOUND, throw DatabaseError(DatabaseErrorCode::NOT_FOUND,
"No such song"); "No such song");
auto server = discovery->GetServer(vpath.front().c_str()); auto server = discovery->GetServer(vpath.front().c_str());
vpath.pop_front(); vpath.pop_front();
if (vpath.empty())
throw DatabaseError(DatabaseErrorCode::NOT_FOUND,
"No such song");
UPnPDirObject dirent; UPnPDirObject dirent;
if (vpath.front() != rootid) { if (vpath.front() != rootid) {
dirent = Namei(server, vpath); dirent = Namei(server, std::move(vpath));
} else { } else {
dirent = ReadNode(server, vpath.back().c_str()); vpath.pop_front();
if (vpath.empty())
throw DatabaseError(DatabaseErrorCode::NOT_FOUND,
"No such song");
dirent = ReadNode(server, vpath.front().c_str());
} }
return new UpnpSong(std::move(dirent), uri); return new UpnpSong(std::move(dirent), uri);
@ -410,7 +417,7 @@ UpnpDatabase::BuildPath(const ContentDirectoryService &server,
// Take server and internal title pathname and return objid and metadata. // Take server and internal title pathname and return objid and metadata.
UPnPDirObject UPnPDirObject
UpnpDatabase::Namei(const ContentDirectoryService &server, UpnpDatabase::Namei(const ContentDirectoryService &server,
const std::list<std::string> &vpath) const std::forward_list<std::string> &&vpath) const
{ {
if (vpath.empty()) if (vpath.empty())
// looking for root info // looking for root info
@ -419,16 +426,17 @@ UpnpDatabase::Namei(const ContentDirectoryService &server,
std::string objid(rootid); std::string objid(rootid);
// Walk the path elements, read each directory and try to find the next one // Walk the path elements, read each directory and try to find the next one
for (auto i = vpath.begin(), last = std::prev(vpath.end());; ++i) { while (true) {
auto dirbuf = server.readDir(handle, objid.c_str()); auto dirbuf = server.readDir(handle, objid.c_str());
// Look for the name in the sub-container list // Look for the name in the sub-container list
UPnPDirObject *child = dirbuf.FindObject(i->c_str()); UPnPDirObject *child = dirbuf.FindObject(vpath.front().c_str());
if (child == nullptr) if (child == nullptr)
throw DatabaseError(DatabaseErrorCode::NOT_FOUND, throw DatabaseError(DatabaseErrorCode::NOT_FOUND,
"No such object"); "No such object");
if (i == last) vpath.pop_front();
if (vpath.empty())
return std::move(*child); return std::move(*child);
if (child->type != UPnPDirObject::Type::CONTAINER) if (child->type != UPnPDirObject::Type::CONTAINER)
@ -497,7 +505,7 @@ VisitObject(const UPnPDirObject &object, const char *uri,
// really just one path parameter. // really just one path parameter.
void void
UpnpDatabase::VisitServer(const ContentDirectoryService &server, UpnpDatabase::VisitServer(const ContentDirectoryService &server,
const std::list<std::string> &vpath, std::forward_list<std::string> &&vpath,
const DatabaseSelection &selection, const DatabaseSelection &selection,
VisitDirectory visit_directory, VisitDirectory visit_directory,
VisitSong visit_song, VisitSong visit_song,
@ -512,20 +520,18 @@ UpnpDatabase::VisitServer(const ContentDirectoryService &server,
because the path is not valid for traversal. Besides, it's because the path is not valid for traversal. Besides, it's
just faster to access the target node directly */ just faster to access the target node directly */
if (!vpath.empty() && vpath.front() == rootid) { if (!vpath.empty() && vpath.front() == rootid) {
switch (vpath.size()) { vpath.pop_front();
case 1: if (vpath.empty())
return; return;
case 2: const std::string objid(std::move(vpath.front()));
break; vpath.pop_front();
if (!vpath.empty())
default:
throw DatabaseError(DatabaseErrorCode::NOT_FOUND, throw DatabaseError(DatabaseErrorCode::NOT_FOUND,
"Not found"); "Not found");
}
if (visit_song) { if (visit_song) {
auto dirent = ReadNode(server, vpath.back().c_str()); auto dirent = ReadNode(server, objid.c_str());
if (dirent.type != UPnPDirObject::Type::ITEM || if (dirent.type != UPnPDirObject::Type::ITEM ||
dirent.item_class != UPnPDirObject::ItemClass::MUSIC) dirent.item_class != UPnPDirObject::ItemClass::MUSIC)
@ -542,7 +548,7 @@ UpnpDatabase::VisitServer(const ContentDirectoryService &server,
} }
// Translate the target path into an object id and the associated metadata. // Translate the target path into an object id and the associated metadata.
const auto tdirent = Namei(server, vpath); const auto tdirent = Namei(server, std::move(vpath));
/* If recursive is set, this is a search... No use sending it /* If recursive is set, this is a search... No use sending it
if the filter is empty. In this case, we implement limited if the filter is empty. In this case, we implement limited
@ -584,7 +590,7 @@ UpnpDatabase::Visit(const DatabaseSelection &selection,
VisitSong visit_song, VisitSong visit_song,
VisitPlaylist visit_playlist) const VisitPlaylist visit_playlist) const
{ {
auto vpath = stringToTokens(selection.uri, '/'); auto vpath = SplitString(selection.uri.c_str(), '/');
if (vpath.empty()) { if (vpath.empty()) {
for (const auto &server : discovery->GetDirectories()) { for (const auto &server : discovery->GetDirectories()) {
if (visit_directory) { if (visit_directory) {
@ -594,7 +600,7 @@ UpnpDatabase::Visit(const DatabaseSelection &selection,
} }
if (selection.recursive) if (selection.recursive)
VisitServer(server, vpath, selection, VisitServer(server, std::move(vpath), selection,
visit_directory, visit_song, visit_directory, visit_song,
visit_playlist); visit_playlist);
} }
@ -607,7 +613,7 @@ UpnpDatabase::Visit(const DatabaseSelection &selection,
vpath.pop_front(); vpath.pop_front();
auto server = discovery->GetServer(servername.c_str()); auto server = discovery->GetServer(servername.c_str());
VisitServer(server, vpath, selection, VisitServer(server, std::move(vpath), selection,
visit_directory, visit_song, visit_playlist); visit_directory, visit_song, visit_playlist);
} }