From dd831d3922ee6b8593894b585560453d22466c19 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Fri, 3 Apr 2020 17:03:35 +0200
Subject: [PATCH] db/simple: pass std::string_view to
 Directory::LookupDirectory()

---
 src/db/Uri.hxx                                |  8 +++++++
 src/db/plugins/simple/Directory.cxx           |  7 +++---
 src/db/plugins/simple/Directory.hxx           |  6 ++---
 .../plugins/simple/SimpleDatabasePlugin.cxx   | 23 +++++++++++--------
 src/db/update/Service.cxx                     |  6 +++--
 5 files changed, 31 insertions(+), 19 deletions(-)

diff --git a/src/db/Uri.hxx b/src/db/Uri.hxx
index 37a2186f3..cb85d0ff2 100644
--- a/src/db/Uri.hxx
+++ b/src/db/Uri.hxx
@@ -20,10 +20,18 @@
 #ifndef MPD_DB_URI_HXX
 #define MPD_DB_URI_HXX
 
+#include <string_view>
+
 static inline bool
 isRootDirectory(const char *name)
 {
 	return name[0] == 0 || (name[0] == '/' && name[1] == 0);
 }
 
+static inline bool
+isRootDirectory(std::string_view name) noexcept
+{
+	return name.empty() || (name.size() == 1 && name.front() == '/');
+}
+
 #endif
diff --git a/src/db/plugins/simple/Directory.cxx b/src/db/plugins/simple/Directory.cxx
index 0b821fac4..e78b6e6fb 100644
--- a/src/db/plugins/simple/Directory.cxx
+++ b/src/db/plugins/simple/Directory.cxx
@@ -127,13 +127,12 @@ Directory::PruneEmpty() noexcept
 }
 
 Directory::LookupResult
-Directory::LookupDirectory(const char *_uri) noexcept
+Directory::LookupDirectory(std::string_view _uri) noexcept
 {
 	assert(holding_db_lock());
-	assert(_uri != nullptr);
 
 	if (isRootDirectory(_uri))
-		return { this, _uri, nullptr };
+		return { this, _uri, {} };
 
 	StringView uri(_uri);
 
@@ -156,7 +155,7 @@ Directory::LookupDirectory(const char *_uri) noexcept
 		uri = rest;
 	} while (uri != nullptr);
 
-	return { d, StringView(_uri, uri.data - 1), uri.data };
+	return { d, _uri.substr(0, uri.data - _uri.data()), uri };
 }
 
 void
diff --git a/src/db/plugins/simple/Directory.hxx b/src/db/plugins/simple/Directory.hxx
index 49df25ee2..7062e609c 100644
--- a/src/db/plugins/simple/Directory.hxx
+++ b/src/db/plugins/simple/Directory.hxx
@@ -189,9 +189,9 @@ public:
 
 		/**
 		 * The remaining URI part (without leading slash) or
-		 * nullptr if the given URI was consumed completely.
+		 * empty if the given URI was consumed completely.
 		 */
-		const char *rest;
+		std::string_view rest;
 	};
 
 	/**
@@ -201,7 +201,7 @@ public:
 	 * @return the Directory, or nullptr if none was found
 	 */
 	gcc_pure
-	LookupResult LookupDirectory(const char *uri) noexcept;
+	LookupResult LookupDirectory(std::string_view uri) noexcept;
 
 	gcc_pure
 	bool IsEmpty() const noexcept {
diff --git a/src/db/plugins/simple/SimpleDatabasePlugin.cxx b/src/db/plugins/simple/SimpleDatabasePlugin.cxx
index f2a420fec..71c40c55e 100644
--- a/src/db/plugins/simple/SimpleDatabasePlugin.cxx
+++ b/src/db/plugins/simple/SimpleDatabasePlugin.cxx
@@ -211,8 +211,10 @@ SimpleDatabase::GetSong(const char *uri) const
 		/* pass the request to the mounted database */
 		protect.unlock();
 
+		/* note: r.rest.data() is actually null-terminated
+		   because it points inside the "uri" parameter */
 		const LightSong *song =
-			r.directory->mounted_database->GetSong(r.rest);
+			r.directory->mounted_database->GetSong(r.rest.data());
 		if (song == nullptr)
 			return nullptr;
 
@@ -222,12 +224,12 @@ SimpleDatabase::GetSong(const char *uri) const
 		return prefixed_light_song;
 	}
 
