Compare commits

...

54 Commits

Author SHA1 Message Date
Max Kellermann
acb798e544 release v0.18.21 2014-12-17 19:13:47 +01:00
k44
773de38bd9 playlist/embcue: fix filename suffix detection
The definition of the playlist_plugin struct member of the embcue
plugin was incorrect.
2014-12-16 18:43:05 +01:00
Max Kellermann
fa4beeee75 decoder/ffmpeg: detect and fix negative time stamps
Works around assertion failure due to something that appears to be a
(minor) FFmpeg bug.
2014-12-15 00:40:46 +01:00
Max Kellermann
d8351772d3 configure.ac: prepare for 0.18.21 2014-12-15 00:39:52 +01:00
Max Kellermann
1b5f33a435 release v0.18.20 2014-12-08 14:57:17 +01:00
Max Kellermann
41b4a63f2b decoder/ffmpeg: support FFmpeg 2.5
Version 2.5 fixed an API oddity, however it broke API compatibility,
at least with C++.  Disable the workaround when a libavformat version
is detected that is recent enough.
2014-12-08 14:25:34 +01:00
Max Kellermann
d8fc2db910 thread/Id: drop "::" prefix before pthread function names
The "::" to explicitly refer to the global namespace appeared like a
good idea in C++, but it breaks with C libraries that implement
standard functions using macros (e.g. musl).
2014-12-08 14:17:17 +01:00
Max Kellermann
dc11dea7cc configure.ac: prepare for 0.18.20 2014-12-08 14:13:20 +01:00
Max Kellermann
04f627c2af release v0.18.19 2014-11-26 19:58:48 +01:00
Max Kellermann
a254f5a3a8 archive/zzip: fix inverted error handler
Set the Error when zzip_seek()==-1 and not on success.  Fixes a crash
after seeking.
2014-11-24 22:08:50 +01:00
Max Kellermann
143c735f96 configure.ac: prepare for 0.18.19 2014-11-24 22:08:50 +01:00
Max Kellermann
7aa2104596 release v0.18.18 2014-11-18 21:34:03 +01:00
Max Kellermann
c8b93d6573 Client: assume uid==0 is local socket
A negative uid value means it's not a "local socket" (PF_LOCAL).
uid==0 means user "root" connected.
2014-11-18 20:56:27 +01:00
Max Kellermann
3f5f96ac91 event/ServerSocket: fix get_remote_uid() error value
Must return -1 on error, not 0.  0 is root.
2014-11-18 20:53:59 +01:00
Florent Le Coz
7e7b403043 Construct a Null AllocatedPath if the filename conversion into UTF8 failed 2014-11-11 17:15:19 +01:00
Max Kellermann
c64ad78c7b decoder/ffmpeg: support opus 2014-11-10 18:00:30 +01:00
Max Kellermann
4a043a915f configure.ac: prepare for 0.18.1 2014-11-10 17:59:06 +01:00
Max Kellermann
38a0d15190 release v0.18.17 2014-11-02 13:06:20 +01:00
Max Kellermann
ec3191f502 input/curl: fix curl_easy_setopt() parameter types 2014-11-02 11:55:48 +01:00
Max Kellermann
32b5654a6e Decoder, Playlist: ignore URI query string for plugin detection
Use the new uri_get_suffix() overload that removes the query string.
2014-11-02 11:54:26 +01:00
Max Kellermann
674091424e util/UriUtil: add uri_get_suffix() overload that ignores query string 2014-11-02 11:53:31 +01:00
Max Kellermann
6ad336743d PlaylistFile: don't allow empty playlist name 2014-11-02 11:52:48 +01:00
Max Kellermann
c882568ccd playlist/m3u: recognize the file suffix ".m3u8" 2014-11-02 11:50:56 +01:00
Max Kellermann
f6b2899dd2 decoder/faad: remove workaround for ancient libfaad2 ABI bug
Many years ago, FAAD had a serious ABI bug: the NeAACDecInit()
prototype in its header declared the "samplerate" parameter to be
"unsigned long *", but internally, the function assumed it was
"uint32_t *" instead.  On 32 bit machines, that was no difference, but
on 64 bit, this left one portion of the return value uninitialized;
and worse, on big-endian, the wrong word was filled.  This bug had to
be worked around in MPD (commit 9c4e97a6).

A few months later, the bug was fixed in the FAAD CVS in commit 1.117
on file libfaad/decoder.c; the commit message was:

 "Use public headers internally to prevent duplicate declarations"

The commit message was too brief at best; the problem was not
duplicate declarations, but a prototype mismatch.  No mention of the
bug fix in the ChangeLog.

