Merge branch 'v0.21.x'

This commit is contained in:
Max Kellermann 2020-03-12 08:11:08 +01:00
commit 01632d37ef
13 changed files with 93 additions and 54 deletions

View File

@ -1,6 +1,6 @@
language: cpp
matrix:
jobs:
include:
# Ubuntu Bionic (18.04) with GCC 7
- os: linux
@ -126,6 +126,7 @@ matrix:
packages:
- ccache
- meson
update: true
env:
- MATRIX_EVAL="export PATH=/usr/local/opt/ccache/libexec:$PATH HOMEBREW_NO_ANALYTICS=1"

12
NEWS
View File

@ -35,6 +35,18 @@ ver 0.22 (not yet released)
* switch to C++17
- GCC 7 or clang 4 (or newer) recommended
ver 0.21.21 (not yet released)
* configuration
- fix bug in "metadata_to_use" setting
* playlist
- xspf: fix corrupt tags in the presence of XML entities
* archive
- iso9660: skip empty file names to work around libcdio bug
* decoder
- gme: ignore empty tags
* output
- solaris: port to NetBSD
ver 0.21.20 (2020/02/16)
* decoder
- audiofile, ffmpeg, sndfile: handle MIME type "audio/wav"

View File

@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd"
android:installLocation="auto"
android:versionCode="43"
android:versionName="0.21.20">
android:versionCode="44"
android:versionName="0.21.21">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>

View File

