Compare commits

...

42 Commits

Author SHA1 Message Date
Max Kellermann
a40510c241 release v0.20.6 2017-03-10 16:57:59 +01:00
Max Kellermann
ac8dce6599 lib/curl/Request: "ICY 200 OK" is a response boundary header 2017-03-10 16:28:02 +01:00
Max Kellermann
190d525099 lib/curl/Request: move code to IsResponseBoundaryHeader() 2017-03-10 16:24:30 +01:00
Max Kellermann
1b6666fa39 Partition: handle SYNC_WITH_PLAYER before TAG_MODIFIED
The TAG_MODIFIED handler (i.e. playlist::TagModified()) works only if
the modified song is the current song - something that is not updated
until SYNC_WITH_PLAYER is finished.  This fixes tag updates right
after a new song is started.
2017-03-10 16:11:34 +01:00
Max Kellermann
1dd01c99e8 decoder/sidplay: make compatible with libsidplayfp < 1.8
https://bugs.musicpd.org/view.php?id=4665
2017-03-10 13:48:52 +01:00
Thomas Zander
d50b30a498 Add missing include for cstdlib, otherwise free() is undefined 2017-03-07 20:02:36 +01:00
Max Kellermann
42a3a87f13 util/HugeAllocator: paranoid check for sysconf()<0
Just in case.
2017-03-01 21:50:26 +01:00
Ben Boeckel
9dfedbe619 ReusableArray: fix build error on GCC7
GCC7 outputs the following error without this change:

    src/util/ReusableArray.hxx:61:35: error: no matching function for call to ‘swap(size_t&, const size_t&)’
       std::swap(capacity, src.capacity);

which can be resolved by just using an rvalue-reference rather than a
const rvalue-reference.

Signed-off-by: Ben Boeckel <mathstuf@gmail.com>
2017-03-01 19:38:41 +01:00
Max Kellermann
88957b4c9d android/build.py: build with libc++ instead of GNU libstdc++
Android is migrating away from GCC, and libstdc++ will disappear
eventually.
2017-03-01 17:31:26 +01:00
Max Kellermann
b2f2c9322b db/simple/Mount: workaround for libc++ 2017-03-01 17:31:26 +01:00
Max Kellermann
3be2051808 decoder/Thread: check ENABLE_FFMPEG, not HAVE_FFMPEG
This repairs the damage to commit 74dbaade6f done by commit
b3f5b4932c
2017-03-01 17:06:23 +01:00
Max Kellermann
ff32b0dc9b input/curl: use %lu instead of %llu
Fixes a GCC warning because %llu appears to be unsupported by the
Windows standard library.
2017-03-01 16:44:11 +01:00
Max Kellermann
c1869a11af input/curl: format Range offset as unsigned 2017-03-01 16:44:08 +01:00
Max Kellermann
e22a4fdba4 command/Error: improve libstdc++ 4.9.x detection for std::rethrow_if_nested() workaround 2017-03-01 16:38:22 +01:00
Max Kellermann
29a7b2c5b5 decoder/mpcdec: ignore empty frames
https://bugs.musicpd.org/view.php?id=4656 describes a crash due to
division by zero because frame.samples==0.  This should never happen,
but apparently can happen after seeking.  The best we can do is to
just ignore this frame.
2017-03-01 16:13:21 +01:00
Max Kellermann
3b6c285c2a configure.ac: prepare for 0.20.6 2017-03-01 16:13:21 +01:00
Max Kellermann
575d1786af release v0.20.5 2017-02-20 21:51:31 +01:00
Max Kellermann
bc1c927952 util/TimeFormat: suppress -Wunused on Windows 2017-02-20 21:44:01 +01:00
Max Kellermann
f95bc85f91 python/build/libs: upgrade FFmpeg to 3.2.4 2017-02-20 21:13:43 +01:00
Max Kellermann
4015195314 doc/user: instructions to compile the Windows binary 2017-02-20 21:06:43 +01:00
Max Kellermann
c3d883c6cb win32/build.py: default to x64 build 2017-02-20 21:06:43 +01:00
Max Kellermann
097e30321b win32/build.py: add option --32 2017-02-20 21:06:31 +01:00
Max Kellermann
b6ddeaacf2 win32/build.py: convert argument parser to loop
Allow multiple arguments.
2017-02-20 21:06:21 +01:00
Max Kellermann
b0c60ec124 win32/build.py: add variable "x64", assign host_arch later 2017-02-20 21:04:34 +01:00
Max Kellermann
f3b788703e tag/Handler: improve snprintf() return value check 2017-02-19 19:34:13 +01:00
Max Kellermann
4bb83781e8 output/httpd/IcyMetaDataServer: cast length to unsigned
Fixes another buffer overflow: if the stream has a very long title or
URL, resulting in a metadata string of more than 2 kB, icy_string[0]
is a negative value, which gets casted to size_t - ouch!

 https://bugs.musicpd.org/view.php?id=4652
