From f9d1bbbffb7bc068aa00d4040d8beefc1a66bad8 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Wed, 3 Sep 2014 19:59:26 +0200
Subject: [PATCH 01/10] configure.ac: prepare for 0.18.14

---
 NEWS         | 2 ++
 configure.ac | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 59c568741..be2fa6966 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,5 @@
+ver 0.18.14 (not yet released)
+
 ver 0.18.13 (2014/08/31)
 * protocol
   - don't change song on "seekcur" in random mode
diff --git a/configure.ac b/configure.ac
index 526b4c7f5..a81b0aff1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
 AC_PREREQ(2.60)
 
-AC_INIT(mpd, 0.18.13, mpd-devel@musicpd.org)
+AC_INIT(mpd, 0.18.14, mpd-devel@musicpd.org)
 
 VERSION_MAJOR=0
 VERSION_MINOR=18

From 4907f610d6116949111fb6ff81c1489ec68b9d43 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Thu, 4 Sep 2014 15:15:58 +0200
Subject: [PATCH 02/10] test/test_protocol: unit test for
 protocol/ArgParser.cxx

---
 .gitignore             |  1 +
 Makefile.am            | 11 ++++++++
 test/test_protocol.cxx | 60 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 72 insertions(+)
 create mode 100644 test/test_protocol.cxx

diff --git a/.gitignore b/.gitignore
index 9b052a29f..790eac57b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/Makefile.am b/Makefile.am
index 6a5e9fb27..147a15bf8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1064,6 +1064,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 +1539,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
diff --git a/test/test_protocol.cxx b/test/test_protocol.cxx
new file mode 100644
index 000000000..d7ea7cd87
--- /dev/null
+++ b/test/test_protocol.cxx
@@ -0,0 +1,60 @@
+#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>
+
+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;
+}

From 421c4ae907e27661902f28c07c1c470c3dba3cf7 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Thu, 4 Sep 2014 14:38:55 +0200
Subject: [PATCH 03/10] 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.
---
 NEWS                       | 2 ++
 src/protocol/ArgParser.cxx | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index be2fa6966..b75bf700e 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,6 @@
 ver 0.18.14 (not yet released)
+* protocol
+  - fix range parser bug on certain 32 bit architectures
 
 ver 0.18.13 (2014/08/31)
 * protocol
diff --git a/src/protocol/ArgParser.cxx b/src/protocol/ArgParser.cxx
index b13ea3f4e..86527c751 100644
--- a/src/protocol/ArgParser.cxx
+++ b/src/protocol/ArgParser.cxx
@@ -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,

From 7ada7def9e797deb7a34ba8da1e33e207d4ed55f Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sat, 6 Sep 2014 19:32:10 +0200
Subject: [PATCH 04/10] decoder/audiofile: fix crash after seeking

Log call was added to the wrong branch.

Fixes regression by commit ca1a1149
---
 NEWS                                   | 2 ++
 src/decoder/AudiofileDecoderPlugin.cxx | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index b75bf700e..78f111ebf 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
 ver 0.18.14 (not yet released)
 * protocol
   - fix range parser bug on certain 32 bit architectures
+* decoder
+  - audiofile: fix crash after seeking
 
 ver 0.18.13 (2014/08/31)
 * protocol
diff --git a/src/decoder/AudiofileDecoderPlugin.cxx b/src/decoder/AudiofileDecoderPlugin.cxx
index 9f097f90b..b1b8bf613 100644
--- a/src/decoder/AudiofileDecoderPlugin.cxx
+++ b/src/decoder/AudiofileDecoderPlugin.cxx
@@ -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;
 	}
 }

From a6bb27483b30f81145c19d1048a342c0aa5401d0 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sun, 7 Sep 2014 21:31:10 +0200
Subject: [PATCH 05/10] DecoderThread: clear the pipe when handling late SEEK

See code comment.  Fixes assertion failure in
decoder_command_finished().
---
 NEWS                  |  1 +
 src/DecoderThread.cxx | 12 +++++++++++-
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 78f111ebf..d5612bfdc 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ ver 0.18.14 (not yet released)
   - fix range parser bug on certain 32 bit architectures
 * decoder
   - audiofile: fix crash after seeking
