duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

error.cpp (5655B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #include "error.h"
      5 #include "string_util.h"
      6 
      7 #include <cstdlib>
      8 #include <cstring>
      9 #include <cwctype>
     10 #include <type_traits>
     11 
     12 #include "fmt/format.h"
     13 
     14 #if defined(_WIN32)
     15 #include "windows_headers.h"
     16 #endif
     17 
     18 Error::Error() = default;
     19 
     20 Error::Error(const Error& c) = default;
     21 
     22 Error::Error(Error&& e) = default;
     23 
     24 Error::~Error() = default;
     25 
     26 void Error::Clear()
     27 {
     28   m_description = {};
     29 }
     30 
     31 void Error::Clear(Error* errptr)
     32 {
     33   if (errptr)
     34     errptr->Clear();
     35 }
     36 
     37 void Error::SetErrno(int err)
     38 {
     39   SetErrno(std::string_view(), err);
     40 }
     41 
     42 void Error::SetErrno(std::string_view prefix, int err)
     43 {
     44   m_type = Type::Errno;
     45 
     46 #ifdef _MSC_VER
     47   char buf[128];
     48   if (strerror_s(buf, sizeof(buf), err) == 0)
     49     m_description = fmt::format("{}errno {}: {}", prefix, err, buf);
     50   else
     51     m_description = fmt::format("{}errno {}: <Could not get error message>", prefix, err);
     52 #else
     53   const char* buf = std::strerror(err);
     54   if (buf)
     55     m_description = fmt::format("{}errno {}: {}", prefix, err, buf);
     56   else
     57     m_description = fmt::format("{}errno {}: <Could not get error message>", prefix, err);
     58 #endif
     59 }
     60 
     61 void Error::SetErrno(Error* errptr, int err)
     62 {
     63   if (errptr)
     64     errptr->SetErrno(err);
     65 }
     66 
     67 void Error::SetErrno(Error* errptr, std::string_view prefix, int err)
     68 {
     69   if (errptr)
     70     errptr->SetErrno(prefix, err);
     71 }
     72 
     73 void Error::SetString(std::string description)
     74 {
     75   m_type = Type::User;
     76   m_description = std::move(description);
     77 }
     78 
     79 void Error::SetStringView(std::string_view description)
     80 {
     81   m_type = Type::User;
     82   m_description = std::string(description);
     83 }
     84 
     85 void Error::SetString(Error* errptr, std::string description)
     86 {
     87   if (errptr)
     88     errptr->SetString(std::move(description));
     89 }
     90 
     91 void Error::SetStringView(Error* errptr, std::string_view description)
     92 {
     93   if (errptr)
     94     errptr->SetStringView(std::move(description));
     95 }
     96 
     97 #ifdef _WIN32
     98 
     99 void Error::SetWin32(unsigned long err)
    100 {
    101   SetWin32(std::string_view(), err);
    102 }
    103 
    104 void Error::SetWin32(std::string_view prefix, unsigned long err)
    105 {
    106   m_type = Type::Win32;
    107 
    108   WCHAR buf[128];
    109   DWORD r = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_USER_DEFAULT, buf,
    110                            static_cast<DWORD>(std::size(buf)), nullptr);
    111   while (r > 0 && std::iswspace(buf[r - 1]))
    112     r--;
    113 
    114   if (r > 0)
    115   {
    116     m_description =
    117       fmt::format("{}Win32 Error {}: {}", prefix, err, StringUtil::WideStringToUTF8String(std::wstring_view(buf, r)));
    118   }
    119   else
    120   {
    121     m_description = fmt::format("{}Win32 Error {}: <Could not resolve system error ID>", prefix, err);
    122   }
    123 }
    124 
    125 void Error::SetWin32(Error* errptr, unsigned long err)
    126 {
    127   if (errptr)
    128     errptr->SetWin32(err);
    129 }
    130 
    131 void Error::SetWin32(Error* errptr, std::string_view prefix, unsigned long err)
    132 {
    133   if (errptr)
    134     errptr->SetWin32(prefix, err);
    135 }
    136 
    137 void Error::SetHResult(long err)
    138 {
    139   SetHResult(std::string_view(), err);
    140 }
    141 
    142 void Error::SetHResult(std::string_view prefix, long err)
    143 {
    144   m_type = Type::HResult;
    145 
    146   WCHAR buf[128];
    147   DWORD r = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, err, LANG_USER_DEFAULT, buf,
    148                            static_cast<DWORD>(std::size(buf)), nullptr);
    149   while (r > 0 && std::iswspace(buf[r - 1]))
    150     r--;
    151 
    152   if (r > 0)
    153   {
    154     m_description = fmt::format("{}HRESULT {:08X}: {}", prefix, static_cast<unsigned>(err),
    155                                 StringUtil::WideStringToUTF8String(std::wstring_view(buf, r)));
    156   }
    157   else
    158   {
    159     m_description = fmt::format("{}HRESULT {:08X}: <Could not resolve system error ID>", prefix, err);
    160   }
    161 }
    162 
    163 void Error::SetHResult(Error* errptr, long err)
    164 {
    165   if (errptr)
    166     errptr->SetHResult(err);
    167 }
    168 
    169 void Error::SetHResult(Error* errptr, std::string_view prefix, long err)
    170 {
    171   if (errptr)
    172     errptr->SetHResult(prefix, err);
    173 }
    174 
    175 #endif
    176 
    177 void Error::SetSocket(int err)
    178 {
    179   SetSocket(std::string_view(), err);
    180 }
    181 
    182 void Error::SetSocket(std::string_view prefix, int err)
    183 {
    184   // Socket errors are win32 errors on windows
    185 #ifdef _WIN32
    186   SetWin32(prefix, err);
    187 #else
    188   SetErrno(prefix, err);
    189 #endif
    190   m_type = Type::Socket;
    191 }
    192 
    193 void Error::SetSocket(Error* errptr, int err)
    194 {
    195   if (errptr)
    196     errptr->SetSocket(err);
    197 }
    198 
    199 void Error::SetSocket(Error* errptr, std::string_view prefix, int err)
    200 {
    201   if (errptr)
    202     errptr->SetSocket(prefix, err);
    203 }
    204 
    205 Error Error::CreateNone()
    206 {
    207   return Error();
    208 }
    209 
    210 Error Error::CreateErrno(int err)
    211 {
    212   Error ret;
    213   ret.SetErrno(err);
    214   return ret;
    215 }
    216 
    217 Error Error::CreateSocket(int err)
    218 {
    219   Error ret;
    220   ret.SetSocket(err);
    221   return ret;
    222 }
    223 
    224 Error Error::CreateString(std::string description)
    225 {
    226   Error ret;
    227   ret.SetString(std::move(description));
    228   return ret;
    229 }
    230 
    231 #ifdef _WIN32
    232 Error Error::CreateWin32(unsigned long err)
    233 {
    234   Error ret;
    235   ret.SetWin32(err);
    236   return ret;
    237 }
    238 
    239 Error Error::CreateHResult(long err)
    240 {
    241   Error ret;
    242   ret.SetHResult(err);
    243   return ret;
    244 }
    245 
    246 #endif
    247 
    248 void Error::AddPrefix(std::string_view prefix)
    249 {
    250   m_description.insert(0, prefix);
    251 }
    252 
    253 void Error::AddSuffix(std::string_view suffix)
    254 {
    255   m_description.append(suffix);
    256 }
    257 
    258 void Error::AddPrefix(Error* errptr, std::string_view prefix)
    259 {
    260   if (errptr)
    261     errptr->AddPrefix(prefix);
    262 }
    263 
    264 void Error::AddSuffix(Error* errptr, std::string_view prefix)
    265 {
    266   if (errptr)
    267     errptr->AddSuffix(prefix);
    268 }
    269 
    270 Error& Error::operator=(const Error& e) = default;
    271 
    272 Error& Error::operator=(Error&& e) = default;
    273 
    274 bool Error::operator==(const Error& e) const
    275 {
    276   return (m_type == e.m_type && m_description == e.m_description);
    277 }
    278 
    279 bool Error::operator!=(const Error& e) const
    280 {
    281   return (m_type != e.m_type || m_description != e.m_description);
    282 }