The MPD project never learned about this bug fix, and so MPD would
always pass a "uin32_t *" dressed up as a "unsigned long *".  Nearly 6
years later, it's about time to fix this second ABI problem.  Let's
kill the workaround!
2014-11-02 11:50:56 +01:00
Steven OBrien
bccd4ef2f7 decoder/ffmpeg: recognize MIME type audio/aacp 2014-11-02 11:50:56 +01:00
Max Kellermann
94c240a026 configure.ac: show DSD in result 2014-11-02 11:50:56 +01:00
Max Kellermann
c50a0cf7bf output/roar: remove unnecessary "volatile" keyword
A mutex acts as a memory barrier, and thus "volatile" is not
necessary.
2014-11-02 11:50:56 +01:00
Max Kellermann
c37f7abb79 TagString: use g_strndup() for unterminated string
Fixes buffer overflow bug.
2014-11-02 11:48:13 +01:00
Max Kellermann
432ce9b1de configure.ac: prepare for 0.18.17 2014-11-02 11:41:40 +01:00
Max Kellermann
fe45f28204 release v0.18.16 2014-09-26 10:57:04 +02:00
Max Kellermann
861067412f configure.ac: fix DSD breakage due to typo 2014-09-26 10:56:20 +02:00
Max Kellermann
7eca886608 configure.ac: prepare for 0.18.16 2014-09-26 10:55:43 +02:00
Max Kellermann
79b6f9e89e release v0.18.15 2014-09-26 09:41:40 +02:00
Max Kellermann
3d17c06777 configure.ac: allow building MPD without decoder plugin
There's always the "PCM" decoder plugin, which was never checked by
configure.ac.
2014-09-26 09:29:18 +02:00
Max Kellermann
d6c08fb79f configure.ac: allow building MPD without output plugin
MPD can easily be used as a database provider for the proxy database
plugin.  In that case, it needs only one "null" output, and no real
output plugin.
2014-09-26 09:29:18 +02:00
Max Kellermann
ef02b20811 CommandLine: update copyright year 2014-09-26 09:29:18 +02:00
Max Kellermann
8bf46a665e configure.ac: add option to disable the DSD decoders
Allow building a smaller MPD binary for people who don't need DSD.
2014-09-26 09:29:18 +02:00
Max Kellermann
c4fca2aa61 playlist/embcue: change name string to "embcue"
The name "cue" was listed twice in "mpd --version".
2014-09-26 09:29:18 +02:00
Max Kellermann
87268c2297 test/test_protocol: add missing stdlib.h include
EXIT_SUCCESS and EXIT_FAILURE are defined in stdlib.h, not unistd.h.
D'oh!
2014-09-24 23:03:28 +02:00
Max Kellermann
e93975cb46 test/test_protocol: add missing unistd.h include 2014-09-24 21:43:11 +02:00
Max Kellermann
b6fa22bd84 OutputThread: retain negative mix ratio
Fixes MixRamp breakage.
2014-09-18 13:50:23 +02:00
Andrzej Rybczak
a0ef27a0cd command/list: reset used size after the list has been processed 2014-09-18 09:15:39 +02:00
Max Kellermann
e304d0f8ee thread/Posix{Cond,Mutex}: don't ues PTHREAD_*_INITIALIZER on NetBSD
On NetBSD, PTHREAD_MUTEX_INITIALIZER and PTHREAD_COND_INITIALIZER are
not compatible with C++11 "constexpr" (see Mantis ticket 0004110).  As
a workaround, don't ues "constexpr", and use the functions
pthread_mutex_init(), pthread_mutex_destroy(), pthread_cond_init() and
pthread_cond_destroy() instead.  This adds some runtime overhead, but
is portable to POSIX implementations that have awkward initializer
macros.
2014-09-13 11:26:17 +02:00
Max Kellermann
ab7b38d4b9 configure.ac: prepare for 0.18.15 2014-09-13 11:14:41 +02:00
Max Kellermann
eaf675dc92 release v0.18.14 2014-09-11 19:09:49 +02:00
Max Kellermann
57068e526c test/run_decoder: dump MixRamp data 2014-09-09 19:17:22 +02:00
Max Kellermann
c14a00eec9 decoder/ffmpeg: use memset() to initialize AVProbeData 2014-09-09 19:07:46 +02:00
Max Kellermann
219c42522f decoder/ffmpeg: pass MIME type to ffmpeg/libav version 11
That attribute was uninitialized before, which could crash
libavformat.

See Debian bug 760669
2014-09-07 22:05:33 +02:00
Max Kellermann
e3a0f15837 Decoder*: add more assertions 2014-09-07 21:52:34 +02:00
Max Kellermann
a6bb27483b DecoderThread: clear the pipe when handling late SEEK
See code comment.  Fixes assertion failure in
decoder_command_finished().
2014-09-07 21:50:00 +02:00
Max Kellermann
7ada7def9e decoder/audiofile: fix crash after seeking
Log call was added to the wrong branch.

Fixes regression by commit ca1a1149
2014-09-06 19:32:10 +02:00
Max Kellermann
421c4ae907 protocol/ArgParser: fix integer overflow in parse_range()
Casting std::numeric_limits<unsigned>::max() to "long" leads to an
overflow if sizeof(unsigned)==sizeof(long), and the result will be -1.

This happens on some 32 bit architectures, for example ARM and WIN32.