2017-02-19 19:28:52 +01:00
Max Kellermann
a73195b7cc output/httpd/IcyMetaDataServer: pad the string with 15 spaces
Fixes a buffer overflow due to the bad formula rounding the buffer
size up.  At the same time, remove the "+1" from the meta_length
calculation, which takes the padding into account and at the same time
implements proper rounding.
2017-02-19 19:27:37 +01:00
Max Kellermann
1bd00b8a9a output/httpd/IcyMetaDataServer: remove the int cast
Why did this cast exist??
2017-02-19 19:27:37 +01:00
Max Kellermann
d84eaeafc5 doc/include/tags.xml: clarify that track/disc are decimal 2017-02-18 19:01:04 +01:00
Max Kellermann
20ae84bff9 {input,mixer}/alsa: cancel the DeferredMonitor in the destructor
Yet another potential crash bug fix.
2017-02-10 15:05:49 +01:00
Max Kellermann
7372c931b3 event/Loop: make IsInsideOrNull() available in the NDEBUG build
Fixes build breakage by commit 4e5271fcdf7; and this method does make
sense in non-debug builds.
2017-02-09 21:21:49 +01:00
Max Kellermann
29e1b6e465 mixer/alsa: reset the MultiSocketMonitor in the destructor
Fixes potential crash bug.
2017-02-09 21:13:19 +01:00
Max Kellermann
eda06993f8 event/MultiSocketMonitor: add method Reset() 2017-02-09 21:12:23 +01:00
Max Kellermann
4b30ef1cf2 event/MultiSocketMonitor: use C++11 initializer 2017-02-09 21:12:23 +01:00
Max Kellermann
e92e5e8eb8 event/MultiSocketMonitor: more API documentation
Now ClearSocketList() may only be called from PrepareSockets().
Calling it before destroying the object doesn't work properly, because
it doesn't unregister the TimeoutMonitor and the IdleMonitor.  Some of
its callers need to be fixed.
2017-02-09 21:12:23 +01:00
Max Kellermann
4e5271fcdf event/Call: allow usage during shutdown
Change EventLoop::IsInside() call to EventLoop::IsInsideOrNull().
This means that BlockingCall() may be used during shutdown, after the
main EventLoop::Run() has finished.  This is important because mixers
are currently registered in the main EventLoop.
2017-02-09 21:12:23 +01:00
Max Kellermann
3c55487a16 configure.ac: don't require libsidutils when building with libsidplayfp
The libsidplayfp fork has merged libsidutils into the main library.
The libsidutils we used to link with was part of the original
libsidplay project.
2017-02-09 13:09:03 +01:00
Max Kellermann
76a1cae5d8 {input,mixer}/alsa: fix off-by-one bug in count check
Doesn't make a practical difference - but it's more correct this way.
2017-02-09 12:46:49 +01:00
Max Kellermann
81a97315e3 NEWS: mention ID3 memory leak fix 2017-02-08 08:44:47 +01:00
Max Kellermann
53c14d97a6 lib/nfs/FileReader: remove debug line 2017-02-08 08:43:56 +01:00
Max Kellermann
69a82eec17 tag/TagId3: use AtScopeExit() for exception-safety 2017-02-06 23:32:07 +01:00
Max Kellermann
45cadef22f configure.ac: prepare for 0.20.5 2017-02-06 23:28:36 +01:00
29 changed files with 311 additions and 53 deletions

