mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +00:00 
			
		
		
		
	Common: Error/FileSystem backports
This commit is contained in:
		
							parent
							
								
									7890051165
								
							
						
					
					
						commit
						39f64a03ee
					
				|  | @ -1,62 +1,120 @@ | |||
| // 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>"); | ||||
|     m_description = fmt::format("errno {}: <Could not get error message>", err); | ||||
| #else | ||||
|   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::SetErrno(Error* errptr, int err) | ||||
| { | ||||
|   if (errptr) | ||||
|     errptr->SetErrno(err); | ||||
| } | ||||
| 
 | ||||
| void Error::SetString(std::string description) | ||||
| { | ||||
|   m_type = Type::User; | ||||
|   m_description = std::move(description); | ||||
| } | ||||
| 
 | ||||
| void Error::SetString(Error* errptr, std::string description) | ||||
| { | ||||
|   if (errptr) | ||||
|     errptr->SetString(std::move(description)); | ||||
| } | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| void Error::SetWin32(unsigned long err) | ||||
| { | ||||
|   m_type = Type::Win32; | ||||
| 
 | ||||
|   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_description = | ||||
|       fmt::format("Win32 Error {}: {}", err, StringUtil::WideStringToUTF8String(std::wstring_view(buf, r))); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     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; | ||||
| 
 | ||||
|   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_description = | ||||
|       fmt::format("HRESULT {:08X}: {}", err, StringUtil::WideStringToUTF8String(std::wstring_view(buf, r))); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     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 | ||||
| 
 | ||||
| void Error::SetSocket(int err) | ||||
| { | ||||
|   // Socket errors are win32 errors on windows
 | ||||
|  | @ -65,118 +123,18 @@ void Error::SetSocket(int err) | |||
| #else | ||||
|   SetErrno(err); | ||||
| #endif | ||||
|   m_type = Type::Socket; | ||||
| } | ||||
| 
 | ||||
| void Error::SetMessage(const char* msg) | ||||
| void Error::SetSocket(Error* errptr, int err) | ||||
| { | ||||
|   m_type = Type::User; | ||||
|   m_error.user = 0; | ||||
|   m_code_string.Clear(); | ||||
|   m_message = msg; | ||||
|   if (errptr) | ||||
|     errptr->SetSocket(err); | ||||
| } | ||||
| 
 | ||||
| void Error::SetUser(int err, const char* msg) | ||||
| { | ||||
|   m_type = Type::User; | ||||
|   m_error.user = err; | ||||
|   m_code_string.Format("%d", err); | ||||
|   m_message = msg; | ||||
| } | ||||
| 
 | ||||
| void Error::SetUser(const char* code, const char* message) | ||||
| { | ||||
|   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); | ||||
| } | ||||
| 
 | ||||
| #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); | ||||
|   if (r > 0) | ||||
|   { | ||||
|     m_message.Resize(r); | ||||
|     m_message.RStrip(); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     m_message = "<Could not resolve system error ID>"; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
|   if (r > 0) | ||||
|   { | ||||
|     m_message.Resize(r); | ||||
|     m_message.RStrip(); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     m_message = "<Could not resolve system error ID>"; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| // constructors
 | ||||
| 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 (m_type != e.m_type || m_description != e.m_description); | ||||
| } | ||||
| 
 | ||||
|   return true; | ||||
| } | ||||
| 
 | ||||
| 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 a new issue
	
	 Stenzek
						Stenzek