summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--NEWS12
-rw-r--r--android/AndroidManifest.xml4
-rw-r--r--src/archive/plugins/Iso9660ArchivePlugin.cxx6
-rw-r--r--src/db/update/InotifyUpdate.cxx4
-rw-r--r--src/db/update/Walk.cxx2
-rw-r--r--src/decoder/plugins/GmeDecoderPlugin.cxx11
-rw-r--r--src/fs/Traits.hxx12
-rw-r--r--src/output/plugins/SolarisOutputPlugin.cxx11
-rw-r--r--src/playlist/plugins/XspfPlaylistPlugin.cxx68
-rw-r--r--src/storage/plugins/LocalStorage.cxx11
-rw-r--r--src/tag/Mask.hxx2
-rw-r--r--src/time/ISO8601.cxx1
13 files changed, 93 insertions, 54 deletions
diff --git a/.travis.yml b/.travis.yml
index c62d7e244..38b72d547 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -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"
diff --git a/NEWS b/NEWS
index 84b9f50bb..b0fb7a816 100644
--- a/NEWS
+++ b/NEWS
@@ -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"
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index a7ea8a550..83286b0b7 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -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"/>
diff --git a/src/archive/plugins/Iso9660ArchivePlugin.cxx b/src/archive/plugins/Iso9660ArchivePlugin.cxx
index af4b02aee..ddf81aa2d 100644
--- a/src/archive/plugins/Iso9660ArchivePlugin.cxx
+++ b/src/archive/plugins/Iso9660ArchivePlugin.cxx
@@ -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);
diff --git a/src/db/update/InotifyUpdate.cxx b/src/db/update/InotifyUpdate.cxx
index af27b7bba..449abb80f 100644
--- a/src/db/update/InotifyUpdate.cxx
+++ b/src/db/update/InotifyUpdate.cxx
@@ -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;
}
diff --git a/src/db/update/Walk.cxx b/src/db/update/Walk.cxx
index 095b701e1..3d95ae5f5 100644
--- a/src/db/update/Walk.cxx
+++ b/src/db/update/Walk.cxx
@@ -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
diff --git a/src/decoder/plugins/GmeDecoderPlugin.cxx b/src/decoder/plugins/GmeDecoderPlugin.cxx
index c83069f30..f7165419a 100644
--- a/src/decoder/plugins/GmeDecoderPlugin.cxx
+++ b/src/decoder/plugins/GmeDecoderPlugin.cxx
@@ -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);
}
diff --git a/src/fs/Traits.hxx b/src/fs/Traits.hxx
index 755c0e6ea..d2a2934a0 100644
--- a/src/fs/Traits.hxx
+++ b/src/fs/Traits.hxx
@@ -109,6 +109,12 @@ struct PathTraitsFS {
}
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);
}
@@ -217,6 +223,12 @@ struct PathTraitsUTF8 {
}
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);
}
diff --git a/src/output/plugins/SolarisOutputPlugin.cxx b/src/output/plugins/SolarisOutputPlugin.cxx
index eb769f055..e50109557 100644
--- a/src/output/plugins/SolarisOutputPlugin.cxx
+++ b/src/output/plugins/SolarisOutputPlugin.cxx
@@ -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 = {
diff --git a/src/playlist/plugins/XspfPlaylistPlugin.cxx b/src/playlist/plugins/XspfPlaylistPlugin.cxx
index 8e31b4883..b8d2da61d 100644
--- a/src/playlist/plugins/XspfPlaylistPlugin.cxx
+++ b/src/playlist/plugins/XspfPlaylistPlugin.cxx
@@ -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;
}
}
diff --git a/src/storage/plugins/LocalStorage.cxx b/src/storage/plugins/LocalStorage.cxx
index 2663c63ef..a9d5a4f9b 100644
--- a/src/storage/plugins/LocalStorage.cxx
+++ b/src/storage/plugins/LocalStorage.cxx
@@ -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 {
diff --git a/src/tag/Mask.hxx b/src/tag/Mask.hxx
index dae4b8765..7e43e8cf3 100644
--- a/src/tag/Mask.hxx
+++ b/src/tag/Mask.hxx
@@ -89,7 +89,7 @@ public:
}
void Unset(TagType tag) noexcept {
- *this |= ~TagMask(tag);
+ *this &= ~TagMask(tag);
}
};
diff --git a/src/time/ISO8601.cxx b/src/time/ISO8601.cxx
index 725215ea6..336ddcd5b 100644
--- a/src/time/ISO8601.cxx
+++ b/src/time/ISO8601.cxx
@@ -37,6 +37,7 @@
#include <stdexcept>
#include <assert.h>
+#include <stdlib.h>
StringBuffer<64>
FormatISO8601(const struct tm &tm) noexcept