20
NEWS

@@ -1,3 +1,23 @@
ver 0.20.6 (2017/03/10)
* input
- curl: fix headers after HTTP redirect to Shoutcast server
* decoder
- ffmpeg: re-enable as fallback
- mpcdec: fix crash (division by zero) after seeking
- sidplay: make compatible with libsidplayfp < 1.8
* fix stream tags after automatic song change
* workaround for GCC 4.9.4 / libstdc++ bug (build failure)
ver 0.20.5 (2017/02/20)
* tags
- id3: fix memory leak on corrupt ID3 tags
* decoder
- sidplay: don't require libsidutils when building with libsidplayfp
* output
- httpd: fix two buffer overflows in IcyMetaData length calculation
* mixer
- alsa: fix crash bug
ver 0.20.4 (2017/02/01)
* input
- nfs: fix freeze after reconnect

@@ -87,9 +87,14 @@ class AndroidNdkToolchain:
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
self.is_windows = False
libstdcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/gnu-libstdc++', gcc_version)
libstdcxx_cppflags = '-isystem ' + os.path.join(libstdcxx_path, 'include') + ' -isystem ' + os.path.join(libstdcxx_path, 'libs', android_abi, 'include')
libstdcxx_ldadd = os.path.join(libstdcxx_path, 'libs', android_abi, 'libgnustl_static.a')
libcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/llvm-libc++')
libcxx_libs_path = os.path.join(libcxx_path, 'libs', android_abi)
libstdcxx_cppflags = '-nostdinc++ -isystem ' + os.path.join(libcxx_path, 'include') + ' -isystem ' + os.path.join(ndk_path, 'sources/android/support/include')
libstdcxx_ldadd = os.path.join(libcxx_libs_path, 'libc++_static.a') + ' ' + os.path.join(libcxx_libs_path, 'libc++abi.a')
if self.is_armv7:
libstdcxx_ldadd += ' ' + os.path.join(libcxx_libs_path, 'libunwind.a')
if use_cxx:
self.libs += ' ' + libstdcxx_ldadd

@@ -1,10 +1,10 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.20.4, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.20.6, musicpd-dev-team@lists.sourceforge.net)
VERSION_MAJOR=0
VERSION_MINOR=20
VERSION_REVISION=4
VERSION_REVISION=6
VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -992,7 +992,7 @@ AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enab
dnl --------------------------------- sidplay ---------------------------------
if test x$enable_sidplay != xno; then
dnl Check for libsidplayfp first
PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp libsidutils],
PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp],
[found_sidplayfp=yes],
[found_sidplayfp=no])
found_sidplay=$found_sidplayfp

@@ -55,7 +55,8 @@
<listitem>
<para>
<varname>track</varname>: the track number within the album.
<varname>track</varname>: the decimal track number within the
album.
</para>
</listitem>
@@ -103,7 +104,8 @@
<listitem>
<para>
<varname>disc</varname>: the disc number in a multi-disc album.
<varname>disc</varname>: the decimal disc number in a multi-disc
album.
</para>
</listitem>

