From be65c7d5d0bb6a1bf46c58f0b488d0685966df1d Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Tue, 2 Jan 2018 17:22:25 +0100
Subject: [PATCH] config/Block: add method GetPositiveValue()

Adds missing checks to several plugins.
---
 src/config/Block.cxx                          | 25 +++++++++++++++++++
 src/config/Block.hxx                          |  3 +++
 src/decoder/plugins/AdPlugDecoderPlugin.cxx   |  2 +-
 .../plugins/FluidsynthDecoderPlugin.cxx       |  2 +-
 src/decoder/plugins/MikmodDecoderPlugin.cxx   |  2 +-
 src/decoder/plugins/SidplayDecoderPlugin.cxx  |  2 +-
 src/output/plugins/AlsaOutputPlugin.cxx       |  6 ++---
 src/output/plugins/AoOutputPlugin.cxx         |  2 +-
 src/output/plugins/HaikuOutputPlugin.cxx      |  2 +-
 src/output/plugins/JackOutputPlugin.cxx       |  2 +-
 10 files changed, 38 insertions(+), 10 deletions(-)

diff --git a/src/config/Block.cxx b/src/config/Block.cxx
index e0f9f0263..51f4321db 100644
--- a/src/config/Block.cxx
+++ b/src/config/Block.cxx
@@ -52,6 +52,21 @@ BlockParam::GetUnsignedValue() const
 	return (unsigned)value2;
 }
 
+unsigned
+BlockParam::GetPositiveValue() const
+{
+	const char *const s = value.c_str();
+	char *endptr;
+	unsigned long value2 = strtoul(s, &endptr, 0);
+	if (endptr == s || *endptr != 0)
+		FormatFatalError("Not a valid number in line %i", line);
+
+	if (value2 <= 0)
+		FormatFatalError("Number in line %i must be positive", line);
+
+	return (unsigned)value2;
+}
+
 bool
 BlockParam::GetBoolValue() const
 {
@@ -131,6 +146,16 @@ ConfigBlock::GetBlockValue(const char *name, unsigned default_value) const
 	return bp->GetUnsignedValue();
 }
 
+unsigned
+ConfigBlock::GetPositiveValue(const char *name, unsigned default_value) const
+{
+	const auto *param = GetBlockParam(name);
+	if (param == nullptr)
+		return default_value;
+
+	return param->GetPositiveValue();
+}
+
 bool
 ConfigBlock::GetBlockValue(const char *name, bool default_value) const
 {
diff --git a/src/config/Block.hxx b/src/config/Block.hxx
index b8257db78..25d67b7f4 100644
--- a/src/config/Block.hxx
+++ b/src/config/Block.hxx
@@ -47,6 +47,7 @@ struct BlockParam {
 	int GetIntValue() const;
 
 	unsigned GetUnsignedValue() const;
+	unsigned GetPositiveValue() const;
 
 	bool GetBoolValue() const;
 };
@@ -117,6 +118,8 @@ struct ConfigBlock {
 
 	unsigned GetBlockValue(const char *name, unsigned default_value) const;
 
+	unsigned GetPositiveValue(const char *name, unsigned default_value) const;
+
 	bool GetBlockValue(const char *name, bool default_value) const;
 };
 
diff --git a/src/decoder/plugins/AdPlugDecoderPlugin.cxx b/src/decoder/plugins/AdPlugDecoderPlugin.cxx
index d3a8ecd55..4d46c281d 100644
--- a/src/decoder/plugins/AdPlugDecoderPlugin.cxx
+++ b/src/decoder/plugins/AdPlugDecoderPlugin.cxx
@@ -42,7 +42,7 @@ adplug_init(const ConfigBlock &block)
 	FormatDebug(adplug_domain, "adplug %s",
 		    CAdPlug::get_version().c_str());
 
-	sample_rate = block.GetBlockValue("sample_rate", 48000u);
+	sample_rate = block.GetPositiveValue("sample_rate", 48000u);
 	CheckSampleRate(sample_rate);
 
 	return true;
diff --git a/src/decoder/plugins/FluidsynthDecoderPlugin.cxx b/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
index 3eaf1d67e..e92c1c306 100644
--- a/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
+++ b/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
@@ -74,7 +74,7 @@ fluidsynth_mpd_log_function(int level, char *message, gcc_unused void *data)
 static bool
 fluidsynth_init(const ConfigBlock &block)
 {
-	sample_rate = block.GetBlockValue("sample_rate", 48000u);
+	sample_rate = block.GetPositiveValue("sample_rate", 48000u);
 	CheckSampleRate(sample_rate);
 
 	soundfont_path = block.GetBlockValue("soundfont",
diff --git a/src/decoder/plugins/MikmodDecoderPlugin.cxx b/src/decoder/plugins/MikmodDecoderPlugin.cxx
index 788a13f73..6af5876c3 100644
--- a/src/decoder/plugins/MikmodDecoderPlugin.cxx
+++ b/src/decoder/plugins/MikmodDecoderPlugin.cxx
@@ -114,7 +114,7 @@ mikmod_decoder_init(const ConfigBlock &block)
 	static char params[] = "";
 
 	mikmod_loop = block.GetBlockValue("loop", false);
-	mikmod_sample_rate = block.GetBlockValue("sample_rate", 44100u);
+	mikmod_sample_rate = block.GetPositiveValue("sample_rate", 44100u);
 	if (!audio_valid_sample_rate(mikmod_sample_rate))
 		throw FormatRuntimeError("Invalid sample rate in line %d: %u",
 					 block.line, mikmod_sample_rate);
diff --git a/src/decoder/plugins/SidplayDecoderPlugin.cxx b/src/decoder/plugins/SidplayDecoderPlugin.cxx
index a217f2b00..c6b4c2ad5 100644
--- a/src/decoder/plugins/SidplayDecoderPlugin.cxx
+++ b/src/decoder/plugins/SidplayDecoderPlugin.cxx
@@ -93,7 +93,7 @@ sidplay_init(const ConfigBlock &block)
 	if (!database_path.IsNull())
 		songlength_database = sidplay_load_songlength_db(database_path);
 
-	default_songlength = block.GetBlockValue("default_songlength", 0u);
+	default_songlength = block.GetPositiveValue("default_songlength", 0u);
 
 	all_files_are_containers =
 		block.GetBlockValue("all_files_are_containers", true);
diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx
index fab0a85d1..81b9766b4 100644
--- a/src/output/plugins/AlsaOutputPlugin.cxx
+++ b/src/output/plugins/AlsaOutputPlugin.cxx
@@ -331,9 +331,9 @@ AlsaOutput::AlsaOutput(EventLoop &_loop, const ConfigBlock &block)
 		     /* legacy name from MPD 0.18 and older: */
 		     block.GetBlockValue("dsd_usb", false)),
 #endif
-	 buffer_time(block.GetBlockValue("buffer_time",
-					 MPD_ALSA_BUFFER_TIME_US)),
-	 period_time(block.GetBlockValue("period_time", 0u))
+	 buffer_time(block.GetPositiveValue("buffer_time",
+					    MPD_ALSA_BUFFER_TIME_US)),
+	 period_time(block.GetPositiveValue("period_time", 0u))
 {
 #ifdef SND_PCM_NO_AUTO_RESAMPLE
 	if (!block.GetBlockValue("auto_resample", true))
diff --git a/src/output/plugins/AoOutputPlugin.cxx b/src/output/plugins/AoOutputPlugin.cxx
index cd40df30b..131a3f694 100644
--- a/src/output/plugins/AoOutputPlugin.cxx
+++ b/src/output/plugins/AoOutputPlugin.cxx
@@ -101,7 +101,7 @@ MakeAoError()
 
 AoOutput::AoOutput(const ConfigBlock &block)
 	:AudioOutput(0),
-	 write_size(block.GetBlockValue("write_size", 1024u))
+	 write_size(block.GetPositiveValue("write_size", 1024u))
 {
 	const char *value = block.GetBlockValue("driver", "default");
 	if (0 == strcmp(value, "default"))
diff --git a/src/output/plugins/HaikuOutputPlugin.cxx b/src/output/plugins/HaikuOutputPlugin.cxx
index ff9c23f94..edba7243f 100644
--- a/src/output/plugins/HaikuOutputPlugin.cxx
+++ b/src/output/plugins/HaikuOutputPlugin.cxx
@@ -64,7 +64,7 @@ public:
 	HaikuOutput(const ConfigBlock &block)
 		:AudioOutput(0),
 		 /* XXX: by default we should let the MediaKit propose the buffer size */
-		 write_size(block.GetBlockValue("write_size", 4096u)) {}
+		 write_size(block.GetPositiveValue("write_size", 4096u)) {}
 
 	~HaikuOutput();
 
diff --git a/src/output/plugins/JackOutputPlugin.cxx b/src/output/plugins/JackOutputPlugin.cxx
index 70a588610..92afc2df1 100644
--- a/src/output/plugins/JackOutputPlugin.cxx
+++ b/src/output/plugins/JackOutputPlugin.cxx
@@ -210,7 +210,7 @@ JackOutput::JackOutput(const ConfigBlock &block)
 			      num_source_ports, num_destination_ports,
 			      block.line);
 
-	ringbuffer_size = block.GetBlockValue("ringbuffer_size", 32768u);
+	ringbuffer_size = block.GetPositiveValue("ringbuffer_size", 32768u);
 }
 
 inline jack_nframes_t