fs/io/Reader: use C++ exceptions instead of class Error
This commit is contained in:
parent
fe60c52c70
commit
e6e7d6dbd6
|
@ -277,13 +277,7 @@ static void help(void)
|
|||
|
||||
class ConfigLoader
|
||||
{
|
||||
Error &error;
|
||||
bool result;
|
||||
public:
|
||||
ConfigLoader(Error &_error) : error(_error), result(false) { }
|
||||
|
||||
bool GetResult() const { return result; }
|
||||
|
||||
bool TryFile(const Path path);
|
||||
bool TryFile(const AllocatedPath &base_path,
|
||||
PathTraitsFS::const_pointer path);
|
||||
|
@ -292,7 +286,7 @@ public:
|
|||
bool ConfigLoader::TryFile(Path path)
|
||||
{
|
||||
if (FileExists(path)) {
|
||||
result = ReadConfigFile(path, error);
|
||||
ReadConfigFile(path);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -386,15 +380,16 @@ parse_cmdline(int argc, char **argv, struct options *options,
|
|||
return false;
|
||||
}
|
||||
|
||||
return ReadConfigFile(Path::FromFS(buffer), error);
|
||||
ReadConfigFile(Path::FromFS(buffer));
|
||||
#else
|
||||
return ReadConfigFile(Path::FromFS(config_file), error);
|
||||
ReadConfigFile(Path::FromFS(config_file));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/* use default configuration file path */
|
||||
|
||||
ConfigLoader loader(error);
|
||||
ConfigLoader loader;
|
||||
|
||||
bool found =
|
||||
#ifdef WIN32
|
||||
|
@ -413,5 +408,5 @@ parse_cmdline(int argc, char **argv, struct options *options,
|
|||
return false;
|
||||
}
|
||||
|
||||
return loader.GetResult();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -453,11 +453,8 @@ int mpd_main(int argc, char *argv[])
|
|||
if (!sdcard.IsNull()) {
|
||||
const auto config_path =
|
||||
AllocatedPath::Build(sdcard, "mpd.conf");
|
||||
if (FileExists(config_path) &&
|
||||
!ReadConfigFile(config_path, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (FileExists(config_path))
|
||||
ReadConfigFile(config_path);
|
||||
}
|
||||
#else
|
||||
if (!parse_cmdline(argc, argv, &options, error)) {
|
||||
|
|
|
@ -254,11 +254,7 @@ LoadPlaylistFile(const char *utf8path, Error &error)
|
|||
if (path_fs.IsNull())
|
||||
return contents;
|
||||
|
||||
TextFile file(path_fs, error);
|
||||
if (file.HasFailed()) {
|
||||
TranslatePlaylistError(error);
|
||||
return contents;
|
||||
}
|
||||
TextFile file(path_fs);
|
||||
|
||||
char *s;
|
||||
while ((s = file.ReadLine()) != nullptr) {
|
||||
|
|
|
@ -102,17 +102,12 @@ StateFile::Write()
|
|||
|
||||
void
|
||||
StateFile::Read()
|
||||
{
|
||||
try {
|
||||
bool success;
|
||||
|
||||
FormatDebug(state_file_domain, "Loading state file %s", path_utf8.c_str());
|
||||
|
||||
Error error;
|
||||
TextFile file(path, error);
|
||||
if (file.HasFailed()) {
|
||||
LogError(error);
|
||||
return;
|
||||
}
|
||||
TextFile file(path);
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
const SongLoader song_loader(partition.instance.database,
|
||||
|
@ -135,6 +130,8 @@ StateFile::Read()
|
|||
}
|
||||
|
||||
RememberVersions();
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include "ConfigTemplates.hxx"
|
||||
#include "util/Tokenizer.hxx"
|
||||
#include "util/StringUtil.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "fs/Path.hxx"
|
||||
|
@ -65,17 +64,14 @@ config_read_name_value(ConfigBlock &block, char *input, unsigned line)
|
|||
}
|
||||
|
||||
static ConfigBlock *
|
||||
config_read_block(BufferedReader &reader, Error &error)
|
||||
config_read_block(BufferedReader &reader)
|
||||
try {
|
||||
std::unique_ptr<ConfigBlock> block(new ConfigBlock(reader.GetLineNumber()));
|
||||
|
||||
while (true) {
|
||||
char *line = reader.ReadLine();
|
||||
if (line == nullptr) {
|
||||
if (reader.Check(error))
|
||||
throw std::runtime_error("Expected '}' before end-of-file");
|
||||
return nullptr;
|
||||
}
|
||||
if (line == nullptr)
|
||||
throw std::runtime_error("Expected '}' before end-of-file");
|
||||
|
||||
line = StripLeft(line);
|
||||
if (*line == 0 || *line == CONF_COMMENT)
|
||||
|
@ -114,11 +110,10 @@ Append(ConfigBlock *&head, ConfigBlock *p)
|
|||
*i = p;
|
||||
}
|
||||
|
||||
static bool
|
||||
static void
|
||||
ReadConfigBlock(ConfigData &config_data, BufferedReader &reader,
|
||||
const char *name, ConfigBlockOption o,
|
||||
Tokenizer &tokenizer,
|
||||
Error &error)
|
||||
Tokenizer &tokenizer)
|
||||
{
|
||||
const unsigned i = unsigned(o);
|
||||
const ConfigTemplate &option = config_block_templates[i];
|
||||
|
@ -143,12 +138,9 @@ ReadConfigBlock(ConfigData &config_data, BufferedReader &reader,
|
|||
throw FormatRuntimeError("line %u: Unknown tokens after '{'",
|
||||
reader.GetLineNumber());
|
||||
|
||||
auto *param = config_read_block(reader, error);
|
||||
if (param == nullptr)
|
||||
return false;
|
||||
|
||||
auto *param = config_read_block(reader);
|
||||
assert(param != nullptr);
|
||||
Append(head, param);
|
||||
return true;
|
||||
}
|
||||
|
||||
gcc_nonnull_all
|
||||
|
@ -196,13 +188,13 @@ ReadConfigParam(ConfigData &config_data, BufferedReader &reader,
|
|||
Append(head, param);
|
||||
}
|
||||
|
||||
static bool
|
||||
ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Error &error)
|
||||
static void
|
||||
ReadConfigFile(ConfigData &config_data, BufferedReader &reader)
|
||||
{
|
||||
while (true) {
|
||||
char *line = reader.ReadLine();
|
||||
if (line == nullptr)
|
||||
return true;
|
||||
return;
|
||||
|
||||
line = StripLeft(line);
|
||||
if (*line == 0 || *line == CONF_COMMENT)
|
||||
|
@ -224,9 +216,8 @@ ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Error &error)
|
|||
ReadConfigParam(config_data, reader, name, o,
|
||||
tokenizer);
|
||||
} else if ((bo = ParseConfigBlockOptionName(name)) != ConfigBlockOption::MAX) {
|
||||
if (!ReadConfigBlock(config_data, reader, name, bo,
|
||||
tokenizer, error))
|
||||
return false;
|
||||
ReadConfigBlock(config_data, reader, name, bo,
|
||||
tokenizer);
|
||||
} else {
|
||||
throw FormatRuntimeError("unrecognized parameter in config file at "
|
||||
"line %u: %s\n",
|
||||
|
@ -235,19 +226,16 @@ ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Error &error)
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ReadConfigFile(ConfigData &config_data, Path path, Error &error)
|
||||
void
|
||||
ReadConfigFile(ConfigData &config_data, Path path)
|
||||
{
|
||||
assert(!path.IsNull());
|
||||
const std::string path_utf8 = path.ToUTF8();
|
||||
|
||||
FormatDebug(config_file_domain, "loading file %s", path_utf8.c_str());
|
||||
|
||||
FileReader file(path, error);
|
||||
if (!file.IsDefined())
|
||||
return false;
|
||||
FileReader file(path);
|
||||
|
||||
BufferedReader reader(file);
|
||||
return ReadConfigFile(config_data, reader, error) &&
|
||||
reader.Check(error);
|
||||
ReadConfigFile(config_data, reader);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ class Error;
|
|||
class Path;
|
||||
struct ConfigData;
|
||||
|
||||
bool
|
||||
ReadConfigFile(ConfigData &data, Path path, Error &error);
|
||||
void
|
||||
ReadConfigFile(ConfigData &data, Path path);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -45,10 +45,10 @@ void config_global_init(void)
|
|||
{
|
||||
}
|
||||
|
||||
bool
|
||||
ReadConfigFile(Path path, Error &error)
|
||||
void
|
||||
ReadConfigFile(Path path)
|
||||
{
|
||||
return ReadConfigFile(config_data, path, error);
|
||||
return ReadConfigFile(config_data, path);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -42,8 +42,8 @@ config_global_finish();
|
|||
void
|
||||
config_global_check();
|
||||
|
||||
bool
|
||||
ReadConfigFile(Path path, Error &error);
|
||||
void
|
||||
ReadConfigFile(Path path);
|
||||
|
||||
gcc_pure
|
||||
const config_param *
|
||||
|
|
|
@ -184,11 +184,9 @@ SimpleDatabase::Load(Error &error)
|
|||
assert(!path.IsNull());
|
||||
assert(root != nullptr);
|
||||
|
||||
TextFile file(path, error);
|
||||
if (file.HasFailed())
|
||||
return false;
|
||||
TextFile file(path);
|
||||
|
||||
if (!db_load_internal(file, *root, error) || !file.Check(error))
|
||||
if (!db_load_internal(file, *root, error))
|
||||
return false;
|
||||
|
||||
FileInfo fi;
|
||||
|
@ -200,7 +198,7 @@ SimpleDatabase::Load(Error &error)
|
|||
|
||||
bool
|
||||
SimpleDatabase::Open(Error &error)
|
||||
{
|
||||
try {
|
||||
assert(prefixed_light_song == nullptr);
|
||||
|
||||
root = Directory::NewRoot();
|
||||
|
@ -223,6 +221,9 @@ SimpleDatabase::Open(Error &error)
|
|||
}
|
||||
|
||||
return true;
|
||||
} catch (const std::exception &e) {
|
||||
error.Set(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -27,41 +27,18 @@
|
|||
#include "fs/Path.hxx"
|
||||
#include "fs/NarrowPath.hxx"
|
||||
#include "fs/io/TextFile.hxx"
|
||||
#include "util/StringUtil.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_CLASS_GLOB
|
||||
|
||||
gcc_pure
|
||||
static bool
|
||||
IsFileNotFound(const Error &error)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return error.IsDomain(win32_domain) &&
|
||||
error.GetCode() == ERROR_FILE_NOT_FOUND;
|
||||
#else
|
||||
return error.IsDomain(errno_domain) && error.GetCode() == ENOENT;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool
|
||||
ExcludeList::LoadFile(Path path_fs)
|
||||
{
|
||||
try {
|
||||
#ifdef HAVE_CLASS_GLOB
|
||||
Error error;
|
||||
TextFile file(path_fs, error);
|
||||
if (file.HasFailed()) {
|
||||
if (!IsFileNotFound(error))
|
||||
LogError(error);
|
||||
return false;
|
||||
}
|
||||
TextFile file(path_fs);
|
||||
|
||||
char *line;
|
||||
while ((line = file.ReadLine()) != nullptr) {
|
||||
|
@ -79,6 +56,13 @@ ExcludeList::LoadFile(Path path_fs)
|
|||
#endif
|
||||
|
||||
return true;
|
||||
} catch (const std::system_error &e) {
|
||||
if (!IsFileNotFound(e))
|
||||
LogError(e);
|
||||
return false;
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "check.h"
|
||||
#include "Path.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "system/Error.hxx"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -63,6 +64,20 @@ class FileInfo {
|
|||
#endif
|
||||
|
||||
public:
|
||||
FileInfo() = default;
|
||||
|
||||
FileInfo(Path path, bool follow_symlinks=true) {
|
||||
if (!GetFileInfo(path, *this, follow_symlinks)) {
|
||||
#ifdef WIN32
|
||||
throw FormatLastError("Failed to access %s",
|
||||
path.ToUTF8().c_str());
|
||||
#else
|
||||
throw FormatErrno("Failed to access %s",
|
||||
path.ToUTF8().c_str());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool IsRegular() const {
|
||||
#ifdef WIN32
|
||||
return (data.dwFileAttributes &
|
||||
|
|
|
@ -200,20 +200,21 @@ ParseConfigLine(char *line, const char *dir_name, AllocatedPath &result_dir)
|
|||
}
|
||||
|
||||
static AllocatedPath GetUserDir(const char *name)
|
||||
{
|
||||
try {
|
||||
auto result = AllocatedPath::Null();
|
||||
auto config_dir = GetUserConfigDir();
|
||||
if (config_dir.IsNull())
|
||||
return result;
|
||||
auto dirs_file = AllocatedPath::Build(config_dir, "user-dirs.dirs");
|
||||
TextFile input(dirs_file, IgnoreError());
|
||||
if (input.HasFailed())
|
||||
return result;
|
||||
|
||||
TextFile input(dirs_file);
|
||||
char *line;
|
||||
while ((line = input.ReadLine()) != nullptr)
|
||||
if (ParseConfigLine(line, name, result))
|
||||
return result;
|
||||
return result;
|
||||
} catch (const std::exception &e) {
|
||||
return AllocatedPath::Null();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "config.h"
|
||||
#include "AutoGunzipReader.hxx"
|
||||
#include "GunzipReader.hxx"
|
||||
#include "util/Error.hxx"
|
||||
|
||||
AutoGunzipReader::~AutoGunzipReader()
|
||||
{
|
||||
|
@ -35,36 +34,27 @@ IsGzip(const uint8_t data[4])
|
|||
(data[3] & 0xe0) == 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
AutoGunzipReader::Detect(Error &error)
|
||||
inline void
|
||||
AutoGunzipReader::Detect()
|
||||
{
|
||||
const uint8_t *data = (const uint8_t *)peek.Peek(4, error);
|
||||
const uint8_t *data = (const uint8_t *)peek.Peek(4);
|
||||
if (data == nullptr) {
|
||||
if (error.IsDefined())
|
||||
return false;
|
||||
|
||||
next = &peek;
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsGzip(data)) {
|
||||
gunzip = new GunzipReader(peek, error);
|
||||
if (!gunzip->IsDefined())
|
||||
return false;
|
||||
|
||||
|
||||
next = gunzip;
|
||||
} else
|
||||
if (IsGzip(data))
|
||||
next = gunzip = new GunzipReader(peek);
|
||||
else
|
||||
next = &peek;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t
|
||||
AutoGunzipReader::Read(void *data, size_t size, Error &error)
|
||||
AutoGunzipReader::Read(void *data, size_t size)
|
||||
{
|
||||
if (next == nullptr && !Detect(error))
|
||||
return false;
|
||||
if (next == nullptr)
|
||||
Detect();
|
||||
|
||||
return next->Read(data, size, error);
|
||||
assert(next != nullptr);
|
||||
return next->Read(data, size);
|
||||
}
|
||||
|
|
|
@ -43,10 +43,10 @@ public:
|
|||
~AutoGunzipReader();
|
||||
|
||||
/* virtual methods from class Reader */
|
||||
virtual size_t Read(void *data, size_t size, Error &error) override;
|
||||
virtual size_t Read(void *data, size_t size) override;
|
||||
|
||||
private:
|
||||
bool Detect(Error &error);
|
||||
void Detect();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,9 +25,6 @@
|
|||
bool
|
||||
BufferedReader::Fill(bool need_more)
|
||||
{
|
||||
if (gcc_unlikely(last_error.IsDefined()))
|
||||
return false;
|
||||
|
||||
if (eof)
|
||||
return !need_more;
|
||||
|
||||
|
@ -41,11 +38,8 @@ BufferedReader::Fill(bool need_more)
|
|||
assert(!w.IsEmpty());
|
||||
}
|
||||
|
||||
size_t nbytes = reader.Read(w.data, w.size, last_error);
|
||||
size_t nbytes = reader.Read(w.data, w.size);
|
||||
if (nbytes == 0) {
|
||||
if (gcc_unlikely(last_error.IsDefined()))
|
||||
return false;
|
||||
|
||||
eof = true;
|
||||
return !need_more;
|
||||
}
|
||||
|
@ -65,7 +59,7 @@ BufferedReader::ReadLine()
|
|||
}
|
||||
} while (Fill(true));
|
||||
|
||||
if (last_error.IsDefined() || !eof || buffer.IsEmpty())
|
||||
if (!eof || buffer.IsEmpty())
|
||||
return nullptr;
|
||||
|
||||
auto w = buffer.Write();
|
||||
|
|
|
@ -23,12 +23,10 @@
|
|||
#include "check.h"
|
||||
#include "Compiler.h"
|
||||
#include "util/DynamicFifoBuffer.hxx"
|
||||
#include "util/Error.hxx"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
class Reader;
|
||||
class Error;
|
||||
|
||||
class BufferedReader {
|
||||
static constexpr size_t MAX_SIZE = 512 * 1024;
|
||||
|
@ -37,8 +35,6 @@ class BufferedReader {
|
|||
|
||||
DynamicFifoBuffer<char> buffer;
|
||||
|
||||
Error last_error;
|
||||
|
||||
bool eof;
|
||||
|
||||
unsigned line_number;
|
||||
|
@ -48,19 +44,6 @@ public:
|
|||
:reader(_reader), buffer(4096), eof(false),
|
||||
line_number(0) {}
|
||||
|
||||
gcc_pure
|
||||
bool Check() const {
|
||||
return !last_error.IsDefined();
|
||||
}
|
||||
|
||||
bool Check(Error &error) const {
|
||||
if (last_error.IsDefined()) {
|
||||
error.Set(last_error);
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Fill(bool need_more);
|
||||
|
||||
gcc_pure
|
||||
|
|
|
@ -20,57 +20,49 @@
|
|||
#include "config.h"
|
||||
#include "FileReader.hxx"
|
||||
#include "fs/FileInfo.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "system/Error.hxx"
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
FileReader::FileReader(Path _path, Error &error)
|
||||
FileReader::FileReader(Path _path)
|
||||
:path(_path),
|
||||
handle(CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ,
|
||||
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr))
|
||||
{
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
const auto path_utf8 = path.ToUTF8();
|
||||
error.FormatLastError("Failed to open %s", path_utf8.c_str());
|
||||
}
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
throw FormatLastError("Failed to open %s", path.ToUTF8().c_str());
|
||||
}
|
||||
|
||||
bool
|
||||
FileReader::GetFileInfo(FileInfo &info, Error &error) const
|
||||
FileInfo
|
||||
FileReader::GetFileInfo() const
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
return ::GetFileInfo(path, info, error);
|
||||
return FileInfo(path);
|
||||
}
|
||||
|
||||
size_t
|
||||
FileReader::Read(void *data, size_t size, Error &error)
|
||||
FileReader::Read(void *data, size_t size)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
DWORD nbytes;
|
||||
if (!ReadFile(handle, data, size, &nbytes, nullptr)) {
|
||||
const auto path_utf8 = path.ToUTF8();
|
||||
error.FormatLastError("Failed to read from %s",
|
||||
path_utf8.c_str());
|
||||
nbytes = 0;
|
||||
}
|
||||
if (!ReadFile(handle, data, size, &nbytes, nullptr))
|
||||
throw FormatLastError("Failed to read from %s",
|
||||
path.ToUTF8().c_str());
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
bool
|
||||
FileReader::Seek(off_t offset, Error &error)
|
||||
void
|
||||
FileReader::Seek(off_t offset)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
auto result = SetFilePointer(handle, offset, nullptr, FILE_BEGIN);
|
||||
const bool success = result != INVALID_SET_FILE_POINTER;
|
||||
if (!success)
|
||||
error.SetLastError("Failed to seek");
|
||||
|
||||
return success;
|
||||
if (result == INVALID_SET_FILE_POINTER)
|
||||
throw MakeLastError("Failed to seek");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -83,52 +75,49 @@ FileReader::Close()
|
|||
|
||||
#else
|
||||
|
||||
FileReader::FileReader(Path _path, Error &error)
|
||||
FileReader::FileReader(Path _path)
|
||||
:path(_path)
|
||||
{
|
||||
fd.OpenReadOnly(path.c_str());
|
||||
if (!fd.IsDefined())
|
||||
error.FormatErrno("Failed to open %s", path.c_str());
|
||||
throw FormatErrno("Failed to open %s", path.ToUTF8().c_str());
|
||||
}
|
||||
|
||||
bool
|
||||
FileReader::GetFileInfo(FileInfo &info, Error &error) const
|
||||
FileInfo
|
||||
FileReader::GetFileInfo() const
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
FileInfo info;
|
||||
const bool success = fstat(fd.Get(), &info.st) == 0;
|
||||
if (!success)
|
||||
error.FormatErrno("Failed to access %s",
|
||||
throw FormatErrno("Failed to access %s",
|
||||
path.ToUTF8().c_str());
|
||||
|
||||
return success;
|
||||
return info;
|
||||
}
|
||||
|
||||
size_t
|
||||
FileReader::Read(void *data, size_t size, Error &error)
|
||||
FileReader::Read(void *data, size_t size)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
ssize_t nbytes = fd.Read(data, size);
|
||||
if (nbytes < 0) {
|
||||
error.FormatErrno("Failed to read from %s", path.c_str());
|
||||
nbytes = 0;
|
||||
}
|
||||
if (nbytes < 0)
|
||||
throw FormatErrno("Failed to read from %s", path.ToUTF8().c_str());
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
bool
|
||||
FileReader::Seek(off_t offset, Error &error)
|
||||
void
|
||||
FileReader::Seek(off_t offset)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
auto result = fd.Seek(offset);
|
||||
const bool success = result >= 0;
|
||||
if (!success)
|
||||
error.SetErrno("Failed to seek");
|
||||
|
||||
return success;
|
||||
throw MakeErrno("Failed to seek");
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -48,7 +48,7 @@ class FileReader final : public Reader {
|
|||
#endif
|
||||
|
||||
public:
|
||||
FileReader(Path _path, Error &error);
|
||||
FileReader(Path _path);
|
||||
|
||||
#ifdef WIN32
|
||||
FileReader(FileReader &&other)
|
||||
|
@ -70,6 +70,7 @@ public:
|
|||
}
|
||||
|
||||
|
||||
protected:
|
||||
bool IsDefined() const {
|
||||
#ifdef WIN32
|
||||
return handle != INVALID_HANDLE_VALUE;
|
||||
|
@ -78,6 +79,7 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
#ifndef WIN32
|
||||
FileDescriptor GetFD() const {
|
||||
return fd;
|
||||
|
@ -86,12 +88,13 @@ public:
|
|||
|
||||
void Close();
|
||||
|
||||
bool GetFileInfo(FileInfo &info, Error &error) const;
|
||||
gcc_pure
|
||||
FileInfo GetFileInfo() const;
|
||||
|
||||
bool Seek(off_t offset, Error &error);
|
||||
void Seek(off_t offset);
|
||||
|
||||
/* virtual methods from class Reader */
|
||||
size_t Read(void *data, size_t size, Error &error) override;
|
||||
size_t Read(void *data, size_t size) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,10 +20,8 @@
|
|||
#include "config.h"
|
||||
#include "GunzipReader.hxx"
|
||||
#include "lib/zlib/Domain.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
GunzipReader::GunzipReader(Reader &_next, Error &error)
|
||||
GunzipReader::GunzipReader(Reader &_next) throw(ZlibError)
|
||||
:next(_next), eof(false)
|
||||
{
|
||||
z.next_in = nullptr;
|
||||
|
@ -33,25 +31,17 @@ GunzipReader::GunzipReader(Reader &_next, Error &error)
|
|||
z.opaque = Z_NULL;
|
||||
|
||||
int result = inflateInit2(&z, 16 + MAX_WBITS);
|
||||
if (result != Z_OK) {
|
||||
z.opaque = this;
|
||||
error.Set(zlib_domain, result, zError(result));
|
||||
}
|
||||
}
|
||||
|
||||
GunzipReader::~GunzipReader()
|
||||
{
|
||||
if (IsDefined())
|
||||
inflateEnd(&z);
|
||||
if (result != Z_OK)
|
||||
throw ZlibError(result);
|
||||
}
|
||||
|
||||
inline bool
|
||||
GunzipReader::FillBuffer(Error &error)
|
||||
GunzipReader::FillBuffer()
|
||||
{
|
||||
auto w = buffer.Write();
|
||||
assert(!w.IsEmpty());
|
||||
|
||||
size_t nbytes = next.Read(w.data, w.size, error);
|
||||
size_t nbytes = next.Read(w.data, w.size);
|
||||
if (nbytes == 0)
|
||||
return false;
|
||||
|
||||
|
@ -60,7 +50,7 @@ GunzipReader::FillBuffer(Error &error)
|
|||
}
|
||||
|
||||
size_t
|
||||
GunzipReader::Read(void *data, size_t size, Error &error)
|
||||
GunzipReader::Read(void *data, size_t size)
|
||||
{
|
||||
if (eof)
|
||||
return 0;
|
||||
|
@ -73,10 +63,8 @@ GunzipReader::Read(void *data, size_t size, Error &error)
|
|||
|
||||
auto r = buffer.Read();
|
||||
if (r.IsEmpty()) {
|
||||
if (FillBuffer(error))
|
||||
if (FillBuffer())
|
||||
r = buffer.Read();
|
||||
else if (error.IsDefined())
|
||||
return 0;
|
||||
else
|
||||
flush = Z_FINISH;
|
||||
}
|
||||
|
@ -88,10 +76,8 @@ GunzipReader::Read(void *data, size_t size, Error &error)
|
|||
if (result == Z_STREAM_END) {
|
||||
eof = true;
|
||||
return size - z.avail_out;
|
||||
} else if (result != Z_OK) {
|
||||
error.Set(zlib_domain, result, zError(result));
|
||||
return 0;
|
||||
}
|
||||
} else if (result != Z_OK)
|
||||
throw ZlibError(result);
|
||||
|
||||
buffer.Consume(r.size - z.avail_in);
|
||||
|
||||
|
|
|
@ -23,13 +23,11 @@
|
|||
#include "check.h"
|
||||
#include "Reader.hxx"
|
||||
#include "util/StaticFifoBuffer.hxx"
|
||||
#include "lib/zlib/Error.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
class Error;
|
||||
class Domain;
|
||||
|
||||
/**
|
||||
* A filter that decompresses data using zlib.
|
||||
*/
|
||||
|
@ -44,25 +42,19 @@ class GunzipReader final : public Reader {
|
|||
|
||||
public:
|
||||
/**
|
||||
* Construct the filter. Call IsDefined() to check whether
|
||||
* the constructor has succeeded. If not, #error will hold
|
||||
* information about the failure.
|
||||
* Construct the filter.
|
||||
*/
|
||||
GunzipReader(Reader &_next, Error &error);
|
||||
~GunzipReader();
|
||||
GunzipReader(Reader &_next) throw(ZlibError);
|
||||
|
||||
/**
|
||||
* Check whether the constructor has succeeded.
|
||||
*/
|
||||
bool IsDefined() const {
|
||||
return z.opaque == nullptr;
|
||||
~GunzipReader() {
|
||||
inflateEnd(&z);
|
||||
}
|
||||
|
||||
/* virtual methods from class Reader */
|
||||
virtual size_t Read(void *data, size_t size, Error &error) override;
|
||||
size_t Read(void *data, size_t size) override;
|
||||
|
||||
private:
|
||||
bool FillBuffer(Error &error);
|
||||
bool FillBuffer();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <string.h>
|
||||
|
||||
const void *
|
||||
PeekReader::Peek(size_t size, Error &error)
|
||||
PeekReader::Peek(size_t size)
|
||||
{
|
||||
assert(size > 0);
|
||||
assert(size < sizeof(buffer));
|
||||
|
@ -35,7 +35,7 @@ PeekReader::Peek(size_t size, Error &error)
|
|||
|
||||
do {
|
||||
size_t nbytes = next.Read(buffer + buffer_size,
|
||||
size - buffer_size, error);
|
||||
size - buffer_size);
|
||||
if (nbytes == 0)
|
||||
return nullptr;
|
||||
|
||||
|
@ -46,7 +46,7 @@ PeekReader::Peek(size_t size, Error &error)
|
|||
}
|
||||
|
||||
size_t
|
||||
PeekReader::Read(void *data, size_t size, Error &error)
|
||||
PeekReader::Read(void *data, size_t size)
|
||||
{
|
||||
size_t buffer_remaining = buffer_size - buffer_position;
|
||||
if (buffer_remaining > 0) {
|
||||
|
@ -56,5 +56,5 @@ PeekReader::Read(void *data, size_t size, Error &error)
|
|||
return nbytes;
|
||||
}
|
||||
|
||||
return next.Read(data, size, error);
|
||||
return next.Read(data, size);
|
||||
}
|
||||
|
|
|
@ -44,10 +44,10 @@ public:
|
|||
PeekReader(Reader &_next)
|
||||
:next(_next), buffer_size(0), buffer_position(0) {}
|
||||
|
||||
const void *Peek(size_t size, Error &error);
|
||||
const void *Peek(size_t size);
|
||||
|
||||
/* virtual methods from class Reader */
|
||||
virtual size_t Read(void *data, size_t size, Error &error) override;
|
||||
virtual size_t Read(void *data, size_t size) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
class Error;
|
||||
|
||||
/**
|
||||
* An interface that can read bytes from a stream until the stream
|
||||
* ends.
|
||||
|
@ -43,10 +41,10 @@ public:
|
|||
* Read data from the stream.
|
||||
*
|
||||
* @return the number of bytes read into the given buffer or 0
|
||||
* on error/end-of-stream
|
||||
* on end-of-stream
|
||||
*/
|
||||
gcc_nonnull_all
|
||||
virtual size_t Read(void *data, size_t size, Error &error) = 0;
|
||||
virtual size_t Read(void *data, size_t size) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,22 +26,18 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
TextFile::TextFile(Path path_fs, Error &error)
|
||||
:file_reader(new FileReader(path_fs, error)),
|
||||
TextFile::TextFile(Path path_fs)
|
||||
:file_reader(new FileReader(path_fs)),
|
||||
#ifdef ENABLE_ZLIB
|
||||
gunzip_reader(file_reader->IsDefined()
|
||||
? new AutoGunzipReader(*file_reader)
|
||||
: nullptr),
|
||||
gunzip_reader(new AutoGunzipReader(*file_reader)),
|
||||
#endif
|
||||
buffered_reader(file_reader->IsDefined()
|
||||
? new BufferedReader(*
|
||||
buffered_reader(new BufferedReader(*
|
||||
#ifdef ENABLE_ZLIB
|
||||
gunzip_reader
|
||||
gunzip_reader
|
||||
#else
|
||||
file_reader
|
||||
file_reader
|
||||
#endif
|
||||
)
|
||||
: nullptr)
|
||||
))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -61,11 +57,3 @@ TextFile::ReadLine()
|
|||
|
||||
return buffered_reader->ReadLine();
|
||||
}
|
||||
|
||||
bool
|
||||
TextFile::Check(Error &error) const
|
||||
{
|
||||
assert(buffered_reader != nullptr);
|
||||
|
||||
return buffered_reader->Check(error);
|
||||
}
|
||||
|
|
|
@ -23,10 +23,7 @@
|
|||
#include "check.h"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
class Path;
|
||||
class Error;
|
||||
class FileReader;
|
||||
class AutoGunzipReader;
|
||||
class BufferedReader;
|
||||
|
@ -41,32 +38,20 @@ class TextFile {
|
|||
BufferedReader *const buffered_reader;
|
||||
|
||||
public:
|
||||
TextFile(Path path_fs, Error &error);
|
||||
TextFile(Path path_fs);
|
||||
|
||||
TextFile(const TextFile &other) = delete;
|
||||
|
||||
~TextFile();
|
||||
|
||||
bool HasFailed() const {
|
||||
return gcc_unlikely(buffered_reader == nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a line from the input file, and strips trailing
|
||||
* space. There is a reasonable maximum line length, only to
|
||||
* prevent denial of service.
|
||||
*
|
||||
* Use Check() after nullptr has been returned to check
|
||||
* whether an error occurred or end-of-file has been reached.
|
||||
*
|
||||
* @return a pointer to the line, or nullptr on end-of-file or error
|
||||
* @return a pointer to the line, or nullptr on end-of-file
|
||||
*/
|
||||
char *ReadLine();
|
||||
|
||||
/**
|
||||
* Check whether a ReadLine() call has thrown an error.
|
||||
*/
|
||||
bool Check(Error &error) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -61,14 +61,10 @@ InputStream *
|
|||
OpenFileInputStream(Path path,
|
||||
Mutex &mutex, Cond &cond,
|
||||
Error &error)
|
||||
{
|
||||
FileReader reader(path, error);
|
||||
if (!reader.IsDefined())
|
||||
return nullptr;
|
||||
try {
|
||||
FileReader reader(path);
|
||||
|
||||
FileInfo info;
|
||||
if (!reader.GetFileInfo(info, error))
|
||||
return nullptr;
|
||||
const FileInfo info = reader.GetFileInfo();
|
||||
|
||||
if (!info.IsRegular()) {
|
||||
error.Format(file_domain, "Not a regular file: %s",
|
||||
|
@ -84,6 +80,9 @@ OpenFileInputStream(Path path,
|
|||
return new FileInputStream(path.ToUTF8().c_str(),
|
||||
std::move(reader), info.GetSize(),
|
||||
mutex, cond);
|
||||
} catch (const std::exception &e) {
|
||||
error.Set(e);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static InputStream *
|
||||
|
@ -98,23 +97,24 @@ input_file_open(gcc_unused const char *filename,
|
|||
|
||||
bool
|
||||
FileInputStream::Seek(offset_type new_offset, Error &error)
|
||||
{
|
||||
if (!reader.Seek((off_t)new_offset, error))
|
||||
return false;
|
||||
|
||||
try {
|
||||
reader.Seek((off_t)new_offset);
|
||||
offset = new_offset;
|
||||
return true;
|
||||
} catch (const std::exception &e) {
|
||||
error.Set(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t
|
||||
FileInputStream::Read(void *ptr, size_t read_size, Error &error)
|
||||
{
|
||||
ssize_t nbytes = reader.Read(ptr, read_size, error);
|
||||
if (nbytes < 0)
|
||||
return 0;
|
||||
|
||||
try {
|
||||
size_t nbytes = reader.Read(ptr, read_size);
|
||||
offset += nbytes;
|
||||
return (size_t)nbytes;
|
||||
return nbytes;
|
||||
} catch (const std::exception &e) {
|
||||
error.Set(e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const InputPlugin input_plugin_file = {
|
||||
|
|
|
@ -110,10 +110,7 @@ try {
|
|||
config_global_init();
|
||||
|
||||
Error error;
|
||||
if (!ReadConfigFile(config_path, error)) {
|
||||
cerr << error.GetMessage() << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ReadConfigFile(config_path);
|
||||
|
||||
TagLoadConfig();
|
||||
|
||||
|
|
|
@ -65,10 +65,7 @@ try {
|
|||
config_global_init();
|
||||
|
||||
Error error;
|
||||
if (!ReadConfigFile(config_path, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ReadConfigFile(config_path);
|
||||
|
||||
const ScopeIOThread io_thread;
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "config.h"
|
||||
#include "config/ConfigGlobal.hxx"
|
||||
#include "fs/Path.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
@ -39,11 +38,7 @@ try {
|
|||
|
||||
config_global_init();
|
||||
|
||||
Error error;
|
||||
if (!ReadConfigFile(config_path, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ReadConfigFile(config_path);
|
||||
|
||||
ConfigOption option = ParseConfigOptionName(name);
|
||||
const char *value = option != ConfigOption::MAX
|
||||
|
|
|
@ -69,7 +69,6 @@ load_filter(const char *name)
|
|||
int main(int argc, char **argv)
|
||||
try {
|
||||
struct audio_format_string af_string;
|
||||
Error error2;
|
||||
char buffer[4096];
|
||||
|
||||
if (argc < 3 || argc > 4) {
|
||||
|
@ -84,8 +83,7 @@ try {
|
|||
/* read configuration file (mpd.conf) */
|
||||
|
||||
config_global_init();
|
||||
if (!ReadConfigFile(config_path, error2))
|
||||
FatalError(error2);
|
||||
ReadConfigFile(config_path);
|
||||
|
||||
/* parse the audio format */
|
||||
|
||||
|
|
|
@ -28,32 +28,32 @@
|
|||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static bool
|
||||
Copy(OutputStream &dest, Reader &src, Error &error)
|
||||
static void
|
||||
Copy(OutputStream &dest, Reader &src)
|
||||
{
|
||||
while (true) {
|
||||
char buffer[4096];
|
||||
size_t nbytes = src.Read(buffer, sizeof(buffer), error);
|
||||
size_t nbytes = src.Read(buffer, sizeof(buffer));
|
||||
if (nbytes == 0)
|
||||
return !error.IsDefined();
|
||||
break;
|
||||
|
||||
dest.Write(buffer, nbytes);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
CopyGunzip(OutputStream &dest, Reader &_src, Error &error)
|
||||
static void
|
||||
CopyGunzip(OutputStream &dest, Reader &_src)
|
||||
{
|
||||
GunzipReader src(_src, error);
|
||||
return src.IsDefined() && Copy(dest, src, error);
|
||||
GunzipReader src(_src);
|
||||
Copy(dest, src);
|
||||
}
|
||||
|
||||
static bool
|
||||
CopyGunzip(FILE *_dest, Path src_path, Error &error)
|
||||
static void
|
||||
CopyGunzip(FILE *_dest, Path src_path)
|
||||
{
|
||||
StdioOutputStream dest(_dest);
|
||||
FileReader src(src_path, error);
|
||||
return src.IsDefined() && CopyGunzip(dest, src, error);
|
||||
FileReader src(src_path);
|
||||
CopyGunzip(dest, src);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -67,12 +67,7 @@ main(int argc, gcc_unused char **argv)
|
|||
Path path = Path::FromFS(argv[1]);
|
||||
|
||||
try {
|
||||
Error error;
|
||||
if (!CopyGunzip(stdout, path, error)) {
|
||||
fprintf(stderr, "%s\n", error.GetMessage());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
CopyGunzip(stdout, path);
|
||||
return EXIT_SUCCESS;
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
|
|
|
@ -59,10 +59,7 @@ try {
|
|||
Error error;
|
||||
|
||||
config_global_init();
|
||||
if (!ReadConfigFile(config_path, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ReadConfigFile(config_path);
|
||||
|
||||
/* initialize the core */
|
||||
|
||||
|
|
|
@ -161,10 +161,7 @@ try {
|
|||
/* read configuration file (mpd.conf) */
|
||||
|
||||
config_global_init();
|
||||
if (!ReadConfigFile(config_path, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ReadConfigFile(config_path);
|
||||
|
||||
EventLoop event_loop;
|
||||
|
||||
|
|
Loading…
Reference in New Issue