input/InputStreams: pass std::unique_lock<> to various methods
This commit is contained in:
parent
040573c636
commit
1b5c1f75a4
@ -72,7 +72,8 @@ public:
|
|||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() noexcept override;
|
bool IsEOF() noexcept override;
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t size) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Open();
|
void Open();
|
||||||
@ -147,7 +148,7 @@ Bzip2InputStream::FillBuffer()
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
Bzip2InputStream::Read(void *ptr, size_t length)
|
Bzip2InputStream::Read(std::unique_lock<Mutex> &, void *ptr, size_t length)
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
|
|
||||||
|
@ -157,7 +157,8 @@ public:
|
|||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() noexcept override;
|
bool IsEOF() noexcept override;
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
@ -174,7 +175,8 @@ Iso9660ArchiveFile::OpenStream(const char *pathname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
Iso9660InputStream::Read(void *ptr, size_t read_size)
|
Iso9660InputStream::Read(std::unique_lock<Mutex> &,
|
||||||
|
void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
|
|
||||||
|
@ -111,8 +111,9 @@ public:
|
|||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() noexcept override;
|
bool IsEOF() noexcept override;
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void Seek(offset_type offset) override;
|
void *ptr, size_t size) override;
|
||||||
|
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
@ -130,7 +131,7 @@ ZzipArchiveFile::OpenStream(const char *pathname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ZzipInputStream::Read(void *ptr, size_t read_size)
|
ZzipInputStream::Read(std::unique_lock<Mutex> &, void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ ZzipInputStream::IsEOF() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ZzipInputStream::Seek(offset_type new_offset)
|
ZzipInputStream::Seek(std::unique_lock<Mutex> &, offset_type new_offset)
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
|
|
||||||
|
@ -292,9 +292,9 @@ read_stream_art(Response &r, const char *uri, size_t offset)
|
|||||||
size_t read_size;
|
size_t read_size;
|
||||||
|
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
std::unique_lock<Mutex> lock(mutex);
|
||||||
is->Seek(offset);
|
is->Seek(lock, offset);
|
||||||
read_size = is->Read(&buffer, CHUNK_SIZE);
|
read_size = is->Read(lock, &buffer, CHUNK_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Format("size: %" PRIoffset "\n"
|
r.Format("size: %" PRIoffset "\n"
|
||||||
|
@ -305,7 +305,7 @@ GetChromaprintCommand::Read(InputStream &is, void *buffer, size_t length)
|
|||||||
cond.wait(lock);
|
cond.wait(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
return is.Read(buffer, length);
|
return is.Read(lock, buffer, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandResult
|
CommandResult
|
||||||
|
@ -403,7 +403,7 @@ try {
|
|||||||
dc.cond.wait(lock);
|
dc.cond.wait(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t nbytes = is.Read(buffer, length);
|
size_t nbytes = is.Read(lock, buffer, length);
|
||||||
assert(nbytes > 0 || is.IsEOF());
|
assert(nbytes > 0 || is.IsEOF());
|
||||||
|
|
||||||
return nbytes;
|
return nbytes;
|
||||||
|
@ -55,7 +55,8 @@ static constexpr Domain decoder_thread_domain("decoder_thread");
|
|||||||
static bool
|
static bool
|
||||||
decoder_stream_decode(const DecoderPlugin &plugin,
|
decoder_stream_decode(const DecoderPlugin &plugin,
|
||||||
DecoderBridge &bridge,
|
DecoderBridge &bridge,
|
||||||
InputStream &input_stream)
|
InputStream &input_stream,
|
||||||
|
std::unique_lock<Mutex> &lock)
|
||||||
{
|
{
|
||||||
assert(plugin.stream_decode != nullptr);
|
assert(plugin.stream_decode != nullptr);
|
||||||
assert(bridge.stream_tag == nullptr);
|
assert(bridge.stream_tag == nullptr);
|
||||||
@ -70,7 +71,7 @@ decoder_stream_decode(const DecoderPlugin &plugin,
|
|||||||
|
|
||||||
/* rewind the stream, so each plugin gets a fresh start */
|
/* rewind the stream, so each plugin gets a fresh start */
|
||||||
try {
|
try {
|
||||||
input_stream.Rewind();
|
input_stream.Rewind(lock);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,6 +162,7 @@ decoder_check_plugin(const DecoderPlugin &plugin, const InputStream &is,
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
decoder_run_stream_plugin(DecoderBridge &bridge, InputStream &is,
|
decoder_run_stream_plugin(DecoderBridge &bridge, InputStream &is,
|
||||||
|
std::unique_lock<Mutex> &lock,
|
||||||
const char *suffix,
|
const char *suffix,
|
||||||
const DecoderPlugin &plugin,
|
const DecoderPlugin &plugin,
|
||||||
bool &tried_r)
|
bool &tried_r)
|
||||||
@ -171,11 +173,12 @@ decoder_run_stream_plugin(DecoderBridge &bridge, InputStream &is,
|
|||||||
bridge.Reset();
|
bridge.Reset();
|
||||||
|
|
||||||
tried_r = true;
|
tried_r = true;
|
||||||
return decoder_stream_decode(plugin, bridge, is);
|
return decoder_stream_decode(plugin, bridge, is, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
decoder_run_stream_locked(DecoderBridge &bridge, InputStream &is,
|
decoder_run_stream_locked(DecoderBridge &bridge, InputStream &is,
|
||||||
|
std::unique_lock<Mutex> &lock,
|
||||||
const char *uri, bool &tried_r)
|
const char *uri, bool &tried_r)
|
||||||
{
|
{
|
||||||
UriSuffixBuffer suffix_buffer;
|
UriSuffixBuffer suffix_buffer;
|
||||||
@ -183,7 +186,8 @@ decoder_run_stream_locked(DecoderBridge &bridge, InputStream &is,
|
|||||||
|
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
const auto f = std::bind(decoder_run_stream_plugin,
|
const auto f = std::bind(decoder_run_stream_plugin,
|
||||||
std::ref(bridge), std::ref(is), suffix,
|
std::ref(bridge), std::ref(is), std::ref(lock),
|
||||||
|
suffix,
|
||||||
_1, std::ref(tried_r));
|
_1, std::ref(tried_r));
|
||||||
return decoder_plugins_try(f);
|
return decoder_plugins_try(f);
|
||||||
}
|
}
|
||||||
@ -192,7 +196,8 @@ decoder_run_stream_locked(DecoderBridge &bridge, InputStream &is,
|
|||||||
* Try decoding a stream, using the fallback plugin.
|
* Try decoding a stream, using the fallback plugin.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
decoder_run_stream_fallback(DecoderBridge &bridge, InputStream &is)
|
decoder_run_stream_fallback(DecoderBridge &bridge, InputStream &is,
|
||||||
|
std::unique_lock<Mutex> &lock)
|
||||||
{
|
{
|
||||||
const struct DecoderPlugin *plugin;
|
const struct DecoderPlugin *plugin;
|
||||||
|
|
||||||
@ -202,7 +207,7 @@ decoder_run_stream_fallback(DecoderBridge &bridge, InputStream &is)
|
|||||||
plugin = decoder_plugin_from_name("mad");
|
plugin = decoder_plugin_from_name("mad");
|
||||||
#endif
|
#endif
|
||||||
return plugin != nullptr && plugin->stream_decode != nullptr &&
|
return plugin != nullptr && plugin->stream_decode != nullptr &&
|
||||||
decoder_stream_decode(*plugin, bridge, is);
|
decoder_stream_decode(*plugin, bridge, is, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,16 +254,16 @@ decoder_run_stream(DecoderBridge &bridge, const char *uri)
|
|||||||
|
|
||||||
MaybeLoadReplayGain(bridge, *input_stream);
|
MaybeLoadReplayGain(bridge, *input_stream);
|
||||||
|
|
||||||
const std::lock_guard<Mutex> protect(dc.mutex);
|
std::unique_lock<Mutex> lock(dc.mutex);
|
||||||
|
|
||||||
bool tried = false;
|
bool tried = false;
|
||||||
return dc.command == DecoderCommand::STOP ||
|
return dc.command == DecoderCommand::STOP ||
|
||||||
decoder_run_stream_locked(bridge, *input_stream, uri,
|
decoder_run_stream_locked(bridge, *input_stream, lock, uri,
|
||||||
tried) ||
|
tried) ||
|
||||||
/* fallback to mp3: this is needed for bastard streams
|
/* fallback to mp3: this is needed for bastard streams
|
||||||
that don't have a suffix or set the mimeType */
|
that don't have a suffix or set the mimeType */
|
||||||
(!tried &&
|
(!tried &&
|
||||||
decoder_run_stream_fallback(bridge, *input_stream));
|
decoder_run_stream_fallback(bridge, *input_stream, lock));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -282,8 +287,9 @@ TryDecoderFile(DecoderBridge &bridge, Path path_fs, const char *suffix,
|
|||||||
const std::lock_guard<Mutex> protect(dc.mutex);
|
const std::lock_guard<Mutex> protect(dc.mutex);
|
||||||
return decoder_file_decode(plugin, bridge, path_fs);
|
return decoder_file_decode(plugin, bridge, path_fs);
|
||||||
} else if (plugin.stream_decode != nullptr) {
|
} else if (plugin.stream_decode != nullptr) {
|
||||||
const std::lock_guard<Mutex> protect(dc.mutex);
|
std::unique_lock<Mutex> lock(dc.mutex);
|
||||||
return decoder_stream_decode(plugin, bridge, input_stream);
|
return decoder_stream_decode(plugin, bridge, input_stream,
|
||||||
|
lock);
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,8 @@ AsyncInputStream::IsEOF() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AsyncInputStream::Seek(offset_type new_offset)
|
AsyncInputStream::Seek(std::unique_lock<Mutex> &lock,
|
||||||
|
offset_type new_offset)
|
||||||
{
|
{
|
||||||
assert(IsReady());
|
assert(IsReady());
|
||||||
assert(seek_state == SeekState::NONE);
|
assert(seek_state == SeekState::NONE);
|
||||||
@ -136,7 +137,7 @@ AsyncInputStream::Seek(offset_type new_offset)
|
|||||||
CondInputStreamHandler cond_handler;
|
CondInputStreamHandler cond_handler;
|
||||||
const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
|
const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
|
||||||
while (seek_state != SeekState::NONE)
|
while (seek_state != SeekState::NONE)
|
||||||
cond_handler.cond.wait(mutex);
|
cond_handler.cond.wait(lock);
|
||||||
|
|
||||||
Check();
|
Check();
|
||||||
}
|
}
|
||||||
@ -171,7 +172,8 @@ AsyncInputStream::IsAvailable() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
AsyncInputStream::Read(void *ptr, size_t read_size)
|
AsyncInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
assert(!GetEventLoop().IsInside());
|
assert(!GetEventLoop().IsInside());
|
||||||
|
|
||||||
@ -187,7 +189,7 @@ AsyncInputStream::Read(void *ptr, size_t read_size)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
|
const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
|
||||||
cond_handler.cond.wait(mutex);
|
cond_handler.cond.wait(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t nbytes = std::min(read_size, r.size);
|
const size_t nbytes = std::min(read_size, r.size);
|
||||||
|
@ -83,10 +83,12 @@ public:
|
|||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
void Check() final;
|
void Check() final;
|
||||||
bool IsEOF() noexcept final;
|
bool IsEOF() noexcept final;
|
||||||
void Seek(offset_type new_offset) final;
|
void Seek(std::unique_lock<Mutex> &lock,
|
||||||
|
offset_type new_offset) final;
|
||||||
std::unique_ptr<Tag> ReadTag() noexcept final;
|
std::unique_ptr<Tag> ReadTag() noexcept final;
|
||||||
bool IsAvailable() noexcept final;
|
bool IsAvailable() noexcept final;
|
||||||
size_t Read(void *ptr, size_t read_size) final;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t read_size) final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
@ -64,7 +64,8 @@ BufferedInputStream::Check()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BufferedInputStream::Seek(offset_type new_offset)
|
BufferedInputStream::Seek(std::unique_lock<Mutex> &lock,
|
||||||
|
offset_type new_offset)
|
||||||
{
|
{
|
||||||
if (new_offset >= size) {
|
if (new_offset >= size) {
|
||||||
offset = size;
|
offset = size;
|
||||||
@ -84,7 +85,7 @@ BufferedInputStream::Seek(offset_type new_offset)
|
|||||||
wake_cond.notify_one();
|
wake_cond.notify_one();
|
||||||
|
|
||||||
while (seek)
|
while (seek)
|
||||||
client_cond.wait(mutex);
|
client_cond.wait(lock);
|
||||||
|
|
||||||
if (seek_error)
|
if (seek_error)
|
||||||
std::rethrow_exception(std::exchange(seek_error, {}));
|
std::rethrow_exception(std::exchange(seek_error, {}));
|
||||||
@ -105,7 +106,8 @@ BufferedInputStream::IsAvailable() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
BufferedInputStream::Read(void *ptr, size_t s)
|
BufferedInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t s)
|
||||||
{
|
{
|
||||||
if (offset >= size)
|
if (offset >= size)
|
||||||
return 0;
|
return 0;
|
||||||
@ -140,7 +142,7 @@ BufferedInputStream::Read(void *ptr, size_t s)
|
|||||||
wake_cond.notify_one();
|
wake_cond.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
client_cond.wait(mutex);
|
client_cond.wait(lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +158,7 @@ BufferedInputStream::RunThread() noexcept
|
|||||||
|
|
||||||
if (seek) {
|
if (seek) {
|
||||||
try {
|
try {
|
||||||
input->Seek(seek_offset);
|
input->Seek(lock, seek_offset);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
seek_error = std::current_exception();
|
seek_error = std::current_exception();
|
||||||
}
|
}
|
||||||
@ -183,7 +185,7 @@ BufferedInputStream::RunThread() noexcept
|
|||||||
offset to prepare filling
|
offset to prepare filling
|
||||||
the buffer from there */
|
the buffer from there */
|
||||||
try {
|
try {
|
||||||
input->Seek(offset);
|
input->Seek(lock, offset);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
read_error = std::current_exception();
|
read_error = std::current_exception();
|
||||||
client_cond.notify_one();
|
client_cond.notify_one();
|
||||||
@ -195,7 +197,8 @@ BufferedInputStream::RunThread() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
size_t nbytes = input->Read(w.data, w.size);
|
size_t nbytes = input->Read(lock,
|
||||||
|
w.data, w.size);
|
||||||
buffer.Commit(read_offset,
|
buffer.Commit(read_offset,
|
||||||
read_offset + nbytes);
|
read_offset + nbytes);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
@ -85,12 +85,13 @@ public:
|
|||||||
/* we don't need to implement Update() because all attributes
|
/* we don't need to implement Update() because all attributes
|
||||||
have been copied already in our constructor */
|
have been copied already in our constructor */
|
||||||
//void Update() noexcept;
|
//void Update() noexcept;
|
||||||
void Seek(offset_type offset) override;
|
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
||||||
bool IsEOF() noexcept override;
|
bool IsEOF() noexcept override;
|
||||||
/* we don't support tags */
|
/* we don't support tags */
|
||||||
// std::unique_ptr<Tag> ReadTag() override;
|
// std::unique_ptr<Tag> ReadTag() override;
|
||||||
bool IsAvailable() noexcept override;
|
bool IsAvailable() noexcept override;
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t size) override;
|
||||||
|
|
||||||
/* virtual methods from class InputStreamHandler */
|
/* virtual methods from class InputStreamHandler */
|
||||||
void OnInputStreamReady() noexcept override {
|
void OnInputStreamReady() noexcept override {
|
||||||
|
@ -45,7 +45,7 @@ public:
|
|||||||
std::rethrow_exception(error);
|
std::rethrow_exception(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Seek(offset_type) override {
|
void Seek(std::unique_lock<Mutex> &, offset_type) override {
|
||||||
std::rethrow_exception(error);
|
std::rethrow_exception(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *, size_t) override {
|
size_t Read(std::unique_lock<Mutex> &, void *, size_t) override {
|
||||||
std::rethrow_exception(error);
|
std::rethrow_exception(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -80,13 +80,14 @@ IcyInputStream::ReadTag() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
IcyInputStream::Read(void *ptr, size_t read_size)
|
IcyInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
if (!IsEnabled())
|
if (!IsEnabled())
|
||||||
return ProxyInputStream::Read(ptr, read_size);
|
return ProxyInputStream::Read(lock, ptr, read_size);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
size_t nbytes = ProxyInputStream::Read(ptr, read_size);
|
size_t nbytes = ProxyInputStream::Read(lock, ptr, read_size);
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -66,7 +66,8 @@ public:
|
|||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
void Update() noexcept override;
|
void Update() noexcept override;
|
||||||
std::unique_ptr<Tag> ReadTag() noexcept override;
|
std::unique_ptr<Tag> ReadTag() noexcept override;
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -72,7 +72,7 @@ InputStream::CheapSeeking() const noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
InputStream::Seek(gcc_unused offset_type new_offset)
|
InputStream::Seek(std::unique_lock<Mutex> &, gcc_unused offset_type new_offset)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Seeking is not implemented");
|
throw std::runtime_error("Seeking is not implemented");
|
||||||
}
|
}
|
||||||
@ -80,15 +80,15 @@ InputStream::Seek(gcc_unused offset_type new_offset)
|
|||||||
void
|
void
|
||||||
InputStream::LockSeek(offset_type _offset)
|
InputStream::LockSeek(offset_type _offset)
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
std::unique_lock<Mutex> lock(mutex);
|
||||||
Seek(_offset);
|
Seek(lock, _offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
InputStream::LockSkip(offset_type _offset)
|
InputStream::LockSkip(offset_type _offset)
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
std::unique_lock<Mutex> lock(mutex);
|
||||||
Skip(_offset);
|
Skip(lock, _offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Tag>
|
std::unique_ptr<Tag>
|
||||||
@ -119,18 +119,18 @@ InputStream::LockRead(void *ptr, size_t _size)
|
|||||||
#endif
|
#endif
|
||||||
assert(_size > 0);
|
assert(_size > 0);
|
||||||
|
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
std::unique_lock<Mutex> lock(mutex);
|
||||||
return Read(ptr, _size);
|
return Read(lock, ptr, _size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
InputStream::ReadFull(void *_ptr, size_t _size)
|
InputStream::ReadFull(std::unique_lock<Mutex> &lock, void *_ptr, size_t _size)
|
||||||
{
|
{
|
||||||
uint8_t *ptr = (uint8_t *)_ptr;
|
uint8_t *ptr = (uint8_t *)_ptr;
|
||||||
|
|
||||||
size_t nbytes_total = 0;
|
size_t nbytes_total = 0;
|
||||||
while (_size > 0) {
|
while (_size > 0) {
|
||||||
size_t nbytes = Read(ptr + nbytes_total, _size);
|
size_t nbytes = Read(lock, ptr + nbytes_total, _size);
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
throw std::runtime_error("Unexpected end of file");
|
throw std::runtime_error("Unexpected end of file");
|
||||||
|
|
||||||
@ -148,8 +148,8 @@ InputStream::LockReadFull(void *ptr, size_t _size)
|
|||||||
#endif
|
#endif
|
||||||
assert(_size > 0);
|
assert(_size > 0);
|
||||||
|
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
std::unique_lock<Mutex> lock(mutex);
|
||||||
ReadFull(ptr, _size);
|
ReadFull(lock, ptr, _size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -271,9 +271,11 @@ public:
|
|||||||
*
|
*
|
||||||
* Throws std::runtime_error on error.
|
* Throws std::runtime_error on error.
|
||||||
*
|
*
|
||||||
|
* @param lock the locked mutex; may be used to wait on
|
||||||
|
* condition variables
|
||||||
* @param offset the relative offset
|
* @param offset the relative offset
|
||||||
*/
|
*/
|
||||||
virtual void Seek(offset_type offset);
|
virtual void Seek(std::unique_lock<Mutex> &lock, offset_type offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for Seek() which locks and unlocks the mutex; the
|
* Wrapper for Seek() which locks and unlocks the mutex; the
|
||||||
@ -285,8 +287,8 @@ public:
|
|||||||
* Rewind to the beginning of the stream. This is a wrapper
|
* Rewind to the beginning of the stream. This is a wrapper
|
||||||
* for Seek(0, error).
|
* for Seek(0, error).
|
||||||
*/
|
*/
|
||||||
void Rewind() {
|
void Rewind(std::unique_lock<Mutex> &lock) {
|
||||||
Seek(0);
|
Seek(lock, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LockRewind() {
|
void LockRewind() {
|
||||||
@ -296,8 +298,9 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Skip input bytes.
|
* Skip input bytes.
|
||||||
*/
|
*/
|
||||||
void Skip(offset_type _offset) {
|
void Skip(std::unique_lock<Mutex> &lock,
|
||||||
Seek(GetOffset() + _offset);
|
offset_type _offset) {
|
||||||
|
Seek(lock, GetOffset() + _offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LockSkip(offset_type _offset);
|
void LockSkip(offset_type _offset);
|
||||||
@ -351,12 +354,15 @@ public:
|
|||||||
*
|
*
|
||||||
* Throws std::runtime_error on error.
|
* Throws std::runtime_error on error.
|
||||||
*
|
*
|
||||||
|
* @param lock the locked mutex; may be used to wait on
|
||||||
|
* condition variables
|
||||||
* @param ptr the buffer to read into
|
* @param ptr the buffer to read into
|
||||||
* @param size the maximum number of bytes to read
|
* @param size the maximum number of bytes to read
|
||||||
* @return the number of bytes read
|
* @return the number of bytes read
|
||||||
*/
|
*/
|
||||||
gcc_nonnull_all
|
gcc_nonnull_all
|
||||||
virtual size_t Read(void *ptr, size_t size) = 0;
|
virtual size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t size) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for Read() which locks and unlocks the mutex;
|
* Wrapper for Read() which locks and unlocks the mutex;
|
||||||
@ -379,7 +385,7 @@ public:
|
|||||||
* @return true if the whole data was read, false otherwise.
|
* @return true if the whole data was read, false otherwise.
|
||||||
*/
|
*/
|
||||||
gcc_nonnull_all
|
gcc_nonnull_all
|
||||||
void ReadFull(void *ptr, size_t size);
|
void ReadFull(std::unique_lock<Mutex> &lock, void *ptr, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for ReadFull() which locks and unlocks the mutex;
|
* Wrapper for ReadFull() which locks and unlocks the mutex;
|
||||||
|
@ -89,12 +89,13 @@ ProxyInputStream::Update() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ProxyInputStream::Seek(offset_type new_offset)
|
ProxyInputStream::Seek(std::unique_lock<Mutex> &lock,
|
||||||
|
offset_type new_offset)
|
||||||
{
|
{
|
||||||
while (!input)
|
while (!input)
|
||||||
set_input_cond.wait(mutex);
|
set_input_cond.wait(lock);
|
||||||
|
|
||||||
input->Seek(new_offset);
|
input->Seek(lock, new_offset);
|
||||||
CopyAttributes();
|
CopyAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,12 +121,13 @@ ProxyInputStream::IsAvailable() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ProxyInputStream::Read(void *ptr, size_t read_size)
|
ProxyInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
while (!input)
|
while (!input)
|
||||||
set_input_cond.wait(mutex);
|
set_input_cond.wait(lock);
|
||||||
|
|
||||||
size_t nbytes = input->Read(ptr, read_size);
|
size_t nbytes = input->Read(lock, ptr, read_size);
|
||||||
CopyAttributes();
|
CopyAttributes();
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
@ -60,11 +60,13 @@ public:
|
|||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
void Check() override;
|
void Check() override;
|
||||||
void Update() noexcept override;
|
void Update() noexcept override;
|
||||||
void Seek(offset_type new_offset) override;
|
void Seek(std::unique_lock<Mutex> &lock,
|
||||||
|
offset_type new_offset) override;
|
||||||
bool IsEOF() noexcept override;
|
bool IsEOF() noexcept override;
|
||||||
std::unique_ptr<Tag> ReadTag() noexcept override;
|
std::unique_ptr<Tag> ReadTag() noexcept override;
|
||||||
bool IsAvailable() noexcept override;
|
bool IsAvailable() noexcept override;
|
||||||
size_t Read(void *ptr, size_t read_size) override;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t read_size) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
@ -60,8 +60,9 @@ public:
|
|||||||
return !ReadingFromBuffer() && ProxyInputStream::IsEOF();
|
return !ReadingFromBuffer() && ProxyInputStream::IsEOF();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void Seek(offset_type offset) override;
|
void *ptr, size_t size) override;
|
||||||
|
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@ -74,7 +75,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
RewindInputStream::Read(void *ptr, size_t read_size)
|
RewindInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
if (ReadingFromBuffer()) {
|
if (ReadingFromBuffer()) {
|
||||||
/* buffered read */
|
/* buffered read */
|
||||||
@ -93,7 +95,7 @@ RewindInputStream::Read(void *ptr, size_t read_size)
|
|||||||
} else {
|
} else {
|
||||||
/* pass method call to underlying stream */
|
/* pass method call to underlying stream */
|
||||||
|
|
||||||
size_t nbytes = input->Read(ptr, read_size);
|
size_t nbytes = input->Read(lock, ptr, read_size);
|
||||||
|
|
||||||
if (input->GetOffset() > (offset_type)sizeof(buffer))
|
if (input->GetOffset() > (offset_type)sizeof(buffer))
|
||||||
/* disable buffering */
|
/* disable buffering */
|
||||||
@ -114,7 +116,7 @@ RewindInputStream::Read(void *ptr, size_t read_size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RewindInputStream::Seek(offset_type new_offset)
|
RewindInputStream::Seek(std::unique_lock<Mutex> &lock, offset_type new_offset)
|
||||||
{
|
{
|
||||||
assert(IsReady());
|
assert(IsReady());
|
||||||
|
|
||||||
@ -132,7 +134,7 @@ RewindInputStream::Seek(offset_type new_offset)
|
|||||||
buffered range now */
|
buffered range now */
|
||||||
tail = 0;
|
tail = 0;
|
||||||
|
|
||||||
ProxyInputStream::Seek(new_offset);
|
ProxyInputStream::Seek(lock, new_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +130,8 @@ ThreadInputStream::IsAvailable() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
ThreadInputStream::Read(void *ptr, size_t read_size)
|
ThreadInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
assert(!thread.IsInside());
|
assert(!thread.IsInside());
|
||||||
|
|
||||||
@ -154,7 +155,7 @@ ThreadInputStream::Read(void *ptr, size_t read_size)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
|
const ScopeExchangeInputStreamHandler h(*this, &cond_handler);
|
||||||
cond_handler.cond.wait(mutex);
|
cond_handler.cond.wait(lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,8 @@ public:
|
|||||||
void Check() override final;
|
void Check() override final;
|
||||||
bool IsEOF() noexcept final;
|
bool IsEOF() noexcept final;
|
||||||
bool IsAvailable() noexcept final;
|
bool IsAvailable() noexcept final;
|
||||||
size_t Read(void *ptr, size_t size) override final;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
|
void *ptr, size_t size) override final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
@ -91,8 +91,9 @@ class CdioParanoiaInputStream final : public InputStream {
|
|||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() noexcept override;
|
bool IsEOF() noexcept override;
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void Seek(offset_type offset) override;
|
void *ptr, size_t size) override;
|
||||||
|
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr Domain cdio_domain("cdio");
|
static constexpr Domain cdio_domain("cdio");
|
||||||
@ -255,7 +256,8 @@ input_cdio_open(const char *uri,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CdioParanoiaInputStream::Seek(offset_type new_offset)
|
CdioParanoiaInputStream::Seek(std::unique_lock<Mutex> &,
|
||||||
|
offset_type new_offset)
|
||||||
{
|
{
|
||||||
if (new_offset > size)
|
if (new_offset > size)
|
||||||
throw FormatRuntimeError("Invalid offset to seek %ld (%ld)",
|
throw FormatRuntimeError("Invalid offset to seek %ld (%ld)",
|
||||||
@ -276,7 +278,8 @@ CdioParanoiaInputStream::Seek(offset_type new_offset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
CdioParanoiaInputStream::Read(void *ptr, size_t length)
|
CdioParanoiaInputStream::Read(std::unique_lock<Mutex> &,
|
||||||
|
void *ptr, size_t length)
|
||||||
{
|
{
|
||||||
size_t nbytes = 0;
|
size_t nbytes = 0;
|
||||||
char *wptr = (char *) ptr;
|
char *wptr = (char *) ptr;
|
||||||
|
@ -49,8 +49,10 @@ public:
|
|||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() noexcept override;
|
bool IsEOF() noexcept override;
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void Seek(offset_type offset) override;
|
void *ptr, size_t size) override;
|
||||||
|
void Seek(std::unique_lock<Mutex> &lock,
|
||||||
|
offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
gcc_const
|
gcc_const
|
||||||
@ -79,7 +81,8 @@ input_ffmpeg_open(const char *uri,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
FfmpegInputStream::Read(void *ptr, size_t read_size)
|
FfmpegInputStream::Read(std::unique_lock<Mutex> &,
|
||||||
|
void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
size_t result;
|
size_t result;
|
||||||
|
|
||||||
@ -99,7 +102,7 @@ FfmpegInputStream::IsEOF() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FfmpegInputStream::Seek(offset_type new_offset)
|
FfmpegInputStream::Seek(std::unique_lock<Mutex> &, offset_type new_offset)
|
||||||
{
|
{
|
||||||
uint64_t result;
|
uint64_t result;
|
||||||
|
|
||||||
|
@ -48,8 +48,10 @@ public:
|
|||||||
return GetOffset() >= GetSize();
|
return GetOffset() >= GetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void Seek(offset_type offset) override;
|
void *ptr, size_t size) override;
|
||||||
|
void Seek(std::unique_lock<Mutex> &lock,
|
||||||
|
offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
@ -74,7 +76,8 @@ OpenFileInputStream(Path path, Mutex &mutex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FileInputStream::Seek(offset_type new_offset)
|
FileInputStream::Seek(std::unique_lock<Mutex> &,
|
||||||
|
offset_type new_offset)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
@ -85,7 +88,8 @@ FileInputStream::Seek(offset_type new_offset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
FileInputStream::Read(void *ptr, size_t read_size)
|
FileInputStream::Read(std::unique_lock<Mutex> &,
|
||||||
|
void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
|
|
||||||
|
@ -56,8 +56,9 @@ public:
|
|||||||
return offset >= size;
|
return offset >= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void Seek(offset_type offset) override;
|
void *ptr, size_t size) override;
|
||||||
|
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -118,7 +119,8 @@ input_smbclient_open(const char *uri,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
SmbclientInputStream::Read(void *ptr, size_t read_size)
|
SmbclientInputStream::Read(std::unique_lock<Mutex> &,
|
||||||
|
void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
ssize_t nbytes;
|
ssize_t nbytes;
|
||||||
|
|
||||||
@ -136,7 +138,8 @@ SmbclientInputStream::Read(void *ptr, size_t read_size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SmbclientInputStream::Seek(offset_type new_offset)
|
SmbclientInputStream::Seek(std::unique_lock<Mutex> &,
|
||||||
|
offset_type new_offset)
|
||||||
{
|
{
|
||||||
off_t result;
|
off_t result;
|
||||||
|
|
||||||
|
@ -39,14 +39,14 @@ struct aiff_chunk_header {
|
|||||||
};
|
};
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
aiff_seek_id3(InputStream &is)
|
aiff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
{
|
{
|
||||||
/* seek to the beginning and read the AIFF header */
|
/* seek to the beginning and read the AIFF header */
|
||||||
|
|
||||||
is.Rewind();
|
is.Rewind(lock);
|
||||||
|
|
||||||
aiff_header header;
|
aiff_header header;
|
||||||
is.ReadFull(&header, sizeof(header));
|
is.ReadFull(lock, &header, sizeof(header));
|
||||||
if (memcmp(header.id, "FORM", 4) != 0 ||
|
if (memcmp(header.id, "FORM", 4) != 0 ||
|
||||||
(is.KnownSize() && FromBE32(header.size) > is.GetSize()) ||
|
(is.KnownSize() && FromBE32(header.size) > is.GetSize()) ||
|
||||||
(memcmp(header.format, "AIFF", 4) != 0 &&
|
(memcmp(header.format, "AIFF", 4) != 0 &&
|
||||||
@ -57,7 +57,7 @@ aiff_seek_id3(InputStream &is)
|
|||||||
/* read the chunk header */
|
/* read the chunk header */
|
||||||
|
|
||||||
aiff_chunk_header chunk;
|
aiff_chunk_header chunk;
|
||||||
is.ReadFull(&chunk, sizeof(chunk));
|
is.ReadFull(lock, &chunk, sizeof(chunk));
|
||||||
|
|
||||||
size_t size = FromBE32(chunk.size);
|
size_t size = FromBE32(chunk.size);
|
||||||
if (size > size_t(std::numeric_limits<int>::max()))
|
if (size > size_t(std::numeric_limits<int>::max()))
|
||||||
@ -73,6 +73,6 @@ aiff_seek_id3(InputStream &is)
|
|||||||
/* pad byte */
|
/* pad byte */
|
||||||
++size;
|
++size;
|
||||||
|
|
||||||
is.Skip(size);
|
is.Skip(lock, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,12 @@
|
|||||||
#ifndef MPD_AIFF_HXX
|
#ifndef MPD_AIFF_HXX
|
||||||
#define MPD_AIFF_HXX
|
#define MPD_AIFF_HXX
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
class InputStream;
|
class InputStream;
|
||||||
|
class Mutex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Seeks the AIFF file to the ID3 chunk.
|
* Seeks the AIFF file to the ID3 chunk.
|
||||||
@ -38,6 +41,6 @@ class InputStream;
|
|||||||
* @return the size of the ID3 chunk
|
* @return the size of the ID3 chunk
|
||||||
*/
|
*/
|
||||||
size_t
|
size_t
|
||||||
aiff_seek_id3(InputStream &is);
|
aiff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -40,15 +40,15 @@ struct ApeFooter {
|
|||||||
bool
|
bool
|
||||||
tag_ape_scan(InputStream &is, ApeTagCallback callback)
|
tag_ape_scan(InputStream &is, ApeTagCallback callback)
|
||||||
try {
|
try {
|
||||||
const std::lock_guard<Mutex> protect(is.mutex);
|
std::unique_lock<Mutex> lock(is.mutex);
|
||||||
|
|
||||||
if (!is.KnownSize() || !is.CheapSeeking())
|
if (!is.KnownSize() || !is.CheapSeeking())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* determine if file has an apeV2 tag */
|
/* determine if file has an apeV2 tag */
|
||||||
ApeFooter footer;
|
ApeFooter footer;
|
||||||
is.Seek(is.GetSize() - sizeof(footer));
|
is.Seek(lock, is.GetSize() - sizeof(footer));
|
||||||
is.ReadFull(&footer, sizeof(footer));
|
is.ReadFull(lock, &footer, sizeof(footer));
|
||||||
|
|
||||||
if (memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0 ||
|
if (memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0 ||
|
||||||
FromLE32(footer.version) != 2000)
|
FromLE32(footer.version) != 2000)
|
||||||
@ -61,14 +61,14 @@ try {
|
|||||||
remaining > 1024 * 1024)
|
remaining > 1024 * 1024)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
is.Seek(is.GetSize() - remaining);
|
is.Seek(lock, is.GetSize() - remaining);
|
||||||
|
|
||||||
/* read tag into buffer */
|
/* read tag into buffer */
|
||||||
remaining -= sizeof(footer);
|
remaining -= sizeof(footer);
|
||||||
assert(remaining > 10);
|
assert(remaining > 10);
|
||||||
|
|
||||||
std::unique_ptr<char[]> buffer(new char[remaining]);
|
std::unique_ptr<char[]> buffer(new char[remaining]);
|
||||||
is.ReadFull(buffer.get(), remaining);
|
is.ReadFull(lock, buffer.get(), remaining);
|
||||||
|
|
||||||
/* read tags */
|
/* read tags */
|
||||||
unsigned n = FromLE32(footer.count);
|
unsigned n = FromLE32(footer.count);
|
||||||
|
@ -37,11 +37,12 @@ tag_is_id3v1(struct id3_tag *tag) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static long
|
static long
|
||||||
get_id3v2_footer_size(InputStream &is, offset_type offset)
|
get_id3v2_footer_size(InputStream &is, std::unique_lock<Mutex> &lock,
|
||||||
|
offset_type offset)
|
||||||
try {
|
try {
|
||||||
id3_byte_t buf[ID3_TAG_QUERYSIZE];
|
id3_byte_t buf[ID3_TAG_QUERYSIZE];
|
||||||
is.Seek(offset);
|
is.Seek(lock, offset);
|
||||||
is.ReadFull(buf, sizeof(buf));
|
is.ReadFull(lock, buf, sizeof(buf));
|
||||||
|
|
||||||
return id3_tag_query(buf, sizeof(buf));
|
return id3_tag_query(buf, sizeof(buf));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@ -49,10 +50,10 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static UniqueId3Tag
|
static UniqueId3Tag
|
||||||
ReadId3Tag(InputStream &is)
|
ReadId3Tag(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
try {
|
try {
|
||||||
id3_byte_t query_buffer[ID3_TAG_QUERYSIZE];
|
id3_byte_t query_buffer[ID3_TAG_QUERYSIZE];
|
||||||
is.ReadFull(query_buffer, sizeof(query_buffer));
|
is.ReadFull(lock, query_buffer, sizeof(query_buffer));
|
||||||
|
|
||||||
/* Look for a tag header */
|
/* Look for a tag header */
|
||||||
long tag_size = id3_tag_query(query_buffer, sizeof(query_buffer));
|
long tag_size = id3_tag_query(query_buffer, sizeof(query_buffer));
|
||||||
@ -72,7 +73,7 @@ try {
|
|||||||
|
|
||||||
/* now read the remaining bytes */
|
/* now read the remaining bytes */
|
||||||
const size_t remaining = tag_size - sizeof(query_buffer);
|
const size_t remaining = tag_size - sizeof(query_buffer);
|
||||||
is.ReadFull(end, remaining);
|
is.ReadFull(lock, end, remaining);
|
||||||
|
|
||||||
return UniqueId3Tag(id3_tag_parse(tag_buffer.get(), tag_size));
|
return UniqueId3Tag(id3_tag_parse(tag_buffer.get(), tag_size));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@ -80,20 +81,20 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static UniqueId3Tag
|
static UniqueId3Tag
|
||||||
ReadId3Tag(InputStream &is, offset_type offset)
|
ReadId3Tag(InputStream &is, std::unique_lock<Mutex> &lock, offset_type offset)
|
||||||
try {
|
try {
|
||||||
is.Seek(offset);
|
is.Seek(lock, offset);
|
||||||
|
|
||||||
return ReadId3Tag(is);
|
return ReadId3Tag(is, lock);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UniqueId3Tag
|
static UniqueId3Tag
|
||||||
ReadId3v1Tag(InputStream &is)
|
ReadId3v1Tag(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
try {
|
try {
|
||||||
id3_byte_t buffer[ID3V1_SIZE];
|
id3_byte_t buffer[ID3V1_SIZE];
|
||||||
is.ReadFull(buffer, ID3V1_SIZE);
|
is.ReadFull(lock, buffer, ID3V1_SIZE);
|
||||||
|
|
||||||
return UniqueId3Tag(id3_tag_parse(buffer, ID3V1_SIZE));
|
return UniqueId3Tag(id3_tag_parse(buffer, ID3V1_SIZE));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@ -101,18 +102,19 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static UniqueId3Tag
|
static UniqueId3Tag
|
||||||
ReadId3v1Tag(InputStream &is, offset_type offset)
|
ReadId3v1Tag(InputStream &is, std::unique_lock<Mutex> &lock,
|
||||||
|
offset_type offset)
|
||||||
try {
|
try {
|
||||||
is.Seek(offset);
|
is.Seek(lock, offset);
|
||||||
return ReadId3v1Tag(is);
|
return ReadId3v1Tag(is, lock);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UniqueId3Tag
|
static UniqueId3Tag
|
||||||
tag_id3_find_from_beginning(InputStream &is)
|
tag_id3_find_from_beginning(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
try {
|
try {
|
||||||
auto tag = ReadId3Tag(is);
|
auto tag = ReadId3Tag(is, lock);
|
||||||
if (!tag) {
|
if (!tag) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (tag_is_id3v1(tag.get())) {
|
} else if (tag_is_id3v1(tag.get())) {
|
||||||
@ -129,7 +131,7 @@ try {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* Get the tag specified by the SEEK frame */
|
/* Get the tag specified by the SEEK frame */
|
||||||
auto seektag = ReadId3Tag(is, is.GetOffset() + seek);
|
auto seektag = ReadId3Tag(is, lock, is.GetOffset() + seek);
|
||||||
if (!seektag || tag_is_id3v1(seektag.get()))
|
if (!seektag || tag_is_id3v1(seektag.get()))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -143,7 +145,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static UniqueId3Tag
|
static UniqueId3Tag
|
||||||
tag_id3_find_from_end(InputStream &is)
|
tag_id3_find_from_end(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
try {
|
try {
|
||||||
if (!is.KnownSize() || !is.CheapSeeking())
|
if (!is.KnownSize() || !is.CheapSeeking())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -155,7 +157,7 @@ try {
|
|||||||
offset_type offset = size - ID3V1_SIZE;
|
offset_type offset = size - ID3V1_SIZE;
|
||||||
|
|
||||||
/* Get an id3v1 tag from the end of file for later use */
|
/* Get an id3v1 tag from the end of file for later use */
|
||||||
auto v1tag = ReadId3v1Tag(is, offset);
|
auto v1tag = ReadId3v1Tag(is, lock, offset);
|
||||||
if (!v1tag)
|
if (!v1tag)
|
||||||
offset = size;
|
offset = size;
|
||||||
|
|
||||||
@ -164,7 +166,7 @@ try {
|
|||||||
return v1tag;
|
return v1tag;
|
||||||
|
|
||||||
long tag_offset =
|
long tag_offset =
|
||||||
get_id3v2_footer_size(is, offset - ID3_TAG_QUERYSIZE);
|
get_id3v2_footer_size(is, lock, offset - ID3_TAG_QUERYSIZE);
|
||||||
if (tag_offset >= 0)
|
if (tag_offset >= 0)
|
||||||
return v1tag;
|
return v1tag;
|
||||||
|
|
||||||
@ -173,7 +175,7 @@ try {
|
|||||||
return v1tag;
|
return v1tag;
|
||||||
|
|
||||||
/* Get the tag which the footer belongs to */
|
/* Get the tag which the footer belongs to */
|
||||||
auto tag = ReadId3Tag(is, offset - tag_size);
|
auto tag = ReadId3Tag(is, lock, offset - tag_size);
|
||||||
if (!tag)
|
if (!tag)
|
||||||
return v1tag;
|
return v1tag;
|
||||||
|
|
||||||
@ -184,13 +186,13 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static UniqueId3Tag
|
static UniqueId3Tag
|
||||||
tag_id3_riff_aiff_load(InputStream &is)
|
tag_id3_riff_aiff_load(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
try {
|
try {
|
||||||
size_t size;
|
size_t size;
|
||||||
try {
|
try {
|
||||||
size = riff_seek_id3(is);
|
size = riff_seek_id3(is, lock);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
size = aiff_seek_id3(is);
|
size = aiff_seek_id3(is, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > 4 * 1024 * 1024)
|
if (size > 4 * 1024 * 1024)
|
||||||
@ -198,7 +200,7 @@ try {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
std::unique_ptr<id3_byte_t[]> buffer(new id3_byte_t[size]);
|
std::unique_ptr<id3_byte_t[]> buffer(new id3_byte_t[size]);
|
||||||
is.ReadFull(buffer.get(), size);
|
is.ReadFull(lock, buffer.get(), size);
|
||||||
|
|
||||||
return UniqueId3Tag(id3_tag_parse(buffer.get(), size));
|
return UniqueId3Tag(id3_tag_parse(buffer.get(), size));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
@ -208,13 +210,13 @@ try {
|
|||||||
UniqueId3Tag
|
UniqueId3Tag
|
||||||
tag_id3_load(InputStream &is)
|
tag_id3_load(InputStream &is)
|
||||||
try {
|
try {
|
||||||
const std::lock_guard<Mutex> protect(is.mutex);
|
std::unique_lock<Mutex> lock(is.mutex);
|
||||||
|
|
||||||
auto tag = tag_id3_find_from_beginning(is);
|
auto tag = tag_id3_find_from_beginning(is, lock);
|
||||||
if (tag == nullptr && is.CheapSeeking()) {
|
if (tag == nullptr && is.CheapSeeking()) {
|
||||||
tag = tag_id3_riff_aiff_load(is);
|
tag = tag_id3_riff_aiff_load(is, lock);
|
||||||
if (tag == nullptr)
|
if (tag == nullptr)
|
||||||
tag = tag_id3_find_from_end(is);
|
tag = tag_id3_find_from_end(is, lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tag;
|
return tag;
|
||||||
|
@ -39,14 +39,14 @@ struct riff_chunk_header {
|
|||||||
};
|
};
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
riff_seek_id3(InputStream &is)
|
riff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
{
|
{
|
||||||
/* seek to the beginning and read the RIFF header */
|
/* seek to the beginning and read the RIFF header */
|
||||||
|
|
||||||
is.Rewind();
|
is.Rewind(lock);
|
||||||
|
|
||||||
riff_header header;
|
riff_header header;
|
||||||
is.ReadFull(&header, sizeof(header));
|
is.ReadFull(lock, &header, sizeof(header));
|
||||||
if (memcmp(header.id, "RIFF", 4) != 0 ||
|
if (memcmp(header.id, "RIFF", 4) != 0 ||
|
||||||
(is.KnownSize() && FromLE32(header.size) > is.GetSize()))
|
(is.KnownSize() && FromLE32(header.size) > is.GetSize()))
|
||||||
throw std::runtime_error("Not a RIFF file");
|
throw std::runtime_error("Not a RIFF file");
|
||||||
@ -55,7 +55,7 @@ riff_seek_id3(InputStream &is)
|
|||||||
/* read the chunk header */
|
/* read the chunk header */
|
||||||
|
|
||||||
riff_chunk_header chunk;
|
riff_chunk_header chunk;
|
||||||
is.ReadFull(&chunk, sizeof(chunk));
|
is.ReadFull(lock, &chunk, sizeof(chunk));
|
||||||
|
|
||||||
size_t size = FromLE32(chunk.size);
|
size_t size = FromLE32(chunk.size);
|
||||||
if (size > size_t(std::numeric_limits<int>::max()))
|
if (size > size_t(std::numeric_limits<int>::max()))
|
||||||
@ -72,6 +72,6 @@ riff_seek_id3(InputStream &is)
|
|||||||
/* pad byte */
|
/* pad byte */
|
||||||
++size;
|
++size;
|
||||||
|
|
||||||
is.Skip(size);
|
is.Skip(lock, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,11 @@
|
|||||||
#ifndef MPD_RIFF_HXX
|
#ifndef MPD_RIFF_HXX
|
||||||
#define MPD_RIFF_HXX
|
#define MPD_RIFF_HXX
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
class Mutex;
|
||||||
class InputStream;
|
class InputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,6 +41,6 @@ class InputStream;
|
|||||||
* @return the size of the ID3 chunk
|
* @return the size of the ID3 chunk
|
||||||
*/
|
*/
|
||||||
size_t
|
size_t
|
||||||
riff_seek_id3(InputStream &is);
|
riff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,7 +28,8 @@ public:
|
|||||||
return remaining == 0;
|
return remaining == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *ptr, size_t read_size) override {
|
size_t Read(std::unique_lock<Mutex> &,
|
||||||
|
void *ptr, size_t read_size) override {
|
||||||
size_t nbytes = std::min(remaining, read_size);
|
size_t nbytes = std::min(remaining, read_size);
|
||||||
memcpy(ptr, data, nbytes);
|
memcpy(ptr, data, nbytes);
|
||||||
data += nbytes;
|
data += nbytes;
|
||||||
@ -51,7 +52,7 @@ TEST(RewindInputStream, Basic)
|
|||||||
EXPECT_TRUE(ris.get() != sis);
|
EXPECT_TRUE(ris.get() != sis);
|
||||||
EXPECT_TRUE(ris != nullptr);
|
EXPECT_TRUE(ris != nullptr);
|
||||||
|
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
std::unique_lock<Mutex> lock(mutex);
|
||||||
|
|
||||||
ris->Update();
|
ris->Update();
|
||||||
EXPECT_TRUE(ris->IsReady());
|
EXPECT_TRUE(ris->IsReady());
|
||||||
@ -59,50 +60,50 @@ TEST(RewindInputStream, Basic)
|
|||||||
EXPECT_EQ(offset_type(0), ris->GetOffset());
|
EXPECT_EQ(offset_type(0), ris->GetOffset());
|
||||||
|
|
||||||
char buffer[16];
|
char buffer[16];
|
||||||
size_t nbytes = ris->Read(buffer, 2);
|
size_t nbytes = ris->Read(lock, buffer, 2);
|
||||||
EXPECT_EQ(size_t(2), nbytes);
|
EXPECT_EQ(size_t(2), nbytes);
|
||||||
EXPECT_EQ('f', buffer[0]);
|
EXPECT_EQ('f', buffer[0]);
|
||||||
EXPECT_EQ('o', buffer[1]);
|
EXPECT_EQ('o', buffer[1]);
|
||||||
EXPECT_EQ(offset_type(2), ris->GetOffset());
|
EXPECT_EQ(offset_type(2), ris->GetOffset());
|
||||||
EXPECT_FALSE(ris->IsEOF());
|
EXPECT_FALSE(ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, 2);
|
nbytes = ris->Read(lock, buffer, 2);
|
||||||
EXPECT_EQ(size_t(2), nbytes);
|
EXPECT_EQ(size_t(2), nbytes);
|
||||||
EXPECT_EQ('o', buffer[0]);
|
EXPECT_EQ('o', buffer[0]);
|
||||||
EXPECT_EQ(' ', buffer[1]);
|
EXPECT_EQ(' ', buffer[1]);
|
||||||
EXPECT_EQ(offset_type(4), ris->GetOffset());
|
EXPECT_EQ(offset_type(4), ris->GetOffset());
|
||||||
EXPECT_FALSE(ris->IsEOF());
|
EXPECT_FALSE(ris->IsEOF());
|
||||||
|
|
||||||
ris->Seek(1);
|
ris->Seek(lock, 1);
|
||||||
EXPECT_EQ(offset_type(1), ris->GetOffset());
|
EXPECT_EQ(offset_type(1), ris->GetOffset());
|
||||||
EXPECT_FALSE(ris->IsEOF());
|
EXPECT_FALSE(ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, 2);
|
nbytes = ris->Read(lock, buffer, 2);
|
||||||
EXPECT_EQ(size_t(2), nbytes);
|
EXPECT_EQ(size_t(2), nbytes);
|
||||||
EXPECT_EQ('o', buffer[0]);
|
EXPECT_EQ('o', buffer[0]);
|
||||||
EXPECT_EQ('o', buffer[1]);
|
EXPECT_EQ('o', buffer[1]);
|
||||||
EXPECT_EQ(offset_type(3), ris->GetOffset());
|
EXPECT_EQ(offset_type(3), ris->GetOffset());
|
||||||
EXPECT_FALSE(ris->IsEOF());
|
EXPECT_FALSE(ris->IsEOF());
|
||||||
|
|
||||||
ris->Seek(0);
|
ris->Seek(lock, 0);
|
||||||
EXPECT_EQ(offset_type(0), ris->GetOffset());
|
EXPECT_EQ(offset_type(0), ris->GetOffset());
|
||||||
EXPECT_FALSE(ris->IsEOF());
|
EXPECT_FALSE(ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, 2);
|
nbytes = ris->Read(lock, buffer, 2);
|
||||||
EXPECT_EQ(size_t(2), nbytes);
|
EXPECT_EQ(size_t(2), nbytes);
|
||||||
EXPECT_EQ('f', buffer[0]);
|
EXPECT_EQ('f', buffer[0]);
|
||||||
EXPECT_EQ('o', buffer[1]);
|
EXPECT_EQ('o', buffer[1]);
|
||||||
EXPECT_EQ(offset_type(2), ris->GetOffset());
|
EXPECT_EQ(offset_type(2), ris->GetOffset());
|
||||||
EXPECT_FALSE(ris->IsEOF());
|
EXPECT_FALSE(ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, sizeof(buffer));
|
nbytes = ris->Read(lock, buffer, sizeof(buffer));
|
||||||
EXPECT_EQ(size_t(2), nbytes);
|
EXPECT_EQ(size_t(2), nbytes);
|
||||||
EXPECT_EQ('o', buffer[0]);
|
EXPECT_EQ('o', buffer[0]);
|
||||||
EXPECT_EQ(' ', buffer[1]);
|
EXPECT_EQ(' ', buffer[1]);
|
||||||
EXPECT_EQ(offset_type(4), ris->GetOffset());
|
EXPECT_EQ(offset_type(4), ris->GetOffset());
|
||||||
EXPECT_FALSE(ris->IsEOF());
|
EXPECT_FALSE(ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, sizeof(buffer));
|
nbytes = ris->Read(lock, buffer, sizeof(buffer));
|
||||||
EXPECT_EQ(size_t(3), nbytes);
|
EXPECT_EQ(size_t(3), nbytes);
|
||||||
EXPECT_EQ('b', buffer[0]);
|
EXPECT_EQ('b', buffer[0]);
|
||||||
EXPECT_EQ('a', buffer[1]);
|
EXPECT_EQ('a', buffer[1]);
|
||||||
@ -110,11 +111,11 @@ TEST(RewindInputStream, Basic)
|
|||||||
EXPECT_EQ(offset_type(7), ris->GetOffset());
|
EXPECT_EQ(offset_type(7), ris->GetOffset());
|
||||||
EXPECT_TRUE(ris->IsEOF());
|
EXPECT_TRUE(ris->IsEOF());
|
||||||
|
|
||||||
ris->Seek(3);
|
ris->Seek(lock, 3);
|
||||||
EXPECT_EQ(offset_type(3), ris->GetOffset());
|
EXPECT_EQ(offset_type(3), ris->GetOffset());
|
||||||
EXPECT_FALSE(ris->IsEOF());
|
EXPECT_FALSE(ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, sizeof(buffer));
|
nbytes = ris->Read(lock, buffer, sizeof(buffer));
|
||||||
EXPECT_EQ(size_t(4), nbytes);
|
EXPECT_EQ(size_t(4), nbytes);
|
||||||
EXPECT_EQ(' ', buffer[0]);
|
EXPECT_EQ(' ', buffer[0]);
|
||||||
EXPECT_EQ('b', buffer[1]);
|
EXPECT_EQ('b', buffer[1]);
|
||||||
|
@ -131,7 +131,7 @@ tag_save(FILE *file, const Tag &tag)
|
|||||||
static int
|
static int
|
||||||
dump_input_stream(InputStream *is)
|
dump_input_stream(InputStream *is)
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(is->mutex);
|
std::unique_lock<Mutex> lock(is->mutex);
|
||||||
|
|
||||||
/* print meta data */
|
/* print meta data */
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ dump_input_stream(InputStream *is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
size_t num_read = is->Read(buffer, sizeof(buffer));
|
size_t num_read = is->Read(lock, buffer, sizeof(buffer));
|
||||||
if (num_read == 0)
|
if (num_read == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user