@@ -135,6 +135,91 @@ apt-get install g++ \
</para>
<programlisting>make install</programlisting>
<section id="windows_build">
<title>Compiling for Windows</title>
<para>
Even though it does not "feel" like a Windows application,
<application>MPD</application> works well under Windows.
Its build process follows the "Linux style", and may seem
awkward for Windows people (who are not used to compiling
their software, anyway).
</para>
<para>
Basically, there are three ways to compile
<application>MPD</application> for Windows:
</para>
<orderedlist>
<listitem>
<para>
Build on Windows for Windows. All you need to do is
described above already: configure and make.
</para>
<para>
For Windows users, this is kind of unusual, because few
Windows users have a GNU toolchain and a UNIX shell
installed.
</para>
</listitem>
<listitem>
<para>
Build on Linux for Windows. This is described above
already: configure and make. You need the <ulink
url="https://mingw-w64.org/"><application>mingw-w64</application>
cross compiler</ulink>. Pass
<parameter>--host=i686-w64-mingw32</parameter> (32 bit)
or <parameter>--host=x86_64-w64-mingw32</parameter> (64
bit) to configure.
</para>
<para>
This is somewhat natural for Linux users. Many
distributions have <application>mingw-w64</application>
packages. The remaining difficulty here is installing
all the external libraries. And
<application>MPD</application> usually needs many,
making this method cumbersome for the casual user.
</para>
</listitem>
<listitem>
<para>
Build on Linux for Windows using the
<application>MPD</application>'s library build script.
</para>
</listitem>
</orderedlist>
<para>
This section is about the latter.
</para>
<para>
Just like with the native build, unpack the
<application>MPD</application> source tarball and change
into the directory. Then, instead of
<command>./configure</command>, type:
</para>
<programlisting>./win32/build.py --64</programlisting>
<para>
This downloads various library sources, and then configures
and builds <application>MPD</application> (for x64; to build
a 32 bit binary, pass <parameter>--32</parameter>). The
resulting EXE files is linked statically, i.e. it contains
all the libraries already, and you do not need carry DLLs
around. It is large, but easy to use. If you wish to have
a small <filename>mpd.exe</filename> with DLLs, you need to
compile manually, without the <filename>build.py</filename>
script.
</para>
</section>
</section>
<section id="systemd_socket">

