4#include "Stroika/Foundation/StroikaPreComp.h"
8#if qStroika_Platform_Windows
16#include "Stroika/Foundation/Execution/Throw.h"
17#include "Stroika/Foundation/Linguistics/MessageUtilities.h"
19#include "Exceptions.h"
22using namespace Characters;
23using namespace Execution;
37 if (activities.empty ()) {
38 return reasonForError;
41 auto tmp = Linguistics::MessageUtilities::Manager::sThe.RemoveTrailingSentencePunctuation (reasonForError);
44 for (
auto i = activities.begin (); i != activities.end ();) {
47 if (i == activities.end ()) {
48 sb << tmp.second.value_or (
"."sv);
65 : fActivities_{activities}
66 , fRawErrorMessage_{reasonForError}
71 : fActivities_{src.fActivities_}
72 , fRawErrorMessage_{src.fRawErrorMessage_}
74 lock_guard lk{src.fBuildMutex_};
75 fBuilt_ = src.fBuilt_;
76 fFullErrorMessage_ = src.fFullErrorMessage_;
77 fSDKCharString_ = src.fSDKCharString_;
95 lock_guard
lk{fBuildMutex_};
100void ExceptionStringHelper::EnsureBuilt_ () const noexcept
103 lock_guard
lk{fBuildMutex_};
121NestedException::NestedException (
const exception_ptr& basedOnException)
134 bool IsNativeSystemCategory_ (
const error_category& c)
noexcept
136#if qStroika_Platform_Windows
137 if (c == Execution::Platform::Windows::Win32_error_category ()) {
141 return c == system_category ();
145#if qStroika_Platform_Windows
149#pragma comment(lib, "Wininet.lib")
152optional<String> TryToOverrideDefaultWindowsSystemCategoryMessage_ (error_code errCode)
154 if (IsNativeSystemCategory_ (errCode.category ())) {
155 switch (errCode.value ()) {
156 case ERROR_NOT_ENOUGH_MEMORY:
157 return "Not enough memory to complete that operation (ERROR_NOT_ENOUGH_MEMORY)"sv;
158 case ERROR_OUTOFMEMORY:
159 return "Not enough memory to complete that operation (ERROR_OUTOFMEMORY)"sv;
160 case WSAEADDRNOTAVAIL:
161 return "Socket address not available (WSAEADDRNOTAVAIL)"sv;
162 case ERROR_INTERNET_INVALID_URL:
163 return "ERROR_INTERNET_INVALID_URL"sv;
164 case ERROR_INTERNET_CANNOT_CONNECT:
165 return "Failed to connect to internet URL (ERROR_INTERNET_CANNOT_CONNECT)"sv;
166 case ERROR_INTERNET_NAME_NOT_RESOLVED:
167 return "ERROR_INTERNET_NAME_NOT_RESOLVED"sv;
168 case ERROR_INTERNET_INCORRECT_HANDLE_STATE:
169 return "ERROR_INTERNET_INCORRECT_HANDLE_STATE"sv;
170 case ERROR_INTERNET_TIMEOUT:
171 return "Operation timed out (ERROR_INTERNET_TIMEOUT)"sv;
172 case ERROR_INTERNET_CONNECTION_ABORTED:
173 return "ERROR_INTERNET_CONNECTION_ABORTED"sv;
174 case ERROR_INTERNET_CONNECTION_RESET:
175 return "ERROR_INTERNET_CONNECTION_RESET"sv;
176 case ERROR_HTTP_INVALID_SERVER_RESPONSE:
177 return "Invalid Server Response (ERROR_HTTP_INVALID_SERVER_RESPONSE)"sv;
178 case ERROR_INTERNET_PROTOCOL_NOT_FOUND: {
180 if (::InternetGetConnectedState (&r, 0) and (r & INTERNET_CONNECTION_OFFLINE) == 0) {
181 return "ERROR_INTERNET_PROTOCOL_NOT_FOUND"sv;
184 return "ERROR_INTERNET_PROTOCOL_NOT_FOUND (offline mode)"sv;
192Characters::String Execution::Private_::SystemErrorExceptionPrivate_::mkMsg_ (error_code errCode)
206 if (errCode.category () == generic_category () and errCode == errc::timed_out) {
207 return "Operation timed out"sv;
209#if qStroika_Platform_Windows
211 if (optional<String> o = TryToOverrideDefaultWindowsSystemCategoryMessage_ (errCode)) {
223 if (errCode.category () == generic_category ()) {
224 sb +=
"{{errno: {}}}"_f(errCode.value ());
226 else if (IsNativeSystemCategory_ (errCode.category ())) {
227#if qStroika_Platform_POSIX
228 sb +=
"{{errno: {}}}"_f(errCode.value ());
229#elif qStroika_Platform_Windows
230 sb +=
"{{Windows error: {}}}"_f(errCode.value ());
232 sb +=
"{{system error: {}}}"_f(errCode.value ());
241void Execution::Private_::SystemErrorExceptionPrivate_::ThrowTranslatedExceptionIfNeeded_ (error_code errCode, [[maybe_unused]]
const String* message)
246 if (errCode == errc::not_enough_memory) {
252#if qStroika_Platform_Windows && qStroika_Foundation_Debug_AssertionsChecked
253 if (IsNativeSystemCategory_ (errCode.category ())) {
254 switch (errCode.value ()) {
255 case ERROR_NOT_ENOUGH_MEMORY:
256 case ERROR_OUTOFMEMORY:
272 rethrow_exception (e);
274 catch (
const system_error& se) {
289#if qStroika_Platform_Windows
292 if (ec.category () == system_category ()) {
293 return error_code{ec.value (), Execution::Platform::Windows::Win32_error_category ()} == cond;
301 return IsA (e.code (), cond);
306 if (
const system_error* se =
dynamic_cast<const system_error*
> (&e)) {
307 return IsA (se->code (), cond);
321 return ec.has_value () and
IsA (*ec, cond);
324#if qStroika_Platform_Windows
335 struct Win32ConditionMapping_ {
339 constexpr Win32ConditionMapping_ kWin32ConditionMappings_[] = {
341 {ERROR_NETNAME_DELETED, errc::connection_reset},
342 {ERROR_NETNAME_DELETED, errc::connection_aborted},
343 {ERROR_CANCELLED, errc::operation_canceled},
344 {ERROR_CONNECTION_REFUSED, errc::connection_refused},
345 {ERROR_PORT_UNREACHABLE, errc::connection_refused},
346 {ERROR_NETWORK_UNREACHABLE, errc::network_unreachable},
347 {ERROR_HOST_UNREACHABLE, errc::host_unreachable},
348 {ERROR_CONNECTION_ABORTED, errc::connection_aborted},
351 {ERROR_INTERNET_TIMEOUT, errc::timed_out},
352 {ERROR_INTERNET_NAME_NOT_RESOLVED, errc::no_such_device},
353 {ERROR_INTERNET_CANNOT_CONNECT, errc::connection_refused},
354 {ERROR_INTERNET_CONNECTION_ABORTED, errc::connection_aborted},
355 {ERROR_INTERNET_CONNECTION_ABORTED, errc::connection_reset},
356 {ERROR_INTERNET_CONNECTION_RESET, errc::connection_reset},
357 {ERROR_HTTP_INVALID_SERVER_RESPONSE, errc::protocol_error},
362 optional<string> GetModuleMessage_ (
int ev)
364 static const HMODULE kModules_[] = {
365 ::LoadLibraryExW (L
"winhttp.dll",
nullptr, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_SEARCH_SYSTEM32),
366 ::LoadLibraryExW (L
"wininet.dll",
nullptr, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_SEARCH_SYSTEM32),
368 for (HMODULE m : kModules_) {
373 DWORD n = ::FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, m,
374 static_cast<DWORD
> (ev), 0,
reinterpret_cast<char*
> (&buf), 0,
nullptr);
375 string result{buf ==
nullptr ?
string{} :
string{buf, n}};
377 while (not result.empty () and (result.back () ==
'\n' or result.back () ==
'\r' or result.back () ==
' ')) {
380 if (not result.empty ()) {
387 class Win32_error_category_ :
public error_category {
389 virtual const char* name () const noexcept
override
391 return system_category ().name ();
393 virtual string message (
int ev)
const override
395 if (INTERNET_ERROR_BASE <= ev and ev < INTERNET_ERROR_BASE + 1000) {
396 if (optional<string> m = GetModuleMessage_ (ev)) {
400 return system_category ().message (ev);
402 virtual error_condition default_error_condition (
int ev)
const noexcept override
404 for (
const Win32ConditionMapping_& i : kWin32ConditionMappings_) {
405 if (i.fWin32 == ev and ev != 0) {
406 return make_error_condition (i.fCondition);
409 return system_category ().default_error_condition (ev);
411 virtual bool equivalent (
int ev,
const error_condition& cond)
const noexcept override
413 for (
const Win32ConditionMapping_& i : kWin32ConditionMappings_) {
414 if (i.fWin32 == ev and ev != 0 and make_error_condition (i.fCondition) == cond) {
418 return system_category ().equivalent (ev, cond);
423const error_category& Execution::Platform::Windows::Win32_error_category () noexcept
425 return Common::Immortalize<Win32_error_category_> ();
428bool Execution::Platform::Windows::IsWin32Error (
const error_code& ec,
int win32Err)
noexcept
430 return ec.value () == win32Err and (ec.category () == Win32_error_category () or ec.category () == system_category ());
#define RequireNotNull(p)
#define AssertNotReached()
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual string AsNarrowSDKString() const
static String FromNarrowSDKString(const char *from)
nonvirtual void ImbueActivities(const optional< Containers::Stack< Activity<> > > &activities)
Set, replace, or clear the activity stack. Any already-computed message text is discarded,...
ExceptionStringHelper()=delete
activities default to NULLOPT - meaning "not specified" - which is different from "specified,...
NestedException contains a new higher level error message (typically based on argument basedOnExcepti...
String ToString(T &&t, ARGS... args)
Return a debug-friendly, display version of the argument: not guaranteed parsable or usable except fo...
void Throw(T &&e2Throw)
like the builtin C++ 'throw', but stamps in the current Activity context and does helpful,...
optional< error_code > GetAssociatedErrorCode(const exception_ptr &e) noexcept
Containers::Stack< Activity<> > CaptureCurrentActivities()
Returns a copyable preservable version of the current activities stack.
bool IsA(const error_code &ec, error_condition cond) noexcept
Does this error MEAN the given condition - regardless of how it happens to be represented?
bool AnyCurrentActivities()
Checks if CaptureCurrentActivities() would produce a non-empty stack (but faster)