InputStream.cxx 3.88 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2014 The Music Player Daemon Project
3
 * http://www.musicpd.org
4 5 6 7 8 9 10 11 12 13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
14 15 16 17
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 19
 */

Max Kellermann's avatar
Max Kellermann committed
20
#include "config.h"
21
#include "InputStream.hxx"
22
#include "InputRegistry.hxx"
23
#include "InputPlugin.hxx"
24
#include "input/RewindInputPlugin.hxx"
Max Kellermann's avatar
Max Kellermann committed
25
#include "util/UriUtil.hxx"
26 27
#include "util/Error.hxx"
#include "util/Domain.hxx"
28

29
#include <assert.h>
30
#include <stdio.h> /* for SEEK_SET */
31

32
static constexpr Domain input_domain("input");
33

34 35 36 37
InputStream *
InputStream::Open(const char *url,
		  Mutex &mutex, Cond &cond,
		  Error &error)
Avuton Olrich's avatar
Avuton Olrich committed
38
{
39
	input_plugins_for_each_enabled(plugin) {
40
		InputStream *is;
Max Kellermann's avatar
Max Kellermann committed
41

42
		is = plugin->open(url, mutex, cond, error);
43 44 45 46 47
		if (is != nullptr) {
			assert(is->plugin.close != nullptr);
			assert(is->plugin.read != nullptr);
			assert(is->plugin.eof != nullptr);
			assert(!is->seekable || is->plugin.seek != nullptr);
48

49
			is = input_rewind_open(is);
50

51
			return is;
52
		} else if (error.IsDefined())
53
			return nullptr;
54
	}
55

56
	error.Set(input_domain, "Unrecognized URI");
57
	return nullptr;
58 59
}

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
InputStream *
InputStream::OpenReady(const char *uri,
		       Mutex &mutex, Cond &cond,
		       Error &error)
{
	InputStream *is = Open(uri, mutex, cond, error);
	if (is == nullptr)
		return nullptr;

	mutex.lock();
	is->WaitReady();
	bool success = is->Check(error);
	mutex.unlock();

	if (!success) {
		is->Close();
		is = nullptr;
	}

	return is;
}

82
bool
83
InputStream::Check(Error &error)
84
{
85
	return plugin.check == nullptr || plugin.check(this, error);
86 87
}

88
void
89
InputStream::Update()
90
{
91 92
	if (plugin.update != nullptr)
		plugin.update(this);
93 94
}

95
void
96
InputStream::WaitReady()
97 98
{
	while (true) {
99 100
		Update();
		if (ready)
101 102
			break;

103
		cond.wait(mutex);
104 105 106 107
	}
}

void
108
InputStream::LockWaitReady()
109
{
110 111
	const ScopeLock protect(mutex);
	WaitReady();
112 113
}

114
bool
115
InputStream::CheapSeeking() const
116
{
117
	return IsSeekable() && !uri_has_scheme(uri.c_str());
118 119
}

120
bool
121
InputStream::Seek(offset_type _offset, int whence, Error &error)
Avuton Olrich's avatar
Avuton Olrich committed
122
{
123
	if (plugin.seek == nullptr)
124 125
		return false;

126
	return plugin.seek(this, _offset, whence, error);
127 128
}

129
bool
130
InputStream::LockSeek(offset_type _offset, int whence, Error &error)
131
{
132
	if (plugin.seek == nullptr)
133 134
		return false;

135 136
	const ScopeLock protect(mutex);
	return Seek(_offset, whence, error);
137 138
}

139
bool
140
InputStream::Rewind(Error &error)
141 142 143 144 145
{
	return Seek(0, SEEK_SET, error);
}

bool
146
InputStream::LockRewind(Error &error)
147 148 149 150
{
	return LockSeek(0, SEEK_SET, error);
}

Max Kellermann's avatar
Max Kellermann committed
151
Tag *
152
InputStream::ReadTag()
153
{
154 155 156
	return plugin.tag != nullptr
		? plugin.tag(this)
		: nullptr;
157 158
}

Max Kellermann's avatar
Max Kellermann committed
159
Tag *
160
InputStream::LockReadTag()
161
{
162
	if (plugin.tag == nullptr)
163
		return nullptr;
164

165 166
	const ScopeLock protect(mutex);
	return ReadTag();
167 168 169
}

bool
170
InputStream::IsAvailable()
171
{
172 173
	return plugin.available != nullptr
		? plugin.available(this)
174 175 176
		: true;
}

177
size_t
178
InputStream::Read(void *ptr, size_t _size, Error &error)
179
{
180
	assert(ptr != nullptr);
181
	assert(_size > 0);
182

183
	return plugin.read(this, ptr, _size, error);
184 185
}

186
size_t
187
InputStream::LockRead(void *ptr, size_t _size, Error &error)
188
{
189
	assert(ptr != nullptr);
190
	assert(_size > 0);
191

192 193
	const ScopeLock protect(mutex);
	return Read(ptr, _size, error);
194 195
}

196
void
197
InputStream::Close()
Avuton Olrich's avatar
Avuton Olrich committed
198
{
199
	plugin.close(this);
200
}
201

202
bool
203
InputStream::IsEOF()
Avuton Olrich's avatar
Avuton Olrich committed
204
{
205
	return plugin.eof(this);
206
}
207

208
bool
209
InputStream::LockIsEOF()
Avuton Olrich's avatar
Avuton Olrich committed
210
{
211 212
	const ScopeLock protect(mutex);
	return IsEOF();
213
}
214