-	if (r.rest == nullptr)
+	if (r.rest.data() == nullptr)
 		/* it's a directory */
 		throw DatabaseError(DatabaseErrorCode::NOT_FOUND,
 				    "No such song");
 
-	if (strchr(r.rest, '/') != nullptr)
+	if (r.rest.find('/') != std::string_view::npos)
 		/* refers to a URI "below" the actual song */
 		throw DatabaseError(DatabaseErrorCode::NOT_FOUND,
 				    "No such song");
@@ -283,14 +285,15 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
 {
 	ScopeDatabaseLock protect;
 
-	auto r = root->LookupDirectory(selection.uri.c_str());
+	auto r = root->LookupDirectory(selection.uri);
 
 	if (r.directory->IsMount()) {
 		/* pass the request and the remaining uri to the mounted database */
 		protect.unlock();
 
 		WalkMount(r.uri, *(r.directory->mounted_database),
-			  (r.rest == nullptr)?"":r.rest, selection,
+			  r.rest,
+			  selection,
 			  visit_directory, visit_song, visit_playlist);
 
 		return;
@@ -298,7 +301,7 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
 
 	DatabaseVisitorHelper helper(CheckSelection(selection), visit_song);
 
-	if (r.rest == nullptr) {
+	if (r.rest.data() == nullptr) {
 		/* it's a directory */
 
 		if (selection.recursive && visit_directory)
@@ -311,7 +314,7 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
 		return;
 	}
 
-	if (strchr(r.rest, '/') == nullptr) {
+	if (r.rest.find('/') == std::string_view::npos) {
 		if (visit_song) {
 			Song *song = r.directory->FindSong(r.rest);
 			if (song != nullptr) {
@@ -402,11 +405,11 @@ SimpleDatabase::Mount(const char *uri, DatabasePtr db)
 	ScopeDatabaseLock protect;
 
 	auto r = root->LookupDirectory(uri);
-	if (r.rest == nullptr)
+	if (r.rest.data() == nullptr)
 		throw DatabaseError(DatabaseErrorCode::CONFLICT,
 				    "Already exists");
 
-	if (strchr(r.rest, '/') != nullptr)
+	if (r.rest.find('/') != std::string_view::npos)
 		throw DatabaseError(DatabaseErrorCode::NOT_FOUND,
 				    "Parent not found");
 
@@ -461,7 +464,7 @@ SimpleDatabase::LockUmountSteal(const char *uri) noexcept
 	ScopeDatabaseLock protect;
 
 	auto r = root->LookupDirectory(uri);
-	if (r.rest != nullptr || !r.directory->IsMount())
+	if (r.rest.data() != nullptr || !r.directory->IsMount())
 		return nullptr;
 
 	auto db = std::move(r.directory->mounted_database);
diff --git a/src/db/update/Service.cxx b/src/db/update/Service.cxx
index dc09d79ad..2cc7e95eb 100644
--- a/src/db/update/Service.cxx
+++ b/src/db/update/Service.cxx
@@ -169,7 +169,7 @@ UpdateService::GenerateId() noexcept
 }
 
 unsigned
-UpdateService::Enqueue(const char *path, bool discard)
+UpdateService::Enqueue(const char *_path, bool discard)
 {
 	assert(GetEventLoop().IsInside());
 
@@ -178,6 +178,8 @@ UpdateService::Enqueue(const char *path, bool discard)
 	SimpleDatabase *db2;
 	Storage *storage2;
 
+	std::string_view path(_path);
+
 	Directory::LookupResult lr;
 	{
 		const ScopeDatabaseLock protect;
@@ -192,7 +194,7 @@ UpdateService::Enqueue(const char *path, bool discard)
 		if (db2 == nullptr)
 			throw std::runtime_error("Cannot update this type of database");
 
-		if (lr.rest == nullptr) {
+		if (lr.rest.data() == nullptr) {
 			storage2 = storage.GetMount(path);
 			path = "";
 		} else {