+  - fix assertion failure after seeking
 
 ver 0.18.13 (2014/08/31)
 * protocol
diff --git a/src/DecoderThread.cxx b/src/DecoderThread.cxx
index 72fc3cfb4..cf21534f0 100644
--- a/src/DecoderThread.cxx
+++ b/src/DecoderThread.cxx
@@ -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"
@@ -418,9 +419,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;
 

From e3a0f158376a38abb2eb9aa4a67b155ff9da6ffe Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sun, 7 Sep 2014 21:50:27 +0200
Subject: [PATCH 06/10] Decoder*: add more assertions

---
 src/DecoderAPI.cxx      | 4 ++++
 src/DecoderInternal.cxx | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/src/DecoderAPI.cxx b/src/DecoderAPI.cxx
index e4122d60e..334d069bf 100644
--- a/src/DecoderAPI.cxx
+++ b/src/DecoderAPI.cxx
@@ -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)) {
diff --git a/src/DecoderInternal.cxx b/src/DecoderInternal.cxx
index d5f40ad48..b5e6c9d57 100644
--- a/src/DecoderInternal.cxx
+++ b/src/DecoderInternal.cxx
@@ -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);
 

From 219c42522f938c5fff08d962a1a54c0872322f00 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sun, 7 Sep 2014 22:05:33 +0200
Subject: [PATCH 07/10] decoder/ffmpeg: pass MIME type to ffmpeg/libav version
 11

That attribute was uninitialized before, which could crash
libavformat.

See Debian bug 760669
---
 NEWS                                | 1 +
 src/decoder/FfmpegDecoderPlugin.cxx | 7 +++++++
 2 files changed, 8 insertions(+)

diff --git a/NEWS b/NEWS
index d5612bfdc..d0fb64623 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ ver 0.18.14 (not yet released)
   - 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)
diff --git a/src/decoder/FfmpegDecoderPlugin.cxx b/src/decoder/FfmpegDecoderPlugin.cxx
index 5133f91ac..1409a3c47 100644
--- a/src/decoder/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/FfmpegDecoderPlugin.cxx
@@ -387,6 +387,13 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
 	avpd.buf_size = nbytes;
 	avpd.filename = is.uri.c_str();
 
+#ifdef AVPROBE_SCORE_MIME
+	/* 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());
+#endif
+
 	return av_probe_input_format(&avpd, true);
 }
 

From c14a00eec92074536591c05f0ac5486bf74980f9 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Tue, 9 Sep 2014 19:07:46 +0200
Subject: [PATCH 08/10] decoder/ffmpeg: use memset() to initialize AVProbeData

---
 src/decoder/FfmpegDecoderPlugin.cxx | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/decoder/FfmpegDecoderPlugin.cxx b/src/decoder/FfmpegDecoderPlugin.cxx
index 1409a3c47..9cd26c4fa 100644
--- a/src/decoder/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/FfmpegDecoderPlugin.cxx
@@ -383,6 +383,12 @@ 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();

From 57068e526c3eae07e742cbdaa5c0e131720fb1d1 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Tue, 9 Sep 2014 19:17:22 +0200
Subject: [PATCH 09/10] test/run_decoder: dump MixRamp data

---
 test/run_decoder.cxx | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/test/run_decoder.cxx b/test/run_decoder.cxx
index 7db8dde22..3fbfc5521 100644
--- a/test/run_decoder.cxx
+++ b/test/run_decoder.cxx
@@ -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)

From eaf675dc92fbe0143fdc0e9c4234bd78a889decf Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Thu, 11 Sep 2014 19:09:49 +0200
Subject: [PATCH 10/10] release v0.18.14

---
 NEWS | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index d0fb64623..89d833071 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-ver 0.18.14 (not yet released)
+ver 0.18.14 (2014/09/11)
 * protocol
   - fix range parser bug on certain 32 bit architectures
 * decoder