db/simple/Save: migrate from class Error to C++ exceptions

This commit is contained in:
Max Kellermann
2016-10-29 09:45:34 +02:00
parent dea46e8d5a
commit 90a14e14f4
11 changed files with 95 additions and 166 deletions

View File

@@ -29,7 +29,7 @@
#include "tag/Settings.hxx"
#include "fs/Charset.hxx"
#include "util/StringCompare.hxx"
#include "util/Error.hxx"
#include "util/RuntimeError.hxx"
#include "Log.hxx"
#include <string.h>
@@ -66,8 +66,8 @@ db_save_internal(BufferedOutputStream &os, const Directory &music_root)
directory_save(os, music_root);
}
bool
db_load_internal(TextFile &file, Directory &music_root, Error &error)
void
db_load_internal(TextFile &file, Directory &music_root)
{
char *line;
unsigned format = 0;
@@ -76,10 +76,8 @@ db_load_internal(TextFile &file, Directory &music_root, Error &error)
/* get initial info */
line = file.ReadLine();
if (line == nullptr || strcmp(DIRECTORY_INFO_BEGIN, line) != 0) {
error.Set(db_domain, "Database corrupted");
return false;
}
if (line == nullptr || strcmp(DIRECTORY_INFO_BEGIN, line) != 0)
throw std::runtime_error("Database corrupted");
memset(tags, false, sizeof(tags));
@@ -90,67 +88,49 @@ db_load_internal(TextFile &file, Directory &music_root, Error &error)
if ((p = StringAfterPrefix(line, DB_FORMAT_PREFIX))) {
format = atoi(p);
} else if (StringStartsWith(line, DIRECTORY_MPD_VERSION)) {
if (found_version) {
error.Set(db_domain, "Duplicate version line");
return false;
}
if (found_version)
throw std::runtime_error("Duplicate version line");
found_version = true;
} else if ((p = StringAfterPrefix(line, DIRECTORY_FS_CHARSET))) {
if (found_charset) {
error.Set(db_domain, "Duplicate charset line");
return false;
}
if (found_charset)
throw std::runtime_error("Duplicate charset line");
found_charset = true;
const char *new_charset = p;
const char *const old_charset = GetFSCharset();
if (*old_charset != 0
&& strcmp(new_charset, old_charset) != 0) {
error.Format(db_domain,
"Existing database has charset "
"\"%s\" instead of \"%s\"; "
"discarding database file",
new_charset, old_charset);
return false;
}
&& strcmp(new_charset, old_charset) != 0)
throw FormatRuntimeError("Existing database has charset "
"\"%s\" instead of \"%s\"; "
"discarding database file",
new_charset, old_charset);
} else if ((p = StringAfterPrefix(line, DB_TAG_PREFIX))) {
const char *name = p;
TagType tag = tag_name_parse(name);
if (tag == TAG_NUM_OF_ITEM_TYPES) {
error.Format(db_domain,
"Unrecognized tag '%s', "
"discarding database file",
name);
return false;
}
if (tag == TAG_NUM_OF_ITEM_TYPES)
throw FormatRuntimeError("Unrecognized tag '%s', "
"discarding database file",
name);
tags[tag] = true;
} else {
error.Format(db_domain, "Malformed line: %s", line);
return false;
throw FormatRuntimeError("Malformed line: %s", line);
}
}
if (format < OLDEST_DB_FORMAT || format > DB_FORMAT) {
error.Set(db_domain,
"Database format mismatch, "
"discarding database file");
return false;
}
if (format < OLDEST_DB_FORMAT || format > DB_FORMAT)
throw std::runtime_error("Database format mismatch, "
"discarding database file");
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) {
if (IsTagEnabled(i) && !tags[i]) {
error.Set(db_domain,
"Tag list mismatch, "
"discarding database file");
return false;
}
}
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
if (IsTagEnabled(i) && !tags[i])
throw std::runtime_error("Tag list mismatch, "
"discarding database file");
LogDebug(db_domain, "reading DB");
const ScopeDatabaseLock protect;
return directory_load(file, music_root, error);
directory_load(file, music_root);
}

View File

@@ -28,7 +28,10 @@ class Error;
void
db_save_internal(BufferedOutputStream &os, const Directory &root);
bool
db_load_internal(TextFile &file, Directory &root, Error &error);
/**
* Throws #std::runtime_error on error.
*/
void
db_load_internal(TextFile &file, Directory &root);
#endif

View File