@ -28,6 +28,7 @@
#include "input/InputStream.hxx"
#include "fs/Path.hxx"
#include "util/RuntimeError.hxx"
#include "util/StringCompare.hxx"
#include <cdio/iso9660.h>
@ -99,7 +100,10 @@ Iso9660ArchiveFile::Visit(char *path, size_t length, size_t capacity,
auto *statbuf = (iso9660_stat_t *)
_cdio_list_node_data(entnode);
const char *filename = statbuf->filename;
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
if (StringIsEmpty(filename) ||
PathTraitsUTF8::IsSpecialFilename(filename))
/* skip empty names (libcdio bug?) */
/* skip special names like "." and ".." */
continue;
size_t filename_length = strlen(filename);

View File

@ -24,6 +24,7 @@
#include "storage/StorageInterface.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/FileInfo.hxx"
#include "fs/Traits.hxx"
#include "Log.hxx"
#include <string>
@ -146,8 +147,7 @@ WatchDirectory::GetUriFS() const noexcept
/* we don't look at "." / ".." nor files with newlines in their name */
static bool skip_path(const char *path)
{
return (path[0] == '.' && path[1] == 0) ||
(path[0] == '.' && path[1] == '.' && path[2] == 0) ||
return PathTraitsFS::IsSpecialFilename(path) ||
strchr(path, '\n') != nullptr;
}

View File

@ -219,7 +219,7 @@ try {
LogError(std::current_exception());
}
/* we don't look at "." / ".." nor files with newlines in their name */
/* we don't look at files with newlines in their name */
gcc_pure
static bool
skip_path(const char *name_utf8) noexcept

View File

@ -28,6 +28,7 @@
#include "fs/AllocatedPath.hxx"
#include "fs/FileSystem.hxx"
#include "util/ScopeExit.hxx"
#include "util/StringCompare.hxx"
#include "util/StringFormat.hxx"
#include "util/StringView.hxx"
#include "util/UriExtract.hxx"
@ -223,7 +224,7 @@ ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count,
if (track_count > 1)
handler.OnTag(TAG_TRACK, StringFormat<16>("%u", song_num + 1).c_str());
if (info.song != nullptr) {
if (!StringIsEmpty(info.song)) {
if (track_count > 1) {
/* start numbering subtunes from 1 */
const auto tag_title =
@ -235,16 +236,16 @@ ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count,
handler.OnTag(TAG_TITLE, info.song);
}
if (info.author != nullptr)
if (!StringIsEmpty(info.author))
handler.OnTag(TAG_ARTIST, info.author);
if (info.game != nullptr)
if (!StringIsEmpty(info.game))
handler.OnTag(TAG_ALBUM, info.game);
if (info.comment != nullptr)
if (!StringIsEmpty(info.comment))
handler.OnTag(TAG_COMMENT, info.comment);
if (info.copyright != nullptr)
if (!StringIsEmpty(info.copyright))
handler.OnTag(TAG_DATE, info.copyright);
}

View File

@ -108,6 +108,12 @@ struct PathTraitsFS {
return IsSeparator(*p);
}
gcc_pure gcc_nonnull_all
static bool IsSpecialFilename(const_pointer name) noexcept {
return (name[0] == '.' && name[1] == 0) ||
(name[0] == '.' && name[1] == '.' && name[2] == 0);
}
gcc_pure gcc_nonnull_all
static size_t GetLength(const_pointer p) noexcept {
return StringLength(p);
@ -216,6 +222,12 @@ struct PathTraitsUTF8 {
return IsSeparator(*p);
}
gcc_pure gcc_nonnull_all
static bool IsSpecialFilename(const_pointer name) noexcept {
return (name[0] == '.' && name[1] == 0) ||
(name[0] == '.' && name[1] == '.' && name[2] == 0);
}
gcc_pure gcc_nonnull_all
static size_t GetLength(const_pointer p) noexcept {
return StringLength(p);

View File

@ -22,22 +22,23 @@
#include "system/FileDescriptor.hxx"
#include "system/Error.hxx"
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#ifdef __sun
#if defined(__sun)
#include <sys/audio.h>
#include <sys/stropts.h>
#elif defined(__NetBSD__)
#include <sys/audioio.h>
#else
/* some fake declarations that allow build this plugin on systems
other than Solaris, just to see if it compiles */
#include <sys/ioctl.h>
#ifndef I_FLUSH
#define I_FLUSH 0
#endif
@ -147,7 +148,11 @@ SolarisOutput::Play(const void *chunk, size_t size)
void
SolarisOutput::Cancel() noexcept
{
#if defined(AUDIO_FLUSH)
ioctl(fd.Get(), AUDIO_FLUSH);
#elif defined(I_FLUSH)
ioctl(fd.Get(), I_FLUSH);
#endif
}
const struct AudioOutputPlugin solaris_output_plugin = {

View File

@ -23,6 +23,7 @@
#include "song/DetachedSong.hxx"
#include "input/InputStream.hxx"
#include "tag/Builder.hxx"
#include "tag/Table.hxx"
#include "util/StringView.hxx"
#include "lib/expat/ExpatParser.hxx"
@ -43,8 +44,8 @@ struct XspfParser {
*/
enum {
ROOT, PLAYLIST, TRACKLIST, TRACK,
LOCATION,
} state;
TAG, LOCATION,
} state = ROOT;
/**
* The current tag within the "track" element. This is only
@ -60,8 +61,20 @@ struct XspfParser {
TagBuilder tag_builder;
XspfParser()
:state(ROOT) {}
std::string value;
};
static constexpr struct tag_table xspf_tag_elements[] = {
{ "title", TAG_TITLE },
/* TAG_COMPOSER would be more correct according to the XSPF
spec */
{ "creator", TAG_ARTIST },
{ "annotation", TAG_COMMENT },
{ "album", TAG_ALBUM },
{ "trackNum", TAG_TRACK },
{ nullptr, TAG_NUM_OF_ITEM_TYPES }
};
static void XMLCALL
@ -69,6 +82,7 @@ xspf_start_element(void *user_data, const XML_Char *element_name,
gcc_unused const XML_Char **atts)
{
auto *parser = (XspfParser *)user_data;
parser->value.clear();
switch (parser->state) {
case XspfParser::ROOT:
@ -87,7 +101,6 @@ xspf_start_element(void *user_data, const XML_Char *element_name,
if (strcmp(element_name, "track") == 0) {
parser->state = XspfParser::TRACK;
parser->location.clear();
parser->tag_type = TAG_NUM_OF_ITEM_TYPES;
}
break;
@ -95,21 +108,16 @@ xspf_start_element(void *user_data, const XML_Char *element_name,
case XspfParser::TRACK:
if (strcmp(element_name, "location") == 0)
parser->state = XspfParser::LOCATION;
else if (strcmp(element_name, "title") == 0)
parser->tag_type = TAG_TITLE;
else if (strcmp(element_name, "creator") == 0)
/* TAG_COMPOSER would be more correct
according to the XSPF spec */
parser->tag_type = TAG_ARTIST;
else if (strcmp(element_name, "annotation") == 0)
parser->tag_type = TAG_COMMENT;
else if (strcmp(element_name, "album") == 0)
parser->tag_type = TAG_ALBUM;
else if (strcmp(element_name, "trackNum") == 0)
parser->tag_type = TAG_TRACK;
else if (!parser->location.empty()) {
parser->tag_type = tag_table_lookup(xspf_tag_elements,
element_name);
if (parser->tag_type != TAG_NUM_OF_ITEM_TYPES)
parser->state = XspfParser::TAG;
}
break;
case XspfParser::TAG:
case XspfParser::LOCATION:
break;
}
@ -143,15 +151,26 @@ xspf_end_element(void *user_data, const XML_Char *element_name)
parser->tag_builder.Commit());
parser->state = XspfParser::TRACKLIST;
} else
parser->tag_type = TAG_NUM_OF_ITEM_TYPES;
}
break;
case XspfParser::TAG:
if (!parser->value.empty())
parser->tag_builder.AddItem(parser->tag_type,
StringView(parser->value.data(),
parser->value.length()));
parser->state = XspfParser::TRACK;
break;
case XspfParser::LOCATION:
parser->location = std::move(parser->value);
parser->state = XspfParser::TRACK;
break;
}
parser->value.clear();
}
static void XMLCALL
@ -163,19 +182,12 @@ xspf_char_data(void *user_data, const XML_Char *s, int len)
case XspfParser::ROOT:
case XspfParser::PLAYLIST:
case XspfParser::TRACKLIST:
break;
case XspfParser::TRACK:
if (!parser->location.empty() &&
parser->tag_type != TAG_NUM_OF_ITEM_TYPES)
parser->tag_builder.AddItem(parser->tag_type,
StringView(s, len));
break;
case XspfParser::TAG:
case XspfParser::LOCATION:
parser->location.assign(s, len);
parser->value.append(s, len);
break;
}
}

View File

@ -144,21 +144,12 @@ LocalStorage::OpenDirectory(const char *uri_utf8)
return std::make_unique<LocalDirectoryReader>(MapFSOrThrow(uri_utf8));
}
gcc_pure
static bool
SkipNameFS(PathTraitsFS::const_pointer name_fs) noexcept
{
return name_fs[0] == '.' &&
(name_fs[1] == 0 ||
(name_fs[1] == '.' && name_fs[2] == 0));
}
const char *
LocalDirectoryReader::Read() noexcept
{
while (reader.ReadEntry()) {
const Path name_fs = reader.GetEntry();
if (SkipNameFS(name_fs.c_str()))
if (PathTraitsFS::IsSpecialFilename(name_fs.c_str()))
continue;
try {

View File

@ -89,7 +89,7 @@ public:
}
void Unset(TagType tag) noexcept {
*this |= ~TagMask(tag);
*this &= ~TagMask(tag);
}
};

View File

@ -37,6 +37,7 @@
#include <stdexcept>
#include <assert.h>
#include <stdlib.h>
StringBuffer<64>
FormatISO8601(const struct tm &tm) noexcept