You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

87 lines
1.9 KiB

#pragma once
#include <cerrno>
#include <cstring>
#include <fstream>
#include <string>
#include "utils/file_util.h"
#include "utils/log.hpp"
#include "utils/stdcompat/optional.hpp"
namespace devilution {
// A wrapper around `std::fstream` that logs errors.
struct LoggedFStream {
public:
bool Open(const char *path, std::ios::openmode mode)
{
s_ = CreateFileStream(path, mode);
return CheckError("new std::fstream(\"{}\", {})", path, OpenModeToString(mode).c_str());
}
void Close()
{
s_ = std::nullopt;
}
[[nodiscard]] bool IsOpen() const
{
return s_ != std::nullopt;
}
bool Seekp(std::streampos pos)
{
s_->seekp(pos);
return CheckError("seekp({})", pos);
}
bool Seekp(std::streamoff pos, std::ios::seekdir dir)
{
s_->seekp(pos, dir);
return CheckError("seekp({}, {})", pos, DirToString(dir));
}
bool Tellp(std::streampos *result)
{
*result = s_->tellp();
return CheckError("tellp() = {}", *result);
}
bool Write(const char *data, std::streamsize size)
{
s_->write(data, size);
return CheckError("write(data, {})", size);
}
bool Read(char *out, std::streamsize size)
{
s_->read(out, size);
return CheckError("read(out, {})", size);
}
private:
static const char *DirToString(std::ios::seekdir dir);
static std::string OpenModeToString(std::ios::openmode mode);
template <typename... PrintFArgs>
bool CheckError(const char *fmt, PrintFArgs... args)
{
if (s_->fail()) {
std::string fmtWithError = fmt;
fmtWithError.append(": failed with \"{}\"");
const char *errorMessage = std::strerror(errno);
if (errorMessage == nullptr)
errorMessage = "";
LogError(LogCategory::System, fmtWithError.c_str(), args..., errorMessage);
} else {
LogVerbose(LogCategory::System, fmt, args...);
}
return !s_->fail();
}
std::optional<std::fstream> s_;
};
} // namespace devilution