db/simple/Directory: LookupDirectory() return remaining URI

Code can now be reused in LookupSong().
This commit is contained in:
Max Kellermann 2014-02-26 19:48:37 +01:00
parent 525789cd36
commit 69a42fc901
3 changed files with 62 additions and 41 deletions

View File

@ -120,38 +120,49 @@ Directory::PruneEmpty()
} }
} }
Directory * Directory::LookupResult
Directory::LookupDirectory(const char *uri) Directory::LookupDirectory(const char *uri)
{ {
assert(holding_db_lock()); assert(holding_db_lock());
assert(uri != nullptr); assert(uri != nullptr);
if (isRootDirectory(uri)) if (isRootDirectory(uri))
return this; return { this, nullptr };
char *duplicated = xstrdup(uri), *name = duplicated; char *duplicated = xstrdup(uri), *name = duplicated;
Directory *d = this; Directory *d = this;
while (1) { while (true) {
char *slash = strchr(name, '/'); char *slash = strchr(name, '/');
if (slash == name) { if (slash == name)
d = nullptr;
break; break;
}
if (slash != nullptr) if (slash != nullptr)
*slash = '\0'; *slash = '\0';
d = d->FindChild(name); Directory *tmp = d->FindChild(name);
if (d == nullptr || slash == nullptr) if (tmp == nullptr)
/* not found */
break; break;
d = tmp;
if (slash == nullptr) {
/* found everything */
name = nullptr;
break;
}
name = slash + 1; name = slash + 1;
} }
free(duplicated); free(duplicated);
return d; const char *rest = name == nullptr
? nullptr
: uri + (name - duplicated);
return { d, rest };
} }
void void
@ -197,26 +208,16 @@ Directory::LookupSong(const char *uri)
assert(holding_db_lock()); assert(holding_db_lock());
assert(uri != nullptr); assert(uri != nullptr);
char *duplicated = xstrdup(uri); auto r = LookupDirectory(uri);
char *base = strrchr(duplicated, '/'); if (r.uri == nullptr)
/* it's a directory */
return nullptr;
Directory *d = this; if (strchr(r.uri, '/') != nullptr)
if (base != nullptr) { /* refers to a URI "below" the actual song */
*base++ = 0; return nullptr;
d = d->LookupDirectory(duplicated);
if (d == nullptr) {
free(duplicated);
return nullptr;
}
} else
base = duplicated;
Song *song = d->FindSong(base);
assert(song == nullptr || song->parent == d);
free(duplicated);
return song;
return r.directory->FindSong(r.uri);
} }
static int static int

View File

@ -149,6 +149,21 @@ public:
return child; return child;
} }
struct LookupResult {
/**
* The last directory that was found. If the given
* URI could not be resolved at all, then this is the
* root directory.
*/
Directory *directory;
/**
* The remaining URI part (without leading slash) or
* nullptr if the given URI was consumed completely.
*/
const char *uri;
};
/** /**
* Looks up a directory by its relative URI. * Looks up a directory by its relative URI.
* *
@ -156,7 +171,7 @@ public:
* @return the Directory, or nullptr if none was found * @return the Directory, or nullptr if none was found
*/ */
gcc_pure gcc_pure
Directory *LookupDirectory(const char *uri); LookupResult LookupDirectory(const char *uri);
gcc_pure gcc_pure
bool IsEmpty() const { bool IsEmpty() const {

View File

@ -244,28 +244,33 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
{ {
ScopeDatabaseLock protect; ScopeDatabaseLock protect;
const Directory *directory = root->LookupDirectory(selection.uri.c_str()); auto r = root->LookupDirectory(selection.uri.c_str());
if (directory == nullptr) { if (r.uri == nullptr) {
/* it's a directory */
if (selection.recursive && visit_directory &&
!visit_directory(r.directory->Export(), error))
return false;
return r.directory->Walk(selection.recursive, selection.filter,
visit_directory, visit_song,
visit_playlist,
error);
}
if (strchr(r.uri, '/') == nullptr) {
if (visit_song) { if (visit_song) {
Song *song = root->LookupSong(selection.uri.c_str()); Song *song = r.directory->FindSong(r.uri);
if (song != nullptr) { if (song != nullptr) {
const LightSong song2 = song->Export(); const LightSong song2 = song->Export();
return !selection.Match(song2) || return !selection.Match(song2) ||
visit_song(song2, error); visit_song(song2, error);
} }
} }
error.Set(db_domain, DB_NOT_FOUND, "No such directory");
return false;
} }
if (selection.recursive && visit_directory && error.Set(db_domain, DB_NOT_FOUND, "No such directory");
!visit_directory(directory->Export(), error)) return false;
return false;
return directory->Walk(selection.recursive, selection.filter,
visit_directory, visit_song, visit_playlist,
error);
} }
bool bool