input/InputStream: pass std::span<std::byte> to Read()
This commit is contained in:
parent
f28d10d934
commit
34f7b38f39
|
@ -48,7 +48,7 @@ class Bzip2InputStream final : public InputStream {
|
||||||
|
|
||||||
bool eof = false;
|
bool eof = false;
|
||||||
|
|
||||||
char buffer[5000];
|
std::byte buffer[5000];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Bzip2InputStream(std::shared_ptr<InputStream> _input,
|
Bzip2InputStream(std::shared_ptr<InputStream> _input,
|
||||||
|
@ -62,7 +62,7 @@ public:
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
[[nodiscard]] bool IsEOF() const noexcept override;
|
[[nodiscard]] bool IsEOF() const noexcept override;
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override;
|
std::span<std::byte> dest) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Open();
|
void Open();
|
||||||
|
@ -114,25 +114,25 @@ Bzip2InputStream::FillBuffer()
|
||||||
if (bzstream.avail_in > 0)
|
if (bzstream.avail_in > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
size_t count = input->LockRead(buffer, sizeof(buffer));
|
size_t count = input->LockRead(buffer);
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bzstream.next_in = buffer;
|
bzstream.next_in = reinterpret_cast<char *>(buffer);
|
||||||
bzstream.avail_in = count;
|
bzstream.avail_in = count;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
Bzip2InputStream::Read(std::unique_lock<Mutex> &, void *ptr, size_t length)
|
Bzip2InputStream::Read(std::unique_lock<Mutex> &, std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
if (eof)
|
if (eof)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
|
|
||||||
bzstream.next_out = (char *)ptr;
|
bzstream.next_out = reinterpret_cast<char *>(dest.data());
|
||||||
bzstream.avail_out = length;
|
bzstream.avail_out = dest.size();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
const bool had_input = FillBuffer();
|
const bool had_input = FillBuffer();
|
||||||
|
@ -147,11 +147,11 @@ Bzip2InputStream::Read(std::unique_lock<Mutex> &, void *ptr, size_t length)
|
||||||
if (bz_result != BZ_OK)
|
if (bz_result != BZ_OK)
|
||||||
throw std::runtime_error("BZ2_bzDecompress() has failed");
|
throw std::runtime_error("BZ2_bzDecompress() has failed");
|
||||||
|
|
||||||
if (!had_input && bzstream.avail_out == length)
|
if (!had_input && bzstream.avail_out == dest.size())
|
||||||
throw std::runtime_error("Unexpected end of bzip2 file");
|
throw std::runtime_error("Unexpected end of bzip2 file");
|
||||||
} while (bzstream.avail_out == length);
|
} while (bzstream.avail_out == dest.size());
|
||||||
|
|
||||||
const size_t nbytes = length - bzstream.avail_out;
|
const size_t nbytes = dest.size() - bzstream.avail_out;
|
||||||
offset += nbytes;
|
offset += nbytes;
|
||||||
|
|
||||||
return nbytes;
|
return nbytes;
|
||||||
|
|
|
@ -205,7 +205,7 @@ public:
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
[[nodiscard]] bool IsEOF() const noexcept override;
|
[[nodiscard]] bool IsEOF() const noexcept override;
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override;
|
std::span<std::byte> dest) override;
|
||||||
|
|
||||||
void Seek(std::unique_lock<Mutex> &, offset_type new_offset) override {
|
void Seek(std::unique_lock<Mutex> &, offset_type new_offset) override {
|
||||||
if (new_offset > size)
|
if (new_offset > size)
|
||||||
|
@ -236,14 +236,14 @@ Iso9660ArchiveFile::OpenStream(const char *pathname,
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
Iso9660InputStream::Read(std::unique_lock<Mutex> &,
|
Iso9660InputStream::Read(std::unique_lock<Mutex> &,
|
||||||
void *ptr, size_t read_size)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
const offset_type remaining = size - offset;
|
const offset_type remaining = size - offset;
|
||||||
if (remaining == 0)
|
if (remaining == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (std::cmp_greater(read_size, remaining))
|
if (std::cmp_greater(dest.size(), remaining))
|
||||||
read_size = remaining;
|
dest = dest.first(remaining);
|
||||||
|
|
||||||
auto r = buffer.Read();
|
auto r = buffer.Read();
|
||||||
|
|
||||||
|
@ -256,11 +256,11 @@ Iso9660InputStream::Read(std::unique_lock<Mutex> &,
|
||||||
|
|
||||||
const lsn_t read_lsn = lsn + offset / ISO_BLOCKSIZE;
|
const lsn_t read_lsn = lsn + offset / ISO_BLOCKSIZE;
|
||||||
|
|
||||||
if (read_size >= ISO_BLOCKSIZE && skip == 0) {
|
if (dest.size() >= ISO_BLOCKSIZE && skip == 0) {
|
||||||
/* big read - read right into the caller's buffer */
|
/* big read - read right into the caller's buffer */
|
||||||
|
|
||||||
auto nbytes = iso->SeekRead(ptr, read_lsn,
|
auto nbytes = iso->SeekRead(dest.data(), read_lsn,
|
||||||
read_size / ISO_BLOCKSIZE);
|
dest.size() / ISO_BLOCKSIZE);
|
||||||
if (nbytes <= 0)
|
if (nbytes <= 0)
|
||||||
throw std::runtime_error("Failed to read ISO9660 file");
|
throw std::runtime_error("Failed to read ISO9660 file");
|
||||||
|
|
||||||
|
@ -294,8 +294,8 @@ Iso9660InputStream::Read(std::unique_lock<Mutex> &,
|
||||||
assert(!r.empty());
|
assert(!r.empty());
|
||||||
assert(skip == 0);
|
assert(skip == 0);
|
||||||
|
|
||||||
size_t nbytes = std::min(read_size, r.size());
|
size_t nbytes = std::min(dest.size(), r.size());
|
||||||
memcpy(ptr, r.data(), nbytes);
|
memcpy(dest.data(), r.data(), nbytes);
|
||||||
buffer.Consume(nbytes);
|
buffer.Consume(nbytes);
|
||||||
offset += nbytes;
|
offset += nbytes;
|
||||||
return nbytes;
|
return nbytes;
|
||||||
|
|
|
@ -107,7 +107,7 @@ public:
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
[[nodiscard]] bool IsEOF() const noexcept override;
|
[[nodiscard]] bool IsEOF() const noexcept override;
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override;
|
std::span<std::byte> dest) override;
|
||||||
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -136,11 +136,11 @@ ZzipArchiveFile::OpenStream(const char *pathname,
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ZzipInputStream::Read(std::unique_lock<Mutex> &, void *ptr, size_t read_size)
|
ZzipInputStream::Read(std::unique_lock<Mutex> &, std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
|
|
||||||
zzip_ssize_t nbytes = zzip_file_read(file, ptr, read_size);
|
zzip_ssize_t nbytes = zzip_file_read(file, dest.data(), dest.size());
|
||||||
if (nbytes < 0)
|
if (nbytes < 0)
|
||||||
throw std::runtime_error("zzip_file_read() has failed");
|
throw std::runtime_error("zzip_file_read() has failed");
|
||||||
|
|
||||||
|
|
|
@ -197,7 +197,7 @@ read_stream_art(Response &r, const std::string_view art_directory,
|
||||||
if (buffer_size > 0) {
|
if (buffer_size > 0) {
|
||||||
std::unique_lock<Mutex> lock(is->mutex);
|
std::unique_lock<Mutex> lock(is->mutex);
|
||||||
is->Seek(lock, offset);
|
is->Seek(lock, offset);
|
||||||
read_size = is->Read(lock, buffer.get(), buffer_size);
|
read_size = is->Read(lock, {buffer.get(), buffer_size});
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Fmt(FMT_STRING("size: {}\n"), art_file_size);
|
r.Fmt(FMT_STRING("size: {}\n"), art_file_size);
|
||||||
|
|
|
@ -70,7 +70,7 @@ private:
|
||||||
/* virtual methods from class DecoderClient */
|
/* virtual methods from class DecoderClient */
|
||||||
InputStreamPtr OpenUri(const char *uri) override;
|
InputStreamPtr OpenUri(const char *uri) override;
|
||||||
size_t Read(InputStream &is,
|
size_t Read(InputStream &is,
|
||||||
void *buffer, size_t length) noexcept override;
|
std::span<std::byte> dest) noexcept override;
|
||||||
|
|
||||||
/* virtual methods from class InputStreamHandler */
|
/* virtual methods from class InputStreamHandler */
|
||||||
void OnInputStreamReady() noexcept override {
|
void OnInputStreamReady() noexcept override {
|
||||||
|
@ -274,12 +274,12 @@ GetChromaprintCommand::OpenUri(const char *uri2)
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
GetChromaprintCommand::Read(InputStream &is,
|
GetChromaprintCommand::Read(InputStream &is,
|
||||||
void *buffer, size_t length) noexcept
|
std::span<std::byte> dest) noexcept
|
||||||
{
|
{
|
||||||
/* overriding ChromaprintDecoderClient's implementation to
|
/* overriding ChromaprintDecoderClient's implementation to
|
||||||
make it cancellable */
|
make it cancellable */
|
||||||
|
|
||||||
if (length == 0)
|
if (dest.empty())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
std::unique_lock<Mutex> lock(mutex);
|
std::unique_lock<Mutex> lock(mutex);
|
||||||
|
@ -295,7 +295,7 @@ GetChromaprintCommand::Read(InputStream &is,
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return is.Read(lock, buffer, length);
|
return is.Read(lock, dest);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
ChromaprintDecoderClient::error = std::current_exception();
|
ChromaprintDecoderClient::error = std::current_exception();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -395,13 +395,12 @@ DecoderBridge::OpenUri(const char *uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
DecoderBridge::Read(InputStream &is, void *buffer, size_t length) noexcept
|
DecoderBridge::Read(InputStream &is, std::span<std::byte> dest) noexcept
|
||||||
try {
|
try {
|
||||||
assert(buffer != nullptr);
|
|
||||||
assert(dc.state == DecoderState::START ||
|
assert(dc.state == DecoderState::START ||
|
||||||
dc.state == DecoderState::DECODE);
|
dc.state == DecoderState::DECODE);
|
||||||
|
|
||||||
if (length == 0)
|
if (dest.empty())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
std::unique_lock<Mutex> lock(is.mutex);
|
std::unique_lock<Mutex> lock(is.mutex);
|
||||||
|
@ -416,7 +415,7 @@ try {
|
||||||
dc.cond.wait(lock);
|
dc.cond.wait(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t nbytes = is.Read(lock, buffer, length);
|
size_t nbytes = is.Read(lock, dest);
|
||||||
assert(nbytes > 0 || is.IsEOF());
|
assert(nbytes > 0 || is.IsEOF());
|
||||||
|
|
||||||
return nbytes;
|
return nbytes;
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
// Copyright The Music Player Daemon Project
|
// Copyright The Music Player Daemon Project
|
||||||
|
|
||||||
#ifndef MPD_DECODER_BRIDGE_HXX
|
#pragma once
|
||||||
#define MPD_DECODER_BRIDGE_HXX
|
|
||||||
|
|
||||||
#include "Client.hxx"
|
#include "Client.hxx"
|
||||||
#include "tag/ReplayGainInfo.hxx"
|
#include "tag/ReplayGainInfo.hxx"
|
||||||
#include "MusicChunkPtr.hxx"
|
#include "MusicChunkPtr.hxx"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
class PcmConvert;
|
class PcmConvert;
|
||||||
struct MusicChunk;
|
struct MusicChunk;
|
||||||
|
@ -159,7 +160,7 @@ public:
|
||||||
void SeekError() noexcept override;
|
void SeekError() noexcept override;
|
||||||
InputStreamPtr OpenUri(const char *uri) override;
|
InputStreamPtr OpenUri(const char *uri) override;
|
||||||
size_t Read(InputStream &is,
|
size_t Read(InputStream &is,
|
||||||
void *buffer, size_t length) noexcept override;
|
std::span<std::byte> dest) noexcept override;
|
||||||
void SubmitTimestamp(FloatDuration t) noexcept override;
|
void SubmitTimestamp(FloatDuration t) noexcept override;
|
||||||
DecoderCommand SubmitAudio(InputStream *is,
|
DecoderCommand SubmitAudio(InputStream *is,
|
||||||
std::span<const std::byte> audio,
|
std::span<const std::byte> audio,
|
||||||
|
@ -191,5 +192,3 @@ private:
|
||||||
|
|
||||||
bool UpdateStreamTag(InputStream *is) noexcept;
|
bool UpdateStreamTag(InputStream *is) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
// Copyright The Music Player Daemon Project
|
// Copyright The Music Player Daemon Project
|
||||||
|
|
||||||
#ifndef MPD_DECODER_CLIENT_HXX
|
#pragma once
|
||||||
#define MPD_DECODER_CLIENT_HXX
|
|
||||||
|
|
||||||
#include "Command.hxx"
|
#include "Command.hxx"
|
||||||
#include "Chrono.hxx"
|
#include "Chrono.hxx"
|
||||||
|
@ -93,7 +92,7 @@ public:
|
||||||
* occurs: end of file; error; command (like SEEK or STOP).
|
* occurs: end of file; error; command (like SEEK or STOP).
|
||||||
*/
|
*/
|
||||||
virtual size_t Read(InputStream &is,
|
virtual size_t Read(InputStream &is,
|
||||||
void *buffer, size_t length) noexcept = 0;
|
std::span<std::byte> dest) noexcept = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the time stamp for the next data chunk [seconds]. The MPD
|
* Sets the time stamp for the next data chunk [seconds]. The MPD
|
||||||
|
@ -171,5 +170,3 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void SubmitMixRamp(MixRampInfo &&mix_ramp) noexcept = 0;
|
virtual void SubmitMixRamp(MixRampInfo &&mix_ramp) noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -10,16 +10,14 @@
|
||||||
size_t
|
size_t
|
||||||
decoder_read(DecoderClient *client,
|
decoder_read(DecoderClient *client,
|
||||||
InputStream &is,
|
InputStream &is,
|
||||||
void *buffer, size_t length) noexcept
|
std::span<std::byte> dest) noexcept
|
||||||
{
|
{
|
||||||
assert(buffer != nullptr);
|
|
||||||
|
|
||||||
/* XXX don't allow client==nullptr */
|
/* XXX don't allow client==nullptr */
|
||||||
if (client != nullptr)
|
if (client != nullptr)
|
||||||
return client->Read(is, buffer, length);
|
return client->Read(is, dest);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return is.LockRead(buffer, length);
|
return is.LockRead(dest);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
LogError(std::current_exception());
|
LogError(std::current_exception());
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -28,20 +26,17 @@ decoder_read(DecoderClient *client,
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
decoder_read_much(DecoderClient *client, InputStream &is,
|
decoder_read_much(DecoderClient *client, InputStream &is,
|
||||||
void *_buffer, size_t size) noexcept
|
std::span<std::byte> dest) noexcept
|
||||||
{
|
{
|
||||||
auto buffer = (uint8_t *)_buffer;
|
|
||||||
|
|
||||||
size_t total = 0;
|
size_t total = 0;
|
||||||
|
|
||||||
while (size > 0 && !is.LockIsEOF()) {
|
while (!dest.empty() && !is.LockIsEOF()) {
|
||||||
size_t nbytes = decoder_read(client, is, buffer, size);
|
size_t nbytes = decoder_read(client, is, dest);
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
dest = dest.subspan(nbytes);
|
||||||
total += nbytes;
|
total += nbytes;
|
||||||
buffer += nbytes;
|
|
||||||
size -= nbytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
|
@ -49,17 +44,14 @@ decoder_read_much(DecoderClient *client, InputStream &is,
|
||||||
|
|
||||||
bool
|
bool
|
||||||
decoder_read_full(DecoderClient *client, InputStream &is,
|
decoder_read_full(DecoderClient *client, InputStream &is,
|
||||||
void *_buffer, size_t size) noexcept
|
std::span<std::byte> dest) noexcept
|
||||||
{
|
{
|
||||||
auto buffer = (uint8_t *)_buffer;
|
while (!dest.empty()) {
|
||||||
|
size_t nbytes = decoder_read(client, is, dest);
|
||||||
while (size > 0) {
|
|
||||||
size_t nbytes = decoder_read(client, is, buffer, size);
|
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
buffer += nbytes;
|
dest = dest.subspan(nbytes);
|
||||||
size -= nbytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -69,9 +61,10 @@ bool
|
||||||
decoder_skip(DecoderClient *client, InputStream &is, size_t size) noexcept
|
decoder_skip(DecoderClient *client, InputStream &is, size_t size) noexcept
|
||||||
{
|
{
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
char buffer[1024];
|
std::byte buffer[1024];
|
||||||
size_t nbytes = decoder_read(client, is, buffer,
|
|
||||||
std::min(sizeof(buffer), size));
|
size_t nbytes = decoder_read(client, is,
|
||||||
|
std::span{buffer, std::min(sizeof(buffer), size)});
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
// Copyright The Music Player Daemon Project
|
// Copyright The Music Player Daemon Project
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
/*! \file
|
/*! \file
|
||||||
* \brief The MPD Decoder API
|
* \brief The MPD Decoder API
|
||||||
*
|
*
|
||||||
|
@ -8,9 +10,6 @@
|
||||||
* communicate with the mpd core.
|
* communicate with the mpd core.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MPD_DECODER_API_HXX
|
|
||||||
#define MPD_DECODER_API_HXX
|
|
||||||
|
|
||||||
// IWYU pragma: begin_exports
|
// IWYU pragma: begin_exports
|
||||||
|
|
||||||
#include "Client.hxx"
|
#include "Client.hxx"
|
||||||
|
@ -26,7 +25,9 @@
|
||||||
|
|
||||||
// IWYU pragma: end_exports
|
// IWYU pragma: end_exports
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throw an instance of this class to stop decoding the current song
|
* Throw an instance of this class to stop decoding the current song
|
||||||
|
@ -47,13 +48,13 @@ class StopDecoder {};
|
||||||
*/
|
*/
|
||||||
size_t
|
size_t
|
||||||
decoder_read(DecoderClient *decoder, InputStream &is,
|
decoder_read(DecoderClient *decoder, InputStream &is,
|
||||||
void *buffer, size_t length) noexcept;
|
std::span<std::byte> dest) noexcept;
|
||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
decoder_read(DecoderClient &decoder, InputStream &is,
|
decoder_read(DecoderClient &decoder, InputStream &is,
|
||||||
void *buffer, size_t length) noexcept
|
std::span<std::byte> dest) noexcept
|
||||||
{
|
{
|
||||||
return decoder_read(&decoder, is, buffer, length);
|
return decoder_read(&decoder, is, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,7 +67,7 @@ decoder_read(DecoderClient &decoder, InputStream &is,
|
||||||
*/
|
*/
|
||||||
size_t
|
size_t
|
||||||
decoder_read_much(DecoderClient *decoder, InputStream &is,
|
decoder_read_much(DecoderClient *decoder, InputStream &is,
|
||||||
void *buffer, size_t size) noexcept;
|
std::span<std::byte> dest) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocking read from the input stream. Attempts to fill the buffer
|
* Blocking read from the input stream. Attempts to fill the buffer
|
||||||
|
@ -77,7 +78,7 @@ decoder_read_much(DecoderClient *decoder, InputStream &is,
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
decoder_read_full(DecoderClient *decoder, InputStream &is,
|
decoder_read_full(DecoderClient *decoder, InputStream &is,
|
||||||
void *buffer, size_t size) noexcept;
|
std::span<std::byte> dest) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skip data on the #InputStream.
|
* Skip data on the #InputStream.
|
||||||
|
@ -86,5 +87,3 @@ decoder_read_full(DecoderClient *decoder, InputStream &is,
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
decoder_skip(DecoderClient *decoder, InputStream &is, size_t size) noexcept;
|
decoder_skip(DecoderClient *decoder, InputStream &is, size_t size) noexcept;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -12,8 +12,7 @@ DecoderBuffer::Fill()
|
||||||
/* buffer is full */
|
/* buffer is full */
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
size_t nbytes = decoder_read(client, is,
|
size_t nbytes = decoder_read(client, is, w);
|
||||||
w.data(), w.size());
|
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
/* end of file, I/O error or decoder command
|
/* end of file, I/O error or decoder command
|
||||||
received */
|
received */
|
||||||
|
|
|
@ -7,5 +7,5 @@
|
||||||
std::size_t
|
std::size_t
|
||||||
DecoderReader::Read(std::span<std::byte> dest)
|
DecoderReader::Read(std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
return decoder_read(client, is, dest.data(), dest.size());
|
return decoder_read(client, is, dest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ struct AudioFileInputStream {
|
||||||
/* libaudiofile does not like partial reads at all,
|
/* libaudiofile does not like partial reads at all,
|
||||||
and will abort playback; therefore always force full
|
and will abort playback; therefore always force full
|
||||||
reads */
|
reads */
|
||||||
return decoder_read_full(client, is, buffer, size)
|
return decoder_read_full(client, is, {reinterpret_cast<std::byte *>(buffer), size})
|
||||||
? size
|
? size
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,8 @@ dsdlib_tag_id3(InputStream &is, TagHandler &handler,
|
||||||
if (id3_buf == nullptr)
|
if (id3_buf == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!decoder_read_full(nullptr, is, id3_buf, count)) {
|
if (!decoder_read_full(nullptr, is,
|
||||||
|
{reinterpret_cast<std::byte *>(id3_buf), count})) {
|
||||||
delete[] id3_buf;
|
delete[] id3_buf;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "pcm/CheckAudioFormat.hxx"
|
#include "pcm/CheckAudioFormat.hxx"
|
||||||
#include "util/BitReverse.hxx"
|
#include "util/BitReverse.hxx"
|
||||||
#include "util/PackedBigEndian.hxx"
|
#include "util/PackedBigEndian.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
#include "tag/Handler.hxx"
|
#include "tag/Handler.hxx"
|
||||||
#include "DsdLib.hxx"
|
#include "DsdLib.hxx"
|
||||||
|
|
||||||
|
@ -75,26 +76,26 @@ static bool
|
||||||
dsdiff_read_id(DecoderClient *client, InputStream &is,
|
dsdiff_read_id(DecoderClient *client, InputStream &is,
|
||||||
DsdId &id)
|
DsdId &id)
|
||||||
{
|
{
|
||||||
return decoder_read_full(client, is, &id, sizeof(id));
|
return decoder_read_full(client, is, ReferenceAsWritableBytes(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
dsdiff_read_chunk_header(DecoderClient *client, InputStream &is,
|
dsdiff_read_chunk_header(DecoderClient *client, InputStream &is,
|
||||||
DsdiffChunkHeader &header)
|
DsdiffChunkHeader &header)
|
||||||
{
|
{
|
||||||
return decoder_read_full(client, is, &header, sizeof(header));
|
return decoder_read_full(client, is, ReferenceAsWritableBytes(header));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
dsdiff_read_payload(DecoderClient *client, InputStream &is,
|
dsdiff_read_payload(DecoderClient *client, InputStream &is,
|
||||||
const DsdiffChunkHeader &header,
|
const DsdiffChunkHeader &header,
|
||||||
void *data, size_t length)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
uint64_t size = header.GetSize();
|
uint64_t size = header.GetSize();
|
||||||
if (size != (uint64_t)length)
|
if (size != (uint64_t)dest.size())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return decoder_read_full(client, is, data, length);
|
return decoder_read_full(client, is, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,8 +119,7 @@ dsdiff_read_prop_snd(DecoderClient *client, InputStream &is,
|
||||||
if (header.id.Equals("FS ")) {
|
if (header.id.Equals("FS ")) {
|
||||||
uint32_t sample_rate;
|
uint32_t sample_rate;
|
||||||
if (!dsdiff_read_payload(client, is, header,
|
if (!dsdiff_read_payload(client, is, header,
|
||||||
&sample_rate,
|
ReferenceAsWritableBytes(sample_rate)))
|
||||||
sizeof(sample_rate)))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
metadata.sample_rate = FromBE32(sample_rate);
|
metadata.sample_rate = FromBE32(sample_rate);
|
||||||
|
@ -127,7 +127,7 @@ dsdiff_read_prop_snd(DecoderClient *client, InputStream &is,
|
||||||
uint16_t channels;
|
uint16_t channels;
|
||||||
if (header.GetSize() < sizeof(channels) ||
|
if (header.GetSize() < sizeof(channels) ||
|
||||||
!decoder_read_full(client, is,
|
!decoder_read_full(client, is,
|
||||||
&channels, sizeof(channels)) ||
|
ReferenceAsWritableBytes(channels)) ||
|
||||||
!dsdlib_skip_to(client, is, chunk_end_offset))
|
!dsdlib_skip_to(client, is, chunk_end_offset))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ dsdiff_read_prop_snd(DecoderClient *client, InputStream &is,
|
||||||
DsdId type;
|
DsdId type;
|
||||||
if (header.GetSize() < sizeof(type) ||
|
if (header.GetSize() < sizeof(type) ||
|
||||||
!decoder_read_full(client, is,
|
!decoder_read_full(client, is,
|
||||||
&type, sizeof(type)) ||
|
ReferenceAsWritableBytes(type)) ||
|
||||||
!dsdlib_skip_to(client, is, chunk_end_offset))
|
!dsdlib_skip_to(client, is, chunk_end_offset))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ dsdiff_handle_native_tag(DecoderClient *client, InputStream &is,
|
||||||
|
|
||||||
struct dsdiff_native_tag metatag;
|
struct dsdiff_native_tag metatag;
|
||||||
|
|
||||||
if (!decoder_read_full(client, is, &metatag, sizeof(metatag)))
|
if (!decoder_read_full(client, is, ReferenceAsWritableBytes(metatag)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32_t length = FromBE32(metatag.size);
|
uint32_t length = FromBE32(metatag.size);
|
||||||
|
@ -203,7 +203,8 @@ dsdiff_handle_native_tag(DecoderClient *client, InputStream &is,
|
||||||
char *label;
|
char *label;
|
||||||
label = string;
|
label = string;
|
||||||
|
|
||||||
if (!decoder_read_full(client, is, label, (size_t)length))
|
if (!decoder_read_full(client, is,
|
||||||
|
{reinterpret_cast<std::byte *>(label), (size_t)length}))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
handler.OnTag(type, {label, length});
|
handler.OnTag(type, {label, length});
|
||||||
|
@ -304,7 +305,7 @@ dsdiff_read_metadata(DecoderClient *client, InputStream &is,
|
||||||
DsdiffChunkHeader &chunk_header)
|
DsdiffChunkHeader &chunk_header)
|
||||||
{
|
{
|
||||||
DsdiffHeader header;
|
DsdiffHeader header;
|
||||||
if (!decoder_read_full(client, is, &header, sizeof(header)) ||
|
if (!decoder_read_full(client, is, ReferenceAsWritableBytes(header)) ||
|
||||||
!header.id.Equals("FRM8") ||
|
!header.id.Equals("FRM8") ||
|
||||||
!header.format.Equals("DSD "))
|
!header.format.Equals("DSD "))
|
||||||
return false;
|
return false;
|
||||||
|
@ -392,7 +393,8 @@ dsdiff_decode_chunk(DecoderClient &client, InputStream &is,
|
||||||
now_size = now_frames * frame_size;
|
now_size = now_frames * frame_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!decoder_read_full(&client, is, buffer, now_size))
|
if (!decoder_read_full(&client, is,
|
||||||
|
std::span{buffer}.first(now_size)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const size_t nbytes = now_size;
|
const size_t nbytes = now_size;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "pcm/CheckAudioFormat.hxx"
|
#include "pcm/CheckAudioFormat.hxx"
|
||||||
#include "util/BitReverse.hxx"
|
#include "util/BitReverse.hxx"
|
||||||
#include "util/PackedLittleEndian.hxx"
|
#include "util/PackedLittleEndian.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
#include "DsdLib.hxx"
|
#include "DsdLib.hxx"
|
||||||
#include "tag/Handler.hxx"
|
#include "tag/Handler.hxx"
|
||||||
|
|
||||||
|
@ -85,7 +86,7 @@ dsf_read_metadata(DecoderClient *client, InputStream &is,
|
||||||
DsfMetaData *metadata)
|
DsfMetaData *metadata)
|
||||||
{
|
{
|
||||||
DsfHeader dsf_header;
|
DsfHeader dsf_header;
|
||||||
if (!decoder_read_full(client, is, &dsf_header, sizeof(dsf_header)) ||
|
if (!decoder_read_full(client, is, ReferenceAsWritableBytes(dsf_header)) ||
|
||||||
!dsf_header.id.Equals("DSD "))
|
!dsf_header.id.Equals("DSD "))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -100,7 +101,7 @@ dsf_read_metadata(DecoderClient *client, InputStream &is,
|
||||||
/* read the 'fmt ' chunk of the DSF file */
|
/* read the 'fmt ' chunk of the DSF file */
|
||||||
DsfFmtChunk dsf_fmt_chunk;
|
DsfFmtChunk dsf_fmt_chunk;
|
||||||
if (!decoder_read_full(client, is,
|
if (!decoder_read_full(client, is,
|
||||||
&dsf_fmt_chunk, sizeof(dsf_fmt_chunk)) ||
|
ReferenceAsWritableBytes(dsf_fmt_chunk)) ||
|
||||||
!dsf_fmt_chunk.id.Equals("fmt "))
|
!dsf_fmt_chunk.id.Equals("fmt "))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -127,7 +128,7 @@ dsf_read_metadata(DecoderClient *client, InputStream &is,
|
||||||
|
|
||||||
/* read the 'data' chunk of the DSF file */
|
/* read the 'data' chunk of the DSF file */
|
||||||
DsfDataChunk data_chunk;
|
DsfDataChunk data_chunk;
|
||||||
if (!decoder_read_full(client, is, &data_chunk, sizeof(data_chunk)) ||
|
if (!decoder_read_full(client, is, ReferenceAsWritableBytes(data_chunk)) ||
|
||||||
!data_chunk.id.Equals("data"))
|
!data_chunk.id.Equals("data"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -264,7 +265,8 @@ dsf_decode_chunk(DecoderClient &client, InputStream &is,
|
||||||
|
|
||||||
/* worst-case buffer size */
|
/* worst-case buffer size */
|
||||||
std::byte buffer[MAX_CHANNELS * DSF_BLOCK_SIZE];
|
std::byte buffer[MAX_CHANNELS * DSF_BLOCK_SIZE];
|
||||||
if (!decoder_read_full(&client, is, buffer, block_size))
|
if (!decoder_read_full(&client, is,
|
||||||
|
std::span{buffer}.first(block_size)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (bitreverse)
|
if (bitreverse)
|
||||||
|
|
|
@ -24,9 +24,9 @@ AvioStream::~AvioStream()
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int
|
inline int
|
||||||
AvioStream::Read(void *dest, int size)
|
AvioStream::Read(std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
const auto nbytes = decoder_read(client, input, dest, size);
|
const auto nbytes = decoder_read(client, input, dest);
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
return AVERROR_EOF;
|
return AVERROR_EOF;
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ AvioStream::_Read(void *opaque, uint8_t *buf, int size)
|
||||||
{
|
{
|
||||||
AvioStream &stream = *(AvioStream *)opaque;
|
AvioStream &stream = *(AvioStream *)opaque;
|
||||||
|
|
||||||
return stream.Read(buf, size);
|
return stream.Read({reinterpret_cast<std::byte *>(buf), static_cast<std::size_t>(size)});
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
// Copyright The Music Player Daemon Project
|
// Copyright The Music Player Daemon Project
|
||||||
|
|
||||||
#ifndef MPD_FFMPEG_IO_HXX
|
#pragma once
|
||||||
#define MPD_FFMPEG_IO_HXX
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "libavformat/avio.h"
|
#include "libavformat/avio.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
class DecoderClient;
|
class DecoderClient;
|
||||||
class InputStream;
|
class InputStream;
|
||||||
|
@ -27,11 +28,9 @@ struct AvioStream {
|
||||||
bool Open();
|
bool Open();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int Read(void *buffer, int size);
|
int Read(std::span<std::byte> dest);
|
||||||
int64_t Seek(int64_t pos, int whence);
|
int64_t Seek(int64_t pos, int whence);
|
||||||
|
|
||||||
static int _Read(void *opaque, uint8_t *buf, int size);
|
static int _Read(void *opaque, uint8_t *buf, int size);
|
||||||
static int64_t _Seek(void *opaque, int64_t pos, int whence);
|
static int64_t _Seek(void *opaque, int64_t pos, int whence);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
inline FLAC__StreamDecoderReadStatus
|
inline FLAC__StreamDecoderReadStatus
|
||||||
FlacInput::Read(FLAC__byte buffer[], size_t *bytes) noexcept
|
FlacInput::Read(FLAC__byte buffer[], size_t *bytes) noexcept
|
||||||
{
|
{
|
||||||
size_t r = decoder_read(client, input_stream, (void *)buffer, *bytes);
|
size_t r = decoder_read(client, input_stream,
|
||||||
|
{reinterpret_cast<std::byte *>(buffer), *bytes});
|
||||||
*bytes = r;
|
*bytes = r;
|
||||||
|
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
|
|
|
@ -237,7 +237,7 @@ MadDecoder::FillBuffer() noexcept
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
size_t nbytes = decoder_read(client, input_stream,
|
size_t nbytes = decoder_read(client, input_stream,
|
||||||
dest, max_read_size);
|
{reinterpret_cast<std::byte *>(dest), max_read_size});
|
||||||
if (nbytes == 0) {
|
if (nbytes == 0) {
|
||||||
if (was_eof || max_read_size < MAD_BUFFER_GUARD)
|
if (was_eof || max_read_size < MAD_BUFFER_GUARD)
|
||||||
return false;
|
return false;
|
||||||
|
@ -271,7 +271,7 @@ MadDecoder::ParseId3(size_t tagsize, Tag *mpd_tag) noexcept
|
||||||
mad_stream_skip(&(stream), count);
|
mad_stream_skip(&(stream), count);
|
||||||
|
|
||||||
if (!decoder_read_full(client, input_stream,
|
if (!decoder_read_full(client, input_stream,
|
||||||
allocated.get() + count, tagsize - count)) {
|
{reinterpret_cast<std::byte *>(allocated.get() + count), tagsize - count})) {
|
||||||
LogDebug(mad_domain, "error parsing ID3 tag");
|
LogDebug(mad_domain, "error parsing ID3 tag");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ mod_loadfile(const Domain *domain, DecoderClient *client, InputStream &is)
|
||||||
std::byte *const end = p + buffer.size();
|
std::byte *const end = p + buffer.size();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
size_t ret = decoder_read(client, is, p, end - p);
|
size_t ret = decoder_read(client, is, {p, end});
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
if (is.LockIsEOF())
|
if (is.LockIsEOF())
|
||||||
/* end of file */
|
/* end of file */
|
||||||
|
|
|
@ -36,7 +36,8 @@ mpc_read_cb(mpc_reader *reader, void *ptr, mpc_int32_t size)
|
||||||
auto *data =
|
auto *data =
|
||||||
(struct mpc_decoder_data *)reader->data;
|
(struct mpc_decoder_data *)reader->data;
|
||||||
|
|
||||||
return decoder_read(data->client, data->is, ptr, size);
|
return decoder_read(data->client, data->is,
|
||||||
|
{reinterpret_cast<std::byte *>(ptr), static_cast<std::size_t>(size)});
|
||||||
}
|
}
|
||||||
|
|
||||||
static mpc_bool_t
|
static mpc_bool_t
|
||||||
|
|
|
@ -77,7 +77,8 @@ mpd_mpg123_read(void *_iohandle, void *data, size_t size) noexcept
|
||||||
auto &iohandle = *reinterpret_cast<mpd_mpg123_iohandle *>(_iohandle);
|
auto &iohandle = *reinterpret_cast<mpd_mpg123_iohandle *>(_iohandle);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return decoder_read_much(iohandle.client, iohandle.is, data, size);
|
return decoder_read_much(iohandle.client, iohandle.is,
|
||||||
|
{reinterpret_cast<std::byte *>(data), size});
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
LogError(std::current_exception(), "Read failed");
|
LogError(std::current_exception(), "Read failed");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -16,8 +16,8 @@ ogg_codec_detect(DecoderClient *client, InputStream &is)
|
||||||
/* oggflac detection based on code in ogg123 and this post
|
/* oggflac detection based on code in ogg123 and this post
|
||||||
* http://lists.xiph.org/pipermail/flac/2004-December/000393.html
|
* http://lists.xiph.org/pipermail/flac/2004-December/000393.html
|
||||||
* ogg123 trunk still doesn't have this patch as of June 2005 */
|
* ogg123 trunk still doesn't have this patch as of June 2005 */
|
||||||
unsigned char buf[41];
|
std::byte buf[41];
|
||||||
size_t r = decoder_read(client, is, buf, sizeof(buf));
|
size_t r = decoder_read(client, is, buf);
|
||||||
if (r < sizeof(buf) || memcmp(buf, "OggS", 4) != 0)
|
if (r < sizeof(buf) || memcmp(buf, "OggS", 4) != 0)
|
||||||
return OGG_CODEC_UNKNOWN;
|
return OGG_CODEC_UNKNOWN;
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ FillBuffer(DecoderClient &client, InputStream &is, B &buffer)
|
||||||
if (w.empty())
|
if (w.empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
size_t nbytes = decoder_read(client, is, w.data(), w.size());
|
size_t nbytes = decoder_read(client, is, w);
|
||||||
if (nbytes == 0 && is.LockIsEOF())
|
if (nbytes == 0 && is.LockIsEOF())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ pcm_stream_decode(DecoderClient &client, InputStream &is)
|
||||||
|
|
||||||
client.Ready(audio_format, is.IsSeekable(), total_time);
|
client.Ready(audio_format, is.IsSeekable(), total_time);
|
||||||
|
|
||||||
StaticFifoBuffer<uint8_t, 4096> buffer;
|
StaticFifoBuffer<std::byte, 4096> buffer;
|
||||||
|
|
||||||
/* a buffer for pcm_unpack_24be() large enough to hold the
|
/* a buffer for pcm_unpack_24be() large enough to hold the
|
||||||
results for a full source buffer */
|
results for a full source buffer */
|
||||||
|
@ -185,9 +185,10 @@ pcm_stream_decode(DecoderClient &client, InputStream &is)
|
||||||
(audio/L24) to native-endian 24 bit (in 32
|
(audio/L24) to native-endian 24 bit (in 32
|
||||||
bit integers) */
|
bit integers) */
|
||||||
pcm_unpack_24be(unpack_buffer,
|
pcm_unpack_24be(unpack_buffer,
|
||||||
r.data(), r.data() + r.size());
|
reinterpret_cast<const uint8_t *>(r.data()),
|
||||||
|
reinterpret_cast<const uint8_t *>(r.data() + r.size()));
|
||||||
r = {
|
r = {
|
||||||
(uint8_t *)&unpack_buffer[0],
|
(std::byte *)&unpack_buffer[0],
|
||||||
(r.size() / 3) * 4,
|
(r.size() / 3) * 4,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,8 @@ struct SndfileInputStream {
|
||||||
size_t Read(void *buffer, size_t size) {
|
size_t Read(void *buffer, size_t size) {
|
||||||
/* libsndfile chokes on partial reads; therefore
|
/* libsndfile chokes on partial reads; therefore
|
||||||
always force full reads */
|
always force full reads */
|
||||||
return decoder_read_much(client, is, buffer, size);
|
return decoder_read_much(client, is,
|
||||||
|
{reinterpret_cast<std::byte *>(buffer), size});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,7 @@ struct WavpackInput {
|
||||||
InputStream &_is) noexcept
|
InputStream &_is) noexcept
|
||||||
:client(_client), is(_is), last_byte(EOF) {}
|
:client(_client), is(_is), last_byte(EOF) {}
|
||||||
|
|
||||||
int32_t ReadBytes(void *data, size_t bcount) noexcept;
|
int32_t ReadBytes(std::span<std::byte> dest) noexcept;
|
||||||
|
|
||||||
[[nodiscard]] InputStream::offset_type GetPos() const noexcept {
|
[[nodiscard]] InputStream::offset_type GetPos() const noexcept {
|
||||||
return is.GetOffset();
|
return is.GetOffset();
|
||||||
|
@ -318,34 +318,32 @@ wpin(void *id) noexcept
|
||||||
static int32_t
|
static int32_t
|
||||||
wavpack_input_read_bytes(void *id, void *data, int32_t bcount) noexcept
|
wavpack_input_read_bytes(void *id, void *data, int32_t bcount) noexcept
|
||||||
{
|
{
|
||||||
return wpin(id)->ReadBytes(data, bcount);
|
return wpin(id)->ReadBytes({reinterpret_cast<std::byte *>(data), static_cast<std::size_t>(bcount)});
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t
|
int32_t
|
||||||
WavpackInput::ReadBytes(void *data, size_t bcount) noexcept
|
WavpackInput::ReadBytes(std::span<std::byte> dest) noexcept
|
||||||
{
|
{
|
||||||
auto *buf = (uint8_t *)data;
|
|
||||||
int32_t i = 0;
|
int32_t i = 0;
|
||||||
|
|
||||||
if (last_byte != EOF) {
|
if (last_byte != EOF) {
|
||||||
*buf++ = last_byte;
|
dest.front() = static_cast<std::byte>(last_byte);
|
||||||
|
dest = dest.subspan(1);
|
||||||
last_byte = EOF;
|
last_byte = EOF;
|
||||||
--bcount;
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wavpack fails if we return a partial read, so we just wait
|
/* wavpack fails if we return a partial read, so we just wait
|
||||||
until the buffer is full */
|
until the buffer is full */
|
||||||
while (bcount > 0) {
|
while (!dest.empty()) {
|
||||||
size_t nbytes = decoder_read(client, is, buf, bcount);
|
size_t nbytes = decoder_read(client, is, dest);
|
||||||
if (nbytes == 0) {
|
if (nbytes == 0) {
|
||||||
/* EOF, error or a decoder command */
|
/* EOF, error or a decoder command */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
i += nbytes;
|
i += nbytes;
|
||||||
bcount -= nbytes;
|
dest = dest.subspan(nbytes);
|
||||||
buf += nbytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
|
|
|
@ -166,7 +166,7 @@ AsyncInputStream::IsAvailable() const noexcept
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
AsyncInputStream::Read(std::unique_lock<Mutex> &lock,
|
AsyncInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t read_size)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
assert(!GetEventLoop().IsInside());
|
assert(!GetEventLoop().IsInside());
|
||||||
|
|
||||||
|
@ -185,8 +185,8 @@ AsyncInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
cond_handler.cond.wait(lock);
|
cond_handler.cond.wait(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t nbytes = std::min(read_size, r.size());
|
const size_t nbytes = std::min(dest.size(), r.size());
|
||||||
memcpy(ptr, r.data(), nbytes);
|
memcpy(dest.data(), r.data(), nbytes);
|
||||||
buffer.Consume(nbytes);
|
buffer.Consume(nbytes);
|
||||||
|
|
||||||
offset += (offset_type)nbytes;
|
offset += (offset_type)nbytes;
|
||||||
|
|
|
@ -72,7 +72,7 @@ public:
|
||||||
std::unique_ptr<Tag> ReadTag() noexcept final;
|
std::unique_ptr<Tag> ReadTag() noexcept final;
|
||||||
bool IsAvailable() const noexcept final;
|
bool IsAvailable() const noexcept final;
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t read_size) final;
|
std::span<std::byte> dest) final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -48,9 +48,9 @@ BufferedInputStream::IsAvailable() const noexcept
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
BufferedInputStream::Read(std::unique_lock<Mutex> &lock,
|
BufferedInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t s)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
size_t nbytes = BufferingInputStream::Read(lock, offset, ptr, s);
|
size_t nbytes = BufferingInputStream::Read(lock, offset, dest);
|
||||||
InputStream::offset += nbytes;
|
InputStream::offset += nbytes;
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
// Copyright The Music Player Daemon Project
|
// Copyright The Music Player Daemon Project
|
||||||
|
|
||||||
#ifndef MPD_BUFFERED_INPUT_STREAM_BUFFER_HXX
|
#pragma once
|
||||||
#define MPD_BUFFERED_INPUT_STREAM_BUFFER_HXX
|
|
||||||
|
|
||||||
#include "InputStream.hxx"
|
#include "InputStream.hxx"
|
||||||
#include "BufferingInputStream.hxx"
|
#include "BufferingInputStream.hxx"
|
||||||
|
@ -44,7 +43,7 @@ public:
|
||||||
// std::unique_ptr<Tag> ReadTag() override;
|
// std::unique_ptr<Tag> ReadTag() override;
|
||||||
bool IsAvailable() const noexcept override;
|
bool IsAvailable() const noexcept override;
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override;
|
std::span<std::byte> dest) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* virtual methods from class BufferingInputStream */
|
/* virtual methods from class BufferingInputStream */
|
||||||
|
@ -52,5 +51,3 @@ private:
|
||||||
InvokeOnAvailable();
|
InvokeOnAvailable();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ BufferingInputStream::IsAvailable(size_t offset) const noexcept
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
BufferingInputStream::Read(std::unique_lock<Mutex> &lock, size_t offset,
|
BufferingInputStream::Read(std::unique_lock<Mutex> &lock, size_t offset,
|
||||||
void *ptr, size_t s)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
if (offset >= size())
|
if (offset >= size())
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -68,8 +68,8 @@ BufferingInputStream::Read(std::unique_lock<Mutex> &lock, size_t offset,
|
||||||
auto r = buffer.Read(offset);
|
auto r = buffer.Read(offset);
|
||||||
if (r.HasData()) {
|
if (r.HasData()) {
|
||||||
/* yay, we have some data */
|
/* yay, we have some data */
|
||||||
size_t nbytes = std::min(s, r.defined_buffer.size());
|
size_t nbytes = std::min(dest.size(), r.defined_buffer.size());
|
||||||
memcpy(ptr, r.defined_buffer.data(), nbytes);
|
memcpy(dest.data(), r.defined_buffer.data(), nbytes);
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,9 +148,10 @@ BufferingInputStream::RunThreadLocked(std::unique_lock<Mutex> &lock)
|
||||||
data has been read */
|
data has been read */
|
||||||
constexpr size_t MAX_READ = 64 * 1024;
|
constexpr size_t MAX_READ = 64 * 1024;
|
||||||
|
|
||||||
size_t nbytes = input->Read(lock, w.data(),
|
if (w.size() > MAX_READ)
|
||||||
std::min(w.size(),
|
w = w.first(MAX_READ);
|
||||||
MAX_READ));
|
|
||||||
|
size_t nbytes = input->Read(lock, w);
|
||||||
buffer.Commit(read_offset, read_offset + nbytes);
|
buffer.Commit(read_offset, read_offset + nbytes);
|
||||||
|
|
||||||
client_cond.notify_all();
|
client_cond.notify_all();
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
// Copyright The Music Player Daemon Project
|
// Copyright The Music Player Daemon Project
|
||||||
|
|
||||||
#ifndef MPD_BUFFERING_INPUT_STREAM_BUFFER_HXX
|
#pragma once
|
||||||
#define MPD_BUFFERING_INPUT_STREAM_BUFFER_HXX
|
|
||||||
|
|
||||||
#include "Ptr.hxx"
|
#include "Ptr.hxx"
|
||||||
#include "Handler.hxx"
|
#include "Handler.hxx"
|
||||||
|
@ -11,6 +10,7 @@
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "util/SparseBuffer.hxx"
|
#include "util/SparseBuffer.hxx"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,7 +39,7 @@ private:
|
||||||
*/
|
*/
|
||||||
Cond client_cond;
|
Cond client_cond;
|
||||||
|
|
||||||
SparseBuffer<uint8_t> buffer;
|
SparseBuffer<std::byte> buffer;
|
||||||
|
|
||||||
bool stop = false;
|
bool stop = false;
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ public:
|
||||||
* @return the number of bytes copied into the given pointer.
|
* @return the number of bytes copied into the given pointer.
|
||||||
*/
|
*/
|
||||||
size_t Read(std::unique_lock<Mutex> &lock, size_t offset,
|
size_t Read(std::unique_lock<Mutex> &lock, size_t offset,
|
||||||
void *ptr, size_t size);
|
std::span<std::byte> dest);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
@ -122,5 +122,3 @@ private:
|
||||||
wake_cond.notify_one();
|
wake_cond.notify_one();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(std::unique_lock<Mutex> &, void *, size_t) override {
|
size_t Read(std::unique_lock<Mutex> &, std::span<std::byte>) override {
|
||||||
std::rethrow_exception(error);
|
std::rethrow_exception(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -68,20 +68,20 @@ IcyInputStream::ReadTag() noexcept
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
IcyInputStream::Read(std::unique_lock<Mutex> &lock,
|
IcyInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t read_size)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
if (!IsEnabled())
|
if (!IsEnabled())
|
||||||
return ProxyInputStream::Read(lock, ptr, read_size);
|
return ProxyInputStream::Read(lock, dest);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
size_t nbytes = ProxyInputStream::Read(lock, ptr, read_size);
|
size_t nbytes = ProxyInputStream::Read(lock, dest);
|
||||||
if (nbytes == 0) {
|
if (nbytes == 0) {
|
||||||
assert(IsEOF());
|
assert(IsEOF());
|
||||||
offset = override_offset;
|
offset = override_offset;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t result = parser->ParseInPlace({static_cast<std::byte *>(ptr), nbytes});
|
size_t result = parser->ParseInPlace(dest.first(nbytes));
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
override_offset += result;
|
override_offset += result;
|
||||||
offset = override_offset;
|
offset = override_offset;
|
||||||
|
|
|
@ -53,7 +53,7 @@ public:
|
||||||
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(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override;
|
std::span<std::byte> dest) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -92,45 +92,35 @@ InputStream::IsAvailable() const noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
InputStream::LockRead(void *ptr, size_t _size)
|
InputStream::LockRead(std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
#if !CLANG_CHECK_VERSION(3,6)
|
assert(!dest.empty());
|
||||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
|
||||||
assert(ptr != nullptr);
|
|
||||||
#endif
|
|
||||||
assert(_size > 0);
|
|
||||||
|
|
||||||
std::unique_lock<Mutex> lock(mutex);
|
std::unique_lock<Mutex> lock(mutex);
|
||||||
return Read(lock, ptr, _size);
|
return Read(lock, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
InputStream::ReadFull(std::unique_lock<Mutex> &lock, void *_ptr, size_t _size)
|
InputStream::ReadFull(std::unique_lock<Mutex> &lock, std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
auto *ptr = (uint8_t *)_ptr;
|
assert(!dest.empty());
|
||||||
|
|
||||||
size_t nbytes_total = 0;
|
do {
|
||||||
while (_size > 0) {
|
std::size_t nbytes = Read(lock, dest);
|
||||||
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");
|
||||||
|
|
||||||
nbytes_total += nbytes;
|
dest = dest.subspan(nbytes);
|
||||||
_size -= nbytes;
|
} while (!dest.empty());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
InputStream::LockReadFull(void *ptr, size_t _size)
|
InputStream::LockReadFull(std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
#if !CLANG_CHECK_VERSION(3,6)
|
assert(!dest.empty());
|
||||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
|
||||||
assert(ptr != nullptr);
|
|
||||||
#endif
|
|
||||||
assert(_size > 0);
|
|
||||||
|
|
||||||
std::unique_lock<Mutex> lock(mutex);
|
std::unique_lock<Mutex> lock(mutex);
|
||||||
ReadFull(lock, ptr, _size);
|
ReadFull(lock, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
// Copyright The Music Player Daemon Project
|
// Copyright The Music Player Daemon Project
|
||||||
|
|
||||||
#ifndef MPD_INPUT_STREAM_HXX
|
#pragma once
|
||||||
#define MPD_INPUT_STREAM_HXX
|
|
||||||
|
|
||||||
#include "Offset.hxx"
|
#include "Offset.hxx"
|
||||||
#include "Ptr.hxx"
|
#include "Ptr.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
@ -350,9 +351,8 @@ public:
|
||||||
* @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
|
||||||
*/
|
*/
|
||||||
[[gnu::nonnull]]
|
virtual std::size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
virtual size_t Read(std::unique_lock<Mutex> &lock,
|
std::span<std::byte> dest) = 0;
|
||||||
void *ptr, size_t size) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for Read() which locks and unlocks the mutex;
|
* Wrapper for Read() which locks and unlocks the mutex;
|
||||||
|
@ -360,8 +360,7 @@ public:
|
||||||
*
|
*
|
||||||
* Throws std::runtime_error on error.
|
* Throws std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
[[gnu::nonnull]]
|
std::size_t LockRead(std::span<std::byte> dest);
|
||||||
size_t LockRead(void *ptr, size_t size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the whole data from the stream into the caller-supplied buffer.
|
* Reads the whole data from the stream into the caller-supplied buffer.
|
||||||
|
@ -374,8 +373,7 @@ public:
|
||||||
* @param size the number of bytes to read
|
* @param size the number of bytes to read
|
||||||
* @return true if the whole data was read, false otherwise.
|
* @return true if the whole data was read, false otherwise.
|
||||||
*/
|
*/
|
||||||
[[gnu::nonnull]]
|
void ReadFull(std::unique_lock<Mutex> &lock, std::span<std::byte> dest);
|
||||||
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;
|
||||||
|
@ -383,8 +381,7 @@ public:
|
||||||
*
|
*
|
||||||
* Throws std::runtime_error on error.
|
* Throws std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
[[gnu::nonnull]]
|
void LockReadFull(std::span<std::byte> dest);
|
||||||
void LockReadFull(void *ptr, size_t size);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InvokeOnReady() noexcept;
|
void InvokeOnReady() noexcept;
|
||||||
|
@ -410,5 +407,3 @@ public:
|
||||||
is.SetHandler(old_handler);
|
is.SetHandler(old_handler);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -105,11 +105,11 @@ ProxyInputStream::IsAvailable() const noexcept
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ProxyInputStream::Read(std::unique_lock<Mutex> &lock,
|
ProxyInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t read_size)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
set_input_cond.wait(lock, [this]{ return !!input; });
|
set_input_cond.wait(lock, [this]{ return !!input; });
|
||||||
|
|
||||||
size_t nbytes = input->Read(lock, ptr, read_size);
|
size_t nbytes = input->Read(lock, dest);
|
||||||
CopyAttributes();
|
CopyAttributes();
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ public:
|
||||||
std::unique_ptr<Tag> ReadTag() noexcept override;
|
std::unique_ptr<Tag> ReadTag() noexcept override;
|
||||||
bool IsAvailable() const noexcept override;
|
bool IsAvailable() const noexcept override;
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t read_size) override;
|
std::span<std::byte> dest) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
std::size_t
|
std::size_t
|
||||||
InputStreamReader::Read(std::span<std::byte> dest)
|
InputStreamReader::Read(std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
size_t nbytes = is.LockRead(dest.data(), dest.size());
|
size_t nbytes = is.LockRead(dest);
|
||||||
assert(nbytes > 0 || is.IsEOF());
|
assert(nbytes > 0 || is.IsEOF());
|
||||||
|
|
||||||
return nbytes;
|
return nbytes;
|
||||||
|
|
|
@ -28,7 +28,7 @@ class RewindInputStream final : public ProxyInputStream {
|
||||||
* The origin of this buffer is always the beginning of the
|
* The origin of this buffer is always the beginning of the
|
||||||
* stream (offset 0).
|
* stream (offset 0).
|
||||||
*/
|
*/
|
||||||
char buffer[64 * 1024];
|
std::byte buffer[64 * 1024];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit RewindInputStream(InputStreamPtr _input)
|
explicit RewindInputStream(InputStreamPtr _input)
|
||||||
|
@ -46,7 +46,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override;
|
std::span<std::byte> dest) override;
|
||||||
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -61,7 +61,7 @@ private:
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
RewindInputStream::Read(std::unique_lock<Mutex> &lock,
|
RewindInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t read_size)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
if (ReadingFromBuffer()) {
|
if (ReadingFromBuffer()) {
|
||||||
/* buffered read */
|
/* buffered read */
|
||||||
|
@ -69,18 +69,18 @@ RewindInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
assert(head == (size_t)offset);
|
assert(head == (size_t)offset);
|
||||||
assert(tail == (size_t)input->GetOffset());
|
assert(tail == (size_t)input->GetOffset());
|
||||||
|
|
||||||
if (read_size > tail - head)
|
if (dest.size() > tail - head)
|
||||||
read_size = tail - head;
|
dest = dest.first(tail - head);
|
||||||
|
|
||||||
memcpy(ptr, buffer + head, read_size);
|
memcpy(dest.data(), buffer + head, dest.size());
|
||||||
head += read_size;
|
head += dest.size();
|
||||||
offset += read_size;
|
offset += dest.size();
|
||||||
|
|
||||||
return read_size;
|
return dest.size();
|
||||||
} else {
|
} else {
|
||||||
/* pass method call to underlying stream */
|
/* pass method call to underlying stream */
|
||||||
|
|
||||||
size_t nbytes = input->Read(lock, ptr, read_size);
|
size_t nbytes = input->Read(lock, dest);
|
||||||
|
|
||||||
if (std::cmp_greater(input->GetOffset(), sizeof(buffer)))
|
if (std::cmp_greater(input->GetOffset(), sizeof(buffer)))
|
||||||
/* disable buffering */
|
/* disable buffering */
|
||||||
|
@ -88,7 +88,7 @@ RewindInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
else if (tail == (size_t)offset) {
|
else if (tail == (size_t)offset) {
|
||||||
/* append to buffer */
|
/* append to buffer */
|
||||||
|
|
||||||
memcpy(buffer + tail, ptr, nbytes);
|
memcpy(buffer + tail, dest.data(), nbytes);
|
||||||
tail += nbytes;
|
tail += nbytes;
|
||||||
|
|
||||||
assert(tail == (size_t)input->GetOffset());
|
assert(tail == (size_t)input->GetOffset());
|
||||||
|
|
|
@ -39,7 +39,7 @@ TextInputStream::ReadLine()
|
||||||
character */
|
character */
|
||||||
dest = dest.first(dest.size() - 1);
|
dest = dest.first(dest.size() - 1);
|
||||||
|
|
||||||
size_t nbytes = is->LockRead(dest.data(), dest.size());
|
size_t nbytes = is->LockRead(std::as_writable_bytes(dest));
|
||||||
|
|
||||||
buffer.Append(nbytes);
|
buffer.Append(nbytes);
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ ThreadInputStream::IsAvailable() const noexcept
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
ThreadInputStream::Read(std::unique_lock<Mutex> &lock,
|
ThreadInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t read_size)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
assert(!thread.IsInside());
|
assert(!thread.IsInside());
|
||||||
|
|
||||||
|
@ -129,8 +129,8 @@ ThreadInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
|
|
||||||
auto r = buffer.Read();
|
auto r = buffer.Read();
|
||||||
if (!r.empty()) {
|
if (!r.empty()) {
|
||||||
size_t nbytes = std::min(read_size, r.size());
|
size_t nbytes = std::min(dest.size(), r.size());
|
||||||
memcpy(ptr, r.data(), nbytes);
|
memcpy(dest.data(), r.data(), nbytes);
|
||||||
buffer.Consume(nbytes);
|
buffer.Consume(nbytes);
|
||||||
wake_cond.notify_all();
|
wake_cond.notify_all();
|
||||||
offset += nbytes;
|
offset += nbytes;
|
||||||
|
|
|
@ -78,7 +78,7 @@ public:
|
||||||
bool IsEOF() const noexcept final;
|
bool IsEOF() const noexcept final;
|
||||||
bool IsAvailable() const noexcept final;
|
bool IsAvailable() const noexcept final;
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override final;
|
std::span<std::byte> dest) override final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -51,7 +51,7 @@ CacheInputStream::IsAvailable() const noexcept
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
CacheInputStream::Read(std::unique_lock<Mutex> &lock,
|
CacheInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t read_size)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
const auto _offset = offset;
|
const auto _offset = offset;
|
||||||
auto &i = GetCacheItem();
|
auto &i = GetCacheItem();
|
||||||
|
@ -62,7 +62,7 @@ CacheInputStream::Read(std::unique_lock<Mutex> &lock,
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
const std::scoped_lock<Mutex> protect(i.mutex);
|
const std::scoped_lock<Mutex> protect(i.mutex);
|
||||||
|
|
||||||
nbytes = i.Read(lock, _offset, ptr, read_size);
|
nbytes = i.Read(lock, _offset, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += nbytes;
|
offset += nbytes;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
// Copyright The Music Player Daemon Project
|
// Copyright The Music Player Daemon Project
|
||||||
|
|
||||||
#ifndef MPD_CACHE_INPUT_STREAM_HXX
|
#pragma once
|
||||||
#define MPD_CACHE_INPUT_STREAM_HXX
|
|
||||||
|
|
||||||
#include "Lease.hxx"
|
#include "Lease.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
|
@ -26,11 +25,9 @@ public:
|
||||||
// std::unique_ptr<Tag> ReadTag() override;
|
// std::unique_ptr<Tag> ReadTag() override;
|
||||||
bool IsAvailable() const noexcept override;
|
bool IsAvailable() const noexcept override;
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override;
|
std::span<std::byte> dest) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* virtual methods from class InputCacheLease */
|
/* virtual methods from class InputCacheLease */
|
||||||
void OnInputCacheAvailable() noexcept override;
|
void OnInputCacheAvailable() noexcept override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ class CdioParanoiaInputStream final : public InputStream {
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
[[nodiscard]] bool IsEOF() const noexcept override;
|
[[nodiscard]] bool IsEOF() const noexcept override;
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override;
|
std::span<std::byte> dest) override;
|
||||||
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -305,7 +305,7 @@ CdioParanoiaInputStream::Seek(std::unique_lock<Mutex> &,
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
CdioParanoiaInputStream::Read(std::unique_lock<Mutex> &,
|
CdioParanoiaInputStream::Read(std::unique_lock<Mutex> &,
|
||||||
void *ptr, size_t length)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
/* end of track ? */
|
/* end of track ? */
|
||||||
if (IsEOF())
|
if (IsEOF())
|
||||||
|
@ -342,10 +342,10 @@ CdioParanoiaInputStream::Read(std::unique_lock<Mutex> &,
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t maxwrite = CDIO_CD_FRAMESIZE_RAW - diff; //# of bytes pending in current buffer
|
const size_t maxwrite = CDIO_CD_FRAMESIZE_RAW - diff; //# of bytes pending in current buffer
|
||||||
const std::size_t nbytes = std::min(length, maxwrite);
|
const std::size_t nbytes = std::min(dest.size(), maxwrite);
|
||||||
|
|
||||||
//skip diff bytes from this lsn
|
//skip diff bytes from this lsn
|
||||||
memcpy(ptr, ((const char *)rbuf) + diff, nbytes);
|
memcpy(dest.data(), ((const char *)rbuf) + diff, nbytes);
|
||||||
|
|
||||||
//update offset
|
//update offset
|
||||||
offset += nbytes;
|
offset += nbytes;
|
||||||
|
|
|
@ -34,7 +34,7 @@ public:
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
[[nodiscard]] bool IsEOF() const noexcept override;
|
[[nodiscard]] bool IsEOF() const noexcept override;
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override;
|
std::span<std::byte> dest) override;
|
||||||
void Seek(std::unique_lock<Mutex> &lock,
|
void Seek(std::unique_lock<Mutex> &lock,
|
||||||
offset_type offset) override;
|
offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
@ -91,13 +91,13 @@ input_ffmpeg_open(const char *uri,
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
FfmpegInputStream::Read(std::unique_lock<Mutex> &,
|
FfmpegInputStream::Read(std::unique_lock<Mutex> &,
|
||||||
void *ptr, size_t read_size)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
size_t result;
|
size_t result;
|
||||||
|
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
result = io.Read(ptr, read_size);
|
result = io.Read(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += result;
|
offset += result;
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override;
|
std::span<std::byte> dest) override;
|
||||||
void Seek(std::unique_lock<Mutex> &lock,
|
void Seek(std::unique_lock<Mutex> &lock,
|
||||||
offset_type offset) override;
|
offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
@ -71,14 +71,13 @@ FileInputStream::Seek(std::unique_lock<Mutex> &,
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
FileInputStream::Read(std::unique_lock<Mutex> &,
|
FileInputStream::Read(std::unique_lock<Mutex> &, std::span<std::byte> dest)
|
||||||
void *ptr, size_t read_size)
|
|
||||||
{
|
{
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
|
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
nbytes = reader.Read({static_cast<std::byte *>(ptr), read_size});
|
nbytes = reader.Read(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nbytes == 0 && !IsEOF())
|
if (nbytes == 0 && !IsEOF())
|
||||||
|
|
|
@ -40,7 +40,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(std::unique_lock<Mutex> &lock,
|
size_t Read(std::unique_lock<Mutex> &lock,
|
||||||
void *ptr, size_t size) override;
|
std::span<std::byte> dest) override;
|
||||||
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
void Seek(std::unique_lock<Mutex> &lock, offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,13 +88,13 @@ input_smbclient_open(const char *uri,
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
SmbclientInputStream::Read(std::unique_lock<Mutex> &,
|
SmbclientInputStream::Read(std::unique_lock<Mutex> &,
|
||||||
void *ptr, size_t read_size)
|
std::span<std::byte> dest)
|
||||||
{
|
{
|
||||||
ssize_t nbytes;
|
ssize_t nbytes;
|
||||||
|
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
nbytes = ctx.Read(handle, ptr, read_size);
|
nbytes = ctx.Read(handle, dest.data(), dest.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nbytes < 0)
|
if (nbytes < 0)
|
||||||
|
|
|
@ -68,10 +68,10 @@ ChromaprintDecoderClient::SubmitAudio(InputStream *,
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ChromaprintDecoderClient::Read(InputStream &is,
|
ChromaprintDecoderClient::Read(InputStream &is,
|
||||||
void *buffer, size_t length) noexcept
|
std::span<std::byte> dest) noexcept
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return is.LockRead(buffer, length);
|
return is.LockRead(dest);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
error = std::current_exception();
|
error = std::current_exception();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -74,7 +74,7 @@ public:
|
||||||
//InputStreamPtr OpenUri(const char *) override;
|
//InputStreamPtr OpenUri(const char *) override;
|
||||||
|
|
||||||
size_t Read(InputStream &is,
|
size_t Read(InputStream &is,
|
||||||
void *buffer, size_t length) noexcept override;
|
std::span<std::byte> dest) noexcept override;
|
||||||
|
|
||||||
void SubmitTimestamp(FloatDuration) noexcept override {}
|
void SubmitTimestamp(FloatDuration) noexcept override {}
|
||||||
DecoderCommand SubmitAudio(InputStream *is,
|
DecoderCommand SubmitAudio(InputStream *is,
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "ExpatParser.hxx"
|
#include "ExpatParser.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
void
|
void
|
||||||
ExpatParser::Parse(InputStream &is)
|
ExpatParser::Parse(InputStream &is)
|
||||||
|
@ -10,12 +11,12 @@ ExpatParser::Parse(InputStream &is)
|
||||||
assert(is.IsReady());
|
assert(is.IsReady());
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
char buffer[4096];
|
std::byte buffer[4096];
|
||||||
size_t nbytes = is.LockRead(buffer, sizeof(buffer));
|
size_t nbytes = is.LockRead(buffer);
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
Parse(buffer, nbytes);
|
Parse(ToStringView(std::span{buffer}.first(nbytes)));
|
||||||
}
|
}
|
||||||
|
|
||||||
CompleteParse();
|
CompleteParse();
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
// Copyright The Music Player Daemon Project
|
// Copyright The Music Player Daemon Project
|
||||||
|
|
||||||
#ifndef MPD_FFMPEG_IO_CONTEXT_HXX
|
#pragma once
|
||||||
#define MPD_FFMPEG_IO_CONTEXT_HXX
|
|
||||||
|
|
||||||
#include "Error.hxx"
|
#include "Error.hxx"
|
||||||
|
|
||||||
|
@ -10,7 +9,9 @@ extern "C" {
|
||||||
#include <libavformat/avio.h>
|
#include <libavformat/avio.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
namespace Ffmpeg {
|
namespace Ffmpeg {
|
||||||
|
|
||||||
|
@ -58,9 +59,10 @@ public:
|
||||||
return avio_feof(io_context) != 0;
|
return avio_feof(io_context) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *buffer, size_t size) {
|
size_t Read(std::span<std::byte> dest) {
|
||||||
int result = avio_read_partial(io_context,
|
int result = avio_read_partial(io_context,
|
||||||
(unsigned char *)buffer, size);
|
reinterpret_cast<unsigned char *>(dest.data()),
|
||||||
|
dest.size());
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
throw MakeFfmpegError(result, "avio_read() failed");
|
throw MakeFfmpegError(result, "avio_read() failed");
|
||||||
|
|
||||||
|
@ -77,5 +79,3 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Ffmpeg
|
} // namespace Ffmpeg
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ FlacIORead(void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
|
||||||
{
|
{
|
||||||
auto *is = (InputStream *)handle;
|
auto *is = (InputStream *)handle;
|
||||||
|
|
||||||
uint8_t *const p0 = (uint8_t *)ptr, *p = p0,
|
std::byte *const p0 = (std::byte *)ptr, *p = p0,
|
||||||
*const end = p0 + size * nmemb;
|
*const end = p0 + size * nmemb;
|
||||||
|
|
||||||
/* libFLAC is very picky about short reads, and expects the IO
|
/* libFLAC is very picky about short reads, and expects the IO
|
||||||
|
@ -22,7 +22,7 @@ FlacIORead(void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
|
||||||
|
|
||||||
while (p < end) {
|
while (p < end) {
|
||||||
try {
|
try {
|
||||||
size_t nbytes = is->LockRead(p, end - p);
|
size_t nbytes = is->LockRead({p, end});
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
/* end of file */
|
/* end of file */
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -10,7 +10,7 @@ Yajl::ParseInputStream(Handle &handle, InputStream &is)
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
unsigned char buffer[4096];
|
unsigned char buffer[4096];
|
||||||
const size_t nbytes = is.LockRead(buffer, sizeof(buffer));
|
const size_t nbytes = is.LockRead(std::as_writable_bytes(std::span{buffer}));
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "Aiff.hxx"
|
#include "Aiff.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "util/ByteOrder.hxx"
|
#include "util/ByteOrder.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
@ -30,7 +31,7 @@ aiff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
is.Rewind(lock);
|
is.Rewind(lock);
|
||||||
|
|
||||||
aiff_header header;
|
aiff_header header;
|
||||||
is.ReadFull(lock, &header, sizeof(header));
|
is.ReadFull(lock, ReferenceAsWritableBytes(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 &&
|
||||||
|
@ -41,7 +42,7 @@ aiff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
/* read the chunk header */
|
/* read the chunk header */
|
||||||
|
|
||||||
aiff_chunk_header chunk;
|
aiff_chunk_header chunk;
|
||||||
is.ReadFull(lock, &chunk, sizeof(chunk));
|
is.ReadFull(lock, ReferenceAsWritableBytes(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()))
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "ApeLoader.hxx"
|
#include "ApeLoader.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "util/PackedLittleEndian.hxx"
|
#include "util/PackedLittleEndian.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
@ -30,7 +31,7 @@ try {
|
||||||
/* determine if file has an apeV2 tag */
|
/* determine if file has an apeV2 tag */
|
||||||
ApeFooter footer;
|
ApeFooter footer;
|
||||||
is.Seek(lock, is.GetSize() - sizeof(footer));
|
is.Seek(lock, is.GetSize() - sizeof(footer));
|
||||||
is.ReadFull(lock, &footer, sizeof(footer));
|
is.ReadFull(lock, ReferenceAsWritableBytes(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)
|
||||||
|
@ -49,12 +50,12 @@ try {
|
||||||
remaining -= sizeof(footer);
|
remaining -= sizeof(footer);
|
||||||
assert(remaining > 10);
|
assert(remaining > 10);
|
||||||
|
|
||||||
auto buffer = std::make_unique<char[]>(remaining);
|
auto buffer = std::make_unique<std::byte[]>(remaining);
|
||||||
is.ReadFull(lock, buffer.get(), remaining);
|
is.ReadFull(lock, {buffer.get(), remaining});
|
||||||
|
|
||||||
/* read tags */
|
/* read tags */
|
||||||
unsigned n = FromLE32(footer.count);
|
unsigned n = FromLE32(footer.count);
|
||||||
const char *p = buffer.get();
|
const char *p = (const char *)buffer.get();
|
||||||
while (n-- && remaining > 10) {
|
while (n-- && remaining > 10) {
|
||||||
size_t size = *(const PackedLE32 *)p;
|
size_t size = *(const PackedLE32 *)p;
|
||||||
p += 4;
|
p += 4;
|
||||||
|
|
|
@ -25,7 +25,7 @@ get_id3v2_footer_size(InputStream &is, std::unique_lock<Mutex> &lock,
|
||||||
try {
|
try {
|
||||||
id3_byte_t buf[ID3_TAG_QUERYSIZE];
|
id3_byte_t buf[ID3_TAG_QUERYSIZE];
|
||||||
is.Seek(lock, offset);
|
is.Seek(lock, offset);
|
||||||
is.ReadFull(lock, buf, sizeof(buf));
|
is.ReadFull(lock, std::as_writable_bytes(std::span{buf}));
|
||||||
|
|
||||||
return id3_tag_query(buf, sizeof(buf));
|
return id3_tag_query(buf, sizeof(buf));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
@ -36,7 +36,7 @@ static UniqueId3Tag
|
||||||
ReadId3Tag(InputStream &is, std::unique_lock<Mutex> &lock)
|
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(lock, query_buffer, sizeof(query_buffer));
|
is.ReadFull(lock, std::as_writable_bytes(std::span{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));
|
||||||
|
@ -56,7 +56,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(lock, end, remaining);
|
is.ReadFull(lock, std::as_writable_bytes(std::span{end, remaining}));
|
||||||
|
|
||||||
return UniqueId3Tag(id3_tag_parse(tag_buffer.get(), tag_size));
|
return UniqueId3Tag(id3_tag_parse(tag_buffer.get(), tag_size));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
@ -77,7 +77,7 @@ static UniqueId3Tag
|
||||||
ReadId3v1Tag(InputStream &is, std::unique_lock<Mutex> &lock)
|
ReadId3v1Tag(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
try {
|
try {
|
||||||
id3_byte_t buffer[ID3V1_SIZE];
|
id3_byte_t buffer[ID3V1_SIZE];
|
||||||
is.ReadFull(lock, buffer, ID3V1_SIZE);
|
is.ReadFull(lock, std::as_writable_bytes(std::span{buffer}));
|
||||||
|
|
||||||
return UniqueId3Tag(id3_tag_parse(buffer, ID3V1_SIZE));
|
return UniqueId3Tag(id3_tag_parse(buffer, ID3V1_SIZE));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
@ -183,7 +183,7 @@ try {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto buffer = std::make_unique<id3_byte_t[]>(size);
|
auto buffer = std::make_unique<id3_byte_t[]>(size);
|
||||||
is.ReadFull(lock, buffer.get(), size);
|
is.ReadFull(lock, std::as_writable_bytes(std::span{buffer.get(), size}));
|
||||||
|
|
||||||
return UniqueId3Tag(id3_tag_parse(buffer.get(), size));
|
return UniqueId3Tag(id3_tag_parse(buffer.get(), size));
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "RiffFormat.hxx"
|
#include "RiffFormat.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "util/ByteOrder.hxx"
|
#include "util/ByteOrder.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
@ -19,7 +20,7 @@ riff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
is.Rewind(lock);
|
is.Rewind(lock);
|
||||||
|
|
||||||
RiffFileHeader header;
|
RiffFileHeader header;
|
||||||
is.ReadFull(lock, &header, sizeof(header));
|
is.ReadFull(lock, ReferenceAsWritableBytes(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");
|
||||||
|
@ -28,7 +29,7 @@ riff_seek_id3(InputStream &is, std::unique_lock<Mutex> &lock)
|
||||||
/* read the chunk header */
|
/* read the chunk header */
|
||||||
|
|
||||||
RiffChunkHeader chunk;
|
RiffChunkHeader chunk;
|
||||||
is.ReadFull(lock, &chunk, sizeof(chunk));
|
is.ReadFull(lock, ReferenceAsWritableBytes(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()))
|
||||||
|
|
|
@ -42,7 +42,7 @@ public:
|
||||||
#ifdef ENABLE_UPNP
|
#ifdef ENABLE_UPNP
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
size_t
|
size_t
|
||||||
InputStream::LockRead(void *, size_t)
|
InputStream::LockRead(std::span<std::byte>)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,10 +60,10 @@ DumpDecoderClient::OpenUri(const char *uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
DumpDecoderClient::Read(InputStream &is, void *buffer, size_t length) noexcept
|
DumpDecoderClient::Read(InputStream &is, std::span<std::byte> dest) noexcept
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return is.LockRead(buffer, length);
|
return is.LockRead(dest);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
void SeekError() noexcept override;
|
void SeekError() noexcept override;
|
||||||
InputStreamPtr OpenUri(const char *uri) override;
|
InputStreamPtr OpenUri(const char *uri) override;
|
||||||
size_t Read(InputStream &is,
|
size_t Read(InputStream &is,
|
||||||
void *buffer, size_t length) noexcept override;
|
std::span<std::byte> dest) noexcept override;
|
||||||
void SubmitTimestamp(FloatDuration t) noexcept override;
|
void SubmitTimestamp(FloatDuration t) noexcept override;
|
||||||
DecoderCommand SubmitAudio(InputStream *is,
|
DecoderCommand SubmitAudio(InputStream *is,
|
||||||
std::span<const std::byte> audio,
|
std::span<const std::byte> audio,
|
||||||
|
|
|
@ -29,9 +29,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(std::unique_lock<Mutex> &,
|
size_t Read(std::unique_lock<Mutex> &,
|
||||||
void *ptr, size_t read_size) override {
|
std::span<std::byte> dest) override {
|
||||||
size_t nbytes = std::min(remaining, read_size);
|
size_t nbytes = std::min(remaining, dest.size());
|
||||||
memcpy(ptr, data, nbytes);
|
memcpy(dest.data(), data, nbytes);
|
||||||
data += nbytes;
|
data += nbytes;
|
||||||
remaining -= nbytes;
|
remaining -= nbytes;
|
||||||
offset += nbytes;
|
offset += nbytes;
|
||||||
|
@ -60,14 +60,14 @@ 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(lock, buffer, 2);
|
size_t nbytes = ris->Read(lock, std::as_writable_bytes(std::span{buffer}.first(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(lock, buffer, 2);
|
nbytes = ris->Read(lock, std::as_writable_bytes(std::span{buffer}.first(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]);
|
||||||
|
@ -78,7 +78,7 @@ TEST(RewindInputStream, Basic)
|
||||||
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(lock, buffer, 2);
|
nbytes = ris->Read(lock, std::as_writable_bytes(std::span{buffer}.first(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]);
|
||||||
|
@ -89,21 +89,21 @@ TEST(RewindInputStream, Basic)
|
||||||
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(lock, buffer, 2);
|
nbytes = ris->Read(lock, std::as_writable_bytes(std::span{buffer}.first(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(lock, buffer, sizeof(buffer));
|
nbytes = ris->Read(lock, std::as_writable_bytes(std::span{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(lock, buffer, sizeof(buffer));
|
nbytes = ris->Read(lock, std::as_writable_bytes(std::span{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]);
|
||||||
|
@ -115,7 +115,7 @@ TEST(RewindInputStream, Basic)
|
||||||
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(lock, buffer, sizeof(buffer));
|
nbytes = ris->Read(lock, std::as_writable_bytes(std::span{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]);
|
||||||
|
|
|
@ -172,7 +172,7 @@ dump_input_stream(InputStream &is, FileDescriptor out,
|
||||||
|
|
||||||
std::byte buffer[MAX_CHUNK_SIZE];
|
std::byte buffer[MAX_CHUNK_SIZE];
|
||||||
assert(chunk_size <= sizeof(buffer));
|
assert(chunk_size <= sizeof(buffer));
|
||||||
size_t num_read = is.Read(lock, buffer, chunk_size);
|
size_t num_read = is.Read(lock, {buffer, chunk_size});
|
||||||
if (num_read == 0)
|
if (num_read == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue