input/plugins: make InputStream the base class

Prepare for adding virtual methods.
This commit is contained in:
Max Kellermann 2014-05-11 16:02:57 +02:00
parent e1383a2d8e
commit f1d0700252
15 changed files with 236 additions and 320 deletions

View File

@ -88,9 +88,7 @@ public:
Error &error) override; Error &error) override;
}; };
struct Bzip2InputStream { struct Bzip2InputStream final : public InputStream {
InputStream base;
Bzip2ArchiveFile *archive; Bzip2ArchiveFile *archive;
bool eof; bool eof;
@ -130,7 +128,7 @@ Bzip2InputStream::Open(Error &error)
return false; return false;
} }
base.ready = true; SetReady();
return true; return true;
} }
@ -157,9 +155,10 @@ bz2_open(Path pathname, Error &error)
/* single archive handling */ /* single archive handling */
Bzip2InputStream::Bzip2InputStream(Bzip2ArchiveFile &_context, const char *uri, Bzip2InputStream::Bzip2InputStream(Bzip2ArchiveFile &_context,
Mutex &mutex, Cond &cond) const char *_uri,
:base(bz2_inputplugin, uri, mutex, cond), Mutex &_mutex, Cond &_cond)
:InputStream(bz2_inputplugin, _uri, _mutex, _cond),
archive(&_context), eof(false) archive(&_context), eof(false)
{ {
archive->Ref(); archive->Ref();
@ -181,7 +180,7 @@ Bzip2ArchiveFile::OpenStream(const char *path,
return nullptr; return nullptr;
} }
return &bis->base; return bis;
} }
static void static void

View File

@ -140,21 +140,19 @@ Iso9660ArchiveFile::Visit(ArchiveVisitor &visitor)
/* single archive handling */ /* single archive handling */
class Iso9660InputStream { class Iso9660InputStream final : public InputStream {
InputStream base;
Iso9660ArchiveFile &archive; Iso9660ArchiveFile &archive;
iso9660_stat_t *statbuf; iso9660_stat_t *statbuf;
public: public:
Iso9660InputStream(Iso9660ArchiveFile &_archive, const char *uri, Iso9660InputStream(Iso9660ArchiveFile &_archive, const char *_uri,
Mutex &mutex, Cond &cond, Mutex &_mutex, Cond &_cond,
iso9660_stat_t *_statbuf) iso9660_stat_t *_statbuf)
:base(iso9660_input_plugin, uri, mutex, cond), :InputStream(iso9660_input_plugin, _uri, _mutex, _cond),
archive(_archive), statbuf(_statbuf) { archive(_archive), statbuf(_statbuf) {
base.ready = true; size = statbuf->size;
base.size = statbuf->size; SetReady();
archive.Ref(); archive.Ref();
} }
@ -164,10 +162,6 @@ public:
archive.Unref(); archive.Unref();
} }
InputStream *Get() {
return &base;
}
size_t Read(void *ptr, size_t size, Error &error); size_t Read(void *ptr, size_t size, Error &error);
}; };
@ -183,10 +177,8 @@ Iso9660ArchiveFile::OpenStream(const char *pathname,
return nullptr; return nullptr;
} }
Iso9660InputStream *iis = return new Iso9660InputStream(*this, pathname, mutex, cond,
new Iso9660InputStream(*this, pathname, mutex, cond, statbuf);
statbuf);
return iis->Get();
} }
static void static void
@ -198,22 +190,22 @@ iso9660_input_close(InputStream *is)
} }
inline size_t inline size_t
Iso9660InputStream::Read(void *ptr, size_t size, Error &error) Iso9660InputStream::Read(void *ptr, size_t read_size, Error &error)
{ {
int readed = 0; int readed = 0;
int no_blocks, cur_block; int no_blocks, cur_block;
size_t left_bytes = statbuf->size - base.offset; size_t left_bytes = statbuf->size - offset;
if (left_bytes < size) { if (left_bytes < read_size) {
no_blocks = CEILING(left_bytes,ISO_BLOCKSIZE); no_blocks = CEILING(left_bytes, ISO_BLOCKSIZE);
} else { } else {
no_blocks = size / ISO_BLOCKSIZE; no_blocks = read_size / ISO_BLOCKSIZE;
} }
if (no_blocks == 0) if (no_blocks == 0)
return 0; return 0;
cur_block = base.offset / ISO_BLOCKSIZE; cur_block = offset / ISO_BLOCKSIZE;
readed = archive.SeekRead(ptr, statbuf->lsn + cur_block, readed = archive.SeekRead(ptr, statbuf->lsn + cur_block,
no_blocks); no_blocks);
@ -224,11 +216,11 @@ Iso9660InputStream::Read(void *ptr, size_t size, Error &error)
(unsigned long)cur_block); (unsigned long)cur_block);
return 0; return 0;
} }
if (left_bytes < size) { if (left_bytes < read_size) {
readed = left_bytes; readed = left_bytes;
} }
base.offset += readed; offset += readed;
return readed; return readed;
} }

View File

@ -97,25 +97,24 @@ ZzipArchiveFile::Visit(ArchiveVisitor &visitor)
/* single archive handling */ /* single archive handling */
struct ZzipInputStream { struct ZzipInputStream final : public InputStream {
InputStream base;
ZzipArchiveFile *archive; ZzipArchiveFile *archive;
ZZIP_FILE *file; ZZIP_FILE *file;
ZzipInputStream(ZzipArchiveFile &_archive, const char *uri, ZzipInputStream(ZzipArchiveFile &_archive, const char *_uri,
Mutex &mutex, Cond &cond, Mutex &_mutex, Cond &_cond,
ZZIP_FILE *_file) ZZIP_FILE *_file)
:base(zzip_input_plugin, uri, mutex, cond), :InputStream(zzip_input_plugin, _uri, _mutex, _cond),
archive(&_archive), file(_file) { archive(&_archive), file(_file) {
base.ready = true;
//we are seekable (but its not recommendent to do so) //we are seekable (but its not recommendent to do so)
base.seekable = true; seekable = true;
ZZIP_STAT z_stat; ZZIP_STAT z_stat;
zzip_file_stat(file, &z_stat); zzip_file_stat(file, &z_stat);
base.size = z_stat.st_size; size = z_stat.st_size;
SetReady();
archive->ref.Increment(); archive->ref.Increment();
} }
@ -138,11 +137,9 @@ ZzipArchiveFile::OpenStream(const char *pathname,
return nullptr; return nullptr;
} }
ZzipInputStream *zis = return new ZzipInputStream(*this, pathname,
new ZzipInputStream(*this, pathname, mutex, cond,
mutex, cond, _file);
_file);
return &zis->base;
} }
static void static void

