Compare commits
	
		
			54 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					acb798e544 | ||
| 
						 | 
					773de38bd9 | ||
| 
						 | 
					fa4beeee75 | ||
| 
						 | 
					d8351772d3 | ||
| 
						 | 
					1b5f33a435 | ||
| 
						 | 
					41b4a63f2b | ||
| 
						 | 
					d8fc2db910 | ||
| 
						 | 
					dc11dea7cc | ||
| 
						 | 
					04f627c2af | ||
| 
						 | 
					a254f5a3a8 | ||
| 
						 | 
					143c735f96 | ||
| 
						 | 
					7aa2104596 | ||
| 
						 | 
					c8b93d6573 | ||
| 
						 | 
					3f5f96ac91 | ||
| 
						 | 
					7e7b403043 | ||
| 
						 | 
					c64ad78c7b | ||
| 
						 | 
					4a043a915f | ||
| 
						 | 
					38a0d15190 | ||
| 
						 | 
					ec3191f502 | ||
| 
						 | 
					32b5654a6e | ||
| 
						 | 
					674091424e | ||
| 
						 | 
					6ad336743d | ||
| 
						 | 
					c882568ccd | ||
| 
						 | 
					f6b2899dd2 | ||
| 
						 | 
					bccd4ef2f7 | ||
| 
						 | 
					94c240a026 | ||
| 
						 | 
					c50a0cf7bf | ||
| 
						 | 
					c37f7abb79 | ||
| 
						 | 
					432ce9b1de | ||
| 
						 | 
					fe45f28204 | ||
| 
						 | 
					861067412f | ||
| 
						 | 
					7eca886608 | ||
| 
						 | 
					79b6f9e89e | ||
| 
						 | 
					3d17c06777 | ||
| 
						 | 
					d6c08fb79f | ||
| 
						 | 
					ef02b20811 | ||
| 
						 | 
					8bf46a665e | ||
| 
						 | 
					c4fca2aa61 | ||
| 
						 | 
					87268c2297 | ||
| 
						 | 
					e93975cb46 | ||
| 
						 | 
					b6fa22bd84 | ||
| 
						 | 
					a0ef27a0cd | ||
| 
						 | 
					e304d0f8ee | ||
| 
						 | 
					ab7b38d4b9 | ||
| 
						 | 
					eaf675dc92 | ||
| 
						 | 
					57068e526c | ||
| 
						 | 
					c14a00eec9 | ||
| 
						 | 
					219c42522f | ||
| 
						 | 
					e3a0f15837 | ||
| 
						 | 
					a6bb27483b | ||
| 
						 | 
					7ada7def9e | ||
| 
						 | 
					421c4ae907 | ||
| 
						 | 
					4907f610d6 | ||
| 
						 | 
					f9d1bbbffb | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								Makefile.am
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								Makefile.am
									
									
									
									
									
								
							@@ -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
									
									
									
									
									
								
							
							
						
						
									
										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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								configure.ac
									
									
									
									
									
								
							@@ -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])
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								m4/faad.m4
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								m4/faad.m4
									
									
									
									
									
								
							@@ -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
									
								
							
							
						
						
									
										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 ®istry = 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() {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user