Mapper: move map_song_detach() to db/DatabaseSong.cxx

Use Storage::MapUTF8() internally, don't use global variables.
This commit is contained in:
Max Kellermann 2014-02-07 00:29:07 +01:00
parent 19a982cf69
commit c13810ebaa
17 changed files with 97 additions and 55 deletions

View File

@ -30,9 +30,12 @@
#include <time.h> #include <time.h>
struct LightSong; struct LightSong;
class Storage;
class DetachedSong { class DetachedSong {
friend DetachedSong map_song_detach(const LightSong &song); friend DetachedSong map_song_detach(const LightSong &song);
friend DetachedSong DatabaseDetachSong(const Storage &db,
const LightSong &song);
/** /**
* An UTF-8-encoded URI referring to the song file. This can * An UTF-8-encoded URI referring to the song file. This can

View File

@ -234,21 +234,6 @@ map_directory_child_fs(const Directory &directory, const char *name)
return AllocatedPath::Build(parent_fs, name_fs); return AllocatedPath::Build(parent_fs, name_fs);
} }
DetachedSong
map_song_detach(const LightSong &song)
{
DetachedSong detached(song);
assert(detached.IsInDatabase());
if (!detached.HasRealURI()) {
const auto uri = song.GetURI();
detached.SetRealURI(PathTraitsUTF8::Build(music_dir_utf8.c_str(),
uri.c_str()));
}
return detached;
}
AllocatedPath AllocatedPath
map_song_fs(const Song &song) map_song_fs(const Song &song)
{ {

View File

@ -91,14 +91,6 @@ gcc_pure
AllocatedPath AllocatedPath
map_uri_fs(const char *uri); map_uri_fs(const char *uri);
/**
* "Detach" the #Song object, i.e. convert it to a #DetachedSong
* instance.
*/
gcc_pure
DetachedSong
map_song_detach(const LightSong &song);
/** /**
* Determines the file system path of a song. This must not be a * Determines the file system path of a song. This must not be a
* remote song. * remote song.

View File

@ -118,7 +118,7 @@ playlist_load_spl(struct playlist &playlist, PlayerControl &pc,
if (end_index > contents.size()) if (end_index > contents.size())
end_index = contents.size(); end_index = contents.size();
const SongLoader loader(nullptr); const SongLoader loader(nullptr, nullptr);
for (unsigned i = start_index; i < end_index; ++i) { for (unsigned i = start_index; i < end_index; ++i) {
const auto &uri_utf8 = contents[i]; const auto &uri_utf8 = contents[i];

View File

@ -36,7 +36,8 @@
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
SongLoader::SongLoader(const Client &_client) SongLoader::SongLoader(const Client &_client)
:client(&_client), db(_client.GetDatabase(IgnoreError())) {} :client(&_client), db(_client.GetDatabase(IgnoreError())),
storage(_client.GetStorage()) {}
#endif #endif
@ -100,7 +101,8 @@ SongLoader::LoadSong(const char *uri_utf8, Error &error) const
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
if (db != nullptr) if (db != nullptr)
return DatabaseDetachSong(*db, uri_utf8, error); return DatabaseDetachSong(*db, *storage,
uri_utf8, error);
#endif #endif
error.Set(playlist_domain, int(PlaylistResult::NO_SUCH_SONG), error.Set(playlist_domain, int(PlaylistResult::NO_SUCH_SONG),

View File

@ -27,6 +27,7 @@
class Client; class Client;
class Database; class Database;
class Storage;
class DetachedSong; class DetachedSong;
class Error; class Error;
@ -41,19 +42,21 @@ class SongLoader {
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
const Database *const db; const Database *const db;
const Storage *const storage;
#endif #endif
public: public:
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
explicit SongLoader(const Client &_client); explicit SongLoader(const Client &_client);
explicit SongLoader(const Database *_db) SongLoader(const Database *_db, const Storage *_storage)
:client(nullptr), db(_db) {} :client(nullptr), db(_db), storage(_storage) {}
explicit SongLoader(const Client &_client, const Database *_db) SongLoader(const Client &_client, const Database *_db,
:client(&_client), db(_db) {} const Storage *_storage)
:client(&_client), db(_db), storage(_storage) {}
#else #else
explicit SongLoader(const Client &_client) explicit SongLoader(const Client &_client)
:client(&_client) {} :client(&_client) {}
explicit SongLoader(std::nullptr_t) explicit SongLoader(std::nullptr_t, std::nullptr_t)
:client(nullptr) {} :client(nullptr) {}
#endif #endif

View File

@ -99,9 +99,10 @@ StateFile::Read()
} }
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
const SongLoader song_loader(partition.instance.database); const SongLoader song_loader(partition.instance.database,
partition.instance.storage);
#else #else
const SongLoader song_loader(nullptr); const SongLoader song_loader(nullptr, nullptr);
#endif #endif
const char *line; const char *line;

View File

@ -33,4 +33,10 @@ Client::GetDatabase(Error &error) const
return partition.instance.GetDatabase(error); return partition.instance.GetDatabase(error);
} }
const Storage *
Client::GetStorage() const
{
return partition.instance.storage;
}
#endif #endif

View File

@ -39,6 +39,7 @@ class EventLoop;
class Path; class Path;
struct Partition; struct Partition;
class Database; class Database;
class Storage;
class Client final : private FullyBufferedSocket, TimeoutMonitor { class Client final : private FullyBufferedSocket, TimeoutMonitor {
public: public:
@ -173,8 +174,12 @@ public:
/** /**
* Wrapper for Instance::GetDatabase(). * Wrapper for Instance::GetDatabase().
*/ */
gcc_pure
const Database *GetDatabase(Error &error) const; const Database *GetDatabase(Error &error) const;
gcc_pure
const Storage *GetStorage() const;
private: private:
/* virtual methods from class BufferedSocket */ /* virtual methods from class BufferedSocket */
virtual InputResult OnSocketInput(void *data, size_t length) override; virtual InputResult OnSocketInput(void *data, size_t length) override;

View File

@ -124,7 +124,8 @@ handle_searchaddpl(Client &client, int argc, char *argv[])
if (db == nullptr) if (db == nullptr)
return print_error(client, error); return print_error(client, error);
return search_add_to_playlist(*db, "", playlist, &filter, error) return search_add_to_playlist(*db, *client.GetStorage(),
"", playlist, &filter, error)
? CommandResult::OK ? CommandResult::OK
: print_error(client, error); : print_error(client, error);
} }

