Common: Error/FileSystem backports
This commit is contained in:
parent
7890051165
commit
39f64a03ee
|
@ -1,182 +1,140 @@
|
|||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#include "error.h"
|
||||
#include "string_util.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
// Platform-specific includes
|
||||
#include "fmt/format.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "windows_headers.h"
|
||||
static_assert(std::is_same<DWORD, unsigned long>::value, "DWORD is unsigned long");
|
||||
static_assert(std::is_same<HRESULT, long>::value, "HRESULT is long");
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
Error::Error() = default;
|
||||
|
||||
Error::Error() : m_type(Type::None)
|
||||
{
|
||||
m_error.none = 0;
|
||||
}
|
||||
Error::Error(const Error& c) = default;
|
||||
|
||||
Error::Error(const Error& c)
|
||||
{
|
||||
m_type = c.m_type;
|
||||
std::memcpy(&m_error, &c.m_error, sizeof(m_error));
|
||||
m_code_string.AppendString(c.m_code_string);
|
||||
m_message.AppendString(c.m_message);
|
||||
}
|
||||
Error::Error(Error&& e) = default;
|
||||
|
||||
Error::~Error() = default;
|
||||
|
||||
void Error::Clear()
|
||||
{
|
||||
m_type = Type::None;
|
||||
m_error.none = 0;
|
||||
m_code_string.Clear();
|
||||
m_message.Clear();
|
||||
m_description = {};
|
||||
}
|
||||
|
||||
void Error::SetErrno(int err)
|
||||
{
|
||||
m_type = Type::Errno;
|
||||
m_error.errno_f = err;
|
||||
|
||||
m_code_string.Format("%i", err);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
strerror_s(m_message.GetWriteableCharArray(), m_message.GetBufferSize(), err);
|
||||
m_message.UpdateSize();
|
||||
#else
|
||||
const char* message = std::strerror(err);
|
||||
if (message)
|
||||
m_message = message;
|
||||
char buf[128];
|
||||
if (strerror_s(buf, sizeof(buf), err) != 0)
|
||||
m_description = fmt::format("errno {}: {}", err, buf);
|
||||
else
|
||||
m_message = StaticString("<Could not get error message>");
|
||||
#endif
|
||||
}
|
||||
|
||||
void Error::SetSocket(int err)
|
||||
{
|
||||
// Socket errors are win32 errors on windows
|
||||
#ifdef _WIN32
|
||||
SetWin32(err);
|
||||
m_description = fmt::format("errno {}: <Could not get error message>", err);
|
||||
#else
|
||||
SetErrno(err);
|
||||
const char* buf = std::strerror(err);
|
||||
if (buf)
|
||||
m_description = fmt::format("errno {}: {}", err, buf);
|
||||
else
|
||||
m_description = fmt::format("errno {}: <Could not get error message>", err);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Error::SetMessage(const char* msg)
|
||||
void Error::SetErrno(Error* errptr, int err)
|
||||
{
|
||||
m_type = Type::User;
|
||||
m_error.user = 0;
|
||||
m_code_string.Clear();
|
||||
m_message = msg;
|
||||
if (errptr)
|
||||
errptr->SetErrno(err);
|
||||
}
|
||||
|
||||
void Error::SetUser(int err, const char* msg)
|
||||
void Error::SetString(std::string description)
|
||||
{
|
||||
m_type = Type::User;
|
||||
m_error.user = err;
|
||||
m_code_string.Format("%d", err);
|
||||
m_message = msg;
|
||||
m_description = std::move(description);
|
||||
}
|
||||
|
||||
void Error::SetUser(const char* code, const char* message)
|
||||
void Error::SetString(Error* errptr, std::string description)
|
||||
{
|
||||
m_type = Type::User;
|
||||
m_error.user = 0;
|
||||
m_code_string = code;
|
||||
m_message = message;
|
||||
}
|
||||
|
||||
void Error::SetUserFormatted(int err, const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
m_type = Type::User;
|
||||
m_error.user = err;
|
||||
m_code_string.Format("%d", err);
|
||||
m_message.FormatVA(format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Error::SetUserFormatted(const char* code, const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
m_type = Type::User;
|
||||
m_error.user = 0;
|
||||
m_code_string = code;
|
||||
m_message.FormatVA(format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Error::SetFormattedMessage(const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
m_type = Type::User;
|
||||
m_error.user = 0;
|
||||
m_code_string.Clear();
|
||||
m_message.FormatVA(format, ap);
|
||||
va_end(ap);
|
||||
if (errptr)
|
||||
errptr->SetString(std::move(description));
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void Error::SetWin32(unsigned long err)
|
||||
{
|
||||
m_type = Type::Win32;
|
||||
m_error.win32 = err;
|
||||
m_code_string.Format("%u", static_cast<u32>(err));
|
||||
m_message.Clear();
|
||||
|
||||
const DWORD r = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, m_error.win32, 0, m_message.GetWriteableCharArray(),
|
||||
m_message.GetWritableBufferSize(), NULL);
|
||||
WCHAR buf[128];
|
||||
const DWORD r = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_USER_DEFAULT, buf,
|
||||
static_cast<DWORD>(std::size(buf)), nullptr);
|
||||
if (r > 0)
|
||||
{
|
||||
m_message.Resize(r);
|
||||
m_message.RStrip();
|
||||
m_description =
|
||||
fmt::format("Win32 Error {}: {}", err, StringUtil::WideStringToUTF8String(std::wstring_view(buf, r)));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_message = "<Could not resolve system error ID>";
|
||||
m_description = fmt::format("Win32 Error {}: <Could not resolve system error ID>", err);
|
||||
}
|
||||
}
|
||||
|
||||
void Error::SetWin32(Error* errptr, unsigned long err)
|
||||
{
|
||||
if (errptr)
|
||||
errptr->SetWin32(err);
|
||||
}
|
||||
|
||||
void Error::SetHResult(long err)
|
||||
{
|
||||
m_type = Type::HResult;
|
||||
m_error.win32 = err;
|
||||
m_code_string.Format("%08X", static_cast<u32>(err));
|
||||
m_message.Clear();
|
||||
|
||||
const DWORD r = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, m_error.win32, 0, m_message.GetWriteableCharArray(),
|
||||
m_message.GetWritableBufferSize(), NULL);
|
||||
WCHAR buf[128];
|
||||
const DWORD r = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_USER_DEFAULT, buf,
|
||||
static_cast<DWORD>(std::size(buf)), nullptr);
|
||||
if (r > 0)
|
||||
{
|
||||
m_message.Resize(r);
|
||||
m_message.RStrip();
|
||||
m_description =
|
||||
fmt::format("HRESULT {:08X}: {}", err, StringUtil::WideStringToUTF8String(std::wstring_view(buf, r)));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_message = "<Could not resolve system error ID>";
|
||||
m_description = fmt::format("HRESULT {:08X}: <Could not resolve system error ID>", err);
|
||||
}
|
||||
}
|
||||
|
||||
void Error::SetHResult(Error* errptr, long err)
|
||||
{
|
||||
if (errptr)
|
||||
errptr->SetHResult(err);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// constructors
|
||||
void Error::SetSocket(int err)
|
||||
{
|
||||
// Socket errors are win32 errors on windows
|
||||
#ifdef _WIN32
|
||||
SetWin32(err);
|
||||
#else
|
||||
SetErrno(err);
|
||||
#endif
|
||||
m_type = Type::Socket;
|
||||
}
|
||||
|
||||
void Error::SetSocket(Error* errptr, int err)
|
||||
{
|
||||
if (errptr)
|
||||
errptr->SetSocket(err);
|
||||
}
|
||||
|
||||
Error Error::CreateNone()
|
||||
{
|
||||
Error ret;
|
||||
ret.Clear();
|
||||
return ret;
|
||||
return Error();
|
||||
}
|
||||
|
||||
Error Error::CreateErrno(int err)
|
||||
|
@ -193,70 +151,10 @@ Error Error::CreateSocket(int err)
|
|||
return ret;
|
||||
}
|
||||
|
||||
Error Error::CreateMessage(const char* msg)
|
||||
Error Error::CreateString(std::string description)
|
||||
{
|
||||
Error ret;
|
||||
ret.SetMessage(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error Error::CreateUser(int err, const char* msg)
|
||||
{
|
||||
Error ret;
|
||||
ret.SetUser(err, msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error Error::CreateUser(const char* code, const char* message)
|
||||
{
|
||||
Error ret;
|
||||
ret.SetUser(code, message);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error Error::CreateMessageFormatted(const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
Error ret;
|
||||
ret.m_type = Type::User;
|
||||
ret.m_message.FormatVA(format, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error Error::CreateUserFormatted(int err, const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
Error ret;
|
||||
ret.m_type = Type::User;
|
||||
ret.m_error.user = err;
|
||||
ret.m_code_string.Format("%d", err);
|
||||
ret.m_message.FormatVA(format, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Error Error::CreateUserFormatted(const char* code, const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
Error ret;
|
||||
ret.m_type = Type::User;
|
||||
ret.m_error.user = 0;
|
||||
ret.m_code_string = code;
|
||||
ret.m_message.FormatVA(format, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
ret.SetString(std::move(description));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -277,86 +175,16 @@ Error Error::CreateHResult(long err)
|
|||
|
||||
#endif
|
||||
|
||||
Error& Error::operator=(const Error& e)
|
||||
{
|
||||
m_type = e.m_type;
|
||||
std::memcpy(&m_error, &e.m_error, sizeof(m_error));
|
||||
m_code_string.Clear();
|
||||
m_code_string.AppendString(e.m_code_string);
|
||||
m_message.Clear();
|
||||
m_message.AppendString(e.m_message);
|
||||
return *this;
|
||||
}
|
||||
Error& Error::operator=(const Error& e) = default;
|
||||
|
||||
Error& Error::operator=(Error&& e) = default;
|
||||
|
||||
bool Error::operator==(const Error& e) const
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case Type::None:
|
||||
return true;
|
||||
|
||||
case Type::Errno:
|
||||
return m_error.errno_f == e.m_error.errno_f;
|
||||
|
||||
case Type::Socket:
|
||||
return m_error.socketerr == e.m_error.socketerr;
|
||||
|
||||
case Type::User:
|
||||
return m_error.user == e.m_error.user;
|
||||
|
||||
#ifdef _WIN32
|
||||
case Type::Win32:
|
||||
return m_error.win32 == e.m_error.win32;
|
||||
|
||||
case Type::HResult:
|
||||
return m_error.hresult == e.m_error.hresult;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
return (m_type == e.m_type && m_description == e.m_description);
|
||||
}
|
||||
|
||||
bool Error::operator!=(const Error& e) const
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case Type::None:
|
||||
return false;
|
||||
|
||||
case Type::Errno:
|
||||
return m_error.errno_f != e.m_error.errno_f;
|
||||
|
||||
case Type::Socket:
|
||||
return m_error.socketerr != e.m_error.socketerr;
|
||||
|
||||
case Type::User:
|
||||
return m_error.user != e.m_error.user;
|
||||
|
||||
#ifdef _WIN32
|
||||
case Type::Win32:
|
||||
return m_error.win32 != e.m_error.win32;
|
||||
|
||||
case Type::HResult:
|
||||
return m_error.hresult != e.m_error.hresult;
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
return (m_type != e.m_type || m_description != e.m_description);
|
||||
}
|
||||
|
||||
SmallString Error::GetCodeAndMessage() const
|
||||
{
|
||||
SmallString ret;
|
||||
GetCodeAndMessage(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Error::GetCodeAndMessage(String& dest) const
|
||||
{
|
||||
if (m_code_string.IsEmpty())
|
||||
dest.Assign(m_message);
|
||||
else
|
||||
dest.Format("[%s]: %s", m_code_string.GetCharArray(), m_message.GetCharArray());
|
||||
}
|
||||
|
||||
} // namespace Common
|
|
@ -1,100 +1,75 @@
|
|||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
#include "string.h"
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace Common {
|
||||
#include <string>
|
||||
|
||||
// this class provides enough storage room for all of these types
|
||||
class Error
|
||||
{
|
||||
public:
|
||||
Error();
|
||||
Error(const Error& e);
|
||||
Error(Error&& e);
|
||||
~Error();
|
||||
|
||||
enum class Type
|
||||
{
|
||||
None = 0, // Set by default constructor, returns 'No Error'.
|
||||
Errno = 1, // Error that is set by system functions, such as open().
|
||||
Socket = 2, // Error that is set by socket functions, such as socket(). On Unix this is the same as errno.
|
||||
User = 3, // When translated, will return 'User Error %u' if no message is specified.
|
||||
Win32 = 4, // Error that is returned by some Win32 functions, such as RegOpenKeyEx. Also used by other APIs through
|
||||
// GetLastError().
|
||||
HResult = 5, // Error that is returned by Win32 COM methods, e.g. S_OK.
|
||||
None = 0,
|
||||
Errno = 1,
|
||||
Socket = 2,
|
||||
User = 3,
|
||||
Win32 = 4,
|
||||
HResult = 5,
|
||||
};
|
||||
|
||||
ALWAYS_INLINE Type GetType() const { return m_type; }
|
||||
ALWAYS_INLINE int GetErrnoCode() const { return m_error.errno_f; }
|
||||
ALWAYS_INLINE int GetSocketCode() const { return m_error.socketerr; }
|
||||
ALWAYS_INLINE int GetUserCode() const { return m_error.user; }
|
||||
#ifdef _WIN32
|
||||
ALWAYS_INLINE unsigned long GetWin32Code() const { return m_error.win32; }
|
||||
ALWAYS_INLINE long GetHResultCode() const { return m_error.hresult; }
|
||||
#endif
|
||||
ALWAYS_INLINE const std::string& GetDescription() const { return m_description; }
|
||||
|
||||
// get code, e.g. "0x00000002"
|
||||
ALWAYS_INLINE const String& GetCodeString() const { return m_code_string; }
|
||||
|
||||
// get description, e.g. "File not Found"
|
||||
ALWAYS_INLINE const String& GetMessage() const { return m_message; }
|
||||
|
||||
// setter functions
|
||||
void Clear();
|
||||
|
||||
/// Error that is set by system functions, such as open().
|
||||
void SetErrno(int err);
|
||||
|
||||
/// Error that is set by socket functions, such as socket(). On Unix this is the same as errno.
|
||||
void SetSocket(int err);
|
||||
void SetMessage(const char* msg);
|
||||
void SetFormattedMessage(const char* format, ...) printflike(2, 3);
|
||||
void SetUser(int err, const char* msg);
|
||||
void SetUser(const char* code, const char* message);
|
||||
void SetUserFormatted(int err, const char* format, ...) printflike(3, 4);
|
||||
void SetUserFormatted(const char* code, const char* format, ...) printflike(3, 4);
|
||||
|
||||
/// Set both description and message.
|
||||
void SetString(std::string description);
|
||||
|
||||
#ifdef _WIN32
|
||||
/// Error that is returned by some Win32 functions, such as RegOpenKeyEx. Also used by other APIs through
|
||||
/// GetLastError().
|
||||
void SetWin32(unsigned long err);
|
||||
|
||||
/// Error that is returned by Win32 COM methods, e.g. S_OK.
|
||||
void SetHResult(long err);
|
||||
#endif
|
||||
|
||||
// constructors
|
||||
static Error CreateNone();
|
||||
static Error CreateErrno(int err);
|
||||
static Error CreateSocket(int err);
|
||||
static Error CreateMessage(const char* msg);
|
||||
static Error CreateMessageFormatted(const char* format, ...) printflike(1, 2);
|
||||
static Error CreateUser(int err, const char* msg);
|
||||
static Error CreateUser(const char* code, const char* message);
|
||||
static Error CreateUserFormatted(int err, const char* format, ...) printflike(2, 3);
|
||||
static Error CreateUserFormatted(const char* code, const char* format, ...) printflike(2, 3);
|
||||
static Error CreateString(std::string description);
|
||||
#ifdef _WIN32
|
||||
static Error CreateWin32(unsigned long err);
|
||||
static Error CreateHResult(long err);
|
||||
#endif
|
||||
|
||||
// get code and description, e.g. "[0x00000002]: File not Found"
|
||||
SmallString GetCodeAndMessage() const;
|
||||
void GetCodeAndMessage(String& dest) const;
|
||||
// helpers for setting
|
||||
static void SetErrno(Error* errptr, int err);
|
||||
static void SetSocket(Error* errptr, int err);
|
||||
static void SetString(Error* errptr, std::string description);
|
||||
static void SetWin32(Error* errptr, unsigned long err);
|
||||
static void SetHResult(Error* errptr, long err);
|
||||
|
||||
// operators
|
||||
Error& operator=(const Error& e);
|
||||
Error& operator=(Error&& e);
|
||||
bool operator==(const Error& e) const;
|
||||
bool operator!=(const Error& e) const;
|
||||
|
||||
private:
|
||||
Type m_type = Type::None;
|
||||
union
|
||||
{
|
||||
int none;
|
||||
int errno_f; // renamed from errno to avoid conflicts with #define'd errnos.
|
||||
int socketerr;
|
||||
int user;
|
||||
#ifdef _WIN32
|
||||
unsigned long win32;
|
||||
long hresult;
|
||||
#endif
|
||||
} m_error{};
|
||||
StackString<16> m_code_string;
|
||||
TinyString m_message;
|
||||
std::string m_description;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
|
||||
#include "file_system.h"
|
||||
#include "assert.h"
|
||||
#include "error.h"
|
||||
#include "log.h"
|
||||
#include "path.h"
|
||||
#include "string_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
@ -587,7 +589,7 @@ std::string Path::Combine(const std::string_view& base, const std::string_view&
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode)
|
||||
std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode, Error* error)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const std::wstring wfilename(StringUtil::UTF8StringToWideString(filename));
|
||||
|
@ -595,23 +597,34 @@ std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode)
|
|||
if (!wfilename.empty() && !wmode.empty())
|
||||
{
|
||||
std::FILE* fp;
|
||||
if (_wfopen_s(&fp, wfilename.c_str(), wmode.c_str()) != 0)
|
||||
const errno_t err = _wfopen_s(&fp, wfilename.c_str(), wmode.c_str());
|
||||
if (err != 0)
|
||||
{
|
||||
Error::SetErrno(error, err);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
std::FILE* fp;
|
||||
if (fopen_s(&fp, filename, mode) != 0)
|
||||
const errno_t err = fopen_s(&fp, filename, mode);
|
||||
if (err != 0)
|
||||
{
|
||||
Error::SetErrno(error, err);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return fp;
|
||||
#else
|
||||
return std::fopen(filename, mode);
|
||||
std::FILE* fp = std::fopen(filename, mode);
|
||||
if (!fp)
|
||||
Error::SetErrno(error, errno);
|
||||
return fp;
|
||||
#endif
|
||||
}
|
||||
|
||||
int FileSystem::OpenFDFile(const char* filename, int flags, int mode)
|
||||
int FileSystem::OpenFDFile(const char* filename, int flags, int mode, Error* error)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const std::wstring wfilename(StringUtil::UTF8StringToWideString(filename));
|
||||
|
@ -620,18 +633,21 @@ int FileSystem::OpenFDFile(const char* filename, int flags, int mode)
|
|||
|
||||
return -1;
|
||||
#else
|
||||
return open(filename, flags, mode);
|
||||
const int fd = open(filename, flags, mode);
|
||||
if (fd < 0)
|
||||
Error::SetErrno(error, errno);
|
||||
return fd;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFile(const char* filename, const char* mode)
|
||||
FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFile(const char* filename, const char* mode, Error* error)
|
||||
{
|
||||
return ManagedCFilePtr(OpenCFile(filename, mode), [](std::FILE* fp) { std::fclose(fp); });
|
||||
return ManagedCFilePtr(OpenCFile(filename, mode, error));
|
||||
}
|
||||
|
||||
std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode)
|
||||
std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const std::wstring wfilename(StringUtil::UTF8StringToWideString(filename));
|
||||
|
@ -661,16 +677,20 @@ std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, F
|
|||
if (fp)
|
||||
return fp;
|
||||
|
||||
Error::SetErrno(error, errno);
|
||||
return nullptr;
|
||||
#else
|
||||
return std::fopen(filename, mode);
|
||||
std::FILE* fp = std::fopen(filename, mode);
|
||||
if (!fp)
|
||||
Error::SetErrno(error, errno);
|
||||
return fp;
|
||||
#endif
|
||||
}
|
||||
|
||||
FileSystem::ManagedCFilePtr FileSystem::OpenManagedSharedCFile(const char* filename, const char* mode,
|
||||
FileShareMode share_mode)
|
||||
FileShareMode share_mode, Error* error)
|
||||
{
|
||||
return ManagedCFilePtr(OpenSharedCFile(filename, mode, share_mode), [](std::FILE* fp) { std::fclose(fp); });
|
||||
return ManagedCFilePtr(OpenSharedCFile(filename, mode, share_mode, error));
|
||||
}
|
||||
|
||||
int FileSystem::FSeek64(std::FILE* fp, s64 offset, int whence)
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
|
@ -11,6 +13,8 @@
|
|||
#include <sys/stat.h>
|
||||
#include <vector>
|
||||
|
||||
class Error;
|
||||
|
||||
#ifdef _WIN32
|
||||
#define FS_OSPATH_SEPARATOR_CHARACTER '\\'
|
||||
#define FS_OSPATH_SEPARATOR_STR "\\"
|
||||
|
@ -87,15 +91,25 @@ bool DeleteFile(const char* path);
|
|||
/// Rename file
|
||||
bool RenamePath(const char* OldPath, const char* NewPath);
|
||||
|
||||
/// Deleter functor for managed file pointers
|
||||
struct FileDeleter
|
||||
{
|
||||
ALWAYS_INLINE void operator()(std::FILE* fp)
|
||||
{
|
||||
if (fp)
|
||||
std::fclose(fp);
|
||||
}
|
||||
};
|
||||
|
||||
/// open files
|
||||
using ManagedCFilePtr = std::unique_ptr<std::FILE, void (*)(std::FILE*)>;
|
||||
ManagedCFilePtr OpenManagedCFile(const char* filename, const char* mode);
|
||||
std::FILE* OpenCFile(const char* filename, const char* mode);
|
||||
using ManagedCFilePtr = std::unique_ptr<std::FILE, FileDeleter>;
|
||||
ManagedCFilePtr OpenManagedCFile(const char* filename, const char* mode, Error* error = nullptr);
|
||||
std::FILE* OpenCFile(const char* filename, const char* mode, Error* error = nullptr);
|
||||
int FSeek64(std::FILE* fp, s64 offset, int whence);
|
||||
s64 FTell64(std::FILE* fp);
|
||||
s64 FSize64(std::FILE* fp);
|
||||
|
||||
int OpenFDFile(const char* filename, int flags, int mode);
|
||||
int OpenFDFile(const char* filename, int flags, int mode, Error* error = nullptr);
|
||||
|
||||
/// Sharing modes for OpenSharedCFile().
|
||||
enum class FileShareMode
|
||||
|
@ -108,8 +122,9 @@ enum class FileShareMode
|
|||
|
||||
/// Opens a file in shareable mode (where other processes can access it concurrently).
|
||||
/// Only has an effect on Windows systems.
|
||||
ManagedCFilePtr OpenManagedSharedCFile(const char* filename, const char* mode, FileShareMode share_mode);
|
||||
std::FILE* OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode);
|
||||
ManagedCFilePtr OpenManagedSharedCFile(const char* filename, const char* mode, FileShareMode share_mode,
|
||||
Error* error = nullptr);
|
||||
std::FILE* OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error = nullptr);
|
||||
|
||||
/// Abstracts a POSIX file lock.
|
||||
#ifndef _WIN32
|
||||
|
|
|
@ -38,7 +38,7 @@ static s32 GetFreeFileHandle()
|
|||
}
|
||||
|
||||
const s32 index = static_cast<s32>(s_files.size());
|
||||
s_files.emplace_back(nullptr, [](std::FILE*) {});
|
||||
s_files.emplace_back(nullptr, FileSystem::FileDeleter());
|
||||
return index;
|
||||
}
|
||||
|
||||
|
|
|
@ -1142,7 +1142,7 @@ bool System::BootSystem(SystemBootParameters parameters)
|
|||
Host::OnSystemStarting();
|
||||
|
||||
// Load CD image up and detect region.
|
||||
Common::Error error;
|
||||
Error error;
|
||||
std::unique_ptr<CDImage> disc;
|
||||
DiscRegion disc_region = DiscRegion::NonPS1;
|
||||
std::string exe_boot;
|
||||
|
@ -1172,7 +1172,7 @@ bool System::BootSystem(SystemBootParameters parameters)
|
|||
if (!disc)
|
||||
{
|
||||
Host::ReportErrorAsync("Error", fmt::format("Failed to load CD image '{}': {}",
|
||||
Path::GetFileName(parameters.filename), error.GetCodeAndMessage()));
|
||||
Path::GetFileName(parameters.filename), error.GetDescription()));
|
||||
s_state = State::Shutdown;
|
||||
Host::OnSystemDestroyed();
|
||||
return false;
|
||||
|
@ -1209,9 +1209,9 @@ bool System::BootSystem(SystemBootParameters parameters)
|
|||
// Switch subimage.
|
||||
if (disc && parameters.media_playlist_index != 0 && !disc->SwitchSubImage(parameters.media_playlist_index, &error))
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("Error", "Failed to switch to subimage %u in '%s': %s",
|
||||
parameters.media_playlist_index, parameters.filename.c_str(),
|
||||
error.GetCodeAndMessage().GetCharArray());
|
||||
Host::ReportErrorAsync("Error",
|
||||
fmt::format("Failed to switch to subimage {] in '{}': {}", parameters.media_playlist_index,
|
||||
parameters.filename, error.GetDescription()));
|
||||
s_state = State::Shutdown;
|
||||
Host::OnSystemDestroyed();
|
||||
return false;
|
||||
|
@ -2137,7 +2137,7 @@ bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool u
|
|||
return false;
|
||||
}
|
||||
|
||||
Common::Error error;
|
||||
Error error;
|
||||
std::string media_filename;
|
||||
std::unique_ptr<CDImage> media;
|
||||
if (header.media_filename_length > 0)
|
||||
|
@ -2166,7 +2166,7 @@ bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool u
|
|||
30.0f,
|
||||
Host::TranslateString("OSDMessage", "Failed to open CD image from save state '%s': %s. Using "
|
||||
"existing image '%s', this may result in instability."),
|
||||
media_filename.c_str(), error.GetCodeAndMessage().GetCharArray(), old_media->GetFileName().c_str());
|
||||
media_filename.c_str(), error.GetDescription().c_str(), old_media->GetFileName().c_str());
|
||||
media = std::move(old_media);
|
||||
header.media_subimage_index = media->GetCurrentSubImage();
|
||||
}
|
||||
|
@ -2174,7 +2174,7 @@ bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool u
|
|||
{
|
||||
Host::ReportFormattedErrorAsync(
|
||||
"Error", Host::TranslateString("System", "Failed to open CD image '%s' used by save state: %s."),
|
||||
media_filename.c_str(), error.GetCodeAndMessage().GetCharArray());
|
||||
media_filename.c_str(), error.GetDescription().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2193,7 +2193,7 @@ bool System::DoLoadState(ByteStream* state, bool force_software_renderer, bool u
|
|||
Host::ReportFormattedErrorAsync(
|
||||
"Error",
|
||||
Host::TranslateString("System", "Failed to switch to subimage %u in CD image '%s' used by save state: %s."),
|
||||
header.media_subimage_index + 1u, media_filename.c_str(), error.GetCodeAndMessage().GetCharArray());
|
||||
header.media_subimage_index + 1u, media_filename.c_str(), error.GetDescription().c_str());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
@ -3081,12 +3081,12 @@ std::string System::GetMediaFileName()
|
|||
|
||||
bool System::InsertMedia(const char* path)
|
||||
{
|
||||
Common::Error error;
|
||||
Error error;
|
||||
std::unique_ptr<CDImage> image = CDImage::Open(path, g_settings.cdrom_load_image_patches, &error);
|
||||
if (!image)
|
||||
{
|
||||
Host::AddFormattedOSDMessage(10.0f, Host::TranslateString("OSDMessage", "Failed to open disc image '%s': %s."),
|
||||
path, error.GetCodeAndMessage().GetCharArray());
|
||||
path, error.GetDescription().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -3272,12 +3272,12 @@ bool System::SwitchMediaSubImage(u32 index)
|
|||
std::unique_ptr<CDImage> image = CDROM::RemoveMedia(true);
|
||||
Assert(image);
|
||||
|
||||
Common::Error error;
|
||||
Error error;
|
||||
if (!image->SwitchSubImage(index, &error))
|
||||
{
|
||||
Host::AddFormattedOSDMessage(10.0f,
|
||||
Host::TranslateString("OSDMessage", "Failed to switch to subimage %u in '%s': %s."),
|
||||
index + 1u, image->GetFileName().c_str(), error.GetCodeAndMessage().GetCharArray());
|
||||
index + 1u, image->GetFileName().c_str(), error.GetDescription().c_str());
|
||||
|
||||
const DiscRegion region = GetRegionForImage(image.get());
|
||||
CDROM::InsertMedia(std::move(image), region);
|
||||
|
|
|
@ -21,7 +21,7 @@ u32 CDImage::GetBytesPerSector(TrackMode mode)
|
|||
return sizes[static_cast<u32>(mode)];
|
||||
}
|
||||
|
||||
std::unique_ptr<CDImage> CDImage::Open(const char* filename, bool allow_patches, Common::Error* error)
|
||||
std::unique_ptr<CDImage> CDImage::Open(const char* filename, bool allow_patches, Error* error)
|
||||
{
|
||||
const char* extension;
|
||||
|
||||
|
@ -94,10 +94,7 @@ std::unique_ptr<CDImage> CDImage::Open(const char* filename, bool allow_patches,
|
|||
{
|
||||
image = CDImage::OverlayPPFPatch(ppf_filename.c_str(), std::move(image));
|
||||
if (!image)
|
||||
{
|
||||
if (error)
|
||||
error->SetFormattedMessage("Failed to apply ppf patch from '%s'.", ppf_filename.c_str());
|
||||
}
|
||||
Error::SetString(error, fmt::format("Failed to apply ppf patch from '{}'.", ppf_filename));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,7 +340,7 @@ u32 CDImage::GetCurrentSubImage() const
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool CDImage::SwitchSubImage(u32 index, Common::Error* error)
|
||||
bool CDImage::SwitchSubImage(u32 index, Error* error)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -11,9 +11,7 @@
|
|||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace Common {
|
||||
class Error;
|
||||
}
|
||||
|
||||
class CDImage
|
||||
{
|
||||
|
@ -220,15 +218,15 @@ public:
|
|||
static bool IsDeviceName(const char* filename);
|
||||
|
||||
// Opening disc image.
|
||||
static std::unique_ptr<CDImage> Open(const char* filename, bool allow_patches, Common::Error* error);
|
||||
static std::unique_ptr<CDImage> OpenBinImage(const char* filename, Common::Error* error);
|
||||
static std::unique_ptr<CDImage> OpenCueSheetImage(const char* filename, Common::Error* error);
|
||||
static std::unique_ptr<CDImage> OpenCHDImage(const char* filename, Common::Error* error);
|
||||
static std::unique_ptr<CDImage> OpenEcmImage(const char* filename, Common::Error* error);
|
||||
static std::unique_ptr<CDImage> OpenMdsImage(const char* filename, Common::Error* error);
|
||||
static std::unique_ptr<CDImage> OpenPBPImage(const char* filename, Common::Error* error);
|
||||
static std::unique_ptr<CDImage> OpenM3uImage(const char* filename, bool apply_patches, Common::Error* error);
|
||||
static std::unique_ptr<CDImage> OpenDeviceImage(const char* filename, Common::Error* error);
|
||||
static std::unique_ptr<CDImage> Open(const char* filename, bool allow_patches, Error* error);
|
||||
static std::unique_ptr<CDImage> OpenBinImage(const char* filename, Error* error);
|
||||
static std::unique_ptr<CDImage> OpenCueSheetImage(const char* filename, Error* error);
|
||||
static std::unique_ptr<CDImage> OpenCHDImage(const char* filename, Error* error);
|
||||
static std::unique_ptr<CDImage> OpenEcmImage(const char* filename, Error* error);
|
||||
static std::unique_ptr<CDImage> OpenMdsImage(const char* filename, Error* error);
|
||||
static std::unique_ptr<CDImage> OpenPBPImage(const char* filename, Error* error);
|
||||
static std::unique_ptr<CDImage> OpenM3uImage(const char* filename, bool apply_patches, Error* error);
|
||||
static std::unique_ptr<CDImage> OpenDeviceImage(const char* filename, Error* error);
|
||||
static std::unique_ptr<CDImage>
|
||||
CreateMemoryImage(CDImage* image, ProgressCallback* progress = ProgressCallback::NullProgressCallback);
|
||||
static std::unique_ptr<CDImage> OverlayPPFPatch(const char* filename, std::unique_ptr<CDImage> parent_image,
|
||||
|
@ -341,7 +339,7 @@ public:
|
|||
virtual u32 GetCurrentSubImage() const;
|
||||
|
||||
// Changes the current sub-image. If this fails, the image state is unchanged.
|
||||
virtual bool SwitchSubImage(u32 index, Common::Error* error);
|
||||
virtual bool SwitchSubImage(u32 index, Error* error);
|
||||
|
||||
// Retrieve sub-image metadata.
|
||||
virtual std::string GetSubImageMetadata(u32 index, const std::string_view& type) const;
|
||||
|
|
|
@ -15,7 +15,7 @@ public:
|
|||
CDImageBin();
|
||||
~CDImageBin() override;
|
||||
|
||||
bool Open(const char* filename, Common::Error* error);
|
||||
bool Open(const char* filename, Error* error);
|
||||
|
||||
bool ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index) override;
|
||||
bool HasNonStandardSubchannel() const override;
|
||||
|
@ -38,7 +38,7 @@ CDImageBin::~CDImageBin()
|
|||
std::fclose(m_fp);
|
||||
}
|
||||
|
||||
bool CDImageBin::Open(const char* filename, Common::Error* error)
|
||||
bool CDImageBin::Open(const char* filename, Error* error)
|
||||
{
|
||||
m_filename = filename;
|
||||
m_fp = FileSystem::OpenCFile(filename, "rb");
|
||||
|
@ -136,7 +136,7 @@ bool CDImageBin::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_i
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<CDImage> CDImage::OpenBinImage(const char* filename, Common::Error* error)
|
||||
std::unique_ptr<CDImage> CDImage::OpenBinImage(const char* filename, Error* error)
|
||||
{
|
||||
std::unique_ptr<CDImageBin> image = std::make_unique<CDImageBin>();
|
||||
if (!image->Open(filename, error))
|
||||
|
|
|
@ -59,7 +59,7 @@ public:
|
|||
CDImageCHD();
|
||||
~CDImageCHD() override;
|
||||
|
||||
bool Open(const char* filename, Common::Error* error);
|
||||
bool Open(const char* filename, Error* error);
|
||||
|
||||
bool ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index) override;
|
||||
bool HasNonStandardSubchannel() const override;
|
||||
|
@ -77,7 +77,7 @@ private:
|
|||
MAX_PARENTS = 32 // Surely someone wouldn't be insane enough to go beyond this...
|
||||
};
|
||||
|
||||
chd_file* OpenCHD(const char* filename, FileSystem::ManagedCFilePtr fp, Common::Error* error, u32 recursion_level);
|
||||
chd_file* OpenCHD(const char* filename, FileSystem::ManagedCFilePtr fp, Error* error, u32 recursion_level);
|
||||
bool ReadHunk(u32 hunk_index);
|
||||
|
||||
chd_file* m_chd = nullptr;
|
||||
|
@ -100,8 +100,7 @@ CDImageCHD::~CDImageCHD()
|
|||
chd_close(m_chd);
|
||||
}
|
||||
|
||||
chd_file* CDImageCHD::OpenCHD(const char* filename, FileSystem::ManagedCFilePtr fp, Common::Error* error,
|
||||
u32 recursion_level)
|
||||
chd_file* CDImageCHD::OpenCHD(const char* filename, FileSystem::ManagedCFilePtr fp, Error* error, u32 recursion_level)
|
||||
{
|
||||
chd_file* chd;
|
||||
chd_error err = chd_open_file(fp.get(), CHD_OPEN_READ | CHD_OPEN_TRANSFER_FILE, nullptr, &chd);
|
||||
|
@ -114,16 +113,14 @@ chd_file* CDImageCHD::OpenCHD(const char* filename, FileSystem::ManagedCFilePtr
|
|||
else if (err != CHDERR_REQUIRES_PARENT)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to open CHD '%s': %s", filename, chd_error_string(err));
|
||||
if (error)
|
||||
error->SetMessage(chd_error_string(err));
|
||||
Error::SetString(error, chd_error_string(err));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (recursion_level >= MAX_PARENTS)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to open CHD '%s': Too many parent files", filename);
|
||||
if (error)
|
||||
error->SetMessage("Too many parent files");
|
||||
Error::SetString(error, "Too many parent files");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -133,8 +130,7 @@ chd_file* CDImageCHD::OpenCHD(const char* filename, FileSystem::ManagedCFilePtr
|
|||
if (err != CHDERR_NONE)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to read CHD header '%s': %s", filename, chd_error_string(err));
|
||||
if (error)
|
||||
error->SetMessage(chd_error_string(err));
|
||||
Error::SetString(error, chd_error_string(err));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -163,15 +159,16 @@ chd_file* CDImageCHD::OpenCHD(const char* filename, FileSystem::ManagedCFilePtr
|
|||
// Match! Open this one.
|
||||
if ((parent_chd = OpenCHD(fd.FileName.c_str(), std::move(parent_fp), error, recursion_level + 1)) != nullptr)
|
||||
{
|
||||
Log_DevPrintf(fmt::format("Found parent CHD '{}' for '{}'.", Path::GetFileName(fd.FileName), Path::GetFileName(filename)).c_str());
|
||||
Log_DevPrintf(
|
||||
fmt::format("Found parent CHD '{}' for '{}'.", Path::GetFileName(fd.FileName), Path::GetFileName(filename))
|
||||
.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!parent_chd)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to open CHD '%s': Failed to find parent CHD, it must be in the same directory.", filename);
|
||||
if (error)
|
||||
error->SetMessage("Failed to find parent CHD, it must be in the same directory.");
|
||||
Error::SetString(error, "Failed to find parent CHD, it must be in the same directory.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -180,8 +177,7 @@ chd_file* CDImageCHD::OpenCHD(const char* filename, FileSystem::ManagedCFilePtr
|
|||
if (err != CHDERR_NONE)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to open CHD '%s': %s", filename, chd_error_string(err));
|
||||
if (error)
|
||||
error->SetMessage(chd_error_string(err));
|
||||
Error::SetString(error, chd_error_string(err));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -190,7 +186,7 @@ chd_file* CDImageCHD::OpenCHD(const char* filename, FileSystem::ManagedCFilePtr
|
|||
return chd;
|
||||
}
|
||||
|
||||
bool CDImageCHD::Open(const char* filename, Common::Error* error)
|
||||
bool CDImageCHD::Open(const char* filename, Error* error)
|
||||
{
|
||||
auto fp = FileSystem::OpenManagedSharedCFile(filename, "rb", FileSystem::FileShareMode::DenyWrite);
|
||||
if (!fp)
|
||||
|
@ -211,9 +207,8 @@ bool CDImageCHD::Open(const char* filename, Common::Error* error)
|
|||
if ((m_hunk_size % CHD_CD_SECTOR_DATA_SIZE) != 0)
|
||||
{
|
||||
Log_ErrorPrintf("Hunk size (%u) is not a multiple of %u", m_hunk_size, CHD_CD_SECTOR_DATA_SIZE);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Hunk size (%u) is not a multiple of %u", m_hunk_size, CHD_CD_SECTOR_DATA_SIZE);
|
||||
|
||||
Error::SetString(error, fmt::format("Hunk size ({}) is not a multiple of {}", m_hunk_size,
|
||||
static_cast<u32>(CHD_CD_SECTOR_DATA_SIZE)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -244,9 +239,7 @@ bool CDImageCHD::Open(const char* filename, Common::Error* error)
|
|||
&pregap_frames, pgtype_str, pgsub_str, &postgap_frames) != 8)
|
||||
{
|
||||
Log_ErrorPrintf("Invalid track v2 metadata: '%s'", metadata_str);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Invalid track v2 metadata: '%s'", metadata_str);
|
||||
|
||||
Error::SetString(error, fmt::format("Invalid track v2 metadata: '{}'", metadata_str));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -264,9 +257,7 @@ bool CDImageCHD::Open(const char* filename, Common::Error* error)
|
|||
if (std::sscanf(metadata_str, CDROM_TRACK_METADATA_FORMAT, &track_num, type_str, subtype_str, &frames) != 4)
|
||||
{
|
||||
Log_ErrorPrintf("Invalid track metadata: '%s'", metadata_str);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Invalid track v2 metadata: '%s'", metadata_str);
|
||||
|
||||
Error::SetString(error, fmt::format("Invalid track v2 metadata: '{}'", metadata_str));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -275,12 +266,8 @@ bool CDImageCHD::Open(const char* filename, Common::Error* error)
|
|||
{
|
||||
Log_ErrorPrintf("Incorrect track number at index %d, expected %d got %d", num_tracks, (num_tracks + 1),
|
||||
track_num);
|
||||
if (error)
|
||||
{
|
||||
error->SetFormattedMessage("Incorrect track number at index %d, expected %d got %d", num_tracks,
|
||||
(num_tracks + 1), track_num);
|
||||
}
|
||||
|
||||
Error::SetString(error, fmt::format("Incorrect track number at index {}, expected {} got {}", num_tracks,
|
||||
(num_tracks + 1), track_num));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -288,9 +275,7 @@ bool CDImageCHD::Open(const char* filename, Common::Error* error)
|
|||
if (!mode.has_value())
|
||||
{
|
||||
Log_ErrorPrintf("Invalid track mode: '%s'", type_str);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Invalid track mode: '%s'", type_str);
|
||||
|
||||
Error::SetString(error, fmt::format("Invalid track mode: '{}'", type_str));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -321,9 +306,7 @@ bool CDImageCHD::Open(const char* filename, Common::Error* error)
|
|||
if (pregap_frames > frames)
|
||||
{
|
||||
Log_ErrorPrintf("Pregap length %u exceeds track length %u", pregap_frames, frames);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Pregap length %u exceeds track length %u", pregap_frames, frames);
|
||||
|
||||
Error::SetString(error, fmt::format("Pregap length {} exceeds track length {}", pregap_frames, frames));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -368,9 +351,7 @@ bool CDImageCHD::Open(const char* filename, Common::Error* error)
|
|||
if (m_tracks.empty())
|
||||
{
|
||||
Log_ErrorPrintf("File '%s' contains no tracks", filename);
|
||||
if (error)
|
||||
error->SetFormattedMessage("File '%s' contains no tracks", filename);
|
||||
|
||||
Error::SetString(error, fmt::format("File '{}' contains no tracks", filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -497,7 +478,7 @@ bool CDImageCHD::ReadHunk(u32 hunk_index)
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<CDImage> CDImage::OpenCHDImage(const char* filename, Common::Error* error)
|
||||
std::unique_ptr<CDImage> CDImage::OpenCHDImage(const char* filename, Error* error)
|
||||
{
|
||||
std::unique_ptr<CDImageCHD> image = std::make_unique<CDImageCHD>();
|
||||
if (!image->Open(filename, error))
|
||||
|
|
|
@ -3,16 +3,21 @@
|
|||
|
||||
#include "cd_image.h"
|
||||
#include "cd_subchannel_replacement.h"
|
||||
#include "cue_parser.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/error.h"
|
||||
#include "common/file_system.h"
|
||||
#include "common/log.h"
|
||||
#include "common/path.h"
|
||||
#include "cue_parser.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <cinttypes>
|
||||
#include <map>
|
||||
|
||||
Log_SetChannel(CDImageCueSheet);
|
||||
|
||||
class CDImageCueSheet : public CDImage
|
||||
|
@ -21,7 +26,7 @@ public:
|
|||
CDImageCueSheet();
|
||||
~CDImageCueSheet() override;
|
||||
|
||||
bool OpenAndParse(const char* filename, Common::Error* error);
|
||||
bool OpenAndParse(const char* filename, Error* error);
|
||||
|
||||
bool ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index) override;
|
||||
bool HasNonStandardSubchannel() const override;
|
||||
|
@ -48,7 +53,7 @@ CDImageCueSheet::~CDImageCueSheet()
|
|||
std::for_each(m_files.begin(), m_files.end(), [](TrackFile& t) { std::fclose(t.file); });
|
||||
}
|
||||
|
||||
bool CDImageCueSheet::OpenAndParse(const char* filename, Common::Error* error)
|
||||
bool CDImageCueSheet::OpenAndParse(const char* filename, Error* error)
|
||||
{
|
||||
std::FILE* fp = FileSystem::OpenCFile(filename, "rb");
|
||||
if (!fp)
|
||||
|
@ -94,7 +99,8 @@ bool CDImageCueSheet::OpenAndParse(const char* filename, Common::Error* error)
|
|||
{
|
||||
const std::string track_full_filename(
|
||||
!Path::IsAbsolute(track_filename) ? Path::BuildRelativePath(m_filename, track_filename) : track_filename);
|
||||
std::FILE* track_fp = FileSystem::OpenCFile(track_full_filename.c_str(), "rb");
|
||||
Error track_error;
|
||||
std::FILE* track_fp = FileSystem::OpenCFile(track_full_filename.c_str(), "rb", &track_error);
|
||||
if (!track_fp && track_file_index == 0)
|
||||
{
|
||||
// many users have bad cuesheets, or they're renamed the files without updating the cuesheet.
|
||||
|
@ -110,14 +116,11 @@ bool CDImageCueSheet::OpenAndParse(const char* filename, Common::Error* error)
|
|||
|
||||
if (!track_fp)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to open track filename '%s' (from '%s' and '%s'): errno %d",
|
||||
track_full_filename.c_str(), track_filename.c_str(), filename, errno);
|
||||
if (error)
|
||||
{
|
||||
error->SetFormattedMessage("Failed to open track filename '%s' (from '%s' and '%s'): errno %d",
|
||||
track_full_filename.c_str(), track_filename.c_str(), filename, errno);
|
||||
}
|
||||
|
||||
Log_ErrorPrintf("Failed to open track filename '%s' (from '%s' and '%s'): %s", track_full_filename.c_str(),
|
||||
track_filename.c_str(), filename, track_error.GetDescription().c_str());
|
||||
Error::SetString(error,
|
||||
fmt::format("Failed to open track filename '{}' (from '{}' and '{}'): {}", track_full_filename,
|
||||
track_filename, filename, track_error.GetDescription()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -148,11 +151,8 @@ bool CDImageCueSheet::OpenAndParse(const char* filename, Common::Error* error)
|
|||
{
|
||||
Log_ErrorPrintf("Failed to open track %u in '%s': track start is out of range (%u vs %" PRIu64 ")", track_num,
|
||||
filename, track_start, file_size);
|
||||
if (error)
|
||||
{
|
||||
error->SetFormattedMessage("Failed to open track %u in '%s': track start is out of range (%u vs %" PRIu64 ")",
|
||||
track_num, filename, track_start, file_size);
|
||||
}
|
||||
Error::SetString(error, fmt::format("Failed to open track {} in '{}': track start is out of range ({} vs {}))",
|
||||
track_num, filename, track_start, file_size));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -283,8 +283,7 @@ bool CDImageCueSheet::OpenAndParse(const char* filename, Common::Error* error)
|
|||
if (m_tracks.empty())
|
||||
{
|
||||
Log_ErrorPrintf("File '%s' contains no tracks", filename);
|
||||
if (error)
|
||||
error->SetFormattedMessage("File '%s' contains no tracks", filename);
|
||||
Error::SetString(error, fmt::format("File '{}' contains no tracks", filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -333,7 +332,7 @@ bool CDImageCueSheet::ReadSectorFromIndex(void* buffer, const Index& index, LBA
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<CDImage> CDImage::OpenCueSheetImage(const char* filename, Common::Error* error)
|
||||
std::unique_ptr<CDImage> CDImage::OpenCueSheetImage(const char* filename, Error* error)
|
||||
{
|
||||
std::unique_ptr<CDImageCueSheet> image = std::make_unique<CDImageCueSheet>();
|
||||
if (!image->OpenAndParse(filename, error))
|
||||
|
|
|
@ -72,7 +72,7 @@ public:
|
|||
CDImageDeviceWin32();
|
||||
~CDImageDeviceWin32() override;
|
||||
|
||||
bool Open(const char* filename, Common::Error* error);
|
||||
bool Open(const char* filename, Error* error);
|
||||
|
||||
bool ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index) override;
|
||||
bool HasNonStandardSubchannel() const override;
|
||||
|
@ -112,7 +112,7 @@ CDImageDeviceWin32::~CDImageDeviceWin32()
|
|||
CloseHandle(m_hDevice);
|
||||
}
|
||||
|
||||
bool CDImageDeviceWin32::Open(const char* filename, Common::Error* error)
|
||||
bool CDImageDeviceWin32::Open(const char* filename, Error* error)
|
||||
{
|
||||
m_filename = filename;
|
||||
m_hDevice = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
|
||||
|
@ -244,8 +244,7 @@ bool CDImageDeviceWin32::Open(const char* filename, Common::Error* error)
|
|||
if (m_tracks.empty())
|
||||
{
|
||||
Log_ErrorPrintf("File '%s' contains no tracks", filename);
|
||||
if (error)
|
||||
error->SetFormattedMessage("File '%s' contains no tracks", filename);
|
||||
Error::SetString(error, fmt::format("File '{}' contains no tracks", filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -270,9 +269,7 @@ bool CDImageDeviceWin32::Open(const char* filename, Common::Error* error)
|
|||
if (!DetermineReadMode())
|
||||
{
|
||||
Log_ErrorPrintf("Could not determine read mode");
|
||||
if (error)
|
||||
error->SetMessage("Could not determine read mode");
|
||||
|
||||
Error::SetString(error, "Could not determine read mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -476,7 +473,7 @@ bool CDImageDeviceWin32::DetermineReadMode()
|
|||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<CDImage> CDImage::OpenDeviceImage(const char* filename, Common::Error* error)
|
||||
std::unique_ptr<CDImage> CDImage::OpenDeviceImage(const char* filename, Error* error)
|
||||
{
|
||||
std::unique_ptr<CDImageDeviceWin32> image = std::make_unique<CDImageDeviceWin32>();
|
||||
if (!image->Open(filename, error))
|
||||
|
@ -528,7 +525,7 @@ bool CDImage::IsDeviceName(const char* filename)
|
|||
|
||||
#else
|
||||
|
||||
std::unique_ptr<CDImage> CDImage::OpenDeviceImage(const char* filename, Common::Error* error)
|
||||
std::unique_ptr<CDImage> CDImage::OpenDeviceImage(const char* filename, Error* error)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ public:
|
|||
CDImageEcm();
|
||||
~CDImageEcm() override;
|
||||
|
||||
bool Open(const char* filename, Common::Error* error);
|
||||
bool Open(const char* filename, Error* error);
|
||||
|
||||
bool ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index) override;
|
||||
bool HasNonStandardSubchannel() const override;
|
||||
|
@ -224,7 +224,7 @@ CDImageEcm::~CDImageEcm()
|
|||
std::fclose(m_fp);
|
||||
}
|
||||
|
||||
bool CDImageEcm::Open(const char* filename, Common::Error* error)
|
||||
bool CDImageEcm::Open(const char* filename, Error* error)
|
||||
{
|
||||
m_filename = filename;
|
||||
m_fp = FileSystem::OpenCFile(filename, "rb");
|
||||
|
@ -253,9 +253,7 @@ bool CDImageEcm::Open(const char* filename, Common::Error* error)
|
|||
header[3] != 0)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to read/invalid header");
|
||||
if (error)
|
||||
error->SetMessage("Failed to read/invalid header");
|
||||
|
||||
Error::SetString(error, "Failed to read/invalid header");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -269,9 +267,7 @@ bool CDImageEcm::Open(const char* filename, Common::Error* error)
|
|||
if (bits == EOF)
|
||||
{
|
||||
Log_ErrorPrintf("Unexpected EOF after %zu chunks", m_data_map.size());
|
||||
if (error)
|
||||
error->SetFormattedMessage("Unexpected EOF after %zu chunks", m_data_map.size());
|
||||
|
||||
Error::SetString(error, fmt::format("Unexpected EOF after {} chunks", m_data_map.size()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -285,9 +281,7 @@ bool CDImageEcm::Open(const char* filename, Common::Error* error)
|
|||
if (bits == EOF)
|
||||
{
|
||||
Log_ErrorPrintf("Unexpected EOF after %zu chunks", m_data_map.size());
|
||||
if (error)
|
||||
error->SetFormattedMessage("Unexpected EOF after %zu chunks", m_data_map.size());
|
||||
|
||||
Error::SetString(error, fmt::format("Unexpected EOF after {} chunks", m_data_map.size()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -305,9 +299,7 @@ bool CDImageEcm::Open(const char* filename, Common::Error* error)
|
|||
if (count >= 0x80000000u)
|
||||
{
|
||||
Log_ErrorPrintf("Corrupted header after %zu chunks", m_data_map.size());
|
||||
if (error)
|
||||
error->SetFormattedMessage("Corrupted header after %zu chunks", m_data_map.size());
|
||||
|
||||
Error::SetString(error, fmt::format("Corrupted header after {} chunks", m_data_map.size()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -324,8 +316,7 @@ bool CDImageEcm::Open(const char* filename, Common::Error* error)
|
|||
if (static_cast<s64>(file_offset) > file_size)
|
||||
{
|
||||
Log_ErrorPrintf("Out of file bounds after %zu chunks", m_data_map.size());
|
||||
if (error)
|
||||
error->SetFormattedMessage("Out of file bounds after %zu chunks", m_data_map.size());
|
||||
Error::SetString(error, fmt::format("Out of file bounds after {} chunks", m_data_map.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -342,8 +333,7 @@ bool CDImageEcm::Open(const char* filename, Common::Error* error)
|
|||
if (static_cast<s64>(file_offset) > file_size)
|
||||
{
|
||||
Log_ErrorPrintf("Out of file bounds after %zu chunks", m_data_map.size());
|
||||
if (error)
|
||||
error->SetFormattedMessage("Out of file bounds after %zu chunks", m_data_map.size());
|
||||
Error::SetString(error, fmt::format("Out of file bounds after {} chunks", m_data_map.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -351,9 +341,7 @@ bool CDImageEcm::Open(const char* filename, Common::Error* error)
|
|||
if (std::fseek(m_fp, file_offset, SEEK_SET) != 0)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to seek to offset %u after %zu chunks", file_offset, m_data_map.size());
|
||||
if (error)
|
||||
error->SetFormattedMessage("Failed to seek to offset %u after %zu chunks", file_offset, m_data_map.size());
|
||||
|
||||
Error::SetString(error, fmt::format("Failed to seek to offset {} after {} chunks", file_offset, m_data_map.size()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -361,9 +349,7 @@ bool CDImageEcm::Open(const char* filename, Common::Error* error)
|
|||
if (m_data_map.empty())
|
||||
{
|
||||
Log_ErrorPrintf("No data in image '%s'", filename);
|
||||
if (error)
|
||||
error->SetFormattedMessage("No data in image '%s'", filename);
|
||||
|
||||
Error::SetString(error, fmt::format("No data in image '{}'", filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -549,7 +535,7 @@ bool CDImageEcm::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_i
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<CDImage> CDImage::OpenEcmImage(const char* filename, Common::Error* error)
|
||||
std::unique_ptr<CDImage> CDImage::OpenEcmImage(const char* filename, Error* error)
|
||||
{
|
||||
std::unique_ptr<CDImageEcm> image = std::make_unique<CDImageEcm>();
|
||||
if (!image->Open(filename, error))
|
||||
|
|
|
@ -20,7 +20,7 @@ public:
|
|||
CDImageM3u();
|
||||
~CDImageM3u() override;
|
||||
|
||||
bool Open(const char* path, bool apply_patches, Common::Error* Error);
|
||||
bool Open(const char* path, bool apply_patches, Error* Error);
|
||||
|
||||
bool ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index) override;
|
||||
bool HasNonStandardSubchannel() const override;
|
||||
|
@ -29,7 +29,7 @@ public:
|
|||
u32 GetSubImageCount() const override;
|
||||
u32 GetCurrentSubImage() const override;
|
||||
std::string GetSubImageMetadata(u32 index, const std::string_view& type) const override;
|
||||
bool SwitchSubImage(u32 index, Common::Error* error) override;
|
||||
bool SwitchSubImage(u32 index, Error* error) override;
|
||||
|
||||
protected:
|
||||
bool ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_in_index) override;
|
||||
|
@ -52,7 +52,7 @@ CDImageM3u::CDImageM3u() = default;
|
|||
|
||||
CDImageM3u::~CDImageM3u() = default;
|
||||
|
||||
bool CDImageM3u::Open(const char* path, bool apply_patches, Common::Error* error)
|
||||
bool CDImageM3u::Open(const char* path, bool apply_patches, Error* error)
|
||||
{
|
||||
std::FILE* fp = FileSystem::OpenCFile(path, "rb");
|
||||
if (!fp)
|
||||
|
@ -62,8 +62,7 @@ bool CDImageM3u::Open(const char* path, bool apply_patches, Common::Error* error
|
|||
std::fclose(fp);
|
||||
if (!m3u_file.has_value() || m3u_file->empty())
|
||||
{
|
||||
if (error)
|
||||
error->SetMessage("Failed to read M3u file");
|
||||
Error::SetString(error, "Failed to read M3u file");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -128,7 +127,7 @@ u32 CDImageM3u::GetCurrentSubImage() const
|
|||
return m_current_image_index;
|
||||
}
|
||||
|
||||
bool CDImageM3u::SwitchSubImage(u32 index, Common::Error* error)
|
||||
bool CDImageM3u::SwitchSubImage(u32 index, Error* error)
|
||||
{
|
||||
if (index >= m_entries.size())
|
||||
return false;
|
||||
|
@ -175,7 +174,7 @@ bool CDImageM3u::ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_
|
|||
return m_current_image->ReadSubChannelQ(subq, index, lba_in_index);
|
||||
}
|
||||
|
||||
std::unique_ptr<CDImage> CDImage::OpenM3uImage(const char* filename, bool apply_patches, Common::Error* error)
|
||||
std::unique_ptr<CDImage> CDImage::OpenM3uImage(const char* filename, bool apply_patches, Error* error)
|
||||
{
|
||||
std::unique_ptr<CDImageM3u> image = std::make_unique<CDImageM3u>();
|
||||
if (!image->Open(filename, apply_patches, error))
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
CDImageMds();
|
||||
~CDImageMds() override;
|
||||
|
||||
bool OpenAndParse(const char* filename, Common::Error* error);
|
||||
bool OpenAndParse(const char* filename, Error* error);
|
||||
|
||||
bool ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index) override;
|
||||
bool HasNonStandardSubchannel() const override;
|
||||
|
@ -61,15 +61,12 @@ CDImageMds::~CDImageMds()
|
|||
std::fclose(m_mdf_file);
|
||||
}
|
||||
|
||||
bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error)
|
||||
bool CDImageMds::OpenAndParse(const char* filename, Error* error)
|
||||
{
|
||||
std::FILE* mds_fp = FileSystem::OpenCFile(filename, "rb");
|
||||
std::FILE* mds_fp = FileSystem::OpenCFile(filename, "rb", error);
|
||||
if (!mds_fp)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to open mds '%s': errno %d", filename, errno);
|
||||
if (error)
|
||||
error->SetErrno(errno);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -78,20 +75,15 @@ bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error)
|
|||
if (!mds_data_opt.has_value() || mds_data_opt->size() < 0x54)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to read mds file '%s'", filename);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Failed to read mds file '%s'", filename);
|
||||
|
||||
Error::SetString(error, fmt::format("Failed to read mds file '{}'", filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string mdf_filename(Path::ReplaceExtension(filename, "mdf"));
|
||||
m_mdf_file = FileSystem::OpenCFile(mdf_filename.c_str(), "rb");
|
||||
m_mdf_file = FileSystem::OpenCFile(mdf_filename.c_str(), "rb", error);
|
||||
if (!m_mdf_file)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to open mdf file '%s': errno %d", mdf_filename.c_str(), errno);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Failed to open mdf file '%s': errno %d", mdf_filename.c_str(), errno);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -100,9 +92,7 @@ bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error)
|
|||
if (std::memcmp(&mds[0], expected_signature, sizeof(expected_signature) - 1) != 0)
|
||||
{
|
||||
Log_ErrorPrintf("Incorrect signature in '%s'", filename);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Incorrect signature in '%s'", filename);
|
||||
|
||||
Error::SetString(error, fmt::format("Incorrect signature in '{}'", filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -111,9 +101,7 @@ bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error)
|
|||
if ((session_offset + 24) > mds.size())
|
||||
{
|
||||
Log_ErrorPrintf("Invalid session offset in '%s'", filename);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Invalid session offset in '%s'", filename);
|
||||
|
||||
Error::SetString(error, fmt::format("Invalid session offset in '{}'", filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -124,9 +112,7 @@ bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error)
|
|||
if (track_count > 99 || track_offset >= mds.size())
|
||||
{
|
||||
Log_ErrorPrintf("Invalid track count/block offset %u/%u in '%s'", track_count, track_offset, filename);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Invalid track count/block offset %u/%u in '%s'", track_count, track_offset, filename);
|
||||
|
||||
Error::SetString(error, fmt::format("Invalid track count/block offset {}/{} in '{}'", track_count, track_offset, filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -145,9 +131,7 @@ bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error)
|
|||
if ((track_offset + sizeof(TrackEntry)) > mds.size())
|
||||
{
|
||||
Log_ErrorPrintf("End of file in '%s' at track %u", filename, track_number);
|
||||
if (error)
|
||||
error->SetFormattedMessage("End of file in '%s' at track %u", filename, track_number);
|
||||
|
||||
Error::SetString(error, fmt::format("End of file in '{}' at track {}", filename, track_number));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -158,9 +142,7 @@ bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error)
|
|||
if (PackedBCDToBinary(track.track_number) != track_number)
|
||||
{
|
||||
Log_ErrorPrintf("Unexpected track number 0x%02X in track %u", track.track_number, track_number);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Unexpected track number 0x%02X in track %u", track.track_number, track_number);
|
||||
|
||||
Error::SetString(error, fmt::format("Unexpected track number 0x{:02X} in track {}", track.track_number, track_number));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -171,9 +153,7 @@ bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error)
|
|||
if ((track.extra_offset + sizeof(u32) + sizeof(u32)) > mds.size())
|
||||
{
|
||||
Log_ErrorPrintf("Invalid extra offset %u in track %u", track.extra_offset, track_number);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Invalid extra offset %u in track %u", track.extra_offset, track_number);
|
||||
|
||||
Error::SetString(error, fmt::format("Invalid extra offset {} in track {}", track.extra_offset, track_number));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -196,9 +176,7 @@ bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error)
|
|||
if (track_pregap > track_start_lba)
|
||||
{
|
||||
Log_ErrorPrintf("Track pregap %u is too large for start lba %u", track_pregap, track_start_lba);
|
||||
if (error)
|
||||
error->SetFormattedMessage("Track pregap %u is too large for start lba %u", track_pregap, track_start_lba);
|
||||
|
||||
Error::SetString(error, fmt::format("Track pregap {} is too large for start lba {}", track_pregap, track_start_lba));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -247,9 +225,7 @@ bool CDImageMds::OpenAndParse(const char* filename, Common::Error* error)
|
|||
if (m_tracks.empty())
|
||||
{
|
||||
Log_ErrorPrintf("File '%s' contains no tracks", filename);
|
||||
if (error)
|
||||
error->SetFormattedMessage("File '%s' contains no tracks", filename);
|
||||
|
||||
Error::SetString(error, fmt::format("File '{}' contains no tracks", filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -297,7 +273,7 @@ bool CDImageMds::ReadSectorFromIndex(void* buffer, const Index& index, LBA lba_i
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<CDImage> CDImage::OpenMdsImage(const char* filename, Common::Error* error)
|
||||
std::unique_ptr<CDImage> CDImage::OpenMdsImage(const char* filename, Error* error)
|
||||
{
|
||||
std::unique_ptr<CDImageMds> image = std::make_unique<CDImageMds>();
|
||||
if (!image->OpenAndParse(filename, error))
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
CDImagePBP() = default;
|
||||
~CDImagePBP() override;
|
||||
|
||||
bool Open(const char* filename, Common::Error* error);
|
||||
bool Open(const char* filename, Error* error);
|
||||
|
||||
bool ReadSubChannelQ(SubChannelQ* subq, const Index& index, LBA lba_in_index) override;
|
||||
bool HasNonStandardSubchannel() const override;
|
||||
|
@ -35,7 +35,7 @@ public:
|
|||
bool HasSubImages() const override;
|
||||
u32 GetSubImageCount() const override;
|
||||
u32 GetCurrentSubImage() const override;
|
||||
bool SwitchSubImage(u32 index, Common::Error* error) override;
|
||||
bool SwitchSubImage(u32 index, Error* error) override;
|
||||
std::string GetMetadata(const std::string_view& type) const override;
|
||||
std::string GetSubImageMetadata(u32 index, const std::string_view& type) const override;
|
||||
|
||||
|
@ -61,12 +61,12 @@ private:
|
|||
bool LoadSFOIndexTable();
|
||||
bool LoadSFOTable();
|
||||
|
||||
bool IsValidEboot(Common::Error* error);
|
||||
bool IsValidEboot(Error* error);
|
||||
|
||||
bool InitDecompressionStream();
|
||||
bool DecompressBlock(const BlockInfo& block_info);
|
||||
|
||||
bool OpenDisc(u32 index, Common::Error* error);
|
||||
bool OpenDisc(u32 index, Error* error);
|
||||
|
||||
static const std::string* LookupStringSFOTableEntry(const char* key, const SFOTable& table);
|
||||
|
||||
|
@ -277,7 +277,7 @@ bool CDImagePBP::LoadSFOTable()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CDImagePBP::IsValidEboot(Common::Error* error)
|
||||
bool CDImagePBP::IsValidEboot(Error* error)
|
||||
{
|
||||
// Check some fields to make sure this is a valid PS1 EBOOT.PBP
|
||||
|
||||
|
@ -288,16 +288,14 @@ bool CDImagePBP::IsValidEboot(Common::Error* error)
|
|||
if (!std::holds_alternative<u32>(data_value) || std::get<u32>(data_value) != 1)
|
||||
{
|
||||
Log_ErrorPrint("Invalid BOOTABLE value");
|
||||
if (error)
|
||||
error->SetMessage("Invalid BOOTABLE value");
|
||||
Error::SetString(error, "Invalid BOOTABLE value");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorPrint("No BOOTABLE value found");
|
||||
if (error)
|
||||
error->SetMessage("No BOOTABLE value found");
|
||||
Error::SetString(error, "No BOOTABLE value found");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -308,23 +306,21 @@ bool CDImagePBP::IsValidEboot(Common::Error* error)
|
|||
if (!std::holds_alternative<std::string>(data_value) || std::get<std::string>(data_value) != "ME")
|
||||
{
|
||||
Log_ErrorPrint("Invalid CATEGORY value");
|
||||
if (error)
|
||||
error->SetMessage("Invalid CATEGORY value");
|
||||
Error::SetString(error, "Invalid CATEGORY value");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log_ErrorPrint("No CATEGORY value found");
|
||||
if (error)
|
||||
error->SetMessage("No CATEGORY value found");
|
||||
Error::SetString(error, "No CATEGORY value found");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDImagePBP::Open(const char* filename, Common::Error* error)
|
||||
bool CDImagePBP::Open(const char* filename, Error* error)
|
||||
{
|
||||
if (!EndianHelper::HostIsLittleEndian())
|
||||
{
|
||||
|
@ -347,8 +343,7 @@ bool CDImagePBP::Open(const char* filename, Common::Error* error)
|
|||
if (!LoadPBPHeader())
|
||||
{
|
||||
Log_ErrorPrint("Failed to load PBP header");
|
||||
if (error)
|
||||
error->SetMessage("Failed to load PBP header");
|
||||
Error::SetString(error, "Failed to load PBP header");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -356,8 +351,7 @@ bool CDImagePBP::Open(const char* filename, Common::Error* error)
|
|||
if (!LoadSFOHeader())
|
||||
{
|
||||
Log_ErrorPrint("Failed to load SFO header");
|
||||
if (error)
|
||||
error->SetMessage("Failed to load SFO header");
|
||||
Error::SetString(error, "Failed to load SFO header");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -365,8 +359,7 @@ bool CDImagePBP::Open(const char* filename, Common::Error* error)
|
|||
if (!LoadSFOIndexTable())
|
||||
{
|
||||
Log_ErrorPrint("Failed to load SFO index table");
|
||||
if (error)
|
||||
error->SetMessage("Failed to load SFO index table");
|
||||
Error::SetString(error, "Failed to load SFO index table");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -374,8 +367,7 @@ bool CDImagePBP::Open(const char* filename, Common::Error* error)
|
|||
if (!LoadSFOTable())
|
||||
{
|
||||
Log_ErrorPrint("Failed to load SFO table");
|
||||
if (error)
|
||||
error->SetMessage("Failed to load SFO table");
|
||||
Error::SetString(error, "Failed to load SFO table");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -412,9 +404,7 @@ bool CDImagePBP::Open(const char* filename, Common::Error* error)
|
|||
if (disc_table[0] == 0x44475000) // "\0PGD"
|
||||
{
|
||||
Log_ErrorPrintf("Encrypted PBP images are not supported, skipping %s", m_filename.c_str());
|
||||
if (error)
|
||||
error->SetMessage("Encrypted PBP images are not supported");
|
||||
|
||||
Error::SetString(error, "Encrypted PBP images are not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -442,13 +432,12 @@ bool CDImagePBP::Open(const char* filename, Common::Error* error)
|
|||
return OpenDisc(0, error);
|
||||
}
|
||||
|
||||
bool CDImagePBP::OpenDisc(u32 index, Common::Error* error)
|
||||
bool CDImagePBP::OpenDisc(u32 index, Error* error)
|
||||
{
|
||||
if (index >= m_disc_offsets.size())
|
||||
{
|
||||
Log_ErrorPrintf("File does not contain disc %u", index + 1);
|
||||
if (error)
|
||||
error->SetMessage(TinyString::FromFormat("File does not contain disc %u", index + 1));
|
||||
Error::SetString(error, fmt::format("File does not contain disc {}", index + 1));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -484,9 +473,7 @@ bool CDImagePBP::OpenDisc(u32 index, Common::Error* error)
|
|||
if (pgd_magic == 0x44475000) // "\0PGD"
|
||||
{
|
||||
Log_ErrorPrintf("Encrypted PBP images are not supported, skipping %s", m_filename.c_str());
|
||||
if (error)
|
||||
error->SetMessage("Encrypted PBP images are not supported");
|
||||
|
||||
Error::SetString(error, "Encrypted PBP images are not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -867,7 +854,7 @@ u32 CDImagePBP::GetCurrentSubImage() const
|
|||
return m_current_disc;
|
||||
}
|
||||
|
||||
bool CDImagePBP::SwitchSubImage(u32 index, Common::Error* error)
|
||||
bool CDImagePBP::SwitchSubImage(u32 index, Error* error)
|
||||
{
|
||||
if (index >= m_disc_offsets.size())
|
||||
return false;
|
||||
|
@ -895,7 +882,7 @@ std::string CDImagePBP::GetSubImageMetadata(u32 index, const std::string_view& t
|
|||
return CDImage::GetSubImageMetadata(index, type);
|
||||
}
|
||||
|
||||
std::unique_ptr<CDImage> CDImage::OpenPBPImage(const char* filename, Common::Error* error)
|
||||
std::unique_ptr<CDImage> CDImage::OpenPBPImage(const char* filename, Error* error)
|
||||
{
|
||||
std::unique_ptr<CDImagePBP> image = std::make_unique<CDImagePBP>();
|
||||
if (!image->Open(filename, error))
|
||||
|
|
|
@ -45,7 +45,7 @@ Track* File::GetMutableTrack(u32 n)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool File::Parse(std::FILE* fp, Common::Error* error)
|
||||
bool File::Parse(std::FILE* fp, Error* error)
|
||||
{
|
||||
char line[1024];
|
||||
u32 line_number = 1;
|
||||
|
@ -66,7 +66,7 @@ bool File::Parse(std::FILE* fp, Common::Error* error)
|
|||
return true;
|
||||
}
|
||||
|
||||
void File::SetError(u32 line_number, Common::Error* error, const char* format, ...)
|
||||
void File::SetError(u32 line_number, Error* error, const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
SmallString str;
|
||||
|
@ -75,9 +75,7 @@ void File::SetError(u32 line_number, Common::Error* error, const char* format, .
|
|||
va_end(ap);
|
||||
|
||||
Log_ErrorPrintf("Cue parse error at line %u: %s", line_number, str.GetCharArray());
|
||||
|
||||
if (error)
|
||||
error->SetFormattedMessage("Cue parse error at line %u: %s", line_number, str.GetCharArray());
|
||||
Error::SetString(error, fmt::format("Cue parse error at line {}: {}", line_number, str));
|
||||
}
|
||||
|
||||
std::string_view File::GetToken(const char*& line)
|
||||
|
@ -166,7 +164,7 @@ std::optional<MSF> File::GetMSF(const std::string_view& token)
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool File::ParseLine(const char* line, u32 line_number, Common::Error* error)
|
||||
bool File::ParseLine(const char* line, u32 line_number, Error* error)
|
||||
{
|
||||
const std::string_view command(GetToken(line));
|
||||
if (command.empty())
|
||||
|
@ -210,7 +208,7 @@ bool File::ParseLine(const char* line, u32 line_number, Common::Error* error)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool File::HandleFileCommand(const char* line, u32 line_number, Common::Error* error)
|
||||
bool File::HandleFileCommand(const char* line, u32 line_number, Error* error)
|
||||
{
|
||||
const std::string_view filename(GetToken(line));
|
||||
const std::string_view mode(GetToken(line));
|
||||
|
@ -232,7 +230,7 @@ bool File::HandleFileCommand(const char* line, u32 line_number, Common::Error* e
|
|||
return true;
|
||||
}
|
||||
|
||||
bool File::HandleTrackCommand(const char* line, u32 line_number, Common::Error* error)
|
||||
bool File::HandleTrackCommand(const char* line, u32 line_number, Error* error)
|
||||
{
|
||||
if (!CompleteLastTrack(line_number, error))
|
||||
return false;
|
||||
|
@ -288,7 +286,7 @@ bool File::HandleTrackCommand(const char* line, u32 line_number, Common::Error*
|
|||
return true;
|
||||
}
|
||||
|
||||
bool File::HandleIndexCommand(const char* line, u32 line_number, Common::Error* error)
|
||||
bool File::HandleIndexCommand(const char* line, u32 line_number, Error* error)
|
||||
{
|
||||
if (!m_current_track.has_value())
|
||||
{
|
||||
|
@ -334,7 +332,7 @@ bool File::HandleIndexCommand(const char* line, u32 line_number, Common::Error*
|
|||
return true;
|
||||
}
|
||||
|
||||
bool File::HandlePregapCommand(const char* line, u32 line_number, Common::Error* error)
|
||||
bool File::HandlePregapCommand(const char* line, u32 line_number, Error* error)
|
||||
{
|
||||
if (!m_current_track.has_value())
|
||||
{
|
||||
|
@ -366,7 +364,7 @@ bool File::HandlePregapCommand(const char* line, u32 line_number, Common::Error*
|
|||
return true;
|
||||
}
|
||||
|
||||
bool File::HandleFlagCommand(const char* line, u32 line_number, Common::Error* error)
|
||||
bool File::HandleFlagCommand(const char* line, u32 line_number, Error* error)
|
||||
{
|
||||
if (!m_current_track.has_value())
|
||||
{
|
||||
|
@ -395,7 +393,7 @@ bool File::HandleFlagCommand(const char* line, u32 line_number, Common::Error* e
|
|||
return true;
|
||||
}
|
||||
|
||||
bool File::CompleteLastTrack(u32 line_number, Common::Error* error)
|
||||
bool File::CompleteLastTrack(u32 line_number, Error* error)
|
||||
{
|
||||
if (!m_current_track.has_value())
|
||||
return true;
|
||||
|
@ -436,7 +434,7 @@ bool File::CompleteLastTrack(u32 line_number, Common::Error* error)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool File::SetTrackLengths(u32 line_number, Common::Error* error)
|
||||
bool File::SetTrackLengths(u32 line_number, Error* error)
|
||||
{
|
||||
for (const Track& track : m_tracks)
|
||||
{
|
||||
|
|
|
@ -60,26 +60,26 @@ public:
|
|||
|
||||
const Track* GetTrack(u32 n) const;
|
||||
|
||||
bool Parse(std::FILE* fp, Common::Error* error);
|
||||
bool Parse(std::FILE* fp, Error* error);
|
||||
|
||||
private:
|
||||
Track* GetMutableTrack(u32 n);
|
||||
|
||||
void SetError(u32 line_number, Common::Error* error, const char* format, ...);
|
||||
void SetError(u32 line_number, Error* error, const char* format, ...);
|
||||
|
||||
static std::string_view GetToken(const char*& line);
|
||||
static std::optional<MSF> GetMSF(const std::string_view& token);
|
||||
|
||||
bool ParseLine(const char* line, u32 line_number, Common::Error* error);
|
||||
bool ParseLine(const char* line, u32 line_number, Error* error);
|
||||
|
||||
bool HandleFileCommand(const char* line, u32 line_number, Common::Error* error);
|
||||
bool HandleTrackCommand(const char* line, u32 line_number, Common::Error* error);
|
||||
bool HandleIndexCommand(const char* line, u32 line_number, Common::Error* error);
|
||||
bool HandlePregapCommand(const char* line, u32 line_number, Common::Error* error);
|
||||
bool HandleFlagCommand(const char* line, u32 line_number, Common::Error* error);
|
||||
bool HandleFileCommand(const char* line, u32 line_number, Error* error);
|
||||
bool HandleTrackCommand(const char* line, u32 line_number, Error* error);
|
||||
bool HandleIndexCommand(const char* line, u32 line_number, Error* error);
|
||||
bool HandlePregapCommand(const char* line, u32 line_number, Error* error);
|
||||
bool HandleFlagCommand(const char* line, u32 line_number, Error* error);
|
||||
|
||||
bool CompleteLastTrack(u32 line_number, Common::Error* error);
|
||||
bool SetTrackLengths(u32 line_number, Common::Error* error);
|
||||
bool CompleteLastTrack(u32 line_number, Error* error);
|
||||
bool SetTrackLengths(u32 line_number, Error* error);
|
||||
|
||||
std::vector<Track> m_tracks;
|
||||
std::optional<std::string> m_current_file;
|
||||
|
|
Loading…
Reference in New Issue