@@ -58,8 +58,8 @@ libmad = AutotoolsProject(
)
ffmpeg = FfmpegProject(
'http://ffmpeg.org/releases/ffmpeg-3.2.2.tar.xz',
'3f01bd1fe1a17a277f8c84869e5d9192b4b978cb660872aa2b54c3cc8a2fedfc',
'http://ffmpeg.org/releases/ffmpeg-3.2.4.tar.xz',
'6e38ff14f080c98b58cf5967573501b8cb586e3a173b591f3807d8f0660daf7a',
'lib/libavcodec.a',
[
'--disable-shared', '--enable-static',

@@ -141,9 +141,9 @@ Partition::OnMixerVolumeChanged(gcc_unused Mixer &mixer, gcc_unused int volume)
void
Partition::OnGlobalEvent(unsigned mask)
{
if ((mask & TAG_MODIFIED) != 0)
TagModified();
if ((mask & SYNC_WITH_PLAYER) != 0)
SyncWithPlayer();
if ((mask & TAG_MODIFIED) != 0)
TagModified();
}

@@ -29,6 +29,29 @@
#include <assert.h>
#define GLIBCXX_490 20140422
#define GLIBCXX_491 20140716
#define GLIBCXX_492 20141030
#define GLIBCXX_492_Debian_9 20141220
#define GLIBCXX_493 20150626
#define GLIBCXX_494 20160803
#define GLIBCXX_49X_NDK_r13b 20150123
/* the big mess attempts to detect whether we're compiling with
libstdc++ 4.9.x; __GLIBCXX__ is a date tag and cannot be used to
check the major version; and just checking the compiler version
isn't enough, because somebody could use an old libstdc++ with
clang - SIGH! */
#if GCC_OLDER_THAN(5,0) || (defined(__GLIBCXX__) && \
(__GLIBCXX__ == GLIBCXX_490 || __GLIBCXX__ == GLIBCXX_491 || \
__GLIBCXX__ == GLIBCXX_492 || \
__GLIBCXX__ == GLIBCXX_492_Debian_9 || \
__GLIBCXX__ == GLIBCXX_493 || \
__GLIBCXX__ == GLIBCXX_494 || \
__GLIBCXX__ == GLIBCXX_49X_NDK_r13b))
#define GLIBCXX_49X
#endif
gcc_const
static enum ack
ToAck(PlaylistResult result)
@@ -100,13 +123,13 @@ ToAck(std::exception_ptr ep)
return ACK_ERROR_SYSTEM;
} catch (const std::invalid_argument &e) {
return ACK_ERROR_ARG;
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20151204
#ifdef GLIBCXX_49X
} catch (const std::exception &e) {
#else
} catch (...) {
#endif
try {
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20151204
#ifdef GLIBCXX_49X
/* workaround for g++ 4.x: no overload for
rethrow_exception(exception_ptr) */
std::rethrow_if_nested(e);

@@ -25,6 +25,13 @@
#include "db/Interface.hxx"
#include "fs/Traits.hxx"
#ifdef _LIBCPP_VERSION
/* workaround for "error: incomplete type 'PlaylistInfo' used in type
trait expression" with libc++ version 3900 (from Android NDK
r13b) */
#include "db/PlaylistInfo.hxx"
#endif
#include <string>
struct PrefixedLightDirectory : LightDirectory {

@@ -235,7 +235,7 @@ decoder_run_stream_fallback(DecoderBridge &bridge, InputStream &is)
{
const struct DecoderPlugin *plugin;
#ifdef HAVE_FFMPEG
#ifdef ENABLE_FFMPEG
plugin = decoder_plugin_from_name("ffmpeg");
#else
plugin = decoder_plugin_from_name("mad");

@@ -207,6 +207,15 @@ mpcdec_decode(DecoderClient &client, InputStream &is)
if (frame.bits == -1)
break;
if (frame.samples <= 0) {
/* empty frame - this has been observed to
happen spuriously after seeking; skip this
obscure frame, and hope libmpcdec
recovers */
cmd = client.GetCommand();
continue;
}
mpc_uint32_t ret = frame.samples;
ret *= info.channels;

@@ -50,6 +50,10 @@
#include <string.h>
#include <stdio.h>
#ifdef HAVE_SIDPLAYFP
#define LIBSIDPLAYFP_VERSION GCC_MAKE_VERSION(LIBSIDPLAYFP_VERSION_MAJ, LIBSIDPLAYFP_VERSION_MIN, LIBSIDPLAYFP_VERSION_LEV)
#endif
#define SUBTUNE_PREFIX "tune_"
static constexpr Domain sidplay_domain("sidplay");
@@ -285,7 +289,11 @@ sidplay_file_decode(DecoderClient &client, Path path_fs)
#endif
#ifdef HAVE_SIDPLAYFP
#if LIBSIDPLAYFP_VERSION >= GCC_MAKE_VERSION(1,8,0)
const bool stereo = tune.getInfo()->sidChips() >= 2;
#else
const bool stereo = tune.getInfo()->isStereo();
#endif
#else
const bool stereo = tune.isStereo();
#endif

@@ -34,6 +34,8 @@
#include <stdexcept>
#include <memory>
#include <cstdlib>
#include <assert.h>
#define ERRORLEN 80

@@ -79,7 +79,7 @@ private:
void
BlockingCall(EventLoop &loop, std::function<void()> &&f)
{
if (loop.IsInside()) {
if (loop.IsInsideOrNull()) {
/* we're already inside the loop - we can simply call
the function */
f();

@@ -222,8 +222,9 @@ EventLoop::Run()
#ifndef NDEBUG
assert(busy);
assert(thread.IsInside());
thread = ThreadId::Null();
#endif
thread = ThreadId::Null();
}
void

@@ -212,12 +212,16 @@ public:
}
#endif
#ifndef NDEBUG
/**
* Like IsInside(), but also returns true if the thread has
* already ended (or was not started yet). This is useful for
* code which may run during startup or shutdown, when events
* are not yet/anymore handled.
*/
gcc_pure
bool IsInsideOrNull() const {
return thread.IsNull() || thread.IsInside();
}
#endif
};
#endif /* MAIN_NOTIFY_H */

@@ -28,12 +28,18 @@
#endif
MultiSocketMonitor::MultiSocketMonitor(EventLoop &_loop)
:IdleMonitor(_loop), TimeoutMonitor(_loop), ready(false) {
:IdleMonitor(_loop), TimeoutMonitor(_loop) {
}
MultiSocketMonitor::~MultiSocketMonitor()
void
MultiSocketMonitor::Reset()
{
// TODO
assert(GetEventLoop().IsInsideOrNull());
fds.clear();
IdleMonitor::Cancel();
TimeoutMonitor::Cancel();
ready = refresh = false;
}
void

@@ -96,7 +96,19 @@ class MultiSocketMonitor : IdleMonitor, TimeoutMonitor
friend class SingleFD;
bool ready, refresh;
/**
* DispatchSockets() should be called.
*/
bool ready = false;
/**
* PrepareSockets() should be called.
*
* Note that this doesn't need to be initialized by the
* constructor; this class is activated with the first
* InvalidateSockets() call, which initializes this flag.
*/
bool refresh;
std::forward_list<SingleFD> fds;
@@ -107,11 +119,26 @@ public:
static constexpr unsigned HANGUP = SocketMonitor::HANGUP;
MultiSocketMonitor(EventLoop &_loop);
~MultiSocketMonitor();
using IdleMonitor::GetEventLoop;
public:
/**
* Clear the socket list and disable all #EventLoop
* registrations. Run this in the #EventLoop thread before
* destroying this object.
*
* Later, this object can be reused and reactivated by calling
* InvalidateSockets().
*
* Note that this class doesn't have a destructor which calls
* this method, because this would be racy and thus pointless:
* at the time ~MultiSocketMonitor() is called, our virtual
* methods have been morphed to be pure again, and in the
* meantime the #EventLoop thread could invoke those pure
* methods.
*/
void Reset();
/**
* Invalidate the socket list. A call to PrepareSockets() is
* scheduled which will then update the list.
@@ -121,12 +148,19 @@ public:
IdleMonitor::Schedule();
}
/**
* Add one socket to the list of monitored sockets.
*
* May only be called from PrepareSockets().
*/
void AddSocket(int fd, unsigned events) {
fds.emplace_front(*this, fd, events);
}
/**
* Remove all sockets.
*
* May only be called from PrepareSockets().
*/
void ClearSocketList();
@@ -135,6 +169,8 @@ public:
* each one; its return value is the events bit mask. A
* return value of 0 means the socket will be removed from the
* list.
*
* May only be called from PrepareSockets().
*/
template<typename E>
void UpdateSocketList(E &&e) {
@@ -157,15 +193,26 @@ public:
/**
* Replace the socket list with the given file descriptors.
* The given pollfd array will be modified by this method.
*
* May only be called from PrepareSockets().
*/
void ReplaceSocketList(pollfd *pfds, unsigned n);
#endif
protected:
/**
* Override this method and update the socket registrations.
* To do that, call AddSocket(), ClearSocketList(),
* UpdateSocketList() and ReplaceSocketList().
*
* @return timeout or a negative value for no timeout
*/
virtual std::chrono::steady_clock::duration PrepareSockets() = 0;
/**
* At least one socket is ready or the timeout has expired.
* This method should be used to perform I/O.
*/
virtual void DispatchSockets() = 0;
private:

@@ -98,12 +98,9 @@ public:
}
~AlsaInputStream() {
/* ClearSocketList must be called from within the
IOThread; if we don't do it manually here, the
~MultiSocketMonitor() will do it in the current
thread */
BlockingCall(MultiSocketMonitor::GetEventLoop(), [this](){
ClearSocketList();
MultiSocketMonitor::Reset();
DeferredMonitor::Cancel();
});
snd_pcm_close(capture_handle);
@@ -181,7 +178,7 @@ AlsaInputStream::PrepareSockets()
}
int count = snd_pcm_poll_descriptors_count(capture_handle);
if (count < 0) {
if (count <= 0) {
ClearSocketList();
return std::chrono::steady_clock::duration(-1);
}

@@ -398,7 +398,12 @@ CurlInputStream::SeekInternal(offset_type new_offset)
/* send the "Range" header */
if (offset > 0) {
sprintf(range, "%lld-", (long long)offset);
#ifdef WIN32
// TODO: what can we use on Windows to format 64 bit?
sprintf(range, "%lu-", (long)offset);
#else
sprintf(range, "%llu-", (unsigned long long)offset);
#endif
request->SetOption(CURLOPT_RANGE, range);
}
}

@@ -168,13 +168,23 @@ CurlRequest::Done(CURLcode result)
}
}
gcc_pure
static bool
IsResponseBoundaryHeader(StringView s)
{
return s.size > 5 && (memcmp(s.data, "HTTP/", 5) == 0 ||
/* the proprietary "ICY 200 OK" is
emitted by Shoutcast */
memcmp(s.data, "ICY 2", 5) == 0);
}
inline void
CurlRequest::HeaderFunction(StringView s)
{
if (state > State::HEADERS)
return;
if (s.size > 5 && memcmp(s.data, "HTTP/", 5) == 0) {
if (IsResponseBoundaryHeader(s)) {
/* this is the boundary to a new response, for example
after a redirect */
headers.clear();

@@ -23,6 +23,7 @@
#include "output/OutputAPI.hxx"
#include "event/MultiSocketMonitor.hxx"
#include "event/DeferredMonitor.hxx"
#include "event/Call.hxx"
#include "util/ASCII.hxx"
#include "util/ReusableArray.hxx"
#include "util/Domain.hxx"
@@ -53,6 +54,13 @@ public:
DeferredMonitor::Schedule();
}
~AlsaMixerMonitor() {
BlockingCall(MultiSocketMonitor::GetEventLoop(), [this](){
MultiSocketMonitor::Reset();
DeferredMonitor::Cancel();
});
}
private:
virtual void RunDeferred() override {
InvalidateSockets();
@@ -102,7 +110,7 @@ AlsaMixerMonitor::PrepareSockets()
}
int count = snd_mixer_poll_descriptors_count(mixer);
if (count < 0)
if (count <= 0)
count = 0;
struct pollfd *pfds = pfd_buffer.Get(count);

@@ -60,7 +60,11 @@ icy_server_metadata_string(const char *stream_title, const char* stream_url)
{
// The leading n is a placeholder for the length information
auto icy_metadata = FormatString("nStreamTitle='%s';"
"StreamUrl='%s';",
"StreamUrl='%s';"
/* pad 15 spaces just in case
the length needs to be
rounded up */
" ",
stream_title,
stream_url);
@@ -68,7 +72,7 @@ icy_server_metadata_string(const char *stream_title, const char* stream_url)
meta_length--; // subtract placeholder
meta_length = ((int)meta_length / 16) + 1;
meta_length = meta_length / 16;
icy_metadata[0] = meta_length;
@@ -109,5 +113,5 @@ icy_server_metadata_page(const Tag &tag, const TagType *types)
if (icy_string.IsNull())
return nullptr;
return Page::Copy(icy_string.c_str(), (icy_string[0] * 16) + 1);
return Page::Copy(icy_string.c_str(), uint8_t(icy_string[0]) * 16 + 1);
}

@@ -44,7 +44,7 @@ add_tag_tag(TagType type, const char *value, void *ctx)
unsigned n = strtoul(value, &end, 10);
if (value != end) {
char s[21];
if (snprintf(s, 21, "%u", n) >= 0)
if (snprintf(s, 21, "%u", n) > 0)
tag.AddItem(type, s);
}
} else

@@ -24,6 +24,7 @@
#include "TagTable.hxx"
#include "TagBuilder.hxx"
#include "util/Alloc.hxx"
#include "util/ScopeExit.hxx"
#include "util/StringUtil.hxx"
#include "Log.hxx"
@@ -78,11 +79,9 @@ import_id3_string(const id3_ucs4_t *ucs4)
if (gcc_unlikely(utf8 == nullptr))
return nullptr;
id3_utf8_t *utf8_stripped = (id3_utf8_t *)
xstrdup(Strip((char *)utf8));
free(utf8);
AtScopeExit(utf8) { free(utf8); };
return utf8_stripped;
return (id3_utf8_t *)xstrdup(Strip((char *)utf8));
}
/**
@@ -126,9 +125,10 @@ tag_id3_import_text_frame(const struct id3_frame *frame,
if (utf8 == nullptr)
continue;
AtScopeExit(utf8) { free(utf8); };
tag_handler_invoke_tag(handler, handler_ctx,
type, (const char *)utf8);
free(utf8);
}
}
@@ -177,8 +177,9 @@ tag_id3_import_comment_frame(const struct id3_frame *frame, TagType type,
if (utf8 == nullptr)
return;
AtScopeExit(utf8) { free(utf8); };
tag_handler_invoke_tag(handler, handler_ctx, type, (const char *)utf8);
free(utf8);
}
/**
@@ -236,22 +237,23 @@ tag_id3_import_musicbrainz(struct id3_tag *id3_tag,
if (name == nullptr)
continue;
AtScopeExit(name) { free(name); };
id3_utf8_t *value = tag_id3_getstring(frame, 2);
if (value == nullptr)
continue;
AtScopeExit(value) { free(value); };
tag_handler_invoke_pair(handler, handler_ctx,
(const char *)name,
(const char *)value);
TagType type = tag_id3_parse_txxx_name((const char*)name);
free(name);
if (type != TAG_NUM_OF_ITEM_TYPES)
tag_handler_invoke_tag(handler, handler_ctx,
type, (const char*)value);
free(value);
}
}

@@ -48,7 +48,7 @@ static size_t
AlignToPageSize(size_t size)
{
static const long page_size = sysconf(_SC_PAGESIZE);
if (page_size == 0)
if (page_size <= 0)
return size;
size_t ps(page_size);

@@ -56,7 +56,7 @@ public:
:buffer(std::exchange(src.buffer, nullptr)),
capacity(std::exchange(src.capacity, 0)) {}
ReusableArray &operator=(const ReusableArray &&src) {
ReusableArray &operator=(ReusableArray &&src) {
std::swap(buffer, src.buffer);
std::swap(capacity, src.capacity);
return *this;

@@ -60,6 +60,8 @@ ParseTimePoint(const char *s, const char *format)
#ifdef WIN32
/* TODO: emulate strptime()? */
(void)s;
(void)format;
throw std::runtime_error("Time parsing not implemented on Windows");
#else
struct tm tm;

@@ -5,11 +5,22 @@ import sys, subprocess
configure_args = sys.argv[1:]
host_arch = 'i686-w64-mingw32'
x64 = True
if len(configure_args) > 0 and configure_args[0] == '--64':
configure_args = configure_args[1:]
while len(configure_args) > 0:
arg = configure_args[0]
if arg == '--64':
x64 = True
elif arg == '--32':
x64 = False
else:
break
configure_args.pop(0)
if x64:
host_arch = 'x86_64-w64-mingw32'
else:
host_arch = 'i686-w64-mingw32'
# the path to the MPD sources
mpd_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]) or '.', '..'))