View File

@ -52,30 +52,30 @@ ThreadInputStream::Start(Error &error)
if (!thread.Start(ThreadFunc, this, error)) if (!thread.Start(ThreadFunc, this, error))
return nullptr; return nullptr;
return &base; return this;
} }
inline void inline void
ThreadInputStream::ThreadFunc() ThreadInputStream::ThreadFunc()
{ {
FormatThreadName("input:%s", base.GetPlugin().name); FormatThreadName("input:%s", GetPlugin().name);
Lock(); Lock();
if (!Open(postponed_error)) { if (!Open(postponed_error)) {
base.cond.broadcast(); cond.broadcast();
Unlock(); Unlock();
return; return;
} }
/* we're ready, tell it to our client */ /* we're ready, tell it to our client */
base.SetReady(); SetReady();
while (!close) { while (!close) {
assert(!postponed_error.IsDefined()); assert(!postponed_error.IsDefined());
auto w = buffer->Write(); auto w = buffer->Write();
if (w.IsEmpty()) { if (w.IsEmpty()) {
wake_cond.wait(base.mutex); wake_cond.wait(mutex);
} else { } else {
Unlock(); Unlock();
@ -83,7 +83,7 @@ ThreadInputStream::ThreadFunc()
size_t nbytes = Read(w.data, w.size, error); size_t nbytes = Read(w.data, w.size, error);
Lock(); Lock();
base.cond.broadcast(); cond.broadcast();
if (nbytes == 0) { if (nbytes == 0) {
eof = true; eof = true;
@ -121,7 +121,8 @@ ThreadInputStream::Check2(Error &error)
bool bool
ThreadInputStream::Check(InputStream *is, Error &error) ThreadInputStream::Check(InputStream *is, Error &error)
{ {
return Cast(is)->Check2(error); ThreadInputStream &tis = *(ThreadInputStream *)is;
return tis.Check2(error);
} }
inline bool inline bool
@ -133,11 +134,12 @@ ThreadInputStream::Available2()
bool bool
ThreadInputStream::Available(InputStream *is) ThreadInputStream::Available(InputStream *is)
{ {
return Cast(is)->Available2(); ThreadInputStream &tis = *(ThreadInputStream *)is;
return tis.Available2();
} }
inline size_t inline size_t
ThreadInputStream::Read2(void *ptr, size_t size, Error &error) ThreadInputStream::Read2(void *ptr, size_t read_size, Error &error)
{ {
while (true) { while (true) {
if (postponed_error.IsDefined()) { if (postponed_error.IsDefined()) {
@ -147,18 +149,18 @@ ThreadInputStream::Read2(void *ptr, size_t size, Error &error)
auto r = buffer->Read(); auto r = buffer->Read();
if (!r.IsEmpty()) { if (!r.IsEmpty()) {
size_t nbytes = std::min(size, r.size); size_t nbytes = std::min(read_size, r.size);
memcpy(ptr, r.data, nbytes); memcpy(ptr, r.data, nbytes);
buffer->Consume(nbytes); buffer->Consume(nbytes);
wake_cond.broadcast(); wake_cond.broadcast();
base.offset += nbytes; offset += nbytes;
return nbytes; return nbytes;
} }
if (eof) if (eof)
return 0; return 0;
base.cond.wait(base.mutex); cond.wait(mutex);
} }
} }
@ -166,7 +168,8 @@ size_t
ThreadInputStream::Read(InputStream *is, void *ptr, size_t size, ThreadInputStream::Read(InputStream *is, void *ptr, size_t size,
Error &error) Error &error)
{ {
return Cast(is)->Read2(ptr, size, error); ThreadInputStream &tis = *(ThreadInputStream *)is;
return tis.Read2(ptr, size, error);
} }
inline void inline void
@ -187,7 +190,8 @@ ThreadInputStream::Close2()
void void
ThreadInputStream::Close(InputStream *is) ThreadInputStream::Close(InputStream *is)
{ {
Cast(is)->Close2(); ThreadInputStream &tis = *(ThreadInputStream *)is;
tis.Close2();
} }
inline bool inline bool
@ -199,5 +203,6 @@ ThreadInputStream::IsEOF2()
bool bool
ThreadInputStream::IsEOF(InputStream *is) ThreadInputStream::IsEOF(InputStream *is)
{ {
return Cast(is)->IsEOF2(); ThreadInputStream &tis = *(ThreadInputStream *)is;
return tis.IsEOF2();
} }

View File

@ -24,7 +24,6 @@
#include "InputStream.hxx" #include "InputStream.hxx"
#include "thread/Thread.hxx" #include "thread/Thread.hxx"
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "util/Cast.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include <stdint.h> #include <stdint.h>
@ -40,9 +39,7 @@ template<typename T> class CircularBuffer;
* *
* This works only for "streams": unknown length, no seeking, no tags. * This works only for "streams": unknown length, no seeking, no tags.
*/ */
class ThreadInputStream { class ThreadInputStream : public InputStream {
InputStream base;
Thread thread; Thread thread;
/** /**
@ -71,7 +68,7 @@ public:
ThreadInputStream(const InputPlugin &_plugin, ThreadInputStream(const InputPlugin &_plugin,
const char *_uri, Mutex &_mutex, Cond &_cond, const char *_uri, Mutex &_mutex, Cond &_cond,
size_t _buffer_size) size_t _buffer_size)
:base(_plugin, _uri, _mutex, _cond), :InputStream(_plugin, _uri, _mutex, _cond),
buffer_size(_buffer_size), buffer_size(_buffer_size),
buffer(nullptr), buffer(nullptr),
close(false), eof(false) {} close(false), eof(false) {}
@ -86,24 +83,10 @@ public:
InputStream *Start(Error &error); InputStream *Start(Error &error);
protected: protected:
void Lock() { void SetMimeType(const char *_mime) {
base.Lock();
}
void Unlock() {
base.Unlock();
}
const char *GetURI() const {
assert(thread.IsInside()); assert(thread.IsInside());
return base.GetURI(); InputStream::SetMimeType(_mime);
}
void SetMimeType(const char *mime) {
assert(thread.IsInside());
base.SetMimeType(mime);
} }
/* to be implemented by the plugin */ /* to be implemented by the plugin */
@ -145,20 +128,6 @@ protected:
virtual void Cancel() {} virtual void Cancel() {}
private: private:
#if GCC_CHECK_VERSION(4,6) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
#endif
static constexpr ThreadInputStream *Cast(InputStream *is) {
return ContainerCast(is, ThreadInputStream, base);
}
#if GCC_CHECK_VERSION(4,6) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
void ThreadFunc(); void ThreadFunc();
static void ThreadFunc(void *ctx); static void ThreadFunc(void *ctx);

View File

@ -32,7 +32,7 @@
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "util/ReusableArray.hxx" #include "util/ReusableArray.hxx"
#include "util/Cast.hxx"
#include "Log.hxx" #include "Log.hxx"
#include "event/MultiSocketMonitor.hxx" #include "event/MultiSocketMonitor.hxx"
#include "event/DeferredMonitor.hxx" #include "event/DeferredMonitor.hxx"
@ -64,8 +64,9 @@ static constexpr unsigned int default_rate = 44100; // cd quality
*/ */
static constexpr size_t read_buffer_size = 4096; static constexpr size_t read_buffer_size = 4096;
class AlsaInputStream final : MultiSocketMonitor, DeferredMonitor { class AlsaInputStream final
InputStream base; : public InputStream,
MultiSocketMonitor, DeferredMonitor {
snd_pcm_t *capture_handle; snd_pcm_t *capture_handle;
size_t frame_size; size_t frame_size;
int frames_to_read; int frames_to_read;
@ -81,23 +82,23 @@ class AlsaInputStream final : MultiSocketMonitor, DeferredMonitor {
public: public:
AlsaInputStream(EventLoop &loop, AlsaInputStream(EventLoop &loop,
const char *uri, Mutex &mutex, Cond &cond, const char *_uri, Mutex &_mutex, Cond &_cond,
snd_pcm_t *_handle, int _frame_size) snd_pcm_t *_handle, int _frame_size)
:MultiSocketMonitor(loop), :InputStream(input_plugin_alsa, _uri, _mutex, _cond),
MultiSocketMonitor(loop),
DeferredMonitor(loop), DeferredMonitor(loop),
base(input_plugin_alsa, uri, mutex, cond),
capture_handle(_handle), capture_handle(_handle),
frame_size(_frame_size), frame_size(_frame_size),
eof(false) eof(false)
{ {
assert(uri != nullptr); assert(_uri != nullptr);
assert(_handle != nullptr); assert(_handle != nullptr);
/* this mime type forces use of the PcmDecoderPlugin. /* this mime type forces use of the PcmDecoderPlugin.
Needs to be generalised when/if that decoder is Needs to be generalised when/if that decoder is
updated to support other audio formats */ updated to support other audio formats */
base.SetMimeType("audio/x-mpd-cdda-pcm"); SetMimeType("audio/x-mpd-cdda-pcm");
base.SetReady(); InputStream::SetReady();
frames_to_read = read_buffer_size / frame_size; frames_to_read = read_buffer_size / frame_size;
@ -115,19 +116,6 @@ public:
static InputStream *Create(const char *uri, Mutex &mutex, Cond &cond, static InputStream *Create(const char *uri, Mutex &mutex, Cond &cond,
Error &error); Error &error);
#if GCC_CHECK_VERSION(4,6) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
#endif
static constexpr AlsaInputStream *Cast(InputStream *is) {
return ContainerCast(is, AlsaInputStream, base);
}
#if GCC_CHECK_VERSION(4,6) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
bool Available() { bool Available() {
if (snd_pcm_avail(capture_handle) > frames_to_read) if (snd_pcm_avail(capture_handle) > frames_to_read)
return true; return true;
@ -188,18 +176,17 @@ AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond,
return nullptr; return nullptr;
int frame_size = snd_pcm_format_width(format) / 8 * channels; int frame_size = snd_pcm_format_width(format) / 8 * channels;
AlsaInputStream *stream = new AlsaInputStream(io_thread_get(), return new AlsaInputStream(io_thread_get(),
uri, mutex, cond, uri, mutex, cond,
handle, frame_size); handle, frame_size);
return &stream->base;
} }
inline size_t inline size_t
AlsaInputStream::Read(void *ptr, size_t size, Error &error) AlsaInputStream::Read(void *ptr, size_t read_size, Error &error)
{ {
assert(ptr != nullptr); assert(ptr != nullptr);
int num_frames = size / frame_size; int num_frames = read_size / frame_size;
int ret; int ret;
while ((ret = snd_pcm_readi(capture_handle, ptr, num_frames)) < 0) { while ((ret = snd_pcm_readi(capture_handle, ptr, num_frames)) < 0) {
if (Recover(ret) < 0) { if (Recover(ret) < 0) {
@ -211,7 +198,7 @@ AlsaInputStream::Read(void *ptr, size_t size, Error &error)
} }
size_t nbytes = ret * frame_size; size_t nbytes = ret * frame_size;
base.offset += nbytes; offset += nbytes;
return nbytes; return nbytes;
} }
@ -244,9 +231,9 @@ AlsaInputStream::DispatchSockets()
{ {
waiting = false; waiting = false;
const ScopeLock protect(base.mutex); const ScopeLock protect(mutex);
/* wake up the thread that is waiting for more data */ /* wake up the thread that is waiting for more data */
base.cond.broadcast(); cond.broadcast();
} }
inline int inline int
@ -389,28 +376,28 @@ alsa_input_open(const char *uri, Mutex &mutex, Cond &cond, Error &error)
static void static void
alsa_input_close(InputStream *is) alsa_input_close(InputStream *is)
{ {
AlsaInputStream *ais = AlsaInputStream::Cast(is); AlsaInputStream *ais = (AlsaInputStream *)is;
delete ais; delete ais;
} }
static bool static bool
alsa_input_available(InputStream *is) alsa_input_available(InputStream *is)
{ {
AlsaInputStream *ais = AlsaInputStream::Cast(is); AlsaInputStream *ais = (AlsaInputStream *)is;
return ais->Available(); return ais->Available();
} }
static size_t static size_t
alsa_input_read(InputStream *is, void *ptr, size_t size, Error &error) alsa_input_read(InputStream *is, void *ptr, size_t size, Error &error)
{ {
AlsaInputStream *ais = AlsaInputStream::Cast(is); AlsaInputStream *ais = (AlsaInputStream *)is;
return ais->Read(ptr, size, error); return ais->Read(ptr, size, error);
} }
static bool static bool
alsa_input_eof(gcc_unused InputStream *is) alsa_input_eof(gcc_unused InputStream *is)
{ {
AlsaInputStream *ais = AlsaInputStream::Cast(is); AlsaInputStream *ais = (AlsaInputStream *)is;
return ais->IsEOF(); return ais->IsEOF();
} }

View File

@ -50,9 +50,7 @@
#include <cdio/cd_types.h> #include <cdio/cd_types.h>
struct CdioParanoiaInputStream { struct CdioParanoiaInputStream final : public InputStream {
InputStream base;
cdrom_drive_t *drv; cdrom_drive_t *drv;
CdIo_t *cdio; CdIo_t *cdio;
cdrom_paranoia_t *para; cdrom_paranoia_t *para;
@ -65,9 +63,9 @@ struct CdioParanoiaInputStream {
char buffer[CDIO_CD_FRAMESIZE_RAW]; char buffer[CDIO_CD_FRAMESIZE_RAW];
int buffer_lsn; int buffer_lsn;
CdioParanoiaInputStream(const char *uri, Mutex &mutex, Cond &cond, CdioParanoiaInputStream(const char *_uri, Mutex &_mutex, Cond &_cond,
int _trackno) int _trackno)
:base(input_plugin_cdio_paranoia, uri, mutex, cond), :InputStream(input_plugin_cdio_paranoia, _uri, _mutex, _cond),
drv(nullptr), cdio(nullptr), para(nullptr), drv(nullptr), cdio(nullptr), para(nullptr),
trackno(_trackno) trackno(_trackno)
{ {
@ -264,16 +262,16 @@ input_cdio_open(const char *uri,
/* seek to beginning of the track */ /* seek to beginning of the track */
cdio_paranoia_seek(i->para, i->lsn_from, SEEK_SET); cdio_paranoia_seek(i->para, i->lsn_from, SEEK_SET);
i->base.ready = true; i->seekable = true;
i->base.seekable = true; i->size = (i->lsn_to - i->lsn_from + 1) * CDIO_CD_FRAMESIZE_RAW;
i->base.size = (i->lsn_to - i->lsn_from + 1) * CDIO_CD_FRAMESIZE_RAW;
/* hack to make MPD select the "pcm" decoder plugin */ /* hack to make MPD select the "pcm" decoder plugin */
i->base.SetMimeType(reverse_endian i->SetMimeType(reverse_endian
? "audio/x-mpd-cdda-pcm-reverse" ? "audio/x-mpd-cdda-pcm-reverse"
: "audio/x-mpd-cdda-pcm"); : "audio/x-mpd-cdda-pcm");
i->SetReady();
return &i->base; return i;
} }
static bool static bool
@ -287,26 +285,26 @@ input_cdio_seek(InputStream *is,
case SEEK_SET: case SEEK_SET:
break; break;
case SEEK_CUR: case SEEK_CUR:
offset += cis->base.offset; offset += cis->offset;
break; break;
case SEEK_END: case SEEK_END:
offset += cis->base.size; offset += cis->size;
break; break;
} }
if (offset < 0 || offset > cis->base.size) { if (offset < 0 || offset > cis->size) {
error.Format(cdio_domain, "Invalid offset to seek %ld (%ld)", error.Format(cdio_domain, "Invalid offset to seek %ld (%ld)",
(long int)offset, (long int)cis->base.size); (long int)offset, (long int)cis->size);
return false; return false;
} }
/* simple case */ /* simple case */
if (offset == cis->base.offset) if (offset == cis->offset)
return true; return true;
/* calculate current LSN */ /* calculate current LSN */
cis->lsn_relofs = offset / CDIO_CD_FRAMESIZE_RAW; cis->lsn_relofs = offset / CDIO_CD_FRAMESIZE_RAW;
cis->base.offset = offset; cis->offset = offset;
cdio_paranoia_seek(cis->para, cis->lsn_from + cis->lsn_relofs, SEEK_SET); cdio_paranoia_seek(cis->para, cis->lsn_from + cis->lsn_relofs, SEEK_SET);
@ -360,7 +358,7 @@ input_cdio_read(InputStream *is, void *ptr, size_t length,
} }
//correct offset //correct offset
diff = cis->base.offset - cis->lsn_relofs * CDIO_CD_FRAMESIZE_RAW; diff = cis->offset - cis->lsn_relofs * CDIO_CD_FRAMESIZE_RAW;
assert(diff >= 0 && diff < CDIO_CD_FRAMESIZE_RAW); assert(diff >= 0 && diff < CDIO_CD_FRAMESIZE_RAW);
@ -374,8 +372,8 @@ input_cdio_read(InputStream *is, void *ptr, size_t length,
nbytes += len; nbytes += len;
//update offset //update offset
cis->base.offset += len; cis->offset += len;
cis->lsn_relofs = cis->base.offset / CDIO_CD_FRAMESIZE_RAW; cis->lsn_relofs = cis->offset / CDIO_CD_FRAMESIZE_RAW;
//update length //update length
length -= len; length -= len;
} }

View File

@ -67,9 +67,7 @@ static const size_t CURL_MAX_BUFFERED = 512 * 1024;
*/ */
static const size_t CURL_RESUME_AT = 384 * 1024; static const size_t CURL_RESUME_AT = 384 * 1024;
struct CurlInputStream { struct CurlInputStream final : public InputStream {
InputStream base;
/* some buffers which were passed to libcurl, which we have /* some buffers which were passed to libcurl, which we have
too free */ too free */
char range[32]; char range[32];
@ -106,9 +104,9 @@ struct CurlInputStream {
Error postponed_error; Error postponed_error;
CurlInputStream(const char *url, Mutex &mutex, Cond &cond, CurlInputStream(const char *_url, Mutex &_mutex, Cond &_cond,
void *_buffer) void *_buffer)
:base(input_plugin_curl, url, mutex, cond), :InputStream(input_plugin_curl, _url, _mutex, _cond),
request_headers(nullptr), request_headers(nullptr),
buffer((uint8_t *)_buffer, CURL_MAX_BUFFERED), buffer((uint8_t *)_buffer, CURL_MAX_BUFFERED),
paused(false), paused(false),
@ -486,7 +484,7 @@ CurlInputStream::RequestDone(CURLcode result, long status)
FreeEasy(); FreeEasy();
const ScopeLock protect(base.mutex); const ScopeLock protect(mutex);
if (result != CURLE_OK) { if (result != CURLE_OK) {
postponed_error.Format(curl_domain, result, postponed_error.Format(curl_domain, result,
@ -497,7 +495,7 @@ CurlInputStream::RequestDone(CURLcode result, long status)
status); status);
} }
base.SetReady(); SetReady();
} }
static void static void
@ -688,7 +686,7 @@ inline bool
CurlInputStream::FillBuffer(Error &error) CurlInputStream::FillBuffer(Error &error)
{ {
while (easy != nullptr && buffer.IsEmpty()) while (easy != nullptr && buffer.IsEmpty())
base.cond.wait(base.mutex); cond.wait(mutex);
if (postponed_error.IsDefined()) { if (postponed_error.IsDefined()) {
error = std::move(postponed_error); error = std::move(postponed_error);
@ -768,7 +766,7 @@ input_curl_available(InputStream *is)
} }
inline size_t inline size_t
CurlInputStream::Read(void *ptr, size_t size, Error &error) CurlInputStream::Read(void *ptr, size_t read_size, Error &error)
{ {
size_t nbytes; size_t nbytes;
@ -778,22 +776,22 @@ CurlInputStream::Read(void *ptr, size_t size, Error &error)
if (!FillBuffer(error)) if (!FillBuffer(error))
return 0; return 0;
nbytes = read_from_buffer(icy, buffer, ptr, size); nbytes = read_from_buffer(icy, buffer, ptr, read_size);
} while (nbytes == 0); } while (nbytes == 0);
if (icy.IsDefined()) if (icy.IsDefined())
CopyIcyTag(); CopyIcyTag();
base.offset += (InputPlugin::offset_type)nbytes; offset += (InputPlugin::offset_type)nbytes;
if (paused && GetTotalBufferSize() < CURL_RESUME_AT) { if (paused && GetTotalBufferSize() < CURL_RESUME_AT) {
base.mutex.unlock(); mutex.unlock();
BlockingCall(io_thread_get(), [this](){ BlockingCall(io_thread_get(), [this](){
Resume(); Resume();
}); });
base.mutex.lock(); mutex.lock();
} }
return nbytes; return nbytes;
@ -828,11 +826,11 @@ CurlInputStream::HeaderReceived(const char *name, std::string &&value)
if (StringEqualsCaseASCII(name, "accept-ranges")) { if (StringEqualsCaseASCII(name, "accept-ranges")) {
/* a stream with icy-metadata is not seekable */ /* a stream with icy-metadata is not seekable */
if (!icy.IsDefined()) if (!icy.IsDefined())
base.seekable = true; seekable = true;
} else if (StringEqualsCaseASCII(name, "content-length")) { } else if (StringEqualsCaseASCII(name, "content-length")) {
base.size = base.offset + ParseUint64(value.c_str()); size = offset + ParseUint64(value.c_str());
} else if (StringEqualsCaseASCII(name, "content-type")) { } else if (StringEqualsCaseASCII(name, "content-type")) {
base.SetMimeType(std::move(value)); SetMimeType(std::move(value));
} else if (StringEqualsCaseASCII(name, "icy-name") || } else if (StringEqualsCaseASCII(name, "icy-name") ||
StringEqualsCaseASCII(name, "ice-name") || StringEqualsCaseASCII(name, "ice-name") ||
StringEqualsCaseASCII(name, "x-audiocast-name")) { StringEqualsCaseASCII(name, "x-audiocast-name")) {
@ -856,7 +854,7 @@ CurlInputStream::HeaderReceived(const char *name, std::string &&value)
/* a stream with icy-metadata is not /* a stream with icy-metadata is not
seekable */ seekable */
base.seekable = false; seekable = false;
} }
} }
} }
@ -898,13 +896,13 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream)
} }
inline size_t inline size_t
CurlInputStream::DataReceived(const void *ptr, size_t size) CurlInputStream::DataReceived(const void *ptr, size_t received_size)
{ {
assert(size > 0); assert(received_size > 0);
const ScopeLock protect(base.mutex); const ScopeLock protect(mutex);
if (size > buffer.GetSpace()) { if (received_size > buffer.GetSpace()) {
paused = true; paused = true;
return CURL_WRITEFUNC_PAUSE; return CURL_WRITEFUNC_PAUSE;
} }
@ -912,23 +910,23 @@ CurlInputStream::DataReceived(const void *ptr, size_t size)
auto w = buffer.Write(); auto w = buffer.Write();
assert(!w.IsEmpty()); assert(!w.IsEmpty());
size_t nbytes = std::min(w.size, size); size_t nbytes = std::min(w.size, received_size);
memcpy(w.data, ptr, nbytes); memcpy(w.data, ptr, nbytes);
buffer.Append(nbytes); buffer.Append(nbytes);
const size_t remaining = size - nbytes; const size_t remaining = received_size - nbytes;
if (remaining > 0) { if (remaining > 0) {
w = buffer.Write(); w = buffer.Write();
assert(!w.IsEmpty()); assert(!w.IsEmpty());
assert(w.size >= remaining); assert(w.size >= remaining);
memcpy(w.data, (const uint8_t *)ptr + nbytes, remaining); memcpy(w.data, (const uint8_t *)ptr + nbytes, remaining);
buffer.Append(size); buffer.Append(received_size);
} }
base.ready = true; ready = true;
base.cond.broadcast(); cond.broadcast();
return size; return received_size;
} }
/** called by curl when new data is available */ /** called by curl when new data is available */
@ -986,7 +984,7 @@ CurlInputStream::InitEasy(Error &error)
curl_easy_setopt(easy, CURLOPT_PROXYUSERPWD, proxy_auth_str); curl_easy_setopt(easy, CURLOPT_PROXYUSERPWD, proxy_auth_str);
} }
CURLcode code = curl_easy_setopt(easy, CURLOPT_URL, base.GetURI()); CURLcode code = curl_easy_setopt(easy, CURLOPT_URL, GetURI());
if (code != CURLE_OK) { if (code != CURLE_OK) {
error.Format(curl_domain, code, error.Format(curl_domain, code,
"curl_easy_setopt() failed: %s", "curl_easy_setopt() failed: %s",
@ -1003,16 +1001,16 @@ CurlInputStream::InitEasy(Error &error)
} }
inline bool inline bool
CurlInputStream::Seek(InputPlugin::offset_type offset, int whence, CurlInputStream::Seek(InputPlugin::offset_type new_offset, int whence,
Error &error) Error &error)
{ {
assert(base.ready); assert(IsReady());
if (whence == SEEK_SET && offset == base.offset) if (whence == SEEK_SET && new_offset == offset)
/* no-op */ /* no-op */
return true; return true;
if (!base.seekable) if (!IsSeekable())
return false; return false;
/* calculate the absolute offset */ /* calculate the absolute offset */
@ -1022,52 +1020,52 @@ CurlInputStream::Seek(InputPlugin::offset_type offset, int whence,
break; break;
case SEEK_CUR: case SEEK_CUR:
offset += base.offset; new_offset += offset;
break; break;
case SEEK_END: case SEEK_END:
if (base.size < 0) if (size < 0)
/* stream size is not known */ /* stream size is not known */
return false; return false;
offset += base.size; new_offset += size;
break; break;
default: default:
return false; return false;
} }
if (offset < 0) if (new_offset < 0)
return false; return false;
/* check if we can fast-forward the buffer */ /* check if we can fast-forward the buffer */
while (offset > base.offset) { while (new_offset > offset) {
auto r = buffer.Read(); auto r = buffer.Read();
if (r.IsEmpty()) if (r.IsEmpty())
break; break;
const size_t nbytes = const size_t nbytes =
offset - base.offset < (InputPlugin::offset_type)r.size new_offset - offset < (InputPlugin::offset_type)r.size
? offset - base.offset ? new_offset - offset
: r.size; : r.size;
buffer.Consume(nbytes); buffer.Consume(nbytes);
base.offset += nbytes; offset += nbytes;
} }
if (offset == base.offset) if (new_offset == offset)
return true; return true;
/* close the old connection and open a new one */ /* close the old connection and open a new one */
base.mutex.unlock(); mutex.unlock();
FreeEasyIndirect(); FreeEasyIndirect();
buffer.Clear(); buffer.Clear();
base.offset = offset; offset = new_offset;
if (base.offset == base.size) { if (offset == size) {
/* seek to EOF: simulate empty result; avoid /* seek to EOF: simulate empty result; avoid
triggering a "416 Requested Range Not Satisfiable" triggering a "416 Requested Range Not Satisfiable"
response */ response */
@ -1079,18 +1077,18 @@ CurlInputStream::Seek(InputPlugin::offset_type offset, int whence,
/* send the "Range" header */ /* send the "Range" header */
if (base.offset > 0) { if (offset > 0) {
sprintf(range, "%lld-", (long long)base.offset); sprintf(range, "%lld-", (long long)offset);
curl_easy_setopt(easy, CURLOPT_RANGE, range); curl_easy_setopt(easy, CURLOPT_RANGE, range);
} }
base.ready = false; ready = false;
if (!input_curl_easy_add_indirect(this, error)) if (!input_curl_easy_add_indirect(this, error))
return false; return false;
base.mutex.lock(); mutex.lock();
base.WaitReady(); WaitReady();
if (postponed_error.IsDefined()) { if (postponed_error.IsDefined()) {
error = std::move(postponed_error); error = std::move(postponed_error);
@ -1127,7 +1125,7 @@ CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond,
return nullptr; return nullptr;
} }
return &c->base; return c;
} }
static InputStream * static InputStream *

View File

@ -36,9 +36,7 @@ extern "C" {
#include <stdio.h> #include <stdio.h>
class DespotifyInputStream { class DespotifyInputStream final : public InputStream {
InputStream base;
struct despotify_session *session; struct despotify_session *session;
struct ds_track *track; struct ds_track *track;
Tag tag; Tag tag;
@ -46,11 +44,11 @@ class DespotifyInputStream {
size_t len_available; size_t len_available;
bool eof; bool eof;
DespotifyInputStream(const char *uri, DespotifyInputStream(const char *_uri,
Mutex &mutex, Cond &cond, Mutex &_mutex, Cond &_cond,
despotify_session *_session, despotify_session *_session,
ds_track *_track) ds_track *_track)
:base(input_plugin_despotify, uri, mutex, cond), :InputStream(input_plugin_despotify, _uri, _mutex, _cond),
session(_session), track(_track), session(_session), track(_track),
tag(mpd_despotify_tag_from_track(*track)), tag(mpd_despotify_tag_from_track(*track)),
len_available(0), eof(false) { len_available(0), eof(false) {
@ -58,8 +56,8 @@ class DespotifyInputStream {
memset(&pcm, 0, sizeof(pcm)); memset(&pcm, 0, sizeof(pcm));
/* Despotify outputs pcm data */ /* Despotify outputs pcm data */
base.SetMimeType("audio/x-mpd-cdda-pcm"); SetMimeType("audio/x-mpd-cdda-pcm");
base.SetReady(); SetReady();
} }
public: public:
@ -190,7 +188,7 @@ DespotifyInputStream::Open(const char *url,
return nullptr; return nullptr;
} }
return &ctx->base; return ctx;
} }
static InputStream * static InputStream *
@ -200,16 +198,17 @@ input_despotify_open(const char *url, Mutex &mutex, Cond &cond, Error &error)
} }
inline size_t inline size_t
DespotifyInputStream::Read(void *ptr, size_t size, gcc_unused Error &error) DespotifyInputStream::Read(void *ptr, size_t read_size,
gcc_unused Error &error)
{ {
if (len_available == 0) if (len_available == 0)
FillBuffer(); FillBuffer();
size_t to_cpy = std::min(size, len_available); size_t to_cpy = std::min(read_size, len_available);
memcpy(ptr, pcm.buf, to_cpy); memcpy(ptr, pcm.buf, to_cpy);
len_available -= to_cpy; len_available -= to_cpy;
base.offset += to_cpy; offset += to_cpy;
return to_cpy; return to_cpy;
} }

View File

@ -33,26 +33,24 @@ extern "C" {
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
} }
struct FfmpegInputStream { struct FfmpegInputStream final : public InputStream {
InputStream base;
AVIOContext *h; AVIOContext *h;
bool eof; bool eof;
FfmpegInputStream(const char *uri, Mutex &mutex, Cond &cond, FfmpegInputStream(const char *_uri, Mutex &_mutex, Cond &_cond,
AVIOContext *_h) AVIOContext *_h)
:base(input_plugin_ffmpeg, uri, mutex, cond), :InputStream(input_plugin_ffmpeg, _uri, _mutex, _cond),
h(_h), eof(false) { h(_h), eof(false) {
base.ready = true; seekable = (h->seekable & AVIO_SEEKABLE_NORMAL) != 0;
base.seekable = (h->seekable & AVIO_SEEKABLE_NORMAL) != 0; size = avio_size(h);
base.size = avio_size(h);
/* hack to make MPD select the "ffmpeg" decoder plugin /* hack to make MPD select the "ffmpeg" decoder plugin
- since avio.h doesn't tell us the MIME type of the - since avio.h doesn't tell us the MIME type of the
resource, we can't select a decoder plugin, but the resource, we can't select a decoder plugin, but the
"ffmpeg" plugin is quite good at auto-detection */ "ffmpeg" plugin is quite good at auto-detection */
base.SetMimeType("audio/x-mpd-ffmpeg"); SetMimeType("audio/x-mpd-ffmpeg");
SetReady();
} }
~FfmpegInputStream() { ~FfmpegInputStream() {
@ -105,8 +103,7 @@ input_ffmpeg_open(const char *uri,
return nullptr; return nullptr;
} }
auto *i = new FfmpegInputStream(uri, mutex, cond, h); return new FfmpegInputStream(uri, mutex, cond, h);
return &i->base;
} }
static size_t static size_t

View File

@ -33,18 +33,16 @@
static constexpr Domain file_domain("file"); static constexpr Domain file_domain("file");
struct FileInputStream { struct FileInputStream final : public InputStream {
InputStream base;
int fd; int fd;
FileInputStream(const char *path, int _fd, off_t size, FileInputStream(const char *path, int _fd, off_t _size,
Mutex &mutex, Cond &cond) Mutex &_mutex, Cond &_cond)
:base(input_plugin_file, path, mutex, cond), :InputStream(input_plugin_file, path, _mutex, _cond),
fd(_fd) { fd(_fd) {
base.size = size; size = _size;
base.seekable = true; seekable = true;
base.SetReady(); SetReady();
} }
~FileInputStream() { ~FileInputStream() {
@ -88,9 +86,7 @@ input_file_open(const char *filename,
posix_fadvise(fd, (off_t)0, st.st_size, POSIX_FADV_SEQUENTIAL); posix_fadvise(fd, (off_t)0, st.st_size, POSIX_FADV_SEQUENTIAL);
#endif #endif
FileInputStream *fis = new FileInputStream(filename, fd, st.st_size, return new FileInputStream(filename, fd, st.st_size, mutex, cond);
mutex, cond);
return &fis->base;
} }
static bool static bool

View File

@ -33,8 +33,8 @@ class MmsInputStream final : public ThreadInputStream {
mmsx_t *mms; mmsx_t *mms;
public: public:
MmsInputStream(const char *uri, Mutex &mutex, Cond &cond) MmsInputStream(const char *_uri, Mutex &_mutex, Cond &_cond)
:ThreadInputStream(input_plugin_mms, uri, mutex, cond, :ThreadInputStream(input_plugin_mms, _uri, _mutex, _cond,
MMS_BUFFER_SIZE) { MMS_BUFFER_SIZE) {
} }
@ -89,9 +89,9 @@ input_mms_open(const char *url,
} }
size_t size_t
MmsInputStream::Read(void *ptr, size_t size, Error &error) MmsInputStream::Read(void *ptr, size_t read_size, Error &error)
{ {
int nbytes = mmsx_read(nullptr, mms, (char *)ptr, size); int nbytes = mmsx_read(nullptr, mms, (char *)ptr, read_size);
if (nbytes <= 0) { if (nbytes <= 0) {
if (nbytes < 0) if (nbytes < 0)
error.SetErrno("mmsx_read() failed"); error.SetErrno("mmsx_read() failed");

View File

@ -33,22 +33,20 @@ extern "C" {
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
class NfsInputStream { class NfsInputStream final : public InputStream {
InputStream base;
nfs_context *ctx; nfs_context *ctx;
nfsfh *fh; nfsfh *fh;
public: public:
NfsInputStream(const char *uri, NfsInputStream(const char *_uri,
Mutex &mutex, Cond &cond, Mutex &_mutex, Cond &_cond,
nfs_context *_ctx, nfsfh *_fh, nfs_context *_ctx, nfsfh *_fh,
InputStream::offset_type size) InputStream::offset_type _size)
:base(input_plugin_nfs, uri, mutex, cond), :InputStream(input_plugin_nfs, _uri, _mutex, _cond),
ctx(_ctx), fh(_fh) { ctx(_ctx), fh(_fh) {
base.ready = true; seekable = true;
base.seekable = true; size = _size;
base.size = size; SetReady();
} }
~NfsInputStream() { ~NfsInputStream() {
@ -56,16 +54,12 @@ public:
nfs_destroy_context(ctx); nfs_destroy_context(ctx);
} }
InputStream *GetBase() {
return &base;
}
bool IsEOF() const { bool IsEOF() const {
return base.offset >= base.size; return offset >= size;
} }
size_t Read(void *ptr, size_t size, Error &error) { size_t Read(void *ptr, size_t read_size, Error &error) {
int nbytes = nfs_read(ctx, fh, size, (char *)ptr); int nbytes = nfs_read(ctx, fh, read_size, (char *)ptr);
if (nbytes < 0) { if (nbytes < 0) {
error.SetErrno(-nbytes, "nfs_read() failed"); error.SetErrno(-nbytes, "nfs_read() failed");
nbytes = 0; nbytes = 0;
@ -74,15 +68,16 @@ public:
return nbytes; return nbytes;
} }
bool Seek(InputStream::offset_type offset, int whence, Error &error) { bool Seek(InputStream::offset_type new_offset, int whence, Error &error) {
uint64_t current_offset; uint64_t current_offset;
int result = nfs_lseek(ctx, fh, offset, whence, &current_offset); int result = nfs_lseek(ctx, fh, new_offset, whence,
&current_offset);
if (result < 0) { if (result < 0) {
error.SetErrno(-result, "smbc_lseek() failed"); error.SetErrno(-result, "smbc_lseek() failed");
return false; return false;
} }
base.offset = current_offset; offset = current_offset;
return true; return true;
} }
}; };
@ -150,8 +145,7 @@ input_nfs_open(const char *uri,
return nullptr; return nullptr;
} }
auto is = new NfsInputStream(uri, mutex, cond, ctx, fh, st.st_size); return new NfsInputStream(uri, mutex, cond, ctx, fh, st.st_size);
return is->GetBase();
} }
static size_t static size_t

View File

@ -28,9 +28,7 @@
extern const InputPlugin rewind_input_plugin; extern const InputPlugin rewind_input_plugin;
class RewindInputStream { class RewindInputStream final : public InputStream {
InputStream base;
InputStream *input; InputStream *input;
/** /**
@ -56,8 +54,8 @@ class RewindInputStream {
public: public:
RewindInputStream(InputStream *_input) RewindInputStream(InputStream *_input)
:base(rewind_input_plugin, _input->GetURI(), :InputStream(rewind_input_plugin, _input->GetURI(),
_input->mutex, _input->cond), _input->mutex, _input->cond),
input(_input), tail(0) { input(_input), tail(0) {
} }
@ -65,10 +63,6 @@ public:
input->Close(); input->Close();
} }
InputStream *GetBase() {
return &base;
}
bool Check(Error &error) { bool Check(Error &error) {
return input->Check(error); return input->Check(error);
} }
@ -100,7 +94,7 @@ private:
* buffer contain more data for the next read operation? * buffer contain more data for the next read operation?
*/ */
bool ReadingFromBuffer() const { bool ReadingFromBuffer() const {
return tail > 0 && base.offset < input->offset; return tail > 0 && offset < input->offset;
} }
/** /**
@ -110,21 +104,20 @@ private:
* attributes. * attributes.
*/ */
void CopyAttributes() { void CopyAttributes() {
InputStream *dest = &base;
const InputStream *src = input; const InputStream *src = input;
assert(dest != src); assert(src != this);
if (!dest->IsReady() && src->IsReady()) { if (!IsReady() && src->IsReady()) {
if (src->HasMimeType()) if (src->HasMimeType())
dest->SetMimeType(src->GetMimeType()); SetMimeType(src->GetMimeType());
dest->size = src->GetSize(); size = src->GetSize();
dest->seekable = src->IsSeekable(); seekable = src->IsSeekable();
dest->SetReady(); SetReady();
} }
dest->offset = src->offset; offset = src->offset;
} }
}; };
@ -169,31 +162,31 @@ input_rewind_available(InputStream *is)
} }
inline size_t inline size_t
RewindInputStream::Read(void *ptr, size_t size, Error &error) RewindInputStream::Read(void *ptr, size_t read_size, Error &error)
{ {
if (ReadingFromBuffer()) { if (ReadingFromBuffer()) {
/* buffered read */ /* buffered read */
assert(head == (size_t)base.offset); assert(head == (size_t)offset);
assert(tail == (size_t)input->offset); assert(tail == (size_t)input->offset);
if (size > tail - head) if (read_size > tail - head)
size = tail - head; read_size = tail - head;
memcpy(ptr, buffer + head, size); memcpy(ptr, buffer + head, read_size);
head += size; head += read_size;
base.offset += size; offset += read_size;
return size; return read_size;
} else { } else {
/* pass method call to underlying stream */ /* pass method call to underlying stream */
size_t nbytes = input->Read(ptr, size, error); size_t nbytes = input->Read(ptr, read_size, error);
if (input->offset > (InputPlugin::offset_type)sizeof(buffer)) if (input->offset > (InputPlugin::offset_type)sizeof(buffer))
/* disable buffering */ /* disable buffering */
tail = 0; tail = 0;
else if (tail == (size_t)base.offset) { else if (tail == (size_t)offset) {
/* append to buffer */ /* append to buffer */
memcpy(buffer + tail, ptr, nbytes); memcpy(buffer + tail, ptr, nbytes);
@ -226,25 +219,25 @@ input_rewind_eof(InputStream *is)
} }
inline bool inline bool
RewindInputStream::Seek(InputPlugin::offset_type offset, int whence, RewindInputStream::Seek(InputPlugin::offset_type new_offset, int whence,
Error &error) Error &error)
{ {
assert(base.IsReady()); assert(IsReady());
if (whence == SEEK_SET && tail > 0 && if (whence == SEEK_SET && tail > 0 &&
offset <= (InputPlugin::offset_type)tail) { new_offset <= (InputPlugin::offset_type)tail) {
/* buffered seek */ /* buffered seek */
assert(!ReadingFromBuffer() || assert(!ReadingFromBuffer() ||
head == (size_t)base.offset); head == (size_t)offset);
assert(tail == (size_t)input->offset); assert(tail == (size_t)input->offset);
head = (size_t)offset; head = (size_t)new_offset;
base.offset = offset; offset = new_offset;
return true; return true;
} else { } else {
bool success = input->Seek(offset, whence, error); bool success = input->Seek(new_offset, whence, error);
CopyAttributes(); CopyAttributes();
/* disable the buffer, because input has left the /* disable the buffer, because input has left the
@ -290,6 +283,5 @@ input_rewind_open(InputStream *is)
/* seekable resources don't need this plugin */ /* seekable resources don't need this plugin */
return is; return is;
RewindInputStream *c = new RewindInputStream(is); return new RewindInputStream(is);
return c->GetBase();
} }

View File

@ -28,21 +28,19 @@
#include <libsmbclient.h> #include <libsmbclient.h>
class SmbclientInputStream { class SmbclientInputStream final : public InputStream {
InputStream base;
SMBCCTX *ctx; SMBCCTX *ctx;
int fd; int fd;
public: public:
SmbclientInputStream(const char *uri, SmbclientInputStream(const char *_uri,
Mutex &mutex, Cond &cond, Mutex &_mutex, Cond &_cond,
SMBCCTX *_ctx, int _fd, const struct stat &st) SMBCCTX *_ctx, int _fd, const struct stat &st)
:base(input_plugin_smbclient, uri, mutex, cond), :InputStream(input_plugin_smbclient, _uri, _mutex, _cond),
ctx(_ctx), fd(_fd) { ctx(_ctx), fd(_fd) {
base.ready = true; seekable = true;
base.seekable = true; size = st.st_size;
base.size = st.st_size; SetReady();
} }
~SmbclientInputStream() { ~SmbclientInputStream() {
@ -52,17 +50,13 @@ public:
smbclient_mutex.unlock(); smbclient_mutex.unlock();
} }
InputStream *GetBase() {
return &base;
}
bool IsEOF() const { bool IsEOF() const {
return base.offset >= base.size; return offset >= size;
} }
size_t Read(void *ptr, size_t size, Error &error) { size_t Read(void *ptr, size_t read_size, Error &error) {
smbclient_mutex.lock(); smbclient_mutex.lock();
ssize_t nbytes = smbc_read(fd, ptr, size); ssize_t nbytes = smbc_read(fd, ptr, read_size);
smbclient_mutex.unlock(); smbclient_mutex.unlock();
if (nbytes < 0) { if (nbytes < 0) {
error.SetErrno("smbc_read() failed"); error.SetErrno("smbc_read() failed");
@ -72,16 +66,16 @@ public:
return nbytes; return nbytes;
} }
bool Seek(InputStream::offset_type offset, int whence, Error &error) { bool Seek(InputStream::offset_type new_offset, int whence, Error &error) {
smbclient_mutex.lock(); smbclient_mutex.lock();
off_t result = smbc_lseek(fd, offset, whence); off_t result = smbc_lseek(fd, new_offset, whence);
smbclient_mutex.unlock(); smbclient_mutex.unlock();
if (result < 0) { if (result < 0) {
error.SetErrno("smbc_lseek() failed"); error.SetErrno("smbc_lseek() failed");
return false; return false;
} }
base.offset = result; offset = result;
return true; return true;
} }
}; };
@ -144,8 +138,7 @@ input_smbclient_open(const char *uri,
return nullptr; return nullptr;
} }
auto s = new SmbclientInputStream(uri, mutex, cond, ctx, fd, st); return new SmbclientInputStream(uri, mutex, cond, ctx, fd, st);
return s->GetBase();
} }
static size_t static size_t