Workaround: use std::numeric_limits<int>::max(), which is the largest
signed integer.  Since sizeof(long)>=sizeof(int), this will never
overflow.

Fixes Mantis ticket 0004080.
2014-09-04 17:37:31 +02:00
Max Kellermann
4907f610d6 test/test_protocol: unit test for protocol/ArgParser.cxx 2014-09-04 17:10:30 +02:00
Max Kellermann
f9d1bbbffb configure.ac: prepare for 0.18.14 2014-09-03 19:59:26 +02:00
38 changed files with 335 additions and 129 deletions

1
.gitignore vendored

@@ -63,6 +63,7 @@ test/run_normalize
test/tmp
test/run_inotify
test/test_queue_priority
test/test_protocol
test/run_ntp_server
test/run_resolver
test/run_tcp_connect

@@ -476,12 +476,6 @@ endif
libdecoder_plugins_a_SOURCES = \
src/decoder/PcmDecoderPlugin.cxx \
src/decoder/PcmDecoderPlugin.hxx \
src/decoder/DsdiffDecoderPlugin.cxx \
src/decoder/DsdiffDecoderPlugin.hxx \
src/decoder/DsfDecoderPlugin.cxx \
src/decoder/DsfDecoderPlugin.hxx \
src/decoder/DsdLib.cxx \
src/decoder/DsdLib.hxx \
src/DecoderBuffer.cxx src/DecoderBuffer.hxx \
src/DecoderPlugin.cxx \
src/DecoderList.cxx src/DecoderList.hxx
@@ -525,6 +519,16 @@ DECODER_LIBS = \
DECODER_SRC =
if ENABLE_DSD
libdecoder_plugins_a_SOURCES += \
src/decoder/DsdiffDecoderPlugin.cxx \
src/decoder/DsdiffDecoderPlugin.hxx \
src/decoder/DsfDecoderPlugin.cxx \
src/decoder/DsfDecoderPlugin.hxx \
src/decoder/DsdLib.cxx \
src/decoder/DsdLib.hxx
endif
if HAVE_MAD
libdecoder_plugins_a_SOURCES += \
src/decoder/MadDecoderPlugin.cxx \
@@ -1064,6 +1068,7 @@ C_TESTS = \
test/test_mixramp \
test/test_icy_parser \
test/test_pcm \
test/test_protocol \
test/test_queue_priority
if ENABLE_ARCHIVE
@@ -1538,6 +1543,16 @@ test_test_archive_LDADD = \
$(GLIB_LIBS) \
$(CPPUNIT_LIBS)
test_test_protocol_SOURCES = \
src/protocol/ArgParser.cxx \
test/test_protocol.cxx
test_test_protocol_CPPFLAGS = $(AM_CPPFLAGS) $(CPPUNIT_CFLAGS) -DCPPUNIT_HAVE_RTTI=0
test_test_protocol_CXXFLAGS = $(AM_CXXFLAGS) -Wno-error=deprecated-declarations
test_test_protocol_LDADD = \
libsystem.a \
libutil.a \
$(CPPUNIT_LIBS)
test_test_queue_priority_SOURCES = \
src/Queue.cxx \
test/test_queue_priority.cxx
@@ -1548,6 +1563,8 @@ test_test_queue_priority_LDADD = \
libutil.a \
$(CPPUNIT_LIBS)
if ENABLE_DSD
noinst_PROGRAMS += src/pcm/dsd2pcm/dsd2pcm
src_pcm_dsd2pcm_dsd2pcm_SOURCES = \
@@ -1560,6 +1577,8 @@ src_pcm_dsd2pcm_dsd2pcm_LDADD = libutil.a
endif
endif
#
# Documentation

47
NEWS

@@ -1,3 +1,50 @@
ver 0.18.21 (2014/12/17)
* playlist
- embcue: fix filename suffix detection
* decoder
- ffmpeg: fix time stamp underflow
ver 0.18.20 (2014/12/08)
* decoder
- ffmpeg: support FFmpeg 2.5
* fix build failure with musl
ver 0.18.19 (2014/11/26)
* archive
- zzip: fix crash after seeking
ver 0.18.18 (2014/11/18)
* decoder
- ffmpeg: support opus
* fix crash on failed filename charset conversion
* fix local socket detection from uid=0 (root)
ver 0.18.17 (2014/11/02)
* playlist
- don't allow empty playlist name
- m3u: recognize the file suffix ".m3u8"
* decoder
- ignore URI query string for plugin detection
- faad: remove workaround for ancient libfaad2 ABI bug
- ffmpeg: recognize MIME type audio/aacp
ver 0.18.16 (2014/09/26)
* fix DSD breakage due to typo in configure.ac
ver 0.18.15 (2014/09/26)
* command
- list: reset used size after the list has been processed
* fix MixRamp
* work around build failure on NetBSD
ver 0.18.14 (2014/09/11)
* protocol
- fix range parser bug on certain 32 bit architectures
* decoder
- audiofile: fix crash after seeking
- ffmpeg: fix crash with ffmpeg/libav version 11
- fix assertion failure after seeking
ver 0.18.13 (2014/08/31)
* protocol
- don't change song on "seekcur" in random mode

