Commit e4a06da1 authored by Max Kellermann's avatar Max Kellermann

fs/io/OutputStream: use C++ exceptions in Write()

parent 36d6ead6
...@@ -239,8 +239,7 @@ SavePlaylistFile(const PlaylistFileContents &contents, const char *utf8path, ...@@ -239,8 +239,7 @@ SavePlaylistFile(const PlaylistFileContents &contents, const char *utf8path,
for (const auto &uri_utf8 : contents) for (const auto &uri_utf8 : contents)
playlist_print_uri(bos, uri_utf8.c_str()); playlist_print_uri(bos, uri_utf8.c_str());
if (!bos.Flush(error)) bos.Flush();
return false;
fos.Commit(); fos.Commit();
return true; return true;
...@@ -415,9 +414,7 @@ spl_append_song(const char *utf8path, const DetachedSong &song, Error &error) ...@@ -415,9 +414,7 @@ spl_append_song(const char *utf8path, const DetachedSong &song, Error &error)
playlist_print_song(bos, song); playlist_print_song(bos, song);
if (!bos.Flush(error)) bos.Flush();
return false;
fos.Commit(); fos.Commit();
idle_add(IDLE_STORED_PLAYLIST); idle_add(IDLE_STORED_PLAYLIST);
......
...@@ -86,9 +86,7 @@ spl_save_queue(const char *name_utf8, const Queue &queue, Error &error) ...@@ -86,9 +86,7 @@ spl_save_queue(const char *name_utf8, const Queue &queue, Error &error)
for (unsigned i = 0; i < queue.GetLength(); i++) for (unsigned i = 0; i < queue.GetLength(); i++)
playlist_print_song(bos, queue.Get(i)); playlist_print_song(bos, queue.Get(i));
if (!bos.Flush(error)) bos.Flush();
return false;
fos.Commit(); fos.Commit();
idle_add(IDLE_STORED_PLAYLIST); idle_add(IDLE_STORED_PLAYLIST);
......
...@@ -75,12 +75,12 @@ StateFile::Write(BufferedOutputStream &os) ...@@ -75,12 +75,12 @@ StateFile::Write(BufferedOutputStream &os)
playlist_state_save(os, partition.playlist, partition.pc); playlist_state_save(os, partition.playlist, partition.pc);
} }
inline bool inline void
StateFile::Write(OutputStream &os, Error &error) StateFile::Write(OutputStream &os)
{ {
BufferedOutputStream bos(os); BufferedOutputStream bos(os);
Write(bos); Write(bos);
return bos.Flush(error); bos.Flush();
} }
void void
...@@ -90,13 +90,8 @@ StateFile::Write() ...@@ -90,13 +90,8 @@ StateFile::Write()
"Saving state file %s", path_utf8.c_str()); "Saving state file %s", path_utf8.c_str());
try { try {
Error error;
FileOutputStream fos(path); FileOutputStream fos(path);
if (!Write(fos, error)) { Write(fos);
LogError(error);
return;
}
fos.Commit(); fos.Commit();
} catch (const std::exception &e) { } catch (const std::exception &e) {
LogError(e); LogError(e);
......
...@@ -60,7 +60,7 @@ public: ...@@ -60,7 +60,7 @@ public:
void CheckModified(); void CheckModified();
private: private:
bool Write(OutputStream &os, Error &error); void Write(OutputStream &os);
void Write(BufferedOutputStream &os); void Write(BufferedOutputStream &os);
/** /**
......
...@@ -90,9 +90,6 @@ directory_save(BufferedOutputStream &os, const Directory &directory) ...@@ -90,9 +90,6 @@ directory_save(BufferedOutputStream &os, const Directory &directory)
if (!child.IsMount()) if (!child.IsMount())
directory_save(os, child); directory_save(os, child);
if (!os.Check())
return;
} }
for (const auto &song : directory.songs) for (const auto &song : directory.songs)
......
...@@ -364,8 +364,8 @@ SimpleDatabase::GetStats(const DatabaseSelection &selection, ...@@ -364,8 +364,8 @@ SimpleDatabase::GetStats(const DatabaseSelection &selection,
return ::GetStats(*this, selection, stats, error); return ::GetStats(*this, selection, stats, error);
} }
bool void
SimpleDatabase::Save(Error &error) SimpleDatabase::Save()
{ {
{ {
const ScopeDatabaseLock protect; const ScopeDatabaseLock protect;
...@@ -395,16 +395,12 @@ SimpleDatabase::Save(Error &error) ...@@ -395,16 +395,12 @@ SimpleDatabase::Save(Error &error)
db_save_internal(bos, *root); db_save_internal(bos, *root);
if (!bos.Flush(error)) { bos.Flush();
return false;
}
#ifdef ENABLE_ZLIB #ifdef ENABLE_ZLIB
if (gzip != nullptr) { if (gzip != nullptr) {
bool success = gzip->Flush(error); gzip->Flush();
gzip.reset(); gzip.reset();
if (!success)
return false;
} }
#endif #endif
...@@ -413,8 +409,6 @@ SimpleDatabase::Save(Error &error) ...@@ -413,8 +409,6 @@ SimpleDatabase::Save(Error &error)
FileInfo fi; FileInfo fi;
if (GetFileInfo(path, fi)) if (GetFileInfo(path, fi))
mtime = fi.GetModificationTime(); mtime = fi.GetModificationTime();
return true;
} }
bool bool
......
...@@ -83,7 +83,7 @@ public: ...@@ -83,7 +83,7 @@ public:
return *root; return *root;
} }
bool Save(Error &error); void Save();
/** /**
* Returns true if there is a valid database file on the disk. * Returns true if there is a valid database file on the disk.
......
...@@ -130,9 +130,7 @@ UpdateService::Task() ...@@ -130,9 +130,7 @@ UpdateService::Task()
if (modified || !next.db->FileExists()) { if (modified || !next.db->FileExists()) {
try { try {
Error error; next.db->Save();
if (!next.db->Save(error))
LogError(error, "Failed to save database");
} catch (const std::exception &e) { } catch (const std::exception &e) {
LogError(e, "Failed to save database"); LogError(e, "Failed to save database");
} }
......
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
#include "EncoderInterface.hxx" #include "EncoderInterface.hxx"
#include "fs/io/OutputStream.hxx" #include "fs/io/OutputStream.hxx"
bool void
EncoderToOutputStream(OutputStream &os, Encoder &encoder, Error &error) EncoderToOutputStream(OutputStream &os, Encoder &encoder)
{ {
while (true) { while (true) {
/* read from the encoder */ /* read from the encoder */
...@@ -31,11 +31,10 @@ EncoderToOutputStream(OutputStream &os, Encoder &encoder, Error &error) ...@@ -31,11 +31,10 @@ EncoderToOutputStream(OutputStream &os, Encoder &encoder, Error &error)
char buffer[32768]; char buffer[32768];
size_t nbytes = encoder_read(&encoder, buffer, sizeof(buffer)); size_t nbytes = encoder_read(&encoder, buffer, sizeof(buffer));
if (nbytes == 0) if (nbytes == 0)
return true; return;
/* write everything to the stream */ /* write everything to the stream */
if (!os.Write(buffer, nbytes, error)) os.Write(buffer, nbytes);
return false;
} }
} }
...@@ -24,9 +24,8 @@ ...@@ -24,9 +24,8 @@
struct Encoder; struct Encoder;
class OutputStream; class OutputStream;
class Error;
bool void
EncoderToOutputStream(OutputStream &os, Encoder &encoder, Error &error); EncoderToOutputStream(OutputStream &os, Encoder &encoder);
#endif #endif
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <stdio.h> #include <stdio.h>
bool bool
BufferedOutputStream::AppendToBuffer(const void *data, size_t size) BufferedOutputStream::AppendToBuffer(const void *data, size_t size) noexcept
{ {
auto r = buffer.Write(); auto r = buffer.Write();
if (r.size < size) if (r.size < size)
...@@ -37,46 +37,36 @@ BufferedOutputStream::AppendToBuffer(const void *data, size_t size) ...@@ -37,46 +37,36 @@ BufferedOutputStream::AppendToBuffer(const void *data, size_t size)
return true; return true;
} }
bool void
BufferedOutputStream::Write(const void *data, size_t size) BufferedOutputStream::Write(const void *data, size_t size)
{ {
if (gcc_unlikely(last_error.IsDefined()))
/* the stream has already failed */
return false;
/* try to append to the current buffer */ /* try to append to the current buffer */
if (AppendToBuffer(data, size)) if (AppendToBuffer(data, size))
return true; return;
/* not enough room in the buffer - flush it */ /* not enough room in the buffer - flush it */
if (!Flush()) Flush();
return false;
/* see if there's now enough room */ /* see if there's now enough room */
if (AppendToBuffer(data, size)) if (AppendToBuffer(data, size))
return true; return;
/* too large for the buffer: direct write */ /* too large for the buffer: direct write */
return os.Write(data, size, last_error); os.Write(data, size);
} }
bool void
BufferedOutputStream::Write(const char *p) BufferedOutputStream::Write(const char *p)
{ {
return Write(p, strlen(p)); Write(p, strlen(p));
} }
bool void
BufferedOutputStream::Format(const char *fmt, ...) BufferedOutputStream::Format(const char *fmt, ...)
{ {
if (gcc_unlikely(last_error.IsDefined()))
return false;
auto r = buffer.Write(); auto r = buffer.Write();
if (r.IsEmpty()) { if (r.IsEmpty()) {
if (!Flush()) Flush();
return false;
r = buffer.Write(); r = buffer.Write();
} }
...@@ -90,8 +80,7 @@ BufferedOutputStream::Format(const char *fmt, ...) ...@@ -90,8 +80,7 @@ BufferedOutputStream::Format(const char *fmt, ...)
/* buffer was not large enough; flush it and try /* buffer was not large enough; flush it and try
again */ again */
if (!Flush()) Flush();
return false;
r = buffer.Write(); r = buffer.Write();
...@@ -112,37 +101,15 @@ BufferedOutputStream::Format(const char *fmt, ...) ...@@ -112,37 +101,15 @@ BufferedOutputStream::Format(const char *fmt, ...)
} }
buffer.Append(size); buffer.Append(size);
return true;
} }
bool void
BufferedOutputStream::Flush() BufferedOutputStream::Flush()
{ {
if (!Check())
return false;
auto r = buffer.Read();
if (r.IsEmpty())
return true;
bool success = os.Write(r.data, r.size, last_error);
if (gcc_likely(success))
buffer.Consume(r.size);
return success;
}
bool
BufferedOutputStream::Flush(Error &error)
{
if (!Check(error))
return false;
auto r = buffer.Read(); auto r = buffer.Read();
if (r.IsEmpty()) if (r.IsEmpty())
return true; return;
bool success = os.Write(r.data, r.size, error); os.Write(r.data, r.size);
if (gcc_likely(success)) buffer.Consume(r.size);
buffer.Consume(r.size);
return success;
} }
...@@ -23,67 +23,37 @@ ...@@ -23,67 +23,37 @@
#include "check.h" #include "check.h"
#include "Compiler.h" #include "Compiler.h"
#include "util/DynamicFifoBuffer.hxx" #include "util/DynamicFifoBuffer.hxx"
#include "util/Error.hxx"
#include <stddef.h> #include <stddef.h>
class OutputStream; class OutputStream;
class Error;
/** /**
* An #OutputStream wrapper that buffers its output to reduce the * An #OutputStream wrapper that buffers its output to reduce the
* number of OutputStream::Write() calls. * number of OutputStream::Write() calls.
*
* It simplifies error handling by managing an #Error attribute.
* Invoke any number of writes, and check for errors in the end using
* Check().
*/ */
class BufferedOutputStream { class BufferedOutputStream {
OutputStream &os; OutputStream &os;
DynamicFifoBuffer<char> buffer; DynamicFifoBuffer<char> buffer;
Error last_error;
public: public:
BufferedOutputStream(OutputStream &_os) BufferedOutputStream(OutputStream &_os)
:os(_os), buffer(32768) {} :os(_os), buffer(32768) {}
bool Write(const void *data, size_t size); void Write(const void *data, size_t size);
bool Write(const char *p); void Write(const char *p);
gcc_printf(2,3) gcc_printf(2,3)
bool Format(const char *fmt, ...); void Format(const char *fmt, ...);
/**
* Returns false if an error has occurred.
*/
gcc_pure
bool Check() const {
return !last_error.IsDefined();
}
/**
* Returns false if an error has occurred. In that case, a
* copy of the #Error is returned.
*/
bool Check(Error &error) const {
if (last_error.IsDefined()) {
error.Set(last_error);
return false;
} else
return true;
}
/** /**
* Write buffer contents to the #OutputStream. * Write buffer contents to the #OutputStream.
*/ */
bool Flush(); void Flush();
bool Flush(Error &error);
private: private:
bool AppendToBuffer(const void *data, size_t size); bool AppendToBuffer(const void *data, size_t size) noexcept;
}; };
#endif #endif
...@@ -21,9 +21,6 @@ ...@@ -21,9 +21,6 @@
#include "FileOutputStream.hxx" #include "FileOutputStream.hxx"
#include "fs/FileSystem.hxx" #include "fs/FileSystem.hxx"
#include "system/Error.hxx" #include "system/Error.hxx"
#include "util/Error.hxx"
#include <system_error>
#ifdef WIN32 #ifdef WIN32
...@@ -50,26 +47,19 @@ BaseFileOutputStream::Tell() const ...@@ -50,26 +47,19 @@ BaseFileOutputStream::Tell() const
return uint64_t(high) << 32 | uint64_t(low); return uint64_t(high) << 32 | uint64_t(low);
} }
bool void
BaseFileOutputStream::Write(const void *data, size_t size, Error &error) BaseFileOutputStream::Write(const void *data, size_t size)
{ {
assert(IsDefined()); assert(IsDefined());
DWORD nbytes; DWORD nbytes;
if (!WriteFile(handle, data, size, &nbytes, nullptr)) { if (!WriteFile(handle, data, size, &nbytes, nullptr))
error.FormatLastError("Failed to write to %s", throw FormatLastError("Failed to write to %s",
path.ToUTF8().c_str()); GetPath().c_str());
return false;
}
if (size_t(nbytes) != size) {
error.FormatLastError(ERROR_DISK_FULL,
"Failed to write to %s",
path.ToUTF8().c_str());
return false;
}
return true; if (size_t(nbytes) != size)
throw FormatLastError(ERROR_DISK_FULL, "Failed to write to %s",
GetPath().c_str());
} }
void void
...@@ -143,22 +133,17 @@ BaseFileOutputStream::Tell() const ...@@ -143,22 +133,17 @@ BaseFileOutputStream::Tell() const
return fd.Tell(); return fd.Tell();
} }
bool void
BaseFileOutputStream::Write(const void *data, size_t size, Error &error) BaseFileOutputStream::Write(const void *data, size_t size)
{ {
assert(IsDefined()); assert(IsDefined());
ssize_t nbytes = fd.Write(data, size); ssize_t nbytes = fd.Write(data, size);
if (nbytes < 0) { if (nbytes < 0)
error.FormatErrno("Failed to write to %s", GetPath().c_str()); throw FormatErrno("Failed to write to %s", GetPath().c_str());
return false; else if ((size_t)nbytes < size)
} else if ((size_t)nbytes < size) { throw FormatErrno(ENOSPC, "Failed to write to %s",
error.FormatErrno(ENOSPC, GetPath().c_str());
"Failed to write to %s", GetPath().c_str());
return false;
}
return true;
} }
void void
......
...@@ -119,7 +119,7 @@ public: ...@@ -119,7 +119,7 @@ public:
uint64_t Tell() const; uint64_t Tell() const;
/* virtual methods from class OutputStream */ /* virtual methods from class OutputStream */
bool Write(const void *data, size_t size, Error &error) override; void Write(const void *data, size_t size) override;
}; };
class FileOutputStream final : public BaseFileOutputStream { class FileOutputStream final : public BaseFileOutputStream {
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include "GzipOutputStream.hxx" #include "GzipOutputStream.hxx"
#include "lib/zlib/Domain.hxx" #include "lib/zlib/Domain.hxx"
#include "lib/zlib/Error.hxx" #include "lib/zlib/Error.hxx"
#include "util/Error.hxx"
GzipOutputStream::GzipOutputStream(OutputStream &_next) throw(ZlibError) GzipOutputStream::GzipOutputStream(OutputStream &_next) throw(ZlibError)
:next(_next) :next(_next)
...@@ -47,8 +46,8 @@ GzipOutputStream::~GzipOutputStream() ...@@ -47,8 +46,8 @@ GzipOutputStream::~GzipOutputStream()
deflateEnd(&z); deflateEnd(&z);
} }
bool void
GzipOutputStream::Flush(Error &error) GzipOutputStream::Flush()
{ {
/* no more input */ /* no more input */
z.next_in = nullptr; z.next_in = nullptr;
...@@ -60,21 +59,18 @@ GzipOutputStream::Flush(Error &error) ...@@ -60,21 +59,18 @@ GzipOutputStream::Flush(Error &error)
z.avail_out = sizeof(output); z.avail_out = sizeof(output);
int result = deflate(&z, Z_FINISH); int result = deflate(&z, Z_FINISH);
if (z.next_out > output && if (z.next_out > output)
!next.Write(output, z.next_out - output, error)) next.Write(output, z.next_out - output);
return false;
if (result == Z_STREAM_END) if (result == Z_STREAM_END)
return true; break;
else if (result != Z_OK) { else if (result != Z_OK)
error.Set(zlib_domain, result, zError(result)); throw ZlibError(result);
return false; }
}
}
} }
bool void
GzipOutputStream::Write(const void *_data, size_t size, Error &error) GzipOutputStream::Write(const void *_data, size_t size)
{ {
/* zlib's API requires non-const input pointer */ /* zlib's API requires non-const input pointer */
void *data = const_cast<void *>(_data); void *data = const_cast<void *>(_data);
...@@ -88,15 +84,10 @@ GzipOutputStream::Write(const void *_data, size_t size, Error &error) ...@@ -88,15 +84,10 @@ GzipOutputStream::Write(const void *_data, size_t size, Error &error)
z.avail_out = sizeof(output); z.avail_out = sizeof(output);
int result = deflate(&z, Z_NO_FLUSH); int result = deflate(&z, Z_NO_FLUSH);
if (result != Z_OK) { if (result != Z_OK)
error.Set(zlib_domain, result, zError(result)); throw ZlibError(result);
return false;
}
if (z.next_out > output && if (z.next_out > output)
!next.Write(output, z.next_out - output, error)) next.Write(output, z.next_out - output);
return false;
} }
return true;
} }
...@@ -28,8 +28,6 @@ ...@@ -28,8 +28,6 @@
#include <assert.h> #include <assert.h>
#include <zlib.h> #include <zlib.h>
class Error;
/** /**
* A filter that compresses data written to it using zlib, forwarding * A filter that compresses data written to it using zlib, forwarding
* compressed data in the "gzip" format. * compressed data in the "gzip" format.
...@@ -52,10 +50,10 @@ public: ...@@ -52,10 +50,10 @@ public:
* Finish the file and write all data remaining in zlib's * Finish the file and write all data remaining in zlib's
* output buffer. * output buffer.
*/ */
bool Flush(Error &error); void Flush();
/* virtual methods from class OutputStream */ /* virtual methods from class OutputStream */
bool Write(const void *data, size_t size, Error &error) override; void Write(const void *data, size_t size) override;
}; };
#endif #endif
...@@ -21,18 +21,18 @@ ...@@ -21,18 +21,18 @@
#define MPD_OUTPUT_STREAM_HXX #define MPD_OUTPUT_STREAM_HXX
#include "check.h" #include "check.h"
#include "Compiler.h"
#include <stddef.h> #include <stddef.h>
class Error;
class OutputStream { class OutputStream {
public: public:
OutputStream() = default; OutputStream() = default;
OutputStream(const OutputStream &) = delete; OutputStream(const OutputStream &) = delete;
virtual bool Write(const void *data, size_t size, Error &error) = 0; /**
* Throws std::exception on error.
*/
virtual void Write(const void *data, size_t size) = 0;
}; };
#endif #endif
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include "check.h" #include "check.h"
#include "OutputStream.hxx" #include "OutputStream.hxx"
#include "fs/AllocatedPath.hxx"
#include "Compiler.h" #include "Compiler.h"
#include <stdio.h> #include <stdio.h>
...@@ -34,12 +33,10 @@ public: ...@@ -34,12 +33,10 @@ public:
StdioOutputStream(FILE *_file):file(_file) {} StdioOutputStream(FILE *_file):file(_file) {}
/* virtual methods from class OutputStream */ /* virtual methods from class OutputStream */
bool Write(const void *data, size_t size, void Write(const void *data, size_t size) override {
gcc_unused Error &error) override {
fwrite(data, 1, size, file); fwrite(data, 1, size, file);
/* this class is debug-only and ignores errors */ /* this class is debug-only and ignores errors */
return true;
} }
}; };
......
...@@ -95,7 +95,7 @@ class RecorderOutput { ...@@ -95,7 +95,7 @@ class RecorderOutput {
/** /**
* Writes pending data from the encoder to the output file. * Writes pending data from the encoder to the output file.
*/ */
bool EncoderToFile(Error &error); void EncoderToFile();
void SendTag(const Tag &tag); void SendTag(const Tag &tag);
...@@ -175,12 +175,12 @@ RecorderOutput::Create(const ConfigBlock &block, Error &error) ...@@ -175,12 +175,12 @@ RecorderOutput::Create(const ConfigBlock &block, Error &error)
return recorder; return recorder;
} }
inline bool inline void
RecorderOutput::EncoderToFile(Error &error) RecorderOutput::EncoderToFile()
{ {
assert(file != nullptr); assert(file != nullptr);
return EncoderToOutputStream(*file, *encoder, error); EncoderToOutputStream(*file, *encoder);
} }
inline bool inline bool
...@@ -213,9 +213,11 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error) ...@@ -213,9 +213,11 @@ RecorderOutput::Open(AudioFormat &audio_format, Error &error)
} }
if (!HasDynamicPath()) { if (!HasDynamicPath()) {
if (!EncoderToFile(error)) { try {
EncoderToFile();
} catch (const std::exception &e) {
encoder->Close(); encoder->Close();
delete file; error.Set(recorder_domain, e.what());
return false; return false;
} }
} else { } else {
...@@ -237,8 +239,15 @@ RecorderOutput::Commit(Error &error) ...@@ -237,8 +239,15 @@ RecorderOutput::Commit(Error &error)
/* flush the encoder and write the rest to the file */ /* flush the encoder and write the rest to the file */
bool success = encoder_end(encoder, error) && bool success = encoder_end(encoder, error);
EncoderToFile(error); if (success) {
try {
EncoderToFile();
} catch (...) {
encoder->Close();
throw;
}
}
/* now really close everything */ /* now really close everything */
...@@ -328,9 +337,12 @@ RecorderOutput::ReopenFormat(AllocatedPath &&new_path, Error &error) ...@@ -328,9 +337,12 @@ RecorderOutput::ReopenFormat(AllocatedPath &&new_path, Error &error)
AudioFormat as before */ AudioFormat as before */
assert(new_audio_format == effective_audio_format); assert(new_audio_format == effective_audio_format);
if (!EncoderToOutputStream(*new_file, *encoder, error)) { try {
EncoderToOutputStream(*new_file, *encoder);
} catch (const std::exception &e) {
encoder->Close(); encoder->Close();
delete new_file; delete new_file;
error.Set(recorder_domain, e.what());
return false; return false;
} }
...@@ -376,9 +388,19 @@ RecorderOutput::SendTag(const Tag &tag) ...@@ -376,9 +388,19 @@ RecorderOutput::SendTag(const Tag &tag)
} }
Error error; Error error;
if (!encoder_pre_tag(encoder, error) || if (!encoder_pre_tag(encoder, error)) {
!EncoderToFile(error) || LogError(error);
!encoder_tag(encoder, tag, error)) return;
}
try {
EncoderToFile();
} catch (const std::exception &e) {
LogError(e);
return;
}
if (!encoder_tag(encoder, tag, error))
LogError(error); LogError(error);
} }
...@@ -393,9 +415,17 @@ RecorderOutput::Play(const void *chunk, size_t size, Error &error) ...@@ -393,9 +415,17 @@ RecorderOutput::Play(const void *chunk, size_t size, Error &error)
return size; return size;
} }
return encoder_write(encoder, chunk, size, error) && if (!encoder_write(encoder, chunk, size, error))
EncoderToFile(error) return 0;
? size : 0;
try {
EncoderToFile();
} catch (const std::exception &e) {
error.Set(recorder_domain, e.what());
return 0;
}
return size;
} }
typedef AudioOutputWrapper<RecorderOutput> Wrapper; typedef AudioOutputWrapper<RecorderOutput> Wrapper;
......
...@@ -43,10 +43,7 @@ Copy(OutputStream &dest, int src) ...@@ -43,10 +43,7 @@ Copy(OutputStream &dest, int src)
if (nbytes == 0) if (nbytes == 0)
return true; return true;
if (!dest.Write(buffer, nbytes, error)) { dest.Write(buffer, nbytes);
fprintf(stderr, "%s\n", error.GetMessage());
return false;
}
} }
} }
......
...@@ -63,60 +63,58 @@ int main(int argc, char **argv) ...@@ -63,60 +63,58 @@ int main(int argc, char **argv)
ConfigBlock block; ConfigBlock block;
block.AddBlockParam("quality", "5.0", -1); block.AddBlockParam("quality", "5.0", -1);
Error error; try {
const auto encoder = encoder_init(*plugin, block, error); Error error;
if (encoder == NULL) { const auto encoder = encoder_init(*plugin, block, error);
LogError(error, "Failed to initialize encoder"); if (encoder == NULL) {
return EXIT_FAILURE; LogError(error, "Failed to initialize encoder");
} return EXIT_FAILURE;
}
/* open the encoder */ /* open the encoder */
AudioFormat audio_format(44100, SampleFormat::S16, 2); AudioFormat audio_format(44100, SampleFormat::S16, 2);
if (argc > 2) { if (argc > 2) {
if (!audio_format_parse(audio_format, argv[2], false, error)) { if (!audio_format_parse(audio_format, argv[2], false, error)) {
LogError(error, "Failed to parse audio format"); LogError(error, "Failed to parse audio format");
return EXIT_FAILURE;
}
}
if (!encoder->Open(audio_format, error)) {
LogError(error, "Failed to open encoder");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
}
if (!encoder->Open(audio_format, error)) { StdioOutputStream os(stdout);
LogError(error, "Failed to open encoder");
return EXIT_FAILURE;
}
StdioOutputStream os(stdout); EncoderToOutputStream(os, *encoder);
if (!EncoderToOutputStream(os, *encoder, error)) { /* do it */
LogError(error);
return EXIT_FAILURE;
}
/* do it */ ssize_t nbytes;
while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) {
if (!encoder_write(encoder, buffer, nbytes, error)) {
LogError(error, "encoder_write() failed");
return EXIT_FAILURE;
}
ssize_t nbytes; EncoderToOutputStream(os, *encoder);
while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) {
if (!encoder_write(encoder, buffer, nbytes, error)) {
LogError(error, "encoder_write() failed");
return EXIT_FAILURE;
} }
if (!EncoderToOutputStream(os, *encoder, error)) { if (!encoder_end(encoder, error)) {
LogError(error); LogError(error, "encoder_flush() failed");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
}
if (!encoder_end(encoder, error)) { EncoderToOutputStream(os, *encoder);
LogError(error, "encoder_flush() failed");
return EXIT_FAILURE;
}
if (!EncoderToOutputStream(os, *encoder, error)) { encoder->Close();
LogError(error); encoder->Dispose();
return EXIT_SUCCESS;
} catch (const std::exception &e) {
LogError(e);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
encoder->Close();
encoder->Dispose();
} }
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "fs/io/GunzipReader.hxx" #include "fs/io/GunzipReader.hxx"
#include "fs/io/FileReader.hxx" #include "fs/io/FileReader.hxx"
#include "fs/io/StdioOutputStream.hxx" #include "fs/io/StdioOutputStream.hxx"
#include "Log.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include <stdio.h> #include <stdio.h>
...@@ -36,8 +37,7 @@ Copy(OutputStream &dest, Reader &src, Error &error) ...@@ -36,8 +37,7 @@ Copy(OutputStream &dest, Reader &src, Error &error)
if (nbytes == 0) if (nbytes == 0)
return !error.IsDefined(); return !error.IsDefined();
if (!dest.Write(buffer, nbytes, error)) dest.Write(buffer, nbytes);
return false;
} }
} }
...@@ -66,11 +66,16 @@ main(int argc, gcc_unused char **argv) ...@@ -66,11 +66,16 @@ main(int argc, gcc_unused char **argv)
Path path = Path::FromFS(argv[1]); Path path = Path::FromFS(argv[1]);
Error error; try {
if (!CopyGunzip(stdout, path, error)) { Error error;
fprintf(stderr, "%s\n", error.GetMessage()); if (!CopyGunzip(stdout, path, error)) {
fprintf(stderr, "%s\n", error.GetMessage());
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
} catch (const std::exception &e) {
LogError(e);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
return EXIT_SUCCESS;
} }
...@@ -41,8 +41,7 @@ Copy(OutputStream &dest, int src, Error &error) ...@@ -41,8 +41,7 @@ Copy(OutputStream &dest, int src, Error &error)
return true; return true;
} }
if (!dest.Write(buffer, nbytes, error)) dest.Write(buffer, nbytes);
return false;
} }
} }
...@@ -50,8 +49,11 @@ static bool ...@@ -50,8 +49,11 @@ static bool
CopyGzip(OutputStream &_dest, int src, Error &error) CopyGzip(OutputStream &_dest, int src, Error &error)
{ {
GzipOutputStream dest(_dest); GzipOutputStream dest(_dest);
return Copy(dest, src, error) && if (!Copy(dest, src, error))
dest.Flush(error); return false;
dest.Flush();
return true;
} }
static bool static bool
......
...@@ -51,72 +51,63 @@ main(gcc_unused int argc, gcc_unused char **argv) ...@@ -51,72 +51,63 @@ main(gcc_unused int argc, gcc_unused char **argv)
const auto encoder = encoder_init(*plugin, block, IgnoreError()); const auto encoder = encoder_init(*plugin, block, IgnoreError());
assert(encoder != NULL); assert(encoder != NULL);
/* open the encoder */ try {
/* open the encoder */
AudioFormat audio_format(44100, SampleFormat::S16, 2); AudioFormat audio_format(44100, SampleFormat::S16, 2);
success = encoder->Open(audio_format, IgnoreError()); success = encoder->Open(audio_format, IgnoreError());
assert(success); assert(success);
StdioOutputStream os(stdout); StdioOutputStream os(stdout);
Error error; EncoderToOutputStream(os, *encoder);
if (!EncoderToOutputStream(os, *encoder, error)) {
LogError(error);
return EXIT_FAILURE;
}
/* write a block of data */ /* write a block of data */
success = encoder_write(encoder, zero, sizeof(zero), IgnoreError()); success = encoder_write(encoder, zero, sizeof(zero), IgnoreError());
assert(success); assert(success);
if (!EncoderToOutputStream(os, *encoder, error)) { EncoderToOutputStream(os, *encoder);
LogError(error);
return EXIT_FAILURE;
}
/* write a tag */ /* write a tag */
success = encoder_pre_tag(encoder, IgnoreError()); success = encoder_pre_tag(encoder, IgnoreError());
assert(success); assert(success);
if (!EncoderToOutputStream(os, *encoder, error)) { EncoderToOutputStream(os, *encoder);
LogError(error);
return EXIT_FAILURE;
}
Tag tag; Tag tag;
{ {
TagBuilder tag_builder; TagBuilder tag_builder;
tag_builder.AddItem(TAG_ARTIST, "Foo"); tag_builder.AddItem(TAG_ARTIST, "Foo");
tag_builder.AddItem(TAG_TITLE, "Bar"); tag_builder.AddItem(TAG_TITLE, "Bar");
tag_builder.Commit(tag); tag_builder.Commit(tag);
} }
success = encoder_tag(encoder, tag, IgnoreError()); success = encoder_tag(encoder, tag, IgnoreError());
assert(success); assert(success);
if (!EncoderToOutputStream(os, *encoder, error)) { EncoderToOutputStream(os, *encoder);
LogError(error);
return EXIT_FAILURE;
}
/* write another block of data */ /* write another block of data */
success = encoder_write(encoder, zero, sizeof(zero), IgnoreError()); success = encoder_write(encoder, zero, sizeof(zero), IgnoreError());
assert(success); assert(success);
/* finish */ /* finish */
success = encoder_end(encoder, IgnoreError()); success = encoder_end(encoder, IgnoreError());
assert(success); assert(success);
if (!EncoderToOutputStream(os, *encoder, error)) { EncoderToOutputStream(os, *encoder);
LogError(error);
encoder->Close();
encoder->Dispose();
return EXIT_SUCCESS;
} catch (const std::exception &e) {
LogError(e);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
encoder->Close();
encoder->Dispose();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment