From 0b4fa41aff35ac8d190e5daaeed12f12614a0e9c Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sun, 11 May 2014 18:34:09 +0200
Subject: [PATCH] InputStream: "protect" attributes

---
 src/decoder/plugins/FfmpegDecoderPlugin.cxx  |  8 ++++----
 src/decoder/plugins/FlacCommon.cxx           |  2 +-
 src/decoder/plugins/FlacDecoderPlugin.cxx    |  4 ++--
 src/decoder/plugins/FlacIOHandle.cxx         |  2 +-
 src/decoder/plugins/FlacIOHandle.hxx         |  2 +-
 src/decoder/plugins/FlacInput.cxx            | 10 +++++-----
 src/decoder/plugins/OggFind.cxx              |  2 +-
 src/decoder/plugins/OpusDecoderPlugin.cxx    | 10 +++++-----
 src/decoder/plugins/VorbisDecoderPlugin.cxx  |  2 +-
 src/decoder/plugins/WavpackDecoderPlugin.cxx | 12 ++++++------
 src/input/InputStream.hxx                    | 18 +++++++++++++++++-
 src/input/plugins/RewindInputPlugin.cxx      | 14 +++++++-------
 src/lib/expat/ExpatParser.cxx                |  2 +-
 src/playlist/PlaylistRegistry.cxx            |  2 +-
 14 files changed, 53 insertions(+), 37 deletions(-)

diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index 3a0fa7389..22a42477d 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -121,12 +121,12 @@ mpd_ffmpeg_stream_seek(void *opaque, int64_t pos, int whence)
 	AvioStream *stream = (AvioStream *)opaque;
 
 	if (whence == AVSEEK_SIZE)
-		return stream->input.size;
+		return stream->input.GetSize();
 
 	if (!stream->input.LockSeek(pos, whence, IgnoreError()))
 		return -1;
 
-	return stream->input.offset;
+	return stream->input.GetOffset();
 }
 
 bool
@@ -135,7 +135,7 @@ AvioStream::Open()
 	io = avio_alloc_context(buffer, sizeof(buffer),
 				false, this,
 				mpd_ffmpeg_stream_read, nullptr,
-				input.seekable
+				input.IsSeekable()
 				? mpd_ffmpeg_stream_seek : nullptr);
 	return io != nullptr;
 }
@@ -481,7 +481,7 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
 		: 0;
 
 	decoder_initialized(decoder, audio_format,
-			    input.seekable, total_time);
+			    input.IsSeekable(), total_time);
 
 #if LIBAVUTIL_VERSION_MAJOR >= 53
 	AVFrame *frame = av_frame_alloc();
diff --git a/src/decoder/plugins/FlacCommon.cxx b/src/decoder/plugins/FlacCommon.cxx
index 7b67585a0..f06a52cf8 100644
--- a/src/decoder/plugins/FlacCommon.cxx
+++ b/src/decoder/plugins/FlacCommon.cxx
@@ -137,7 +137,7 @@ flac_got_first_frame(struct flac_data *data, const FLAC__FrameHeader *header)
 	data->frame_size = data->audio_format.GetFrameSize();
 
 	decoder_initialized(data->decoder, data->audio_format,
-			    data->input_stream.seekable,
+			    data->input_stream.IsSeekable(),
 			    (float)data->total_frames /
 			    (float)data->audio_format.sample_rate);
 