@@ -1,10 +1,10 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.18.13, mpd-devel@musicpd.org)
AC_INIT(mpd, 0.18.21, mpd-devel@musicpd.org)
VERSION_MAJOR=0
VERSION_MINOR=18
VERSION_REVISION=0
VERSION_REVISION=21
VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -214,6 +214,11 @@ AC_ARG_ENABLE(documentation,
[build documentation (default: disable)]),,
[enable_documentation=no])
AC_ARG_ENABLE(dsd,
AS_HELP_STRING([--enable-dsd],
[enable DSD decoder (default: enable)]),,
[enable_dsd=yes])
AC_ARG_ENABLE(ffmpeg,
AS_HELP_STRING([--enable-ffmpeg],
[enable FFMPEG support]),,
@@ -846,6 +851,14 @@ if test x$enable_audiofile = xyes; then
AC_DEFINE(HAVE_AUDIOFILE, 1, [Define for audiofile support])
fi
dnl ----------------------------------- DSD -----------------------------------
if test x$enable_dsd = xyes; then
AC_DEFINE(ENABLE_DSD, 1, [Define for the DSD decoder])
fi
AM_CONDITIONAL(ENABLE_DSD, test x$enable_dsd = xyes)
dnl ----------------------------------- FAAD ----------------------------------
AM_PATH_FAAD()
@@ -1081,27 +1094,6 @@ AM_CONDITIONAL(ENABLE_WILDMIDI, test x$enable_wildmidi = xyes)
dnl ------------------------ Post Decoder Plugins Tests -----------------------
if
test x$enable_aac = xno &&
test x$enable_audiofile = xno &&
test x$enable_ffmpeg = xno &&
test x$enable_flac = xno &&
test x$enable_fluidsynth = xno &&
test x$enable_mad = xno &&
test x$enable_mikmod = xno; then
test x$enable_modplug = xno &&
test x$enable_mpc = xno &&
test x$enable_mpg123 = xno &&
test x$enable_opus = xno &&
test x$enable_sidplay = xno &&
test x$enable_tremor = xno &&
test x$enable_vorbis = xno &&
test x$enable_wavpack = xno &&
test x$enable_wildmidi = xno &&
AC_MSG_ERROR([No input plugins supported!])
fi
AM_CONDITIONAL(HAVE_XIPH,
test x$enable_vorbis = xyes || test x$enable_tremor = xyes || test x$enable_flac = xyes || test x$enable_opus = xyes)
@@ -1410,27 +1402,6 @@ esac
AM_CONDITIONAL(ENABLE_WINMM_OUTPUT, test x$enable_winmm_output = xyes)
dnl --------------------- Post Audio Output Plugins Tests ---------------------
if
test x$enable_alsa = xno &&
test x$enable_roar = xno &&
test x$enable_ao = xno &&
test x$enable_fifo = xno &&
test x$enable_httpd_output = xno &&
test x$enable_jack = xno &&
test x$enable_openal = xno &&
test x$enable_oss = xno &&
test x$enable_osx = xno &&
test x$enable_pipe_output = xno &&
test x$enable_pulse = xno &&
test x$enable_recorder_output = xno &&
test x$enable_shout = xno &&
test x$enable_solaris_output = xno &&
test x$enable_winmm_output = xno; then
AC_MSG_ERROR([No Audio Output types configured!])
fi
dnl ---------------------------------------------------------------------------
dnl Documentation
dnl ---------------------------------------------------------------------------
@@ -1552,6 +1523,7 @@ results(un,[UNIX Domain Sockets])
printf '\nFile format support:\n\t'
results(aac, [AAC])
results(adplug, [AdPlug])
results(dsd, [DSD])
results(sidplay, [C64 SID])
results(ffmpeg, [FFMPEG])
results(flac, [FLAC])

@@ -62,36 +62,7 @@ int main() {
CPPFLAGS=$oldcppflags
fi
if test x$enable_aac = xyes; then
oldcflags=$CFLAGS
oldlibs=$LIBS
oldcppflags=$CPPFLAGS
CFLAGS="$CFLAGS $FAAD_CFLAGS -Werror"
LIBS="$LIBS $FAAD_LIBS"
CPPFLAGS=$CFLAGS
AC_MSG_CHECKING(for broken libfaad headers)
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <faad.h>
#include <stddef.h>
#include <stdint.h>
int main() {
unsigned char channels;
uint32_t sample_rate;
NeAACDecInit2(NULL, NULL, 0, &sample_rate, &channels);
return 0;
}
])],
[AC_MSG_RESULT(correct)],
[AC_MSG_RESULT(broken);
AC_DEFINE(HAVE_FAAD_LONG, 1, [Define if faad.h uses the broken "unsigned long" pointers])])
CFLAGS=$oldcflags
LIBS=$oldlibs
CPPFLAGS=$oldcppflags
else
if test x$enable_aac = xno; then
FAAD_LIBS=""
FAAD_CFLAGS=""
fi