@@ -28,8 +28,7 @@
#include "fs/io/BufferedOutputStream.hxx"
#include "util/StringCompare.hxx"
#include "util/NumberParser.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "util/RuntimeError.hxx"
#include <string.h>
@@ -39,8 +38,6 @@
#define DIRECTORY_BEGIN "begin: "
#define DIRECTORY_END "end: "
static constexpr Domain directory_domain("directory");
gcc_const
static const char *
DeviceToTypeString(unsigned device)
@@ -115,49 +112,37 @@ ParseLine(Directory &directory, const char *line)
}
static Directory *
directory_load_subdir(TextFile &file, Directory &parent, const char *name,
Error &error)
directory_load_subdir(TextFile &file, Directory &parent, const char *name)
{
bool success;
if (parent.FindChild(name) != nullptr) {
error.Format(directory_domain,
"Duplicate subdirectory '%s'", name);
return nullptr;
}
if (parent.FindChild(name) != nullptr)
throw FormatRuntimeError("Duplicate subdirectory '%s'", name);
Directory *directory = parent.CreateChild(name);
while (true) {
const char *line = file.ReadLine();
if (line == nullptr) {
error.Set(directory_domain, "Unexpected end of file");
directory->Delete();
return nullptr;
try {
while (true) {
const char *line = file.ReadLine();
if (line == nullptr)
throw std::runtime_error("Unexpected end of file");
if (StringStartsWith(line, DIRECTORY_BEGIN))
break;
if (!ParseLine(*directory, line))
throw FormatRuntimeError("Malformed line: %s", line);
}
if (StringStartsWith(line, DIRECTORY_BEGIN))
break;
if (!ParseLine(*directory, line)) {
error.Format(directory_domain,
"Malformed line: %s", line);
directory->Delete();
return nullptr;
}
}
success = directory_load(file, *directory, error);
if (!success) {
directory_load(file, *directory);
} catch (...) {
directory->Delete();
return nullptr;
throw;
}
return directory;
}
bool
directory_load(TextFile &file, Directory &directory, Error &error)
void
directory_load(TextFile &file, Directory &directory)
{
const char *line;
@@ -165,38 +150,23 @@ directory_load(TextFile &file, Directory &directory, Error &error)
!StringStartsWith(line, DIRECTORY_END)) {
const char *p;
if ((p = StringAfterPrefix(line, DIRECTORY_DIR))) {
Directory *subdir =
directory_load_subdir(file, directory,
p, error);
if (subdir == nullptr)
return false;
directory_load_subdir(file, directory, p);
} else if ((p = StringAfterPrefix(line, SONG_BEGIN))) {
const char *name = p;
if (directory.FindSong(name) != nullptr) {
error.Format(directory_domain,
"Duplicate song '%s'", name);
return false;
}
if (directory.FindSong(name) != nullptr)
throw FormatRuntimeError("Duplicate song '%s'", name);
DetachedSong *song = song_load(file, name, error);
if (song == nullptr)
return false;
DetachedSong *song = song_load(file, name);
directory.AddSong(Song::NewFrom(std::move(*song),
directory));
delete song;
} else if ((p = StringAfterPrefix(line, PLAYLIST_META_BEGIN))) {
const char *name = p;
if (!playlist_metadata_load(file, directory.playlists,
name, error))
return false;
playlist_metadata_load(file, directory.playlists, name);
} else {
error.Format(directory_domain,
"Malformed line: %s", line);
return false;
throw FormatRuntimeError("Malformed line: %s", line);
}
}
return true;
}

View File

@@ -28,7 +28,10 @@ class Error;
void
directory_save(BufferedOutputStream &os, const Directory &directory);
bool
directory_load(TextFile &file, Directory &directory, Error &error);
/**
* Throws #std::runtime_error on error.
*/
void
directory_load(TextFile &file, Directory &directory);
#endif

View File

@@ -142,22 +142,19 @@ SimpleDatabase::Check() const
#endif
}
bool
SimpleDatabase::Load(Error &error)
void
SimpleDatabase::Load()
{
assert(!path.IsNull());
assert(root != nullptr);
TextFile file(path);
if (!db_load_internal(file, *root, error))
return false;
db_load_internal(file, *root);
FileInfo fi;
if (GetFileInfo(path, fi))
mtime = fi.GetModificationTime();
return true;
}
void
@@ -173,16 +170,7 @@ SimpleDatabase::Open()
#endif
try {
Error error2;
if (!Load(error2)) {
LogError(error2);
delete root;
Check();
root = Directory::NewRoot();
}
Load();
} catch (const std::exception &e) {
LogError(e);

View File

@@ -136,7 +136,10 @@ private:
void Check() const;
bool Load(Error &error);
/**
* Throws #std::runtime_error on error.
*/
void Load();
Database *LockUmountSteal(const char *uri);
};