input/InputStream: migrate from class Error to C++ exceptions

This commit is contained in:
Max Kellermann 2016-09-09 18:47:42 +02:00
parent 597e59f10d
commit 8c744efd56
64 changed files with 440 additions and 473 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;
} }

View File

@ -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 */

View File

@ -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) {

View File

@ -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);

View File

@ -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;
} }
} }

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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);
} }

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;
} }

View File

@ -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

View File

@ -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);

View File

@ -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);
} }

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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())

View File

@ -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:
/** /**

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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:
/** /**

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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());

View File

@ -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) {

View File

@ -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;

View File

@ -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 = {

View File

@ -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 = {

View 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);
} }
} }

View File

@ -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 = {

View File

@ -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 *

View File

@ -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

View File

@ -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)
{ {

View File

@ -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);

View File

@ -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

View File

@ -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));

View File

@ -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();

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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;
} }
} }

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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 &) {

View File

@ -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;
} }
} }

View File

@ -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);

View File

@ -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;
} }

View File

@ -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

View File

@ -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;
} }

View File

@ -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 */

View File

@ -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]);