@@ -109,7 +109,7 @@ public:
* a local (UNIX domain) socket?
*/
bool IsLocal() const {
return uid > 0;
return uid >= 0;
}
unsigned GetPermission() const {

@@ -47,7 +47,7 @@ client_allow_file(const Client &client, Path path_fs, Error &error)
instance */
return true;
if (uid <= 0) {
if (uid < 0) {
/* unauthenticated client */
error.Set(ack_domain, ACK_ERROR_PERMISSION, "Access denied");
return false;

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -69,7 +69,7 @@ static void version(void)
puts("Music Player Daemon " VERSION "\n"
"\n"
"Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
"Copyright (C) 2008-2013 Max Kellermann <max@duempel.org>\n"
"Copyright (C) 2008-2014 Max Kellermann <max@duempel.org>\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
"\n"

@@ -47,6 +47,7 @@ decoder_initialized(Decoder &decoder,
assert(dc.state == DecoderState::START);
assert(dc.pipe != nullptr);
assert(dc.pipe->IsEmpty());
assert(decoder.stream_tag == nullptr);
assert(decoder.decoder_tag == nullptr);
assert(!decoder.seeking);
@@ -405,6 +406,9 @@ decoder_data(Decoder &decoder,
length == 0)
return cmd;
assert(!decoder.initial_seek_pending);
assert(!decoder.initial_seek_running);
/* send stream tags */
if (update_stream_tag(decoder, is)) {

@@ -83,6 +83,9 @@ void
decoder_flush_chunk(Decoder &decoder)
{
DecoderControl &dc = decoder.dc;
assert(!decoder.seeking);
assert(!decoder.initial_seek_running);
assert(!decoder.initial_seek_pending);
assert(decoder.chunk != nullptr);

@@ -73,8 +73,10 @@ const struct DecoderPlugin *const decoder_plugins[] = {
#ifdef HAVE_AUDIOFILE
&audiofile_decoder_plugin,
#endif
#ifdef ENABLE_DSD
&dsdiff_decoder_plugin,
&dsf_decoder_plugin,
#endif
#ifdef HAVE_FAAD
&faad_decoder_plugin,
#endif

@@ -26,6 +26,7 @@
#include "Song.hxx"
#include "system/FatalError.hxx"
#include "Mapper.hxx"
#include "MusicPipe.hxx"
#include "fs/Traits.hxx"
#include "fs/AllocatedPath.hxx"
#include "DecoderAPI.hxx"
@@ -211,7 +212,8 @@ static bool
decoder_run_stream_locked(Decoder &decoder, InputStream &is,
const char *uri, bool &tried_r)
{
const char *const suffix = uri_get_suffix(uri);
UriSuffixBuffer suffix_buffer;
const char *const suffix = uri_get_suffix(uri, suffix_buffer);
using namespace std::placeholders;
const auto f = std::bind(decoder_run_stream_plugin,
@@ -418,9 +420,18 @@ decoder_task(void *arg)
dc.replay_gain_prev_db = dc.replay_gain_db;
dc.replay_gain_db = 0;
/* fall through */
decoder_run(dc);
break;
case DecoderCommand::SEEK:
/* this seek was too late, and the decoder had
already finished; start a new decoder */
/* we need to clear the pipe here; usually the
PlayerThread is responsible, but it is not
aware that the decoder has finished */
dc.pipe->Clear(*dc.buffer);
decoder_run(dc);
break;

@@ -385,11 +385,20 @@ ao_filter_chunk(struct audio_output *ao, const struct music_chunk *chunk,
if (length > other_length)
length = other_length;
float mix_ratio = chunk->mix_ratio;
if (mix_ratio >= 0)
/* reverse the mix ratio (because the
arguments to pcm_mix() are reversed), but
only if the mix ratio is non-negative; a
negative mix ratio is a MixRamp special
case */
mix_ratio = 1.0 - mix_ratio;
void *dest = ao->cross_fade_buffer.Get(other_length);
memcpy(dest, other_data, other_length);
if (!pcm_mix(dest, data, length,
ao->in_audio_format.format,
1.0 - chunk->mix_ratio)) {
mix_ratio)) {
FormatError(output_domain,
"Cannot cross-fade format %s",
sample_format_to_string(ao->in_audio_format.format));

@@ -69,6 +69,10 @@ spl_global_init(void)
bool
spl_valid_name(const char *name_utf8)
{
if (*name_utf8 == 0)
/* empty name not allowed */
return false;
/*
* Not supporting '/' was done out of laziness, and we should
* really strive to support it in the future.

@@ -164,12 +164,12 @@ static SongEnumerator *
playlist_list_open_uri_suffix(const char *uri, Mutex &mutex, Cond &cond,
const bool *tried)
{
const char *suffix;
SongEnumerator *playlist = nullptr;
assert(uri != nullptr);
suffix = uri_get_suffix(uri);
UriSuffixBuffer suffix_buffer;
const char *const suffix = uri_get_suffix(uri, suffix_buffer);
if (suffix == nullptr)
return nullptr;
@@ -273,8 +273,6 @@ playlist_list_open_stream_suffix(InputStream &is, const char *suffix)
SongEnumerator *
playlist_list_open_stream(InputStream &is, const char *uri)
{
const char *suffix;
is.LockWaitReady();
const char *const mime = is.GetMimeType();
@@ -284,7 +282,10 @@ playlist_list_open_stream(InputStream &is, const char *uri)
return playlist;
}
suffix = uri != nullptr ? uri_get_suffix(uri) : nullptr;
UriSuffixBuffer suffix_buffer;
const char *suffix = uri != nullptr
? uri_get_suffix(uri, suffix_buffer)
: nullptr;
if (suffix != nullptr) {
auto playlist = playlist_list_open_stream_suffix(is, suffix);
if (playlist != nullptr)

@@ -186,12 +186,13 @@ zzip_input_seek(InputStream *is, InputPlugin::offset_type offset,
{
ZzipInputStream *zis = (ZzipInputStream *)is;
zzip_off_t ofs = zzip_seek(zis->file, offset, whence);
if (ofs != -1) {
if (ofs < 0) {
error.Set(zzip_domain, "zzip_seek() has failed");
is->offset = ofs;
return true;
return false;
}
return false;
is->offset = ofs;
return true;
}
/* exported structures */

@@ -27,6 +27,7 @@ void
CommandListBuilder::Reset()
{
list.clear();
size = 0;
mode = Mode::DISABLED;
}

@@ -110,9 +110,9 @@ audiofile_file_seek(AFvirtualfile *vfile, AFfileoffset offset, int is_relative)
Error error;
if (is.LockSeek(offset, whence, error)) {
LogError(error, "Seek failed");
return is.GetOffset();
} else {
LogError(error, "Seek failed");
return -1;
}
}

@@ -277,20 +277,12 @@ faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
}
uint8_t channels;
uint32_t sample_rate;
#ifdef HAVE_FAAD_LONG
/* neaacdec.h declares all arguments as "unsigned long", but
internally expects uint32_t pointers. To avoid gcc
warnings, use this workaround. */
unsigned long *sample_rate_p = (unsigned long *)(void *)&sample_rate;
#else
uint32_t *sample_rate_p = &sample_rate;
#endif
unsigned long sample_rate;
long nbytes = NeAACDecInit(decoder,
/* deconst hack, libfaad requires this */
const_cast<unsigned char *>(data),
length,
sample_rate_p, &channels);
&sample_rate, &channels);
if (nbytes < 0) {
error.Set(faad_decoder_domain, "Not an AAC stream");
return false;

@@ -284,10 +284,13 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is,
AVFrame *frame,
uint8_t **buffer, int *buffer_size)
{
if (packet->pts >= 0 && packet->pts != (int64_t)AV_NOPTS_VALUE)
decoder_timestamp(decoder,
time_from_ffmpeg(packet->pts - start_time_fallback(*stream),
stream->time_base));
if (packet->pts >= 0 && packet->pts != (int64_t)AV_NOPTS_VALUE) {
auto start = start_time_fallback(*stream);
if (packet->pts >= start)
decoder_timestamp(decoder,
time_from_ffmpeg(packet->pts - start,
stream->time_base));
}
AVPacket packet2 = *packet;
@@ -383,10 +386,28 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
nbytes -= PADDING;
AVProbeData avpd;
/* new versions of ffmpeg may add new attributes, and leaving
them uninitialized may crash; hopefully, zero-initializing
everything we don't know is ok */
memset(&avpd, 0, sizeof(avpd));
avpd.buf = buffer;
avpd.buf_size = nbytes;
avpd.filename = is.uri.c_str();
#ifdef AVPROBE_SCORE_MIME
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(56, 5, 1)
/* this attribute was added in libav/ffmpeg version 11, but
unfortunately it's "uint8_t" instead of "char", and it's
not "const" - wtf? */
avpd.mime_type = (uint8_t *)const_cast<char *>(is.GetMimeType());
#else
/* API problem fixed in FFmpeg 2.5 */
avpd.mime_type = is.GetMimeType();
#endif
#endif
return av_probe_input_format(&avpd, true);
}
@@ -607,7 +628,7 @@ static const char *const ffmpeg_suffixes[] = {
"mj2", "mjpeg", "mjpg", "mka", "mkv", "mlp", "mm", "mmf", "mov", "mp+",
"mp1", "mp2", "mp3", "mp4", "mpc", "mpeg", "mpg", "mpga", "mpp", "mpu",
"mve", "mvi", "mxf", "nc", "nsv", "nut", "nuv", "oga", "ogm", "ogv",
"ogx", "oma", "ogg", "omg", "psp", "pva", "qcp", "qt", "r3d", "ra",
"ogx", "oma", "ogg", "omg", "opus", "psp", "pva", "qcp", "qt", "r3d", "ra",
"ram", "rl2", "rm", "rmvb", "roq", "rpl", "rvc", "shn", "smk", "snd",
"sol", "son", "spx", "str", "swf", "tgi", "tgq", "tgv", "thp", "ts",
"tsp", "tta", "xa", "xvid", "uv", "uv2", "vb", "vid", "vob", "voc",
@@ -630,6 +651,7 @@ static const char *const ffmpeg_mime_types[] = {
"audio/8svx",
"audio/16sv",
"audio/aac",
"audio/aacp",
"audio/ac3",
"audio/aiff"
"audio/amr",
@@ -640,6 +662,7 @@ static const char *const ffmpeg_mime_types[] = {
"audio/mpeg",
"audio/musepack",
"audio/ogg",
"audio/opus",
"audio/qcelp",
"audio/vorbis",
"audio/vorbis+ogg",

@@ -141,7 +141,7 @@ get_remote_uid(int fd)
socklen_t len = sizeof (cred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0)
return 0;
return -1;
return cred.uid;
#else

@@ -46,7 +46,11 @@ AllocatedPath::Build(const_pointer a, const_pointer b)
AllocatedPath
AllocatedPath::FromUTF8(const char *path_utf8)
{
return AllocatedPath(Donate(), ::PathFromUTF8(path_utf8));
char *path = ::PathFromUTF8(path_utf8);
if (path == nullptr)
return AllocatedPath::Null();
return AllocatedPath(Donate(), path);
}
AllocatedPath

@@ -983,10 +983,10 @@ input_curl_easy_init(struct input_curl *c, Error &error)
input_curl_writefunction);
curl_easy_setopt(c->easy, CURLOPT_WRITEDATA, c);
curl_easy_setopt(c->easy, CURLOPT_HTTP200ALIASES, http_200_aliases);
curl_easy_setopt(c->easy, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(c->easy, CURLOPT_NETRC, 1);
curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5);
curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, true);
curl_easy_setopt(c->easy, CURLOPT_FOLLOWLOCATION, 1l);
curl_easy_setopt(c->easy, CURLOPT_NETRC, 1l);
curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5l);
curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, 1l);
curl_easy_setopt(c->easy, CURLOPT_ERRORBUFFER, c->error);
curl_easy_setopt(c->easy, CURLOPT_NOPROGRESS, 1l);
curl_easy_setopt(c->easy, CURLOPT_NOSIGNAL, 1l);

@@ -28,7 +28,7 @@ struct notify {
Cond cond;
bool pending;
#ifndef WIN32
#if !defined(WIN32) && !defined(__NetBSD__)
constexpr
#endif
notify():pending(false) {}

@@ -46,7 +46,7 @@ class RoarOutput {
struct roar_connection con;
struct roar_audio_info info;
mutable Mutex mutex;
volatile bool alive;
bool alive;
public:
RoarOutput()

@@ -171,14 +171,14 @@ static const char *const embcue_playlist_suffixes[] = {
};
const struct playlist_plugin embcue_playlist_plugin = {
"cue",
"embcue",
nullptr,
nullptr,
embcue_playlist_open_uri,
nullptr,
nullptr,
embcue_playlist_suffixes,
nullptr,
nullptr,
};

@@ -135,7 +135,8 @@ ExtM3uPlaylist::NextSong()
static const char *const extm3u_suffixes[] = {
"m3u",
NULL
"m3u8",
nullptr
};
static const char *const extm3u_mime_types[] = {

@@ -61,6 +61,7 @@ M3uPlaylist::NextSong()
static const char *const m3u_suffixes[] = {
"m3u",
"m3u8",
nullptr
};

@@ -81,7 +81,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
/* compatibility with older MPD versions: specifying
"-1" makes MPD display the whole list */
*value_r1 = 0;
*value_r2 = std::numeric_limits<unsigned>::max();
*value_r2 = std::numeric_limits<int>::max();
return true;
}
@@ -108,7 +108,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
}
if (test == test2)
value = std::numeric_limits<unsigned>::max();
value = std::numeric_limits<int>::max();
if (value < 0) {
command_error(client, ACK_ERROR_ARG,

@@ -33,7 +33,7 @@ patch_utf8(const char *src, size_t length, const gchar *end)
{
/* duplicate the string, and replace invalid bytes in that
buffer */
char *dest = g_strdup(src);
char *dest = g_strndup(src, length);
do {
dest[end - src] = '?';

@@ -75,7 +75,7 @@ public:
#ifdef WIN32
return ::GetCurrentThreadId();
#else
return ::pthread_self();
return pthread_self();
#endif
}
@@ -84,7 +84,7 @@ public:
#ifdef WIN32
return id == other.id;
#else
return ::pthread_equal(id, other.id);
return pthread_equal(id, other.id);
#endif
}

@@ -41,7 +41,21 @@ class PosixCond {
pthread_cond_t cond;
public:
#ifdef __NetBSD__
/* NetBSD's PTHREAD_COND_INITIALIZER is not compatible with
"constexpr" */
PosixCond() {
pthread_cond_init(&cond, nullptr);
}
~PosixCond() {
pthread_cond_destroy(&cond);
}
#else
/* optimized constexpr constructor for sane POSIX
implementations */
constexpr PosixCond():cond(PTHREAD_COND_INITIALIZER) {}
#endif
PosixCond(const PosixCond &other) = delete;
PosixCond &operator=(const PosixCond &other) = delete;

@@ -41,7 +41,21 @@ class PosixMutex {
pthread_mutex_t mutex;
public:
#ifdef __NetBSD__
/* NetBSD's PTHREAD_MUTEX_INITIALIZER is not compatible with
"constexpr" */
PosixMutex() {
pthread_mutex_init(&mutex, nullptr);
}
~PosixMutex() {
pthread_mutex_destroy(&mutex);
}
#else
/* optimized constexpr constructor for sane POSIX
implementations */
constexpr PosixMutex():mutex(PTHREAD_MUTEX_INITIALIZER) {}
#endif
PosixMutex(const PosixMutex &other) = delete;
PosixMutex &operator=(const PosixMutex &other) = delete;

@@ -44,6 +44,23 @@ uri_get_suffix(const char *uri)
return suffix;
}
const char *
uri_get_suffix(const char *uri, UriSuffixBuffer &buffer)
{
const char *suffix = uri_get_suffix(uri);
if (suffix == nullptr)
return nullptr;
const char *q = strchr(suffix, '?');
if (q != nullptr && size_t(q - suffix) < sizeof(buffer.data)) {
memcpy(buffer.data, suffix, q - suffix);
buffer.data[q - suffix] = 0;
suffix = buffer.data;
}
return suffix;
}
static const char *
verify_uri_segment(const char *p)
{

@@ -35,6 +35,17 @@ gcc_pure
const char *
uri_get_suffix(const char *uri);
struct UriSuffixBuffer {
char data[8];
};
/**
* Returns the file name suffix, ignoring the query string.
*/
gcc_pure
const char *
uri_get_suffix(const char *uri, UriSuffixBuffer &buffer);
/**
* Returns true if this is a safe "local" URI:
*

@@ -175,8 +175,10 @@ decoder_replay_gain(gcc_unused Decoder &decoder,
}
void
decoder_mixramp(gcc_unused Decoder &decoder, gcc_unused MixRampInfo &&mix_ramp)
decoder_mixramp(gcc_unused Decoder &decoder, MixRampInfo &&mix_ramp)
{
fprintf(stderr, "MixRamp: start='%s' end='%s'\n",
mix_ramp.GetStart(), mix_ramp.GetEnd());
}
int main(int argc, char **argv)

62
test/test_protocol.cxx Normal file

@@ -0,0 +1,62 @@
#include "config.h"
#include "protocol/ArgParser.hxx"
#include "protocol/Result.hxx"
#include "Compiler.h"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <stdlib.h>
static enum ack last_error = ack(-1);
void
command_error(gcc_unused Client &client, enum ack error,
gcc_unused const char *fmt, ...)
{
last_error = error;
}
class ArgParserTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ArgParserTest);
CPPUNIT_TEST(TestRange);
CPPUNIT_TEST_SUITE_END();
public:
void TestRange();
};
void
ArgParserTest::TestRange()
{
Client &client = *(Client *)nullptr;
unsigned a, b;
CPPUNIT_ASSERT(check_range(client, &a, &b, "1"));
CPPUNIT_ASSERT_EQUAL(1u, a);
CPPUNIT_ASSERT_EQUAL(2u, b);
CPPUNIT_ASSERT(check_range(client, &a, &b, "1:5"));
CPPUNIT_ASSERT_EQUAL(1u, a);
CPPUNIT_ASSERT_EQUAL(5u, b);
CPPUNIT_ASSERT(check_range(client, &a, &b, "1:"));
CPPUNIT_ASSERT_EQUAL(1u, a);
CPPUNIT_ASSERT(b >= 999999u);
CPPUNIT_ASSERT(!check_range(client, &a, &b, "-2"));
CPPUNIT_ASSERT_EQUAL(ACK_ERROR_ARG, last_error);
}
CPPUNIT_TEST_SUITE_REGISTRATION(ArgParserTest);
int
main(gcc_unused int argc, gcc_unused char **argv)
{
CppUnit::TextUi::TestRunner runner;
auto &registry = CppUnit::TestFactoryRegistry::getRegistry();
runner.addTest(registry.makeTest());
return runner.run() ? EXIT_SUCCESS : EXIT_FAILURE;
}

@@ -33,6 +33,25 @@ public:
uri_get_suffix(".jpg"));
CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix("/foo/.jpg"));
/* the first overload does not eliminate the query
string */
CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string"),
"jpg?query_string"));
/* ... but the second one does */
UriSuffixBuffer buffer;
CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string",
buffer),
"jpg"));
/* repeat some of the above tests with the second overload */
CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix("/foo/bar", buffer));
CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix("/foo.jpg/bar", buffer));
CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg", buffer),
"jpg"));
}
void TestRemoveAuth() {