input/InputStream: migrate from class Error to C++ exceptions
This commit is contained in:
parent
597e59f10d
commit
8c744efd56
@ -68,8 +68,12 @@ public:
|
|||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
is->LockRewind(IgnoreError());
|
try {
|
||||||
|
is->LockRewind();
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* now try the stream_tag() method */
|
/* now try the stream_tag() method */
|
||||||
return plugin.ScanStream(*is, handler, handler_ctx);
|
return plugin.ScanStream(*is, handler, handler_ctx);
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,7 +65,10 @@ tag_stream_scan(InputStream &is, const TagHandler &handler, void *ctx)
|
|||||||
|
|
||||||
return decoder_plugins_try([suffix, mime, &is,
|
return decoder_plugins_try([suffix, mime, &is,
|
||||||
&handler, ctx](const DecoderPlugin &plugin){
|
&handler, ctx](const DecoderPlugin &plugin){
|
||||||
is.LockRewind(IgnoreError());
|
try {
|
||||||
|
is.LockRewind();
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
}
|
||||||
|
|
||||||
return CheckDecoderPlugin(plugin, suffix, mime) &&
|
return CheckDecoderPlugin(plugin, suffix, mime) &&
|
||||||
plugin.ScanStream(is, handler, ctx);
|
plugin.ScanStream(is, handler, ctx);
|
||||||
|
@ -30,8 +30,6 @@
|
|||||||
#include "input/LocalOpen.hxx"
|
#include "input/LocalOpen.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "util/RefCount.hxx"
|
#include "util/RefCount.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/Domain.hxx"
|
|
||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
|
|
||||||
#include <bzlib.h>
|
#include <bzlib.h>
|
||||||
@ -96,15 +94,13 @@ public:
|
|||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() override;
|
bool IsEOF() override;
|
||||||
size_t Read(void *ptr, size_t size, Error &error) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Open();
|
void Open();
|
||||||
bool FillBuffer(Error &error);
|
bool FillBuffer();
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr Domain bz2_domain("bz2");
|
|
||||||
|
|
||||||
/* single archive handling allocation helpers */
|
/* single archive handling allocation helpers */
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@ -161,13 +157,12 @@ Bzip2ArchiveFile::OpenStream(const char *path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
Bzip2InputStream::FillBuffer(Error &error)
|
Bzip2InputStream::FillBuffer()
|
||||||
{
|
{
|
||||||
if (bzstream.avail_in > 0)
|
if (bzstream.avail_in > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
size_t count = archive->istream->Read(buffer, sizeof(buffer),
|
size_t count = archive->istream->Read(buffer, sizeof(buffer));
|
||||||
error);
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -177,7 +172,7 @@ Bzip2InputStream::FillBuffer(Error &error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
Bzip2InputStream::Read(void *ptr, size_t length, Error &error)
|
Bzip2InputStream::Read(void *ptr, size_t length)
|
||||||
{
|
{
|
||||||
int bz_result;
|
int bz_result;
|
||||||
size_t nbytes = 0;
|
size_t nbytes = 0;
|
||||||
@ -189,7 +184,7 @@ Bzip2InputStream::Read(void *ptr, size_t length, Error &error)
|
|||||||
bzstream.avail_out = length;
|
bzstream.avail_out = length;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (!FillBuffer(error))
|
if (!FillBuffer())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bz_result = BZ2_bzDecompress(&bzstream);
|
bz_result = BZ2_bzDecompress(&bzstream);
|
||||||
@ -199,11 +194,8 @@ Bzip2InputStream::Read(void *ptr, size_t length, Error &error)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bz_result != BZ_OK) {
|
if (bz_result != BZ_OK)
|
||||||
error.Set(bz2_domain, bz_result,
|
throw std::runtime_error("BZ2_bzDecompress() has failed");
|
||||||
"BZ2_bzDecompress() has failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} while (bzstream.avail_out == length);
|
} while (bzstream.avail_out == length);
|
||||||
|
|
||||||
nbytes = length - bzstream.avail_out;
|
nbytes = length - bzstream.avail_out;
|
||||||
|
@ -30,8 +30,6 @@
|
|||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
#include "util/RefCount.hxx"
|
#include "util/RefCount.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/Domain.hxx"
|
|
||||||
|
|
||||||
#include <cdio/iso9660.h>
|
#include <cdio/iso9660.h>
|
||||||
|
|
||||||
@ -82,8 +80,6 @@ public:
|
|||||||
Mutex &mutex, Cond &cond) override;
|
Mutex &mutex, Cond &cond) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr Domain iso9660_domain("iso9660");
|
|
||||||
|
|
||||||
/* archive open && listing routine */
|
/* archive open && listing routine */
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@ -167,7 +163,7 @@ public:
|
|||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() override;
|
bool IsEOF() override;
|
||||||
size_t Read(void *ptr, size_t size, Error &error) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
InputStream *
|
InputStream *
|
||||||
@ -184,7 +180,7 @@ Iso9660ArchiveFile::OpenStream(const char *pathname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
Iso9660InputStream::Read(void *ptr, size_t read_size, Error &error)
|
Iso9660InputStream::Read(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
int readed = 0;
|
int readed = 0;
|
||||||
int no_blocks, cur_block;
|
int no_blocks, cur_block;
|
||||||
@ -204,12 +200,10 @@ Iso9660InputStream::Read(void *ptr, size_t read_size, Error &error)
|
|||||||
readed = archive.SeekRead(ptr, statbuf->lsn + cur_block,
|
readed = archive.SeekRead(ptr, statbuf->lsn + cur_block,
|
||||||
no_blocks);
|
no_blocks);
|
||||||
|
|
||||||
if (readed != no_blocks * ISO_BLOCKSIZE) {
|
if (readed != no_blocks * ISO_BLOCKSIZE)
|
||||||
error.Format(iso9660_domain,
|
throw FormatRuntimeError("error reading ISO file at lsn %lu",
|
||||||
"error reading ISO file at lsn %lu",
|
|
||||||
(unsigned long)cur_block);
|
(unsigned long)cur_block);
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (left_bytes < read_size) {
|
if (left_bytes < read_size) {
|
||||||
readed = left_bytes;
|
readed = left_bytes;
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,6 @@
|
|||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
#include "util/RefCount.hxx"
|
#include "util/RefCount.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/Domain.hxx"
|
|
||||||
|
|
||||||
#include <zzip/zzip.h>
|
#include <zzip/zzip.h>
|
||||||
|
|
||||||
@ -63,8 +61,6 @@ public:
|
|||||||
Mutex &mutex, Cond &cond) override;
|
Mutex &mutex, Cond &cond) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr Domain zzip_domain("zzip");
|
|
||||||
|
|
||||||
/* archive open && listing routine */
|
/* archive open && listing routine */
|
||||||
|
|
||||||
static ArchiveFile *
|
static ArchiveFile *
|
||||||
@ -121,8 +117,8 @@ struct ZzipInputStream final : public InputStream {
|
|||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() override;
|
bool IsEOF() override;
|
||||||
size_t Read(void *ptr, size_t size, Error &error) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
bool Seek(offset_type offset, Error &error) override;
|
void Seek(offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
InputStream *
|
InputStream *
|
||||||
@ -140,13 +136,11 @@ ZzipArchiveFile::OpenStream(const char *pathname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ZzipInputStream::Read(void *ptr, size_t read_size, Error &error)
|
ZzipInputStream::Read(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
int ret = zzip_file_read(file, ptr, read_size);
|
int ret = zzip_file_read(file, ptr, read_size);
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
error.Set(zzip_domain, "zzip_file_read() has failed");
|
throw std::runtime_error("zzip_file_read() has failed");
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = zzip_tell(file);
|
offset = zzip_tell(file);
|
||||||
return ret;
|
return ret;
|
||||||
@ -158,17 +152,14 @@ ZzipInputStream::IsEOF()
|
|||||||
return offset_type(zzip_tell(file)) == size;
|
return offset_type(zzip_tell(file)) == size;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
ZzipInputStream::Seek(offset_type new_offset, Error &error)
|
ZzipInputStream::Seek(offset_type new_offset)
|
||||||
{
|
{
|
||||||
zzip_off_t ofs = zzip_seek(file, new_offset, SEEK_SET);
|
zzip_off_t ofs = zzip_seek(file, new_offset, SEEK_SET);
|
||||||
if (ofs < 0) {
|
if (ofs < 0)
|
||||||
error.Set(zzip_domain, "zzip_seek() has failed");
|
throw std::runtime_error("zzip_seek() has failed");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = ofs;
|
offset = ofs;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* exported structures */
|
/* exported structures */
|
||||||
|
@ -334,15 +334,8 @@ try {
|
|||||||
is.cond.wait(is.mutex);
|
is.cond.wait(is.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error error;
|
size_t nbytes = is.Read(buffer, length);
|
||||||
size_t nbytes = is.Read(buffer, length, error);
|
assert(nbytes > 0 || is.IsEOF());
|
||||||
assert(nbytes == 0 || !error.IsDefined());
|
|
||||||
assert(nbytes > 0 || error.IsDefined() || is.IsEOF());
|
|
||||||
|
|
||||||
lock.Unlock();
|
|
||||||
|
|
||||||
if (gcc_unlikely(nbytes == 0 && error.IsDefined()))
|
|
||||||
LogError(error);
|
|
||||||
|
|
||||||
return nbytes;
|
return nbytes;
|
||||||
} catch (const std::runtime_error &e) {
|
} catch (const std::runtime_error &e) {
|
||||||
|
@ -73,9 +73,7 @@ decoder_input_stream_open(DecoderControl &dc, const char *uri)
|
|||||||
is->Update();
|
is->Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error error;
|
is->Check();
|
||||||
if (!is->Check(error))
|
|
||||||
throw error;
|
|
||||||
|
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
@ -112,7 +110,10 @@ decoder_stream_decode(const DecoderPlugin &plugin,
|
|||||||
throw StopDecoder();
|
throw StopDecoder();
|
||||||
|
|
||||||
/* rewind the stream, so each plugin gets a fresh start */
|
/* rewind the stream, so each plugin gets a fresh start */
|
||||||
input_stream.Rewind(IgnoreError());
|
try {
|
||||||
|
input_stream.Rewind();
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const ScopeUnlock unlock(decoder.dc.mutex);
|
const ScopeUnlock unlock(decoder.dc.mutex);
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
#include <audiofile.h>
|
#include <audiofile.h>
|
||||||
#include <af_vfs.h>
|
#include <af_vfs.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@ -115,11 +117,11 @@ audiofile_file_seek(AFvirtualfile *vfile, AFfileoffset _offset,
|
|||||||
if (is_relative)
|
if (is_relative)
|
||||||
offset += is.GetOffset();
|
offset += is.GetOffset();
|
||||||
|
|
||||||
Error error;
|
try {
|
||||||
if (is.LockSeek(offset, error)) {
|
is.LockSeek(offset);
|
||||||
return is.GetOffset();
|
return is.GetOffset();
|
||||||
} else {
|
} catch (const std::runtime_error &e) {
|
||||||
LogError(error, "Seek failed");
|
LogError(e, "Seek failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,15 +28,16 @@
|
|||||||
#include "../DecoderAPI.hxx"
|
#include "../DecoderAPI.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "tag/TagId3.hxx"
|
#include "tag/TagId3.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#ifdef ENABLE_ID3TAG
|
#ifdef ENABLE_ID3TAG
|
||||||
#include <id3tag.h>
|
#include <id3tag.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DsdId::Equals(const char *s) const
|
DsdId::Equals(const char *s) const
|
||||||
{
|
{
|
||||||
@ -53,8 +54,13 @@ bool
|
|||||||
dsdlib_skip_to(Decoder *decoder, InputStream &is,
|
dsdlib_skip_to(Decoder *decoder, InputStream &is,
|
||||||
offset_type offset)
|
offset_type offset)
|
||||||
{
|
{
|
||||||
if (is.IsSeekable())
|
if (is.IsSeekable()) {
|
||||||
return is.LockSeek(offset, IgnoreError());
|
try {
|
||||||
|
is.LockSeek(offset);
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is.GetOffset() > offset)
|
if (is.GetOffset() > offset)
|
||||||
return false;
|
return false;
|
||||||
@ -72,8 +78,13 @@ dsdlib_skip(Decoder *decoder, InputStream &is,
|
|||||||
if (delta == 0)
|
if (delta == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (is.IsSeekable())
|
if (is.IsSeekable()) {
|
||||||
return is.LockSeek(is.GetOffset() + delta, IgnoreError());
|
try {
|
||||||
|
is.LockSeek(is.GetOffset() + delta);
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (delta > 1024 * 1024)
|
if (delta > 1024 * 1024)
|
||||||
/* don't skip more than one megabyte; it would be too
|
/* don't skip more than one megabyte; it would be too
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
#include <neaacdec.h>
|
#include <neaacdec.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -192,7 +194,10 @@ faad_song_duration(DecoderBuffer &buffer, InputStream &is)
|
|||||||
|
|
||||||
auto song_length = adts_song_duration(buffer);
|
auto song_length = adts_song_duration(buffer);
|
||||||
|
|
||||||
is.LockSeek(tagsize, IgnoreError());
|
try {
|
||||||
|
is.LockSeek(tagsize);
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
}
|
||||||
|
|
||||||
buffer.Clear();
|
buffer.Clear();
|
||||||
|
|
||||||
|
@ -460,9 +460,15 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
|
|||||||
|
|
||||||
unsigned char buffer[BUFFER_SIZE];
|
unsigned char buffer[BUFFER_SIZE];
|
||||||
size_t nbytes = decoder_read(decoder, is, buffer, BUFFER_SIZE);
|
size_t nbytes = decoder_read(decoder, is, buffer, BUFFER_SIZE);
|
||||||
if (nbytes <= PADDING || !is.LockRewind(IgnoreError()))
|
if (nbytes <= PADDING)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
try {
|
||||||
|
is.LockRewind();
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/* some ffmpeg parsers (e.g. ac3_parser.c) read a few bytes
|
/* some ffmpeg parsers (e.g. ac3_parser.c) read a few bytes
|
||||||
beyond the declared buffer limit, which makes valgrind
|
beyond the declared buffer limit, which makes valgrind
|
||||||
angry; this workaround removes some padding from the buffer
|
angry; this workaround removes some padding from the buffer
|
||||||
|
@ -24,7 +24,8 @@
|
|||||||
#include "FfmpegIo.hxx"
|
#include "FfmpegIo.hxx"
|
||||||
#include "../DecoderAPI.hxx"
|
#include "../DecoderAPI.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
AvioStream::~AvioStream()
|
AvioStream::~AvioStream()
|
||||||
{
|
{
|
||||||
@ -68,10 +69,12 @@ AvioStream::Seek(int64_t pos, int whence)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!input.LockSeek(pos, IgnoreError()))
|
try {
|
||||||
return -1;
|
input.LockSeek(pos);
|
||||||
|
|
||||||
return input.GetOffset();
|
return input.GetOffset();
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -330,7 +330,10 @@ oggflac_decode(Decoder &decoder, InputStream &input_stream)
|
|||||||
|
|
||||||
/* rewind the stream, because ogg_codec_detect() has
|
/* rewind the stream, because ogg_codec_detect() has
|
||||||
moved it */
|
moved it */
|
||||||
input_stream.LockRewind(IgnoreError());
|
try {
|
||||||
|
input_stream.LockRewind();
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
}
|
||||||
|
|
||||||
flac_decode_internal(decoder, input_stream, true);
|
flac_decode_internal(decoder, input_stream, true);
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,11 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "FlacIOHandle.hxx"
|
#include "FlacIOHandle.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@ -37,24 +38,29 @@ FlacIORead(void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
|
|||||||
/* libFLAC is very picky about short reads, and expects the IO
|
/* libFLAC is very picky about short reads, and expects the IO
|
||||||
callback to fill the whole buffer (undocumented!) */
|
callback to fill the whole buffer (undocumented!) */
|
||||||
|
|
||||||
Error error;
|
|
||||||
while (p < end) {
|
while (p < end) {
|
||||||
size_t nbytes = is->LockRead(p, end - p, error);
|
try {
|
||||||
if (nbytes == 0) {
|
size_t nbytes = is->LockRead(p, end - p);
|
||||||
if (!error.IsDefined())
|
if (nbytes == 0)
|
||||||
/* end of file */
|
/* end of file */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (error.IsDomain(errno_domain))
|
p += nbytes;
|
||||||
errno = error.GetCode();
|
|
||||||
else
|
#ifndef WIN32
|
||||||
/* just some random non-zero
|
} catch (const std::system_error &e) {
|
||||||
errno value */
|
errno = e.code().category() == std::system_category()
|
||||||
|
? e.code().value()
|
||||||
|
/* just some random non-zero errno
|
||||||
|
value */
|
||||||
|
: EINVAL;
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
/* just some random non-zero errno value */
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p += nbytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* libFLAC expects a clean errno after returning from the IO
|
/* libFLAC expects a clean errno after returning from the IO
|
||||||
@ -88,13 +94,13 @@ FlacIOSeek(FLAC__IOHandle handle, FLAC__int64 _offset, int whence)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error error;
|
try {
|
||||||
if (!is->LockSeek(offset, error)) {
|
is->LockSeek(offset);
|
||||||
LogError(error);
|
return 0;
|
||||||
|
} catch (const std::runtime_error &e) {
|
||||||
|
LogError(e);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__int64
|
static FLAC__int64
|
||||||
|
@ -22,10 +22,11 @@
|
|||||||
#include "FlacDomain.hxx"
|
#include "FlacDomain.hxx"
|
||||||
#include "../DecoderAPI.hxx"
|
#include "../DecoderAPI.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
FLAC__StreamDecoderReadStatus
|
FLAC__StreamDecoderReadStatus
|
||||||
FlacInput::Read(FLAC__byte buffer[], size_t *bytes)
|
FlacInput::Read(FLAC__byte buffer[], size_t *bytes)
|
||||||
{
|
{
|
||||||
@ -50,13 +51,13 @@ FlacInput::Seek(FLAC__uint64 absolute_byte_offset)
|
|||||||
if (!input_stream.IsSeekable())
|
if (!input_stream.IsSeekable())
|
||||||
return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
|
return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
::Error error;
|
try {
|
||||||
if (!input_stream.LockSeek(absolute_byte_offset, error)) {
|
input_stream.LockSeek(absolute_byte_offset);
|
||||||
LogError(error);
|
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
|
||||||
|
} catch (const std::runtime_error &e) {
|
||||||
|
LogError(e);
|
||||||
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
|
return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FLAC__StreamDecoderTellStatus
|
FLAC__StreamDecoderTellStatus
|
||||||
|
@ -39,6 +39,8 @@
|
|||||||
#include <id3tag.h>
|
#include <id3tag.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -217,9 +219,11 @@ MadDecoder::MadDecoder(Decoder *_decoder,
|
|||||||
inline bool
|
inline bool
|
||||||
MadDecoder::Seek(long offset)
|
MadDecoder::Seek(long offset)
|
||||||
{
|
{
|
||||||
Error error;
|
try {
|
||||||
if (!input_stream.LockSeek(offset, error))
|
input_stream.LockSeek(offset);
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
mad_stream_buffer(&stream, input_buffer, 0);
|
mad_stream_buffer(&stream, input_buffer, 0);
|
||||||
stream.error = MAD_ERROR_NONE;
|
stream.error = MAD_ERROR_NONE;
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
#include <mpc/mpcdec.h>
|
#include <mpc/mpcdec.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
struct mpc_decoder_data {
|
struct mpc_decoder_data {
|
||||||
@ -62,7 +64,12 @@ mpc_seek_cb(mpc_reader *reader, mpc_int32_t offset)
|
|||||||
struct mpc_decoder_data *data =
|
struct mpc_decoder_data *data =
|
||||||
(struct mpc_decoder_data *)reader->data;
|
(struct mpc_decoder_data *)reader->data;
|
||||||
|
|
||||||
return data->is.LockSeek(offset, IgnoreError());
|
try {
|
||||||
|
data->is.LockSeek(offset);
|
||||||
|
return true;
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mpc_int32_t
|
static mpc_int32_t
|
||||||
|
@ -21,7 +21,8 @@
|
|||||||
#include "OggDecoder.hxx"
|
#include "OggDecoder.hxx"
|
||||||
#include "lib/xiph/OggFind.hxx"
|
#include "lib/xiph/OggFind.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the end-of-stream packet and restore the previous file
|
* Load the end-of-stream packet and restore the previous file
|
||||||
@ -52,7 +53,10 @@ OggDecoder::LoadEndPacket(ogg_packet &packet) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* restore the previous file position */
|
/* restore the previous file position */
|
||||||
input_stream.LockSeek(old_offset, IgnoreError());
|
try {
|
||||||
|
input_stream.LockSeek(old_offset);
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -67,8 +71,8 @@ OggDecoder::LoadEndGranulePos() const
|
|||||||
return packet.granulepos;
|
return packet.granulepos;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
OggDecoder::SeekGranulePos(ogg_int64_t where_granulepos, Error &error)
|
OggDecoder::SeekGranulePos(ogg_int64_t where_granulepos)
|
||||||
{
|
{
|
||||||
assert(IsSeekable());
|
assert(IsSeekable());
|
||||||
|
|
||||||
@ -78,10 +82,7 @@ OggDecoder::SeekGranulePos(ogg_int64_t where_granulepos, Error &error)
|
|||||||
offset_type offset(where_granulepos * input_stream.GetSize()
|
offset_type offset(where_granulepos * input_stream.GetSize()
|
||||||
/ end_granulepos);
|
/ end_granulepos);
|
||||||
|
|
||||||
if (!input_stream.LockSeek(offset, error))
|
input_stream.LockSeek(offset);
|
||||||
return false;
|
|
||||||
|
|
||||||
PostSeek();
|
PostSeek();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,6 @@
|
|||||||
#include "lib/xiph/OggVisitor.hxx"
|
#include "lib/xiph/OggVisitor.hxx"
|
||||||
#include "decoder/Reader.hxx"
|
#include "decoder/Reader.hxx"
|
||||||
|
|
||||||
class Error;
|
|
||||||
|
|
||||||
class OggDecoder : public OggVisitor {
|
class OggDecoder : public OggVisitor {
|
||||||
ogg_int64_t end_granulepos;
|
ogg_int64_t end_granulepos;
|
||||||
|
|
||||||
@ -58,7 +56,7 @@ protected:
|
|||||||
return end_granulepos > 0;
|
return end_granulepos > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SeekGranulePos(ogg_int64_t where_granulepos, Error &error);
|
void SeekGranulePos(ogg_int64_t where_granulepos);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -261,7 +261,12 @@ MPDOpusDecoder::Seek(uint64_t where_frame)
|
|||||||
|
|
||||||
const ogg_int64_t where_granulepos(where_frame);
|
const ogg_int64_t where_granulepos(where_frame);
|
||||||
|
|
||||||
return SeekGranulePos(where_granulepos, IgnoreError());
|
try {
|
||||||
|
SeekGranulePos(where_granulepos);
|
||||||
|
return true;
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -273,7 +278,10 @@ mpd_opus_stream_decode(Decoder &decoder,
|
|||||||
|
|
||||||
/* rewind the stream, because ogg_codec_detect() has
|
/* rewind the stream, because ogg_codec_detect() has
|
||||||
moved it */
|
moved it */
|
||||||
input_stream.LockRewind(IgnoreError());
|
try {
|
||||||
|
input_stream.LockRewind();
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
}
|
||||||
|
|
||||||
DecoderReader reader(decoder, input_stream);
|
DecoderReader reader(decoder, input_stream);
|
||||||
|
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
#include "util/MimeType.hxx"
|
#include "util/MimeType.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -145,11 +147,11 @@ pcm_stream_decode(Decoder &decoder, InputStream &is)
|
|||||||
uint64_t frame = decoder_seek_where_frame(decoder);
|
uint64_t frame = decoder_seek_where_frame(decoder);
|
||||||
offset_type offset = frame * frame_size;
|
offset_type offset = frame * frame_size;
|
||||||
|
|
||||||
Error error;
|
try {
|
||||||
if (is.LockSeek(offset, error)) {
|
is.LockSeek(offset);
|
||||||
decoder_command_finished(decoder);
|
decoder_command_finished(decoder);
|
||||||
} else {
|
} catch (const std::runtime_error &e) {
|
||||||
LogError(error);
|
LogError(e);
|
||||||
decoder_seek_error(decoder);
|
decoder_seek_error(decoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <sndfile.h>
|
#include <sndfile.h>
|
||||||
|
|
||||||
static constexpr Domain sndfile_domain("sndfile");
|
static constexpr Domain sndfile_domain("sndfile");
|
||||||
@ -89,13 +91,13 @@ sndfile_vio_seek(sf_count_t _offset, int whence, void *user_data)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error error;
|
try {
|
||||||
if (!is.LockSeek(offset, error)) {
|
is.LockSeek(offset);
|
||||||
LogError(error, "Seek failed");
|
return is.GetOffset();
|
||||||
|
} catch (const std::runtime_error &e) {
|
||||||
|
LogError(e, "Seek failed");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return is.GetOffset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static sf_count_t
|
static sf_count_t
|
||||||
|
@ -126,11 +126,13 @@ VorbisDecoder::Seek(uint64_t where_frame)
|
|||||||
|
|
||||||
const ogg_int64_t where_granulepos(where_frame);
|
const ogg_int64_t where_granulepos(where_frame);
|
||||||
|
|
||||||
if (!SeekGranulePos(where_granulepos, IgnoreError()))
|
try {
|
||||||
return false;
|
SeekGranulePos(where_granulepos);
|
||||||
|
|
||||||
vorbis_synthesis_restart(&dsp);
|
vorbis_synthesis_restart(&dsp);
|
||||||
return true;
|
return true;
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -311,7 +313,10 @@ vorbis_stream_decode(Decoder &decoder,
|
|||||||
|
|
||||||
/* rewind the stream, because ogg_codec_detect() has
|
/* rewind the stream, because ogg_codec_detect() has
|
||||||
moved it */
|
moved it */
|
||||||
input_stream.LockRewind(IgnoreError());
|
try {
|
||||||
|
input_stream.LockRewind();
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
}
|
||||||
|
|
||||||
DecoderReader reader(decoder, input_stream);
|
DecoderReader reader(decoder, input_stream);
|
||||||
VorbisDecoder d(reader);
|
VorbisDecoder d(reader);
|
||||||
|
@ -400,7 +400,12 @@ wavpack_input_set_pos_abs(void *id, uint32_t pos)
|
|||||||
{
|
{
|
||||||
WavpackInput &wpi = *wpin(id);
|
WavpackInput &wpi = *wpin(id);
|
||||||
|
|
||||||
return wpi.is.LockSeek(pos, IgnoreError()) ? 0 : -1;
|
try {
|
||||||
|
wpi.is.LockSeek(pos);
|
||||||
|
return 0;
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -429,7 +434,12 @@ wavpack_input_set_pos_rel(void *id, int32_t delta, int mode)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return is.LockSeek(offset, IgnoreError()) ? 0 : -1;
|
try {
|
||||||
|
wpi.is.LockSeek(offset);
|
||||||
|
return 0;
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -78,16 +78,14 @@ AsyncInputStream::Resume()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
AsyncInputStream::Check(Error &)
|
AsyncInputStream::Check()
|
||||||
{
|
{
|
||||||
if (postponed_exception) {
|
if (postponed_exception) {
|
||||||
auto e = std::move(postponed_exception);
|
auto e = std::move(postponed_exception);
|
||||||
postponed_exception = std::exception_ptr();
|
postponed_exception = std::exception_ptr();
|
||||||
std::rethrow_exception(e);
|
std::rethrow_exception(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -97,15 +95,15 @@ AsyncInputStream::IsEOF()
|
|||||||
(!open && buffer.IsEmpty());
|
(!open && buffer.IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
AsyncInputStream::Seek(offset_type new_offset, Error &error)
|
AsyncInputStream::Seek(offset_type new_offset)
|
||||||
{
|
{
|
||||||
assert(IsReady());
|
assert(IsReady());
|
||||||
assert(seek_state == SeekState::NONE);
|
assert(seek_state == SeekState::NONE);
|
||||||
|
|
||||||
if (new_offset == offset)
|
if (new_offset == offset)
|
||||||
/* no-op */
|
/* no-op */
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
if (!IsSeekable())
|
if (!IsSeekable())
|
||||||
throw std::runtime_error("Not seekable");
|
throw std::runtime_error("Not seekable");
|
||||||
@ -127,7 +125,7 @@ AsyncInputStream::Seek(offset_type new_offset, Error &error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (new_offset == offset)
|
if (new_offset == offset)
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
/* no: ask the implementation to seek */
|
/* no: ask the implementation to seek */
|
||||||
|
|
||||||
@ -139,10 +137,7 @@ AsyncInputStream::Seek(offset_type new_offset, Error &error)
|
|||||||
while (seek_state != SeekState::NONE)
|
while (seek_state != SeekState::NONE)
|
||||||
cond.wait(mutex);
|
cond.wait(mutex);
|
||||||
|
|
||||||
if (!Check(error))
|
Check();
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -177,15 +172,14 @@ AsyncInputStream::IsAvailable()
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
AsyncInputStream::Read(void *ptr, size_t read_size, Error &error)
|
AsyncInputStream::Read(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
assert(!io_thread_inside());
|
assert(!io_thread_inside());
|
||||||
|
|
||||||
/* wait for data */
|
/* wait for data */
|
||||||
CircularBuffer<uint8_t>::Range r;
|
CircularBuffer<uint8_t>::Range r;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!Check(error))
|
Check();
|
||||||
return 0;
|
|
||||||
|
|
||||||
r = buffer.Read();
|
r = buffer.Read();
|
||||||
if (!r.IsEmpty() || IsEOF())
|
if (!r.IsEmpty() || IsEOF())
|
||||||
|
@ -81,12 +81,12 @@ public:
|
|||||||
virtual ~AsyncInputStream();
|
virtual ~AsyncInputStream();
|
||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool Check(Error &error) final;
|
void Check() final;
|
||||||
bool IsEOF() final;
|
bool IsEOF() final;
|
||||||
bool Seek(offset_type new_offset, Error &error) final;
|
void Seek(offset_type new_offset) final;
|
||||||
Tag *ReadTag() final;
|
Tag *ReadTag() final;
|
||||||
bool IsAvailable() final;
|
bool IsAvailable() final;
|
||||||
size_t Read(void *ptr, size_t read_size, Error &error) final;
|
size_t Read(void *ptr, size_t read_size) final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
@ -79,13 +79,13 @@ IcyInputStream::ReadTag()
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
IcyInputStream::Read(void *ptr, size_t read_size, Error &error)
|
IcyInputStream::Read(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
if (!IsEnabled())
|
if (!IsEnabled())
|
||||||
return ProxyInputStream::Read(ptr, read_size, error);
|
return ProxyInputStream::Read(ptr, read_size);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
size_t nbytes = ProxyInputStream::Read(ptr, read_size, error);
|
size_t nbytes = ProxyInputStream::Read(ptr, read_size);
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ public:
|
|||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
void Update() override;
|
void Update() override;
|
||||||
Tag *ReadTag() override;
|
Tag *ReadTag() override;
|
||||||
size_t Read(void *ptr, size_t size, Error &error) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,16 +22,17 @@
|
|||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
InputStream::~InputStream()
|
InputStream::~InputStream()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
InputStream::Check(gcc_unused Error &error)
|
InputStream::Check()
|
||||||
{
|
{
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -86,25 +87,24 @@ InputStream::CheapSeeking() const
|
|||||||
return IsSeekable() && !ExpensiveSeeking(uri.c_str());
|
return IsSeekable() && !ExpensiveSeeking(uri.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
InputStream::Seek(gcc_unused offset_type new_offset,
|
InputStream::Seek(gcc_unused offset_type new_offset)
|
||||||
gcc_unused Error &error)
|
|
||||||
{
|
{
|
||||||
return false;
|
throw std::runtime_error("Seeking is not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
InputStream::LockSeek(offset_type _offset, Error &error)
|
InputStream::LockSeek(offset_type _offset)
|
||||||
{
|
{
|
||||||
const ScopeLock protect(mutex);
|
const ScopeLock protect(mutex);
|
||||||
return Seek(_offset, error);
|
Seek(_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
InputStream::LockSkip(offset_type _offset, Error &error)
|
InputStream::LockSkip(offset_type _offset)
|
||||||
{
|
{
|
||||||
const ScopeLock protect(mutex);
|
const ScopeLock protect(mutex);
|
||||||
return Skip(_offset, error);
|
Skip(_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Tag *
|
Tag *
|
||||||
@ -127,7 +127,7 @@ InputStream::IsAvailable()
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
InputStream::LockRead(void *ptr, size_t _size, Error &error)
|
InputStream::LockRead(void *ptr, size_t _size)
|
||||||
{
|
{
|
||||||
#if !CLANG_CHECK_VERSION(3,6)
|
#if !CLANG_CHECK_VERSION(3,6)
|
||||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||||
@ -136,28 +136,27 @@ InputStream::LockRead(void *ptr, size_t _size, Error &error)
|
|||||||
assert(_size > 0);
|
assert(_size > 0);
|
||||||
|
|
||||||
const ScopeLock protect(mutex);
|
const ScopeLock protect(mutex);
|
||||||
return Read(ptr, _size, error);
|
return Read(ptr, _size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
InputStream::ReadFull(void *_ptr, size_t _size, Error &error)
|
InputStream::ReadFull(void *_ptr, size_t _size)
|
||||||
{
|
{
|
||||||
uint8_t *ptr = (uint8_t *)_ptr;
|
uint8_t *ptr = (uint8_t *)_ptr;
|
||||||
|
|
||||||
size_t nbytes_total = 0;
|
size_t nbytes_total = 0;
|
||||||
while (_size > 0) {
|
while (_size > 0) {
|
||||||
size_t nbytes = Read(ptr + nbytes_total, _size, error);
|
size_t nbytes = Read(ptr + nbytes_total, _size);
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
return false;
|
throw std::runtime_error("Unexpected end of file");
|
||||||
|
|
||||||
nbytes_total += nbytes;
|
nbytes_total += nbytes;
|
||||||
_size -= nbytes;
|
_size -= nbytes;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
InputStream::LockReadFull(void *ptr, size_t _size, Error &error)
|
InputStream::LockReadFull(void *ptr, size_t _size)
|
||||||
{
|
{
|
||||||
#if !CLANG_CHECK_VERSION(3,6)
|
#if !CLANG_CHECK_VERSION(3,6)
|
||||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||||
@ -166,7 +165,7 @@ InputStream::LockReadFull(void *ptr, size_t _size, Error &error)
|
|||||||
assert(_size > 0);
|
assert(_size > 0);
|
||||||
|
|
||||||
const ScopeLock protect(mutex);
|
const ScopeLock protect(mutex);
|
||||||
return ReadFull(ptr, _size, error);
|
ReadFull(ptr, _size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -154,10 +154,9 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check for errors that may have occurred in the I/O thread.
|
* Check for errors that may have occurred in the I/O thread.
|
||||||
*
|
* Throws std::runtime_error on error.
|
||||||
* @return false on error
|
|
||||||
*/
|
*/
|
||||||
virtual bool Check(Error &error);
|
virtual void Check();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the public attributes. Call before accessing attributes
|
* Update the public attributes. Call before accessing attributes
|
||||||
@ -271,36 +270,38 @@ public:
|
|||||||
*
|
*
|
||||||
* The caller must lock the mutex.
|
* The caller must lock the mutex.
|
||||||
*
|
*
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
|
*
|
||||||
* @param offset the relative offset
|
* @param offset the relative offset
|
||||||
*/
|
*/
|
||||||
virtual bool Seek(offset_type offset, Error &error);
|
virtual void Seek(offset_type offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for Seek() which locks and unlocks the mutex; the
|
* Wrapper for Seek() which locks and unlocks the mutex; the
|
||||||
* caller must not be holding it already.
|
* caller must not be holding it already.
|
||||||
*/
|
*/
|
||||||
bool LockSeek(offset_type offset, Error &error);
|
void LockSeek(offset_type offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rewind to the beginning of the stream. This is a wrapper
|
* Rewind to the beginning of the stream. This is a wrapper
|
||||||
* for Seek(0, error).
|
* for Seek(0, error).
|
||||||
*/
|
*/
|
||||||
bool Rewind(Error &error) {
|
void Rewind() {
|
||||||
return Seek(0, error);
|
Seek(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LockRewind(Error &error) {
|
void LockRewind() {
|
||||||
return LockSeek(0, error);
|
LockSeek(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skip input bytes.
|
* Skip input bytes.
|
||||||
*/
|
*/
|
||||||
bool Skip(offset_type _offset, Error &error) {
|
void Skip(offset_type _offset) {
|
||||||
return Seek(GetOffset() + _offset, error);
|
Seek(GetOffset() + _offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LockSkip(offset_type _offset, Error &error);
|
void LockSkip(offset_type _offset);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the stream has reached end-of-file.
|
* Returns true if the stream has reached end-of-file.
|
||||||
@ -351,38 +352,46 @@ public:
|
|||||||
*
|
*
|
||||||
* The caller must lock the mutex.
|
* The caller must lock the mutex.
|
||||||
*
|
*
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
|
*
|
||||||
* @param ptr the buffer to read into
|
* @param ptr the buffer to read into
|
||||||
* @param size the maximum number of bytes to read
|
* @param size the maximum number of bytes to read
|
||||||
* @return the number of bytes read
|
* @return the number of bytes read
|
||||||
*/
|
*/
|
||||||
gcc_nonnull_all
|
gcc_nonnull_all
|
||||||
virtual size_t Read(void *ptr, size_t size, Error &error) = 0;
|
virtual size_t Read(void *ptr, size_t size) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for Read() which locks and unlocks the mutex;
|
* Wrapper for Read() which locks and unlocks the mutex;
|
||||||
* the caller must not be holding it already.
|
* the caller must not be holding it already.
|
||||||
|
*
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
gcc_nonnull_all
|
gcc_nonnull_all
|
||||||
size_t LockRead(void *ptr, size_t size, Error &error);
|
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.
|
||||||
*
|
*
|
||||||
* The caller must lock the mutex.
|
* The caller must lock the mutex.
|
||||||
*
|
*
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
|
*
|
||||||
* @param ptr the buffer to read into
|
* @param ptr the buffer to read into
|
||||||
* @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.
|
||||||
*/
|
*/
|
||||||
gcc_nonnull_all
|
gcc_nonnull_all
|
||||||
bool ReadFull(void *ptr, size_t size, Error &error);
|
void ReadFull(void *ptr, size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for ReadFull() which locks and unlocks the mutex;
|
* Wrapper for ReadFull() which locks and unlocks the mutex;
|
||||||
* the caller must not be holding it already.
|
* the caller must not be holding it already.
|
||||||
|
*
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
gcc_nonnull_all
|
gcc_nonnull_all
|
||||||
bool LockReadFull(void *ptr, size_t size, Error &error);
|
void LockReadFull(void *ptr, size_t size);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -63,20 +63,11 @@ InputStream::OpenReady(const char *uri,
|
|||||||
{
|
{
|
||||||
auto is = Open(uri, mutex, cond);
|
auto is = Open(uri, mutex, cond);
|
||||||
|
|
||||||
bool success;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
const ScopeLock protect(mutex);
|
const ScopeLock protect(mutex);
|
||||||
is->WaitReady();
|
is->WaitReady();
|
||||||
|
is->Check();
|
||||||
Error error;
|
|
||||||
success = is->Check(error);
|
|
||||||
if (!success)
|
|
||||||
throw std::runtime_error(error.GetMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success)
|
|
||||||
is.reset();
|
|
||||||
|
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
@ -49,10 +49,10 @@ ProxyInputStream::CopyAttributes()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
ProxyInputStream::Check(Error &error)
|
ProxyInputStream::Check()
|
||||||
{
|
{
|
||||||
return input.Check(error);
|
input.Check();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -62,12 +62,11 @@ ProxyInputStream::Update()
|
|||||||
CopyAttributes();
|
CopyAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
ProxyInputStream::Seek(offset_type new_offset, Error &error)
|
ProxyInputStream::Seek(offset_type new_offset)
|
||||||
{
|
{
|
||||||
bool success = input.Seek(new_offset, error);
|
input.Seek(new_offset);
|
||||||
CopyAttributes();
|
CopyAttributes();
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -89,9 +88,9 @@ ProxyInputStream::IsAvailable()
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ProxyInputStream::Read(void *ptr, size_t read_size, Error &error)
|
ProxyInputStream::Read(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
size_t nbytes = input.Read(ptr, read_size, error);
|
size_t nbytes = input.Read(ptr, read_size);
|
||||||
CopyAttributes();
|
CopyAttributes();
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
@ -43,13 +43,13 @@ public:
|
|||||||
ProxyInputStream &operator=(const ProxyInputStream &) = delete;
|
ProxyInputStream &operator=(const ProxyInputStream &) = delete;
|
||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool Check(Error &error) override;
|
void Check() override;
|
||||||
void Update() override;
|
void Update() override;
|
||||||
bool Seek(offset_type new_offset, Error &error) override;
|
void Seek(offset_type new_offset) override;
|
||||||
bool IsEOF() override;
|
bool IsEOF() override;
|
||||||
Tag *ReadTag() override;
|
Tag *ReadTag() override;
|
||||||
bool IsAvailable() override;
|
bool IsAvailable() override;
|
||||||
size_t Read(void *ptr, size_t read_size, Error &error) override;
|
size_t Read(void *ptr, size_t read_size) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
@ -20,19 +20,12 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Reader.hxx"
|
#include "Reader.hxx"
|
||||||
#include "InputStream.hxx"
|
#include "InputStream.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "Log.hxx"
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
InputStreamReader::Read(void *data, size_t size)
|
InputStreamReader::Read(void *data, size_t size)
|
||||||
{
|
{
|
||||||
Error error;
|
size_t nbytes = is.LockRead(data, size);
|
||||||
size_t nbytes = is.LockRead(data, size, error);
|
assert(nbytes > 0 || is.IsEOF());
|
||||||
assert(nbytes == 0 || !error.IsDefined());
|
|
||||||
assert(nbytes > 0 || error.IsDefined() || is.IsEOF());
|
|
||||||
|
|
||||||
if (gcc_unlikely(nbytes == 0 && error.IsDefined()))
|
|
||||||
LogError(error);
|
|
||||||
|
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
@ -20,10 +20,11 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "TextInputStream.hxx"
|
#include "TextInputStream.hxx"
|
||||||
#include "InputStream.hxx"
|
#include "InputStream.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/TextFile.hxx"
|
#include "util/TextFile.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
TextInputStream::TextInputStream(InputStreamPtr &&_is)
|
TextInputStream::TextInputStream(InputStreamPtr &&_is)
|
||||||
@ -58,12 +59,12 @@ TextInputStream::ReadLine()
|
|||||||
character */
|
character */
|
||||||
--dest.size;
|
--dest.size;
|
||||||
|
|
||||||
Error error;
|
size_t nbytes;
|
||||||
size_t nbytes = is->LockRead(dest.data, dest.size, error);
|
|
||||||
if (nbytes > 0)
|
try {
|
||||||
buffer.Append(nbytes);
|
nbytes = is->LockRead(dest.data, dest.size);
|
||||||
else if (error.IsDefined()) {
|
} catch (const std::runtime_error &e) {
|
||||||
LogError(error);
|
LogError(e);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,15 +114,13 @@ ThreadInputStream::ThreadFunc(void *ctx)
|
|||||||
tis.ThreadFunc();
|
tis.ThreadFunc();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
ThreadInputStream::Check(Error &)
|
ThreadInputStream::Check()
|
||||||
{
|
{
|
||||||
assert(!thread.IsInside());
|
assert(!thread.IsInside());
|
||||||
|
|
||||||
if (postponed_exception)
|
if (postponed_exception)
|
||||||
std::rethrow_exception(postponed_exception);
|
std::rethrow_exception(postponed_exception);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -134,7 +132,7 @@ ThreadInputStream::IsAvailable()
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline size_t
|
inline size_t
|
||||||
ThreadInputStream::Read(void *ptr, size_t read_size, Error &)
|
ThreadInputStream::Read(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
assert(!thread.IsInside());
|
assert(!thread.IsInside());
|
||||||
|
|
||||||
|
@ -83,10 +83,10 @@ public:
|
|||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool Check(Error &error) override final;
|
void Check() override final;
|
||||||
bool IsEOF() override final;
|
bool IsEOF() override final;
|
||||||
bool IsAvailable() override final;
|
bool IsAvailable() override final;
|
||||||
size_t Read(void *ptr, size_t size, Error &error) override final;
|
size_t Read(void *ptr, size_t size) override final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void SetMimeType(const char *_mime) {
|
void SetMimeType(const char *_mime) {
|
||||||
|
@ -98,8 +98,8 @@ class CdioParanoiaInputStream final : public InputStream {
|
|||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() override;
|
bool IsEOF() override;
|
||||||
size_t Read(void *ptr, size_t size, Error &error) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
bool Seek(offset_type offset, Error &error) override;
|
void Seek(offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr Domain cdio_domain("cdio");
|
static constexpr Domain cdio_domain("cdio");
|
||||||
@ -256,30 +256,26 @@ input_cdio_open(const char *uri,
|
|||||||
lsn_from, lsn_to);
|
lsn_from, lsn_to);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
CdioParanoiaInputStream::Seek(offset_type new_offset, Error &error)
|
CdioParanoiaInputStream::Seek(offset_type new_offset)
|
||||||
{
|
{
|
||||||
if (new_offset > size) {
|
if (new_offset > size)
|
||||||
error.Format(cdio_domain, "Invalid offset to seek %ld (%ld)",
|
throw FormatRuntimeError("Invalid offset to seek %ld (%ld)",
|
||||||
(long int)new_offset, (long int)size);
|
(long int)new_offset, (long int)size);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* simple case */
|
/* simple case */
|
||||||
if (new_offset == offset)
|
if (new_offset == offset)
|
||||||
return true;
|
return;
|
||||||
|
|
||||||
/* calculate current LSN */
|
/* calculate current LSN */
|
||||||
lsn_relofs = new_offset / CDIO_CD_FRAMESIZE_RAW;
|
lsn_relofs = new_offset / CDIO_CD_FRAMESIZE_RAW;
|
||||||
offset = new_offset;
|
offset = new_offset;
|
||||||
|
|
||||||
cdio_paranoia_seek(para, lsn_from + lsn_relofs, SEEK_SET);
|
cdio_paranoia_seek(para, lsn_from + lsn_relofs, SEEK_SET);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
CdioParanoiaInputStream::Read(void *ptr, size_t length, Error &error)
|
CdioParanoiaInputStream::Read(void *ptr, size_t length)
|
||||||
{
|
{
|
||||||
size_t nbytes = 0;
|
size_t nbytes = 0;
|
||||||
int diff;
|
int diff;
|
||||||
@ -309,11 +305,9 @@ CdioParanoiaInputStream::Read(void *ptr, size_t length, Error &error)
|
|||||||
if (s_mess) {
|
if (s_mess) {
|
||||||
free(s_mess);
|
free(s_mess);
|
||||||
}
|
}
|
||||||
if (!rbuf) {
|
if (!rbuf)
|
||||||
error.Set(cdio_domain,
|
throw std::runtime_error("paranoia read error");
|
||||||
"paranoia read error. Stopping.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
//store current buffer
|
//store current buffer
|
||||||
memcpy(buffer, rbuf, CDIO_CD_FRAMESIZE_RAW);
|
memcpy(buffer, rbuf, CDIO_CD_FRAMESIZE_RAW);
|
||||||
buffer_lsn = lsn_relofs;
|
buffer_lsn = lsn_relofs;
|
||||||
|
@ -61,8 +61,8 @@ struct FfmpegInputStream final : public InputStream {
|
|||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() override;
|
bool IsEOF() override;
|
||||||
size_t Read(void *ptr, size_t size, Error &error) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
bool Seek(offset_type offset, Error &error) override;
|
void Seek(offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@ -103,15 +103,15 @@ input_ffmpeg_open(const char *uri,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
FfmpegInputStream::Read(void *ptr, size_t read_size, Error &error)
|
FfmpegInputStream::Read(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
auto result = avio_read(h, (unsigned char *)ptr, read_size);
|
auto result = avio_read(h, (unsigned char *)ptr, read_size);
|
||||||
if (result <= 0) {
|
if (result <= 0) {
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
SetFfmpegError(error, result, "avio_read() failed");
|
throw MakeFfmpegError(result, "avio_read() failed");
|
||||||
|
|
||||||
eof = true;
|
eof = true;
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += result;
|
offset += result;
|
||||||
@ -124,19 +124,16 @@ FfmpegInputStream::IsEOF()
|
|||||||
return eof;
|
return eof;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
FfmpegInputStream::Seek(offset_type new_offset, Error &error)
|
FfmpegInputStream::Seek(offset_type new_offset)
|
||||||
{
|
{
|
||||||
auto result = avio_seek(h, new_offset, SEEK_SET);
|
auto result = avio_seek(h, new_offset, SEEK_SET);
|
||||||
|
|
||||||
if (result < 0) {
|
if (result < 0)
|
||||||
SetFfmpegError(error, result, "avio_seek() failed");
|
throw MakeFfmpegError(result, "avio_seek() failed");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = result;
|
offset = result;
|
||||||
eof = false;
|
eof = false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputPlugin input_plugin_ffmpeg = {
|
const InputPlugin input_plugin_ffmpeg = {
|
||||||
|
@ -49,8 +49,8 @@ public:
|
|||||||
return GetOffset() >= GetSize();
|
return GetOffset() >= GetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *ptr, size_t size, Error &error) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
bool Seek(offset_type offset, Error &error) override;
|
void Seek(offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
InputStreamPtr
|
InputStreamPtr
|
||||||
@ -84,26 +84,19 @@ input_file_open(gcc_unused const char *filename,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
FileInputStream::Seek(offset_type new_offset, Error &error)
|
FileInputStream::Seek(offset_type new_offset)
|
||||||
try {
|
{
|
||||||
reader.Seek((off_t)new_offset);
|
reader.Seek((off_t)new_offset);
|
||||||
offset = new_offset;
|
offset = new_offset;
|
||||||
return true;
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
error.Set(std::current_exception());
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
FileInputStream::Read(void *ptr, size_t read_size, Error &error)
|
FileInputStream::Read(void *ptr, size_t read_size)
|
||||||
try {
|
{
|
||||||
size_t nbytes = reader.Read(ptr, read_size);
|
size_t nbytes = reader.Read(ptr, read_size);
|
||||||
offset += nbytes;
|
offset += nbytes;
|
||||||
return nbytes;
|
return nbytes;
|
||||||
} catch (const std::exception &e) {
|
|
||||||
error.Set(std::current_exception());
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputPlugin input_plugin_file = {
|
const InputPlugin input_plugin_file = {
|
||||||
|
@ -63,8 +63,8 @@ public:
|
|||||||
return !ReadingFromBuffer() && ProxyInputStream::IsEOF();
|
return !ReadingFromBuffer() && ProxyInputStream::IsEOF();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *ptr, size_t size, Error &error) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
bool Seek(offset_type offset, Error &error) override;
|
void Seek(offset_type offset) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@ -77,7 +77,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
RewindInputStream::Read(void *ptr, size_t read_size, Error &error)
|
RewindInputStream::Read(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
if (ReadingFromBuffer()) {
|
if (ReadingFromBuffer()) {
|
||||||
/* buffered read */
|
/* buffered read */
|
||||||
@ -96,7 +96,7 @@ RewindInputStream::Read(void *ptr, size_t read_size, Error &error)
|
|||||||
} else {
|
} else {
|
||||||
/* pass method call to underlying stream */
|
/* pass method call to underlying stream */
|
||||||
|
|
||||||
size_t nbytes = input.Read(ptr, read_size, error);
|
size_t nbytes = input.Read(ptr, read_size);
|
||||||
|
|
||||||
if (input.GetOffset() > (offset_type)sizeof(buffer))
|
if (input.GetOffset() > (offset_type)sizeof(buffer))
|
||||||
/* disable buffering */
|
/* disable buffering */
|
||||||
@ -116,9 +116,8 @@ RewindInputStream::Read(void *ptr, size_t read_size, Error &error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
RewindInputStream::Seek(offset_type new_offset,
|
RewindInputStream::Seek(offset_type new_offset)
|
||||||
Error &error)
|
|
||||||
{
|
{
|
||||||
assert(IsReady());
|
assert(IsReady());
|
||||||
|
|
||||||
@ -131,14 +130,12 @@ RewindInputStream::Seek(offset_type new_offset,
|
|||||||
|
|
||||||
head = (size_t)new_offset;
|
head = (size_t)new_offset;
|
||||||
offset = new_offset;
|
offset = new_offset;
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
/* disable the buffer, because input has left the
|
/* disable the buffer, because input has left the
|
||||||
buffered range now */
|
buffered range now */
|
||||||
tail = 0;
|
tail = 0;
|
||||||
|
|
||||||
return ProxyInputStream::Seek(new_offset, error);
|
ProxyInputStream::Seek(new_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include "PluginUnavailable.hxx"
|
#include "PluginUnavailable.hxx"
|
||||||
#include "system/Error.hxx"
|
#include "system/Error.hxx"
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
|
||||||
#include <libsmbclient.h>
|
#include <libsmbclient.h>
|
||||||
|
|
||||||
@ -60,8 +59,8 @@ public:
|
|||||||
return offset >= size;
|
return offset >= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *ptr, size_t size, Error &error) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
bool Seek(offset_type offset, Error &error) override;
|
void Seek(offset_type offset) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -124,33 +123,28 @@ input_smbclient_open(const char *uri,
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
SmbclientInputStream::Read(void *ptr, size_t read_size, Error &error)
|
SmbclientInputStream::Read(void *ptr, size_t read_size)
|
||||||
{
|
{
|
||||||
smbclient_mutex.lock();
|
smbclient_mutex.lock();
|
||||||
ssize_t nbytes = smbc_read(fd, ptr, read_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");
|
throw MakeErrno("smbc_read() failed");
|
||||||
nbytes = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += nbytes;
|
offset += nbytes;
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
SmbclientInputStream::Seek(offset_type new_offset, Error &error)
|
SmbclientInputStream::Seek(offset_type new_offset)
|
||||||
{
|
{
|
||||||
smbclient_mutex.lock();
|
smbclient_mutex.lock();
|
||||||
off_t result = smbc_lseek(fd, new_offset, SEEK_SET);
|
off_t result = smbc_lseek(fd, new_offset, SEEK_SET);
|
||||||
smbclient_mutex.unlock();
|
smbclient_mutex.unlock();
|
||||||
if (result < 0) {
|
if (result < 0)
|
||||||
error.SetErrno("smbc_lseek() failed");
|
throw MakeErrno("smbc_lseek() failed");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = result;
|
offset = result;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputPlugin input_plugin_smbclient = {
|
const InputPlugin input_plugin_smbclient = {
|
||||||
|
@ -43,25 +43,21 @@ ExpatParser::Parse(const char *data, size_t length, bool is_final)
|
|||||||
throw ExpatError(parser);
|
throw ExpatError(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
ExpatParser::Parse(InputStream &is, Error &error)
|
ExpatParser::Parse(InputStream &is)
|
||||||
{
|
{
|
||||||
assert(is.IsReady());
|
assert(is.IsReady());
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
size_t nbytes = is.LockRead(buffer, sizeof(buffer), error);
|
size_t nbytes = is.LockRead(buffer, sizeof(buffer));
|
||||||
if (nbytes == 0)
|
if (nbytes == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
Parse(buffer, nbytes, false);
|
Parse(buffer, nbytes, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error.IsDefined())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Parse("", 0, true);
|
Parse("", 0, true);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
|
@ -66,7 +66,7 @@ public:
|
|||||||
|
|
||||||
void Parse(const char *data, size_t length, bool is_final);
|
void Parse(const char *data, size_t length, bool is_final);
|
||||||
|
|
||||||
bool Parse(InputStream &is, Error &error);
|
void Parse(InputStream &is);
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static const char *GetAttribute(const XML_Char **atts,
|
static const char *GetAttribute(const XML_Char **atts,
|
||||||
@ -97,8 +97,8 @@ public:
|
|||||||
parser.Parse(data, length, is_final);
|
parser.Parse(data, length, is_final);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parse(InputStream &is, Error &error) {
|
void Parse(InputStream &is) {
|
||||||
return parser.Parse(is, error);
|
parser.Parse(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "Error.hxx"
|
#include "Error.hxx"
|
||||||
#include "Domain.hxx"
|
#include "Domain.hxx"
|
||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
|
#include "util/RuntimeError.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libavutil/error.h>
|
#include <libavutil/error.h>
|
||||||
@ -34,6 +35,14 @@ MakeFfmpegError(int errnum)
|
|||||||
return std::runtime_error(msg);
|
return std::runtime_error(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::runtime_error
|
||||||
|
MakeFfmpegError(int errnum, const char *prefix)
|
||||||
|
{
|
||||||
|
char msg[256];
|
||||||
|
av_strerror(errnum, msg, sizeof(msg));
|
||||||
|
return FormatRuntimeError("%s: %s", prefix, msg);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SetFfmpegError(Error &error, int errnum)
|
SetFfmpegError(Error &error, int errnum)
|
||||||
{
|
{
|
||||||
|
@ -27,6 +27,9 @@ class Error;
|
|||||||
std::runtime_error
|
std::runtime_error
|
||||||
MakeFfmpegError(int errnum);
|
MakeFfmpegError(int errnum);
|
||||||
|
|
||||||
|
std::runtime_error
|
||||||
|
MakeFfmpegError(int errnum, const char *prefix);
|
||||||
|
|
||||||
void
|
void
|
||||||
SetFfmpegError(Error &error, int errnum);
|
SetFfmpegError(Error &error, int errnum);
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@
|
|||||||
#include "OggFind.hxx"
|
#include "OggFind.hxx"
|
||||||
#include "lib/xiph/OggSyncState.hxx"
|
#include "lib/xiph/OggSyncState.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
bool
|
bool
|
||||||
OggFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet)
|
OggFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet)
|
||||||
@ -48,8 +49,13 @@ OggSeekPageAtOffset(OggSyncState &oy, ogg_stream_state &os, InputStream &is,
|
|||||||
data */
|
data */
|
||||||
ogg_stream_reset(&os);
|
ogg_stream_reset(&os);
|
||||||
|
|
||||||
return is.LockSeek(offset, IgnoreError()) &&
|
try {
|
||||||
oy.ExpectPageSeekIn(os);
|
is.LockSeek(offset);
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return oy.ExpectPageSeekIn(os);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -34,11 +34,12 @@
|
|||||||
#include "util/MimeType.hxx"
|
#include "util/MimeType.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
#include "util/UriUtil.hxx"
|
||||||
#include "util/StringUtil.hxx"
|
#include "util/StringUtil.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/Macros.hxx"
|
#include "util/Macros.hxx"
|
||||||
#include "config/ConfigGlobal.hxx"
|
#include "config/ConfigGlobal.hxx"
|
||||||
#include "config/Block.hxx"
|
#include "config/Block.hxx"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -193,7 +194,10 @@ playlist_list_open_stream_mime2(InputStreamPtr &&is, const char *mime)
|
|||||||
StringArrayContainsCase(plugin->mime_types, mime)) {
|
StringArrayContainsCase(plugin->mime_types, mime)) {
|
||||||
/* rewind the stream, so each plugin gets a
|
/* rewind the stream, so each plugin gets a
|
||||||
fresh start */
|
fresh start */
|
||||||
is->Rewind(IgnoreError());
|
try {
|
||||||
|
is->Rewind();
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
}
|
||||||
|
|
||||||
auto playlist = playlist_plugin_open_stream(plugin,
|
auto playlist = playlist_plugin_open_stream(plugin,
|
||||||
std::move(is));
|
std::move(is));
|
||||||
@ -234,7 +238,10 @@ playlist_list_open_stream_suffix(InputStreamPtr &&is, const char *suffix)
|
|||||||
StringArrayContainsCase(plugin->suffixes, suffix)) {
|
StringArrayContainsCase(plugin->suffixes, suffix)) {
|
||||||
/* rewind the stream, so each plugin gets a
|
/* rewind the stream, so each plugin gets a
|
||||||
fresh start */
|
fresh start */
|
||||||
is->Rewind(IgnoreError());
|
try {
|
||||||
|
is->Rewind();
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
}
|
||||||
|
|
||||||
auto playlist = playlist_plugin_open_stream(plugin,
|
auto playlist = playlist_plugin_open_stream(plugin,
|
||||||
std::move(is));
|
std::move(is));
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "../MemorySongEnumerator.hxx"
|
#include "../MemorySongEnumerator.hxx"
|
||||||
#include "tag/TagBuilder.hxx"
|
#include "tag/TagBuilder.hxx"
|
||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/StringView.hxx"
|
#include "util/StringView.hxx"
|
||||||
#include "lib/expat/ExpatParser.hxx"
|
#include "lib/expat/ExpatParser.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
@ -152,12 +151,7 @@ asx_open_stream(InputStreamPtr &&is)
|
|||||||
ExpatParser expat(&parser);
|
ExpatParser expat(&parser);
|
||||||
expat.SetElementHandler(asx_start_element, asx_end_element);
|
expat.SetElementHandler(asx_start_element, asx_end_element);
|
||||||
expat.SetCharacterDataHandler(asx_char_data);
|
expat.SetCharacterDataHandler(asx_char_data);
|
||||||
|
expat.Parse(*is);
|
||||||
Error error;
|
|
||||||
if (!expat.Parse(*is, error)) {
|
|
||||||
LogError(error);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.songs.reverse();
|
parser.songs.reverse();
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "../MemorySongEnumerator.hxx"
|
#include "../MemorySongEnumerator.hxx"
|
||||||
#include "tag/TagBuilder.hxx"
|
#include "tag/TagBuilder.hxx"
|
||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/StringView.hxx"
|
#include "util/StringView.hxx"
|
||||||
#include "lib/expat/ExpatParser.hxx"
|
#include "lib/expat/ExpatParser.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
@ -150,12 +149,7 @@ rss_open_stream(InputStreamPtr &&is)
|
|||||||
ExpatParser expat(&parser);
|
ExpatParser expat(&parser);
|
||||||
expat.SetElementHandler(rss_start_element, rss_end_element);
|
expat.SetElementHandler(rss_start_element, rss_end_element);
|
||||||
expat.SetCharacterDataHandler(rss_char_data);
|
expat.SetCharacterDataHandler(rss_char_data);
|
||||||
|
expat.Parse(*is);
|
||||||
Error error;
|
|
||||||
if (!expat.Parse(*is, error)) {
|
|
||||||
LogError(error);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.songs.reverse();
|
parser.songs.reverse();
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include "tag/TagBuilder.hxx"
|
#include "tag/TagBuilder.hxx"
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
#include "util/Alloc.hxx"
|
#include "util/Alloc.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
@ -231,29 +230,20 @@ static int
|
|||||||
soundcloud_parse_json(const char *url, yajl_handle hand,
|
soundcloud_parse_json(const char *url, yajl_handle hand,
|
||||||
Mutex &mutex, Cond &cond)
|
Mutex &mutex, Cond &cond)
|
||||||
try {
|
try {
|
||||||
Error error;
|
|
||||||
auto input_stream = InputStream::OpenReady(url, mutex, cond);
|
auto input_stream = InputStream::OpenReady(url, mutex, cond);
|
||||||
|
|
||||||
const ScopeLock protect(mutex);
|
const ScopeLock protect(mutex);
|
||||||
|
|
||||||
yajl_status stat;
|
yajl_status stat;
|
||||||
int done = 0;
|
bool done = false;
|
||||||
|
|
||||||
while (!done) {
|
while (!done) {
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
unsigned char *ubuffer = (unsigned char *)buffer;
|
unsigned char *ubuffer = (unsigned char *)buffer;
|
||||||
const size_t nbytes =
|
const size_t nbytes =
|
||||||
input_stream->Read(buffer, sizeof(buffer), error);
|
input_stream->Read(buffer, sizeof(buffer));
|
||||||
if (nbytes == 0) {
|
if (nbytes == 0)
|
||||||
if (error.IsDefined())
|
|
||||||
LogError(error);
|
|
||||||
|
|
||||||
if (input_stream->IsEOF()) {
|
|
||||||
done = true;
|
done = true;
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
stat = yajl_complete_parse(hand);
|
stat = yajl_complete_parse(hand);
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "DetachedSong.hxx"
|
#include "DetachedSong.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "tag/TagBuilder.hxx"
|
#include "tag/TagBuilder.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/StringView.hxx"
|
#include "util/StringView.hxx"
|
||||||
#include "lib/expat/ExpatParser.hxx"
|
#include "lib/expat/ExpatParser.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
@ -197,12 +196,7 @@ xspf_open_stream(InputStreamPtr &&is)
|
|||||||
ExpatParser expat(&parser);
|
ExpatParser expat(&parser);
|
||||||
expat.SetElementHandler(xspf_start_element, xspf_end_element);
|
expat.SetElementHandler(xspf_start_element, xspf_end_element);
|
||||||
expat.SetCharacterDataHandler(xspf_char_data);
|
expat.SetCharacterDataHandler(xspf_char_data);
|
||||||
|
expat.Parse(*is);
|
||||||
Error error;
|
|
||||||
if (!expat.Parse(*is, error)) {
|
|
||||||
LogError(error);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.songs.reverse();
|
parser.songs.reverse();
|
||||||
|
@ -21,10 +21,9 @@
|
|||||||
#include "Aiff.hxx"
|
#include "Aiff.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "system/ByteOrder.hxx"
|
#include "system/ByteOrder.hxx"
|
||||||
#include "Log.hxx"
|
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -45,33 +44,27 @@ aiff_seek_id3(InputStream &is)
|
|||||||
{
|
{
|
||||||
/* seek to the beginning and read the AIFF header */
|
/* seek to the beginning and read the AIFF header */
|
||||||
|
|
||||||
Error error;
|
is.Rewind();
|
||||||
if (!is.Rewind(error)) {
|
|
||||||
LogError(error, "Failed to seek");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
aiff_header header;
|
aiff_header header;
|
||||||
if (!is.ReadFull(&header, sizeof(header), IgnoreError()) ||
|
is.ReadFull(&header, sizeof(header));
|
||||||
memcmp(header.id, "FORM", 4) != 0 ||
|
if (memcmp(header.id, "FORM", 4) != 0 ||
|
||||||
(is.KnownSize() && FromLE32(header.size) > is.GetSize()) ||
|
(is.KnownSize() && FromLE32(header.size) > is.GetSize()) ||
|
||||||
(memcmp(header.format, "AIFF", 4) != 0 &&
|
(memcmp(header.format, "AIFF", 4) != 0 &&
|
||||||
memcmp(header.format, "AIFC", 4) != 0))
|
memcmp(header.format, "AIFC", 4) != 0))
|
||||||
/* not a AIFF file */
|
throw std::runtime_error("Not an AIFF file");
|
||||||
return 0;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
/* read the chunk header */
|
/* read the chunk header */
|
||||||
|
|
||||||
aiff_chunk_header chunk;
|
aiff_chunk_header chunk;
|
||||||
if (!is.ReadFull(&chunk, sizeof(chunk), IgnoreError()))
|
is.ReadFull(&chunk, sizeof(chunk));
|
||||||
return 0;
|
|
||||||
|
|
||||||
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()))
|
||||||
/* too dangerous, bail out: possible integer
|
/* too dangerous, bail out: possible integer
|
||||||
underflow when casting to off_t */
|
underflow when casting to off_t */
|
||||||
return 0;
|
throw std::runtime_error("AIFF chunk is too large");
|
||||||
|
|
||||||
if (memcmp(chunk.id, "ID3 ", 4) == 0)
|
if (memcmp(chunk.id, "ID3 ", 4) == 0)
|
||||||
/* found it! */
|
/* found it! */
|
||||||
@ -81,7 +74,6 @@ aiff_seek_id3(InputStream &is)
|
|||||||
/* pad byte */
|
/* pad byte */
|
||||||
++size;
|
++size;
|
||||||
|
|
||||||
if (!is.Skip(size, IgnoreError()))
|
is.Skip(size);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,10 @@ class InputStream;
|
|||||||
/**
|
/**
|
||||||
* Seeks the AIFF file to the ID3 chunk.
|
* Seeks the AIFF file to the ID3 chunk.
|
||||||
*
|
*
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
|
*
|
||||||
* @param is a locked #InputStream
|
* @param is a locked #InputStream
|
||||||
* @return the size of the ID3 chunk on success, or 0 if this is not a
|
* @return the size of the ID3 chunk
|
||||||
* AIFF file or no ID3 chunk was found
|
|
||||||
*/
|
*/
|
||||||
size_t
|
size_t
|
||||||
aiff_seek_id3(InputStream &is);
|
aiff_seek_id3(InputStream &is);
|
||||||
|
@ -50,9 +50,10 @@ try {
|
|||||||
|
|
||||||
/* determine if file has an apeV2 tag */
|
/* determine if file has an apeV2 tag */
|
||||||
ApeFooter footer;
|
ApeFooter footer;
|
||||||
if (!is.Seek(is.GetSize() - sizeof(footer), IgnoreError()) ||
|
is.Seek(is.GetSize() - sizeof(footer));
|
||||||
!is.ReadFull(&footer, sizeof(footer), IgnoreError()) ||
|
is.ReadFull(&footer, sizeof(footer));
|
||||||
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)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -60,17 +61,17 @@ try {
|
|||||||
size_t remaining = FromLE32(footer.length);
|
size_t remaining = FromLE32(footer.length);
|
||||||
if (remaining <= sizeof(footer) + 10 ||
|
if (remaining <= sizeof(footer) + 10 ||
|
||||||
/* refuse to load more than one megabyte of tag data */
|
/* refuse to load more than one megabyte of tag data */
|
||||||
remaining > 1024 * 1024 ||
|
remaining > 1024 * 1024)
|
||||||
!is.Seek(is.GetSize() - remaining, IgnoreError()))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
is.Seek(is.GetSize() - remaining);
|
||||||
|
|
||||||
/* read tag into buffer */
|
/* read tag into buffer */
|
||||||
remaining -= sizeof(footer);
|
remaining -= sizeof(footer);
|
||||||
assert(remaining > 10);
|
assert(remaining > 10);
|
||||||
|
|
||||||
std::unique_ptr<char[]> buffer(new char[remaining]);
|
std::unique_ptr<char[]> buffer(new char[remaining]);
|
||||||
if (!is.ReadFull(buffer.get(), remaining, IgnoreError()))
|
is.ReadFull(buffer.get(), remaining);
|
||||||
return false;
|
|
||||||
|
|
||||||
/* read tags */
|
/* read tags */
|
||||||
unsigned n = FromLE32(footer.count);
|
unsigned n = FromLE32(footer.count);
|
||||||
|
@ -38,8 +38,11 @@ ScanGenericTags(InputStream &is, const TagHandler &handler, void *ctx)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
#ifdef ENABLE_ID3TAG
|
#ifdef ENABLE_ID3TAG
|
||||||
if (!is.LockRewind(IgnoreError()))
|
try {
|
||||||
|
is.LockRewind();
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return tag_id3_scan(is, handler, ctx);
|
return tag_id3_scan(is, handler, ctx);
|
||||||
#else
|
#else
|
||||||
|
@ -19,8 +19,6 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Id3Load.hxx"
|
#include "Id3Load.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "util/Domain.hxx"
|
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "Riff.hxx"
|
#include "Riff.hxx"
|
||||||
#include "Aiff.hxx"
|
#include "Aiff.hxx"
|
||||||
@ -31,8 +29,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
static constexpr Domain id3_domain("id3");
|
|
||||||
|
|
||||||
static constexpr size_t ID3V1_SIZE = 128;
|
static constexpr size_t ID3V1_SIZE = 128;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
@ -46,11 +42,8 @@ static long
|
|||||||
get_id3v2_footer_size(InputStream &is, offset_type offset)
|
get_id3v2_footer_size(InputStream &is, offset_type offset)
|
||||||
try {
|
try {
|
||||||
id3_byte_t buf[ID3_TAG_QUERYSIZE];
|
id3_byte_t buf[ID3_TAG_QUERYSIZE];
|
||||||
if (!is.Seek(offset, IgnoreError()))
|
is.Seek(offset);
|
||||||
return 0;
|
is.ReadFull(buf, sizeof(buf));
|
||||||
|
|
||||||
if (!is.ReadFull(buf, sizeof(buf), IgnoreError()))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return id3_tag_query(buf, sizeof(buf));
|
return id3_tag_query(buf, sizeof(buf));
|
||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
@ -61,8 +54,7 @@ static UniqueId3Tag
|
|||||||
ReadId3Tag(InputStream &is)
|
ReadId3Tag(InputStream &is)
|
||||||
try {
|
try {
|
||||||
id3_byte_t query_buffer[ID3_TAG_QUERYSIZE];
|
id3_byte_t query_buffer[ID3_TAG_QUERYSIZE];
|
||||||
if (!is.ReadFull(query_buffer, sizeof(query_buffer), IgnoreError()))
|
is.ReadFull(query_buffer, sizeof(query_buffer));
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
/* 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));
|
||||||
@ -82,9 +74,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);
|
||||||
const size_t nbytes = is.Read(end, remaining, IgnoreError());
|
is.ReadFull(end, remaining);
|
||||||
if (nbytes != remaining)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return UniqueId3Tag(id3_tag_parse(tag_buffer.get(), tag_size));
|
return UniqueId3Tag(id3_tag_parse(tag_buffer.get(), tag_size));
|
||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
@ -94,8 +84,7 @@ try {
|
|||||||
static UniqueId3Tag
|
static UniqueId3Tag
|
||||||
ReadId3Tag(InputStream &is, offset_type offset)
|
ReadId3Tag(InputStream &is, offset_type offset)
|
||||||
try {
|
try {
|
||||||
if (!is.Seek(offset, IgnoreError()))
|
is.Seek(offset);
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return ReadId3Tag(is);
|
return ReadId3Tag(is);
|
||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
@ -106,9 +95,7 @@ static UniqueId3Tag
|
|||||||
ReadId3v1Tag(InputStream &is)
|
ReadId3v1Tag(InputStream &is)
|
||||||
try {
|
try {
|
||||||
id3_byte_t buffer[ID3V1_SIZE];
|
id3_byte_t buffer[ID3V1_SIZE];
|
||||||
|
is.ReadFull(buffer, ID3V1_SIZE);
|
||||||
if (is.Read(buffer, ID3V1_SIZE, IgnoreError()) != ID3V1_SIZE)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return UniqueId3Tag(id3_tag_parse(buffer, ID3V1_SIZE));
|
return UniqueId3Tag(id3_tag_parse(buffer, ID3V1_SIZE));
|
||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
@ -118,9 +105,7 @@ try {
|
|||||||
static UniqueId3Tag
|
static UniqueId3Tag
|
||||||
ReadId3v1Tag(InputStream &is, offset_type offset)
|
ReadId3v1Tag(InputStream &is, offset_type offset)
|
||||||
try {
|
try {
|
||||||
if (!is.Seek(offset, IgnoreError()))
|
is.Seek(offset);
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return ReadId3v1Tag(is);
|
return ReadId3v1Tag(is);
|
||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -203,21 +188,19 @@ try {
|
|||||||
static UniqueId3Tag
|
static UniqueId3Tag
|
||||||
tag_id3_riff_aiff_load(InputStream &is)
|
tag_id3_riff_aiff_load(InputStream &is)
|
||||||
try {
|
try {
|
||||||
size_t size = riff_seek_id3(is);
|
size_t size;
|
||||||
if (size == 0)
|
try {
|
||||||
|
size = riff_seek_id3(is);
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
size = aiff_seek_id3(is);
|
size = aiff_seek_id3(is);
|
||||||
if (size == 0)
|
}
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
if (size > 4 * 1024 * 1024)
|
if (size > 4 * 1024 * 1024)
|
||||||
/* too large, don't allocate so much memory */
|
/* too large, don't allocate so much memory */
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
std::unique_ptr<id3_byte_t[]> buffer(new id3_byte_t[size]);
|
std::unique_ptr<id3_byte_t[]> buffer(new id3_byte_t[size]);
|
||||||
if (!is.ReadFull(buffer.get(), size, IgnoreError())) {
|
is.ReadFull(buffer.get(), size);
|
||||||
LogWarning(id3_domain, "Failed to read RIFF chunk");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return UniqueId3Tag(id3_tag_parse(buffer.get(), size));
|
return UniqueId3Tag(id3_tag_parse(buffer.get(), size));
|
||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
|
@ -21,10 +21,9 @@
|
|||||||
#include "Riff.hxx"
|
#include "Riff.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "system/ByteOrder.hxx"
|
#include "system/ByteOrder.hxx"
|
||||||
#include "Log.hxx"
|
|
||||||
#include "util/Error.hxx"
|
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -45,31 +44,25 @@ riff_seek_id3(InputStream &is)
|
|||||||
{
|
{
|
||||||
/* seek to the beginning and read the RIFF header */
|
/* seek to the beginning and read the RIFF header */
|
||||||
|
|
||||||
Error error;
|
is.Rewind();
|
||||||
if (!is.Rewind(error)) {
|
|
||||||
LogError(error, "Failed to seek");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
riff_header header;
|
riff_header header;
|
||||||
if (!is.ReadFull(&header, sizeof(header), IgnoreError()) ||
|
is.ReadFull(&header, sizeof(header));
|
||||||
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()))
|
||||||
/* not a RIFF file */
|
throw std::runtime_error("Not a RIFF file");
|
||||||
return 0;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
/* read the chunk header */
|
/* read the chunk header */
|
||||||
|
|
||||||
riff_chunk_header chunk;
|
riff_chunk_header chunk;
|
||||||
if (!is.ReadFull(&chunk, sizeof(chunk), IgnoreError()))
|
is.ReadFull(&chunk, sizeof(chunk));
|
||||||
return 0;
|
|
||||||
|
|
||||||
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()))
|
||||||
/* too dangerous, bail out: possible integer
|
/* too dangerous, bail out: possible integer
|
||||||
underflow when casting to off_t */
|
underflow when casting to off_t */
|
||||||
return 0;
|
throw std::runtime_error("RIFF chunk is too large");
|
||||||
|
|
||||||
if (memcmp(chunk.id, "id3 ", 4) == 0 ||
|
if (memcmp(chunk.id, "id3 ", 4) == 0 ||
|
||||||
memcmp(chunk.id, "ID3 ", 4) == 0)
|
memcmp(chunk.id, "ID3 ", 4) == 0)
|
||||||
@ -80,7 +73,6 @@ riff_seek_id3(InputStream &is)
|
|||||||
/* pad byte */
|
/* pad byte */
|
||||||
++size;
|
++size;
|
||||||
|
|
||||||
if (!is.Skip(size, IgnoreError()))
|
is.Skip(size);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,10 @@ class InputStream;
|
|||||||
/**
|
/**
|
||||||
* Seeks the RIFF file to the ID3 chunk.
|
* Seeks the RIFF file to the ID3 chunk.
|
||||||
*
|
*
|
||||||
|
* Throws std::runtime_error on error.
|
||||||
|
*
|
||||||
* @param is a locked #InputStream
|
* @param is a locked #InputStream
|
||||||
* @return the size of the ID3 chunk on success, or 0 if this is not a
|
* @return the size of the ID3 chunk
|
||||||
* RIFF file or no ID3 chunk was found
|
|
||||||
*/
|
*/
|
||||||
size_t
|
size_t
|
||||||
riff_seek_id3(InputStream &is);
|
riff_seek_id3(InputStream &is);
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "util/Error.hxx"
|
#include "util/Error.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
using std::cout;
|
using std::cout;
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
@ -46,7 +47,7 @@ using std::endl;
|
|||||||
#ifdef ENABLE_UPNP
|
#ifdef ENABLE_UPNP
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
size_t
|
size_t
|
||||||
InputStream::LockRead(void *, size_t, Error &)
|
InputStream::LockRead(void *, size_t)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,10 @@
|
|||||||
#include "FakeDecoderAPI.hxx"
|
#include "FakeDecoderAPI.hxx"
|
||||||
#include "decoder/DecoderAPI.hxx"
|
#include "decoder/DecoderAPI.hxx"
|
||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@ -84,7 +85,11 @@ decoder_read(gcc_unused Decoder *decoder,
|
|||||||
InputStream &is,
|
InputStream &is,
|
||||||
void *buffer, size_t length)
|
void *buffer, size_t length)
|
||||||
{
|
{
|
||||||
return is.LockRead(buffer, length, IgnoreError());
|
try {
|
||||||
|
return is.LockRead(buffer, length);
|
||||||
|
} catch (const std::runtime_error &) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "input/TextInputStream.hxx"
|
#include "input/TextInputStream.hxx"
|
||||||
#include "config/ConfigGlobal.hxx"
|
#include "config/ConfigGlobal.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
@ -55,12 +54,7 @@ dump_input_stream(InputStreamPtr &&is)
|
|||||||
|
|
||||||
const ScopeLock protect(is->mutex);
|
const ScopeLock protect(is->mutex);
|
||||||
|
|
||||||
Error error;
|
is->Check();
|
||||||
if (!is->Check(error)) {
|
|
||||||
LogError(error);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "input/InputStream.hxx"
|
#include "input/InputStream.hxx"
|
||||||
#include "input/Init.hxx"
|
#include "input/Init.hxx"
|
||||||
#include "ScopeIOThread.hxx"
|
#include "ScopeIOThread.hxx"
|
||||||
#include "util/Error.hxx"
|
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "fs/io/BufferedOutputStream.hxx"
|
||||||
@ -68,26 +67,17 @@ dump_input_stream(InputStream *is)
|
|||||||
delete tag;
|
delete tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error error;
|
|
||||||
char buffer[4096];
|
char buffer[4096];
|
||||||
size_t num_read = is->Read(buffer, sizeof(buffer), error);
|
size_t num_read = is->Read(buffer, sizeof(buffer));
|
||||||
if (num_read == 0) {
|
if (num_read == 0)
|
||||||
if (error.IsDefined())
|
|
||||||
LogError(error);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t num_written = write(1, buffer, num_read);
|
ssize_t num_written = write(1, buffer, num_read);
|
||||||
if (num_written <= 0)
|
if (num_written <= 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error error;
|
is->Check();
|
||||||
if (!is->Check(error)) {
|
|
||||||
LogError(error);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -109,7 +99,6 @@ try {
|
|||||||
archive_plugin_init_all();
|
archive_plugin_init_all();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Error error;
|
|
||||||
input_stream_global_init();
|
input_stream_global_init();
|
||||||
|
|
||||||
/* open the stream and dump it */
|
/* open the stream and dump it */
|
||||||
|
@ -37,8 +37,7 @@ public:
|
|||||||
return remaining == 0;
|
return remaining == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Read(void *ptr, size_t read_size,
|
size_t Read(void *ptr, size_t read_size) override {
|
||||||
gcc_unused Error &error) override {
|
|
||||||
size_t nbytes = std::min(remaining, read_size);
|
size_t nbytes = std::min(remaining, read_size);
|
||||||
memcpy(ptr, data, nbytes);
|
memcpy(ptr, data, nbytes);
|
||||||
data += nbytes;
|
data += nbytes;
|
||||||
@ -76,50 +75,50 @@ public:
|
|||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
char buffer[16];
|
char buffer[16];
|
||||||
size_t nbytes = ris->Read(buffer, 2, error);
|
size_t nbytes = ris->Read(buffer, 2);
|
||||||
CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
|
CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
|
||||||
CPPUNIT_ASSERT_EQUAL('f', buffer[0]);
|
CPPUNIT_ASSERT_EQUAL('f', buffer[0]);
|
||||||
CPPUNIT_ASSERT_EQUAL('o', buffer[1]);
|
CPPUNIT_ASSERT_EQUAL('o', buffer[1]);
|
||||||
CPPUNIT_ASSERT_EQUAL(offset_type(2), ris->GetOffset());
|
CPPUNIT_ASSERT_EQUAL(offset_type(2), ris->GetOffset());
|
||||||
CPPUNIT_ASSERT(!ris->IsEOF());
|
CPPUNIT_ASSERT(!ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, 2, error);
|
nbytes = ris->Read(buffer, 2);
|
||||||
CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
|
CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
|
||||||
CPPUNIT_ASSERT_EQUAL('o', buffer[0]);
|
CPPUNIT_ASSERT_EQUAL('o', buffer[0]);
|
||||||
CPPUNIT_ASSERT_EQUAL(' ', buffer[1]);
|
CPPUNIT_ASSERT_EQUAL(' ', buffer[1]);
|
||||||
CPPUNIT_ASSERT_EQUAL(offset_type(4), ris->GetOffset());
|
CPPUNIT_ASSERT_EQUAL(offset_type(4), ris->GetOffset());
|
||||||
CPPUNIT_ASSERT(!ris->IsEOF());
|
CPPUNIT_ASSERT(!ris->IsEOF());
|
||||||
|
|
||||||
CPPUNIT_ASSERT(ris->Seek(1, error));
|
ris->Seek(1);
|
||||||
CPPUNIT_ASSERT_EQUAL(offset_type(1), ris->GetOffset());
|
CPPUNIT_ASSERT_EQUAL(offset_type(1), ris->GetOffset());
|
||||||
CPPUNIT_ASSERT(!ris->IsEOF());
|
CPPUNIT_ASSERT(!ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, 2, error);
|
nbytes = ris->Read(buffer, 2);
|
||||||
CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
|
CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
|
||||||
CPPUNIT_ASSERT_EQUAL('o', buffer[0]);
|
CPPUNIT_ASSERT_EQUAL('o', buffer[0]);
|
||||||
CPPUNIT_ASSERT_EQUAL('o', buffer[1]);
|
CPPUNIT_ASSERT_EQUAL('o', buffer[1]);
|
||||||
CPPUNIT_ASSERT_EQUAL(offset_type(3), ris->GetOffset());
|
CPPUNIT_ASSERT_EQUAL(offset_type(3), ris->GetOffset());
|
||||||
CPPUNIT_ASSERT(!ris->IsEOF());
|
CPPUNIT_ASSERT(!ris->IsEOF());
|
||||||
|
|
||||||
CPPUNIT_ASSERT(ris->Seek(0, error));
|
ris->Seek(0);
|
||||||
CPPUNIT_ASSERT_EQUAL(offset_type(0), ris->GetOffset());
|
CPPUNIT_ASSERT_EQUAL(offset_type(0), ris->GetOffset());
|
||||||
CPPUNIT_ASSERT(!ris->IsEOF());
|
CPPUNIT_ASSERT(!ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, 2, error);
|
nbytes = ris->Read(buffer, 2);
|
||||||
CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
|
CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
|
||||||
CPPUNIT_ASSERT_EQUAL('f', buffer[0]);
|
CPPUNIT_ASSERT_EQUAL('f', buffer[0]);
|
||||||
CPPUNIT_ASSERT_EQUAL('o', buffer[1]);
|
CPPUNIT_ASSERT_EQUAL('o', buffer[1]);
|
||||||
CPPUNIT_ASSERT_EQUAL(offset_type(2), ris->GetOffset());
|
CPPUNIT_ASSERT_EQUAL(offset_type(2), ris->GetOffset());
|
||||||
CPPUNIT_ASSERT(!ris->IsEOF());
|
CPPUNIT_ASSERT(!ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, sizeof(buffer), error);
|
nbytes = ris->Read(buffer, sizeof(buffer));
|
||||||
CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
|
CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes);
|
||||||
CPPUNIT_ASSERT_EQUAL('o', buffer[0]);
|
CPPUNIT_ASSERT_EQUAL('o', buffer[0]);
|
||||||
CPPUNIT_ASSERT_EQUAL(' ', buffer[1]);
|
CPPUNIT_ASSERT_EQUAL(' ', buffer[1]);
|
||||||
CPPUNIT_ASSERT_EQUAL(offset_type(4), ris->GetOffset());
|
CPPUNIT_ASSERT_EQUAL(offset_type(4), ris->GetOffset());
|
||||||
CPPUNIT_ASSERT(!ris->IsEOF());
|
CPPUNIT_ASSERT(!ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, sizeof(buffer), error);
|
nbytes = ris->Read(buffer, sizeof(buffer));
|
||||||
CPPUNIT_ASSERT_EQUAL(size_t(3), nbytes);
|
CPPUNIT_ASSERT_EQUAL(size_t(3), nbytes);
|
||||||
CPPUNIT_ASSERT_EQUAL('b', buffer[0]);
|
CPPUNIT_ASSERT_EQUAL('b', buffer[0]);
|
||||||
CPPUNIT_ASSERT_EQUAL('a', buffer[1]);
|
CPPUNIT_ASSERT_EQUAL('a', buffer[1]);
|
||||||
@ -127,11 +126,11 @@ public:
|
|||||||
CPPUNIT_ASSERT_EQUAL(offset_type(7), ris->GetOffset());
|
CPPUNIT_ASSERT_EQUAL(offset_type(7), ris->GetOffset());
|
||||||
CPPUNIT_ASSERT(ris->IsEOF());
|
CPPUNIT_ASSERT(ris->IsEOF());
|
||||||
|
|
||||||
CPPUNIT_ASSERT(ris->Seek(3, error));
|
ris->Seek(3);
|
||||||
CPPUNIT_ASSERT_EQUAL(offset_type(3), ris->GetOffset());
|
CPPUNIT_ASSERT_EQUAL(offset_type(3), ris->GetOffset());
|
||||||
CPPUNIT_ASSERT(!ris->IsEOF());
|
CPPUNIT_ASSERT(!ris->IsEOF());
|
||||||
|
|
||||||
nbytes = ris->Read(buffer, sizeof(buffer), error);
|
nbytes = ris->Read(buffer, sizeof(buffer));
|
||||||
CPPUNIT_ASSERT_EQUAL(size_t(4), nbytes);
|
CPPUNIT_ASSERT_EQUAL(size_t(4), nbytes);
|
||||||
CPPUNIT_ASSERT_EQUAL(' ', buffer[0]);
|
CPPUNIT_ASSERT_EQUAL(' ', buffer[0]);
|
||||||
CPPUNIT_ASSERT_EQUAL('b', buffer[1]);
|
CPPUNIT_ASSERT_EQUAL('b', buffer[1]);
|
||||||
|
Loading…
Reference in New Issue
Block a user