View File

@ -196,7 +196,8 @@ handle_playlistadd(Client &client, gcc_unused int argc, char *argv[])
if (db == nullptr) if (db == nullptr)
return print_error(client, error); return print_error(client, error);
success = search_add_to_playlist(*db, uri, playlist, nullptr, success = search_add_to_playlist(*db, *client.GetStorage(),
uri, playlist, nullptr,
error); error);
#else #else
success = false; success = false;

View File

@ -19,24 +19,26 @@
#include "config.h" #include "config.h"
#include "DatabasePlaylist.hxx" #include "DatabasePlaylist.hxx"
#include "DatabaseSong.hxx"
#include "Selection.hxx" #include "Selection.hxx"
#include "PlaylistFile.hxx" #include "PlaylistFile.hxx"
#include "DatabasePlugin.hxx" #include "DatabasePlugin.hxx"
#include "DetachedSong.hxx" #include "DetachedSong.hxx"
#include "Mapper.hxx" #include "storage/StorageInterface.hxx"
#include <functional> #include <functional>
static bool static bool
AddSong(const char *playlist_path_utf8, AddSong(const Storage &storage, const char *playlist_path_utf8,
const LightSong &song, Error &error) const LightSong &song, Error &error)
{ {
return spl_append_song(playlist_path_utf8, map_song_detach(song), return spl_append_song(playlist_path_utf8,
DatabaseDetachSong(storage, song),
error); error);
} }
bool bool
search_add_to_playlist(const Database &db, search_add_to_playlist(const Database &db, const Storage &storage,
const char *uri, const char *playlist_path_utf8, const char *uri, const char *playlist_path_utf8,
const SongFilter *filter, const SongFilter *filter,
Error &error) Error &error)
@ -44,6 +46,7 @@ search_add_to_playlist(const Database &db,
const DatabaseSelection selection(uri, true, filter); const DatabaseSelection selection(uri, true, filter);
using namespace std::placeholders; using namespace std::placeholders;
const auto f = std::bind(AddSong, playlist_path_utf8, _1, _2); const auto f = std::bind(AddSong, std::ref(storage),
playlist_path_utf8, _1, _2);
return db.Visit(selection, f, error); return db.Visit(selection, f, error);
} }

