Merge tag 'v0.22.4'

release v0.22.4
This commit is contained in:
Max Kellermann
2021-01-21 17:42:26 +01:00
33 changed files with 353 additions and 101 deletions

View File

@@ -18,11 +18,11 @@
*/
#include "Directory.hxx"
#include "ExportedSong.hxx"
#include "SongSort.hxx"
#include "Song.hxx"
#include "Mount.hxx"
#include "db/LightDirectory.hxx"
#include "song/LightSong.hxx"
#include "db/Uri.hxx"
#include "db/DatabaseLock.hxx"
#include "db/Interface.hxx"
@@ -234,7 +234,7 @@ Directory::Walk(bool recursive, const SongFilter *filter,
if (visit_song) {
for (auto &song : songs){
const LightSong song2 = song.Export();
const auto song2 = song.Export();
if (filter == nullptr || filter->Match(song2))
visit_song(song2);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2003-2021 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_DB_SIMPLE_EXPORTED_SONG_HXX
#define MPD_DB_SIMPLE_EXPORTED_SONG_HXX
#include "song/LightSong.hxx"
#include "tag/Tag.hxx"
/**
* The return type for Song::Export(). In addition to implementing
* #LightSong, it hold allocations necessary to represent the #Song as
* a #LightSong, e.g. a merged #Tag.
*/
class ExportedSong : public LightSong {
Tag tag_buffer;
public:
using LightSong::LightSong;
ExportedSong(const char *_uri, Tag &&_tag) noexcept
:LightSong(_uri, tag_buffer),
tag_buffer(std::move(_tag)) {}
};
#endif

View File

@@ -233,25 +233,25 @@ SimpleDatabase::GetSong(std::string_view uri) const
"No such song");
const Song *song = r.directory->FindSong(r.rest);
protect.unlock();
if (song == nullptr)
throw DatabaseError(DatabaseErrorCode::NOT_FOUND,
"No such song");
light_song.Construct(song->Export());
exported_song.Construct(song->Export());
protect.unlock();
#ifndef NDEBUG
++borrowed_song_count;
#endif
return &light_song.Get();
return &exported_song.Get();
}
void
SimpleDatabase::ReturnSong([[maybe_unused]] const LightSong *song) const noexcept
{
assert(song != nullptr);
assert(song == prefixed_light_song || song == &light_song.Get());
assert(song == prefixed_light_song || song == &exported_song.Get());
if (prefixed_light_song != nullptr) {
delete prefixed_light_song;
@@ -262,7 +262,7 @@ SimpleDatabase::ReturnSong([[maybe_unused]] const LightSong *song) const noexcep
--borrowed_song_count;
#endif
light_song.Destruct();
exported_song.Destruct();
}
}
@@ -316,7 +316,7 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
if (visit_song) {
Song *song = r.directory->FindSong(r.rest);
if (song != nullptr) {
const LightSong song2 = song->Export();
const auto song2 = song->Export();
if (selection.Match(song2))
visit_song(song2);

View File

@@ -20,10 +20,10 @@
#ifndef MPD_SIMPLE_DATABASE_PLUGIN_HXX
#define MPD_SIMPLE_DATABASE_PLUGIN_HXX
#include "ExportedSong.hxx"
#include "db/Interface.hxx"
#include "db/Ptr.hxx"
#include "fs/AllocatedPath.hxx"
#include "song/LightSong.hxx"
#include "util/Manual.hxx"
#include "util/Compiler.h"
#include "config.h"
@@ -63,7 +63,7 @@ class SimpleDatabase : public Database {
/**
* A buffer for GetSong().
*/
mutable Manual<LightSong> light_song;
mutable Manual<ExportedSong> exported_song;
#ifndef NDEBUG
mutable unsigned borrowed_song_count;

View File

@@ -18,11 +18,15 @@
*/
#include "Song.hxx"
#include "ExportedSong.hxx"
#include "Directory.hxx"
#include "tag/Tag.hxx"
#include "tag/Builder.hxx"
#include "song/DetachedSong.hxx"
#include "song/LightSong.hxx"
#include "fs/Traits.hxx"
#include "time/ChronoUtil.hxx"
#include "util/IterableSplitString.hxx"
Song::Song(DetachedSong &&other, Directory &_parent) noexcept
:tag(std::move(other.WritableTag())),
@@ -53,17 +57,87 @@ Song::GetURI() const noexcept
}
}
LightSong
/**
* Path name traversal of a #Directory.
*/
gcc_pure
static const Directory *
FindTargetDirectory(const Directory &base, StringView path) noexcept
{
const auto *directory = &base;
for (const StringView name : IterableSplitString(path, '/')) {
if (name.empty() || name.Equals("."))
continue;
directory = name.Equals("..")
? directory->parent
: directory->FindChild(name);
if (directory == nullptr)
break;
}
return directory;
}
/**
* Path name traversal of a #Song.
*/
gcc_pure
static const Song *
FindTargetSong(const Directory &_directory, StringView target) noexcept
{
auto [path, last] = target.SplitLast('/');
if (last == nullptr) {
last = path;
path = nullptr;
}
if (last.empty())
return nullptr;
const auto *directory = FindTargetDirectory(_directory, path);
if (directory == nullptr)
return nullptr;
return directory->FindSong(last);
}
ExportedSong
Song::Export() const noexcept
{
LightSong dest(filename.c_str(), tag);
const auto *target_song = !target.empty()
? FindTargetSong(parent, (std::string_view)target)
: nullptr;
Tag merged_tag;
if (target_song != nullptr) {
/* if we found the target song (which may be the
underlying song file of a CUE file), merge the tags
from that song with this song's tags (from the CUE
file) */
TagBuilder builder(tag);
builder.Complement(target_song->tag);
merged_tag = builder.Commit();
}
ExportedSong dest = merged_tag.IsDefined()
? ExportedSong(filename.c_str(), std::move(merged_tag))
: ExportedSong(filename.c_str(), tag);
if (!parent.IsRoot())
dest.directory = parent.GetPath();
if (!target.empty())
dest.real_uri = target.c_str();
dest.mtime = mtime;
dest.start_time = start_time;
dest.end_time = end_time;
dest.audio_format = audio_format;
dest.mtime = IsNegative(mtime) && target_song != nullptr
? target_song->mtime
: mtime;
dest.start_time = start_time.IsZero() && target_song != nullptr
? target_song->start_time
: start_time;
dest.end_time = end_time.IsZero() && target_song != nullptr
? target_song->end_time
: end_time;
dest.audio_format = audio_format.IsDefined() || target_song == nullptr
? audio_format
: target_song->audio_format;
return dest;
}

View File

@@ -32,8 +32,8 @@
#include <string>
struct StringView;
struct LightSong;
struct Directory;
class ExportedSong;
class DetachedSong;
class Storage;
class ArchiveFile;
@@ -153,7 +153,7 @@ struct Song {
std::string GetURI() const noexcept;
gcc_pure
LightSong Export() const noexcept;
ExportedSong Export() const noexcept;
};
typedef boost::intrusive::list<Song,