diff --git a/src/decoder/plugins/FlacDecoderPlugin.cxx b/src/decoder/plugins/FlacDecoderPlugin.cxx
index c39aeadd9..39a0fce73 100644
--- a/src/decoder/plugins/FlacDecoderPlugin.cxx
+++ b/src/decoder/plugins/FlacDecoderPlugin.cxx
@@ -145,13 +145,13 @@ flac_decoder_initialize(struct flac_data *data, FLAC__StreamDecoder *sd,
 	if (data->initialized) {
 		/* done */
 		decoder_initialized(data->decoder, data->audio_format,
-				    data->input_stream.seekable,
+				    data->input_stream.IsSeekable(),
 				    (float)data->total_frames /
 				    (float)data->audio_format.sample_rate);
 		return true;
 	}
 
-	if (data->input_stream.seekable)
+	if (data->input_stream.IsSeekable())
 		/* allow the workaround below only for nonseekable
 		   streams*/
 		return false;
diff --git a/src/decoder/plugins/FlacIOHandle.cxx b/src/decoder/plugins/FlacIOHandle.cxx
index aecee638b..6444e02cf 100644
--- a/src/decoder/plugins/FlacIOHandle.cxx
+++ b/src/decoder/plugins/FlacIOHandle.cxx
@@ -75,7 +75,7 @@ FlacIOTell(FLAC__IOHandle handle)
 {
 	InputStream *is = (InputStream *)handle;
 
-	return is->offset;
+	return is->GetOffset();
 }
 
 static int
diff --git a/src/decoder/plugins/FlacIOHandle.hxx b/src/decoder/plugins/FlacIOHandle.hxx
index a4c3ab86d..90acc66af 100644
--- a/src/decoder/plugins/FlacIOHandle.hxx
+++ b/src/decoder/plugins/FlacIOHandle.hxx
@@ -37,7 +37,7 @@ ToFlacIOHandle(InputStream &is)
 static inline const FLAC__IOCallbacks &
 GetFlacIOCallbacks(const InputStream &is)
 {
-	return is.seekable
+	return is.IsSeekable()
 		? flac_io_callbacks_seekable
 		: flac_io_callbacks;
 }
diff --git a/src/decoder/plugins/FlacInput.cxx b/src/decoder/plugins/FlacInput.cxx
index 720b115f7..d7fc72025 100644
--- a/src/decoder/plugins/FlacInput.cxx
+++ b/src/decoder/plugins/FlacInput.cxx
@@ -47,7 +47,7 @@ FlacInput::Read(FLAC__byte buffer[], size_t *bytes)
 FLAC__StreamDecoderSeekStatus
 FlacInput::Seek(FLAC__uint64 absolute_byte_offset)
 {
-	if (!input_stream.seekable)
+	if (!input_stream.IsSeekable())
 		return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
 
 	::Error error;
@@ -62,20 +62,20 @@ FlacInput::Seek(FLAC__uint64 absolute_byte_offset)
 FLAC__StreamDecoderTellStatus
 FlacInput::Tell(FLAC__uint64 *absolute_byte_offset)
 {
-	if (!input_stream.seekable)
+	if (!input_stream.IsSeekable())
 		return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
 
-	*absolute_byte_offset = (FLAC__uint64)input_stream.offset;
+	*absolute_byte_offset = (FLAC__uint64)input_stream.GetOffset();
 	return FLAC__STREAM_DECODER_TELL_STATUS_OK;
 }
 
 FLAC__StreamDecoderLengthStatus
 FlacInput::Length(FLAC__uint64 *stream_length)
 {
-	if (input_stream.size < 0)
+	if (!input_stream.KnownSize())
 		return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
 
-	*stream_length = (FLAC__uint64)input_stream.size;
+	*stream_length = (FLAC__uint64)input_stream.GetSize();
 	return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
 }
 
diff --git a/src/decoder/plugins/OggFind.cxx b/src/decoder/plugins/OggFind.cxx
index df4318da2..d7a3dc04a 100644
--- a/src/decoder/plugins/OggFind.cxx
+++ b/src/decoder/plugins/OggFind.cxx
@@ -57,7 +57,7 @@ bool
 OggSeekFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet,
 	       InputStream &is)
 {
-	if (is.size > 0 && is.size - is.offset < 65536)
+	if (is.KnownSize() && is.GetRest() < 65536)
 		return OggFindEOS(oy, os, packet);
 
 	if (!is.CheapSeeking())
diff --git a/src/decoder/plugins/OpusDecoderPlugin.cxx b/src/decoder/plugins/OpusDecoderPlugin.cxx
index 67bbe7a54..983d17278 100644
--- a/src/decoder/plugins/OpusDecoderPlugin.cxx
+++ b/src/decoder/plugins/OpusDecoderPlugin.cxx
@@ -185,7 +185,7 @@ LoadEOSPacket(InputStream &is, Decoder *decoder, int serialno,
 		   troubl */
 		return -1;
 
-	const auto old_offset = is.offset;
+	const auto old_offset = is.GetOffset();
 	if (old_offset < 0)
 		return -1;
 
@@ -332,16 +332,16 @@ bool
 MPDOpusDecoder::Seek(OggSyncState &oy, double where_s)
 {
 	assert(eos_granulepos > 0);
-	assert(input_stream.seekable);
-	assert(input_stream.size > 0);
-	assert(input_stream.offset >= 0);
+	assert(input_stream.IsSeekable());
+	assert(input_stream.KnownSize());
+	assert(input_stream.GetOffset() >= 0);
 
 	const ogg_int64_t where_granulepos(where_s * opus_sample_rate);
 
 	/* interpolate the file offset where we expect to find the
 	   given granule position */
 	/* TODO: implement binary search */
-	InputStream::offset_type offset(where_granulepos * input_stream.size
+	InputStream::offset_type offset(where_granulepos * input_stream.GetSize()
 					/ eos_granulepos);
 
 	if (!OggSeekPageAtOffset(oy, os, input_stream, offset, SEEK_SET))
diff --git a/src/decoder/plugins/VorbisDecoderPlugin.cxx b/src/decoder/plugins/VorbisDecoderPlugin.cxx
index fd110f457..d1cf6fae4 100644
--- a/src/decoder/plugins/VorbisDecoderPlugin.cxx
+++ b/src/decoder/plugins/VorbisDecoderPlugin.cxx
@@ -88,7 +88,7 @@ static long ogg_tell_cb(void *data)
 {
 	struct vorbis_input_stream *vis = (struct vorbis_input_stream *)data;
 
-	return (long)vis->input_stream->offset;
+	return (long)vis->input_stream->GetOffset();
 }
 
 static const ov_callbacks vorbis_is_callbacks = {
diff --git a/src/decoder/plugins/WavpackDecoderPlugin.cxx b/src/decoder/plugins/WavpackDecoderPlugin.cxx
index eb15a3380..d3b161adf 100644
--- a/src/decoder/plugins/WavpackDecoderPlugin.cxx
+++ b/src/decoder/plugins/WavpackDecoderPlugin.cxx
@@ -377,7 +377,7 @@ wavpack_input_read_bytes(void *id, void *data, int32_t bcount)
 static uint32_t
 wavpack_input_get_pos(void *id)
 {
-	return wpin(id)->is->offset;
+	return wpin(id)->is->GetOffset();
 }
 
 static int
@@ -406,16 +406,16 @@ wavpack_input_push_back_byte(void *id, int c)
 static uint32_t
 wavpack_input_get_length(void *id)
 {
-	if (wpin(id)->is->size < 0)
+	if (!wpin(id)->is->KnownSize())
 		return 0;
 
-	return wpin(id)->is->size;
+	return wpin(id)->is->GetSize();
 }
 
 static int
 wavpack_input_can_seek(void *id)
 {
-	return wpin(id)->is->seekable;
+	return wpin(id)->is->IsSeekable();
 }
 
 static WavpackStreamReader mpd_is_reader = {
@@ -484,7 +484,7 @@ static void
 wavpack_streamdecode(Decoder &decoder, InputStream &is)
 {
 	int open_flags = OPEN_NORMALIZE;
-	bool can_seek = is.seekable;
+	bool can_seek = is.IsSeekable();
 
 	wavpack_input isp_wvc;
 	InputStream *is_wvc = wavpack_open_wvc(decoder, is.GetURI(),
@@ -492,7 +492,7 @@ wavpack_streamdecode(Decoder &decoder, InputStream &is)
 					       &isp_wvc);
 	if (is_wvc != nullptr) {
 		open_flags |= OPEN_WVC;
-		can_seek &= is_wvc->seekable;
+		can_seek &= is_wvc->IsSeekable();
 	}
 
 	if (!can_seek) {
diff --git a/src/input/InputStream.hxx b/src/input/InputStream.hxx
index 13f6af32b..5f754940b 100644
--- a/src/input/InputStream.hxx
+++ b/src/input/InputStream.hxx
@@ -64,6 +64,7 @@ public:
 	 */
 	Cond &cond;
 
+protected:
 	/**
 	 * indicates whether the stream is ready for reading and
 	 * whether the other attributes in this struct are valid
@@ -80,7 +81,6 @@ public:
 	 */
 	offset_type size;
 
-public:
 	/**
 	 * the current offset within the stream
 	 */
@@ -217,6 +217,13 @@ public:
 		mime = _mime;
 	}
 
+	gcc_pure
+	bool KnownSize() const {
+		assert(ready);
+
+		return size >= 0;
+	}
+
 	gcc_pure
 	offset_type GetSize() const {
 		assert(ready);
@@ -239,6 +246,15 @@ public:
 		return offset;
 	}
 
+	gcc_pure
+	offset_type GetRest() const {
+		assert(ready);
+		assert(size >= 0);
+		assert(offset >= 0);
+
+		return size - offset;
+	}
+
 	gcc_pure
 	bool IsSeekable() const {
 		assert(ready);
diff --git a/src/input/plugins/RewindInputPlugin.cxx b/src/input/plugins/RewindInputPlugin.cxx
index 80f3beea1..eee395a8b 100644
--- a/src/input/plugins/RewindInputPlugin.cxx
+++ b/src/input/plugins/RewindInputPlugin.cxx
@@ -93,7 +93,7 @@ private:
 	 * buffer contain more data for the next read operation?
 	 */
 	bool ReadingFromBuffer() const {
-		return tail > 0 && offset < input->offset;
+		return tail > 0 && offset < input->GetOffset();
 	}
 
 	/**
@@ -116,7 +116,7 @@ private:
 			SetReady();
 		}
 
-		offset = src->offset;
+		offset = src->GetOffset();
 	}
 };
 
@@ -127,7 +127,7 @@ RewindInputStream::Read(void *ptr, size_t read_size, Error &error)
 		/* buffered read */
 
 		assert(head == (size_t)offset);
-		assert(tail == (size_t)input->offset);
+		assert(tail == (size_t)input->GetOffset());
 
 		if (read_size > tail - head)
 			read_size = tail - head;
@@ -142,7 +142,7 @@ RewindInputStream::Read(void *ptr, size_t read_size, Error &error)
 
 		size_t nbytes = input->Read(ptr, read_size, error);
 
-		if (input->offset > (InputPlugin::offset_type)sizeof(buffer))
+		if (input->GetOffset() > (offset_type)sizeof(buffer))
 			/* disable buffering */
 			tail = 0;
 		else if (tail == (size_t)offset) {
@@ -151,7 +151,7 @@ RewindInputStream::Read(void *ptr, size_t read_size, Error &error)
 			memcpy(buffer + tail, ptr, nbytes);
 			tail += nbytes;
 
-			assert(tail == (size_t)input->offset);
+			assert(tail == (size_t)input->GetOffset());
 		}
 
 		CopyAttributes();
@@ -172,7 +172,7 @@ RewindInputStream::Seek(InputPlugin::offset_type new_offset, int whence,
 
 		assert(!ReadingFromBuffer() ||
 		       head == (size_t)offset);
-		assert(tail == (size_t)input->offset);
+		assert(tail == (size_t)input->GetOffset());
 
 		head = (size_t)new_offset;
 		offset = new_offset;
@@ -194,7 +194,7 @@ InputStream *
 input_rewind_open(InputStream *is)
 {
 	assert(is != nullptr);
-	assert(is->offset == 0);
+	assert(is->GetOffset() == 0);
 
 	if (is->IsReady() && is->IsSeekable())
 		/* seekable resources don't need this plugin */
diff --git a/src/lib/expat/ExpatParser.cxx b/src/lib/expat/ExpatParser.cxx
index b69dc55b4..c6b1abe76 100644
--- a/src/lib/expat/ExpatParser.cxx
+++ b/src/lib/expat/ExpatParser.cxx
@@ -51,7 +51,7 @@ ExpatParser::Parse(const char *data, size_t length, bool is_final,
 bool
 ExpatParser::Parse(InputStream &is, Error &error)
 {
-	assert(is.ready);
+	assert(is.IsReady());
 
 	while (true) {
 		char buffer[4096];
diff --git a/src/playlist/PlaylistRegistry.cxx b/src/playlist/PlaylistRegistry.cxx
index 1b58c5c0f..bc5932de3 100644
--- a/src/playlist/PlaylistRegistry.cxx
+++ b/src/playlist/PlaylistRegistry.cxx
@@ -248,7 +248,7 @@ playlist_list_open_stream_suffix(InputStream &is, const char *suffix)
 SongEnumerator *
 playlist_list_open_stream(InputStream &is, const char *uri)
 {
-	assert(is.ready);
+	assert(is.IsReady());
 
 	const char *const mime = is.GetMimeType();
 	if (mime != nullptr) {