View File

@ -23,12 +23,13 @@
#include "Compiler.h" #include "Compiler.h"
class Database; class Database;
class Storage;
class SongFilter; class SongFilter;
class Error; class Error;
gcc_nonnull(2,3) gcc_nonnull(3,4)
bool bool
search_add_to_playlist(const Database &db, search_add_to_playlist(const Database &db, const Storage &storage,
const char *uri, const char *path_utf8, const char *uri, const char *path_utf8,
const SongFilter *filter, const SongFilter *filter,
Error &error); Error &error);

View File

@ -19,22 +19,23 @@
#include "config.h" #include "config.h"
#include "DatabaseQueue.hxx" #include "DatabaseQueue.hxx"
#include "DatabaseGlue.hxx" #include "DatabaseSong.hxx"
#include "DatabasePlugin.hxx" #include "DatabasePlugin.hxx"
#include "Partition.hxx" #include "Partition.hxx"
#include "Instance.hxx" #include "Instance.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "DetachedSong.hxx" #include "DetachedSong.hxx"
#include "Mapper.hxx"
#include <functional> #include <functional>
static bool static bool
AddToQueue(Partition &partition, const LightSong &song, Error &error) AddToQueue(Partition &partition, const LightSong &song, Error &error)
{ {
const Storage &storage = *partition.instance.storage;
PlaylistResult result = PlaylistResult result =
partition.playlist.AppendSong(partition.pc, partition.playlist.AppendSong(partition.pc,
map_song_detach(song), DatabaseDetachSong(storage,
song),
nullptr); nullptr);
if (result != PlaylistResult::SUCCESS) { if (result != PlaylistResult::SUCCESS) {
error.Set(playlist_domain, int(result), "Playlist error"); error.Set(playlist_domain, int(result), "Playlist error");

View File

@ -19,18 +19,35 @@
#include "config.h" #include "config.h"
#include "DatabaseSong.hxx" #include "DatabaseSong.hxx"
#include "LightSong.hxx"
#include "DatabasePlugin.hxx" #include "DatabasePlugin.hxx"
#include "DetachedSong.hxx" #include "DetachedSong.hxx"
#include "Mapper.hxx" #include "storage/StorageInterface.hxx"
DetachedSong
DatabaseDetachSong(const Storage &storage, const LightSong &song)
{
DetachedSong detached(song);
assert(detached.IsInDatabase());
if (!detached.HasRealURI()) {
const auto uri = song.GetURI();
detached.SetRealURI(storage.MapUTF8(uri.c_str()));
}
return detached;
}
DetachedSong * DetachedSong *
DatabaseDetachSong(const Database &db, const char *uri, Error &error) DatabaseDetachSong(const Database &db, const Storage &storage, const char *uri,
Error &error)
{ {
const LightSong *tmp = db.GetSong(uri, error); const LightSong *tmp = db.GetSong(uri, error);
if (tmp == nullptr) if (tmp == nullptr)
return nullptr; return nullptr;
DetachedSong *song = new DetachedSong(map_song_detach(*tmp)); DetachedSong *song = new DetachedSong(DatabaseDetachSong(storage,
*tmp));
db.ReturnSong(tmp); db.ReturnSong(tmp);
return song; return song;
} }

View File

@ -22,10 +22,20 @@
#include "Compiler.h" #include "Compiler.h"
struct LightSong;
class Database; class Database;
class Storage;
class DetachedSong; class DetachedSong;
class Error; class Error;
/**
* "Detach" the #Song object, i.e. convert it to a #DetachedSong
* instance.
*/
gcc_pure
DetachedSong
DatabaseDetachSong(const Storage &storage, const LightSong &song);
/** /**
* Look up a song in the database and convert it to a #DetachedSong * Look up a song in the database and convert it to a #DetachedSong
* instance. The caller is responsible for freeing it. * instance. The caller is responsible for freeing it.
@ -34,6 +44,7 @@ class Error;
*/ */
gcc_malloc gcc_nonnull_all gcc_malloc gcc_nonnull_all
DetachedSong * DetachedSong *
DatabaseDetachSong(const Database &db, const char *uri, Error &error); DatabaseDetachSong(const Database &db, const Storage &storage, const char *uri,
Error &error);
#endif #endif

View File

@ -117,7 +117,9 @@ static const char *uri1 = "/foo/bar.ogg";
static const char *uri2 = "foo/bar.ogg"; static const char *uri2 = "foo/bar.ogg";
DetachedSong * DetachedSong *
DatabaseDetachSong(gcc_unused const Database &db, const char *uri, DatabaseDetachSong(gcc_unused const Database &db,
gcc_unused const Storage &storage,
const char *uri,
gcc_unused Error &error) gcc_unused Error &error)
{ {
if (strcmp(uri, uri2) == 0) if (strcmp(uri, uri2) == 0)
@ -143,6 +145,12 @@ Client::GetDatabase(gcc_unused Error &error) const
return reinterpret_cast<const Database *>(this); return reinterpret_cast<const Database *>(this);
} }
const Storage *
Client::GetStorage() const
{
return reinterpret_cast<const Storage *>(this);
}
bool bool
Client::AllowFile(gcc_unused Path path_fs, gcc_unused Error &error) const Client::AllowFile(gcc_unused Path path_fs, gcc_unused Error &error) const
{ {
@ -217,7 +225,7 @@ class TranslateSongTest : public CppUnit::TestFixture {
void TestAbsoluteURI() { void TestAbsoluteURI() {
DetachedSong song1("http://example.com/foo.ogg"); DetachedSong song1("http://example.com/foo.ogg");
auto se = ToString(song1); auto se = ToString(song1);
const SongLoader loader(nullptr); const SongLoader loader(nullptr, nullptr);
CPPUNIT_ASSERT(playlist_check_translate_song(song1, "/ignored", CPPUNIT_ASSERT(playlist_check_translate_song(song1, "/ignored",
loader)); loader));
CPPUNIT_ASSERT_EQUAL(se, ToString(song1)); CPPUNIT_ASSERT_EQUAL(se, ToString(song1));
@ -236,14 +244,15 @@ class TranslateSongTest : public CppUnit::TestFixture {
auto s1 = ToString(song1); auto s1 = ToString(song1);
auto se = ToString(DetachedSong(uri1, MakeTag1c())); auto se = ToString(DetachedSong(uri1, MakeTag1c()));
const SongLoader loader(nullptr); const SongLoader loader(nullptr, nullptr);
CPPUNIT_ASSERT(playlist_check_translate_song(song1, "/ignored", CPPUNIT_ASSERT(playlist_check_translate_song(song1, "/ignored",
loader)); loader));
CPPUNIT_ASSERT_EQUAL(se, ToString(song1)); CPPUNIT_ASSERT_EQUAL(se, ToString(song1));
} }
void TestInDatabase() { void TestInDatabase() {
const SongLoader loader(reinterpret_cast<const Database *>(1)); const SongLoader loader(reinterpret_cast<const Database *>(1),
reinterpret_cast<const Storage *>(2));
DetachedSong song1("doesntexist"); DetachedSong song1("doesntexist");
CPPUNIT_ASSERT(!playlist_check_translate_song(song1, nullptr, CPPUNIT_ASSERT(!playlist_check_translate_song(song1, nullptr,
@ -266,9 +275,10 @@ class TranslateSongTest : public CppUnit::TestFixture {
void TestRelative() { void TestRelative() {
const Database &db = *reinterpret_cast<const Database *>(1); const Database &db = *reinterpret_cast<const Database *>(1);
const SongLoader secure_loader(&db); const Storage &storage = *reinterpret_cast<const Storage *>(2);
const SongLoader secure_loader(&db, &storage);
const SongLoader insecure_loader(*reinterpret_cast<const Client *>(1), const SongLoader insecure_loader(*reinterpret_cast<const Client *>(1),
&db); &db, &storage);
/* map to music_directory */ /* map to music_directory */
DetachedSong song1("bar.ogg", MakeTag2b()); DetachedSong song1("bar.ogg", MakeTag2b());