55 * FILE: core/CrashHandler.h
66 * PURPOSE: Header file for crash handling functions
77 *
8- * THIS FILE CREDITS: "Debugging Applications" (Microsoft Press) by John Robbins
8+ * THIS FILE CREDITS (IS BASED ON): "Debugging Applications" (Microsoft Press) by John Robbins
9+ * Copyright (c) 1997-2000 John Robbins -- All rights reserved
910 *
1011 * Multi Theft Auto is available from https://www.multitheftauto.com/
1112 *
1516
1617#define WIN32_LEAN_AND_MEAN
1718#include < windows.h>
19+ #include < algorithm>
1820#include < chrono>
21+ #include < cstdarg>
22+ #include < cstdio>
23+ #include < cstring>
1924#include < exception>
2025#include < optional>
2126#include < string>
3136#endif
3237
3338constexpr std::size_t DEBUG_BUFFER_SIZE = 256 ;
39+ static_assert (DEBUG_BUFFER_SIZE > 1 , " DEBUG_BUFFER_SIZE must allow for null termination" );
3440
3541constexpr DWORD CPP_EXCEPTION_CODE = 0xE06D7363 ;
3642constexpr DWORD STATUS_INVALID_CRUNTIME_PARAMETER_CODE = 0xC0000417 ;
@@ -73,12 +79,25 @@ inline constexpr std::string_view DEBUG_SEPARATOR = "!!!!!!!!!!!!!!!!!!!!!!!!!!!
7379
7480inline void SafeDebugOutput (std::string_view message) noexcept
7581{
76- if (!message.empty () && message.data () != nullptr )
82+ const char * data = message.data ();
83+ std::size_t remaining = message.size ();
84+
85+ if (data == nullptr || remaining == 0 )
7786 {
78- // string_view from string literal is null-terminated, but views from substrings may not be
79- // Create temporary null-terminated string for safety with OutputDebugStringA
80- const std::string temp{message};
81- OutputDebugStringA (temp.c_str ());
87+ return ;
88+ }
89+
90+ char buffer[DEBUG_BUFFER_SIZE] = {};
91+
92+ while (remaining > 0 )
93+ {
94+ const std::size_t chunkLength = std::min<std::size_t >(remaining, DEBUG_BUFFER_SIZE - 1 );
95+ std::memcpy (buffer, data, chunkLength);
96+ buffer[chunkLength] = ' \0 ' ;
97+ OutputDebugStringA (buffer);
98+
99+ data += chunkLength;
100+ remaining -= chunkLength;
82101 }
83102}
84103
@@ -100,33 +119,81 @@ inline void SafeDebugOutput(const std::string& message) noexcept
100119 }
101120}
102121
103- #define SAFE_DEBUG_PRINT (buffer, format, ...) \
104- do \
105- { \
106- if ((buffer).data () != nullptr && (buffer).size () > 0 ) \
107- { \
108- memset ((buffer).data (), 0 , (buffer).size ()); \
109- int result = _snprintf_s ((buffer).data (), (buffer).size (), _TRUNCATE, format, __VA_ARGS__); \
110- if (result > 0 ) \
111- { \
112- OutputDebugStringA ((buffer).data ()); \
113- } \
114- } \
115- } while (false )
116-
117- #define SAFE_DEBUG_PRINT_C (buffer, bufferSize, format, ...) \
118- do \
119- { \
120- if (buffer != nullptr && bufferSize > 0 ) \
121- { \
122- int result = _snprintf_s (buffer, bufferSize, _TRUNCATE, format, __VA_ARGS__); \
123- if (result > 0 ) \
124- { \
125- OutputDebugStringA (buffer); \
126- } \
127- } \
128- } while (false )
122+ template <typename Buffer>
123+ inline void SafeDebugPrint (Buffer& buffer, const char * format, ...) noexcept
124+ {
125+ if (format == nullptr )
126+ return ;
127+
128+ auto * data = buffer.data ();
129+ const std::size_t size = buffer.size ();
130+
131+ if (data == nullptr || size == 0 )
132+ return ;
133+
134+ std::memset (data, 0 , size);
135+
136+ va_list args;
137+ va_start (args, format);
138+ const int written = _vsnprintf_s (data, size, _TRUNCATE, format, args);
139+ va_end (args);
140+
141+ if (written > 0 )
142+ {
143+ OutputDebugStringA (data);
144+ }
145+ }
146+
147+ inline void SafeDebugPrintC (char * buffer, std::size_t bufferSize, const char * format, ...) noexcept
148+ {
149+ if (buffer == nullptr || bufferSize == 0 || format == nullptr )
150+ return ;
151+
152+ va_list args;
153+ va_start (args, format);
154+ const int written = _vsnprintf_s (buffer, bufferSize, _TRUNCATE, format, args);
155+ va_end (args);
156+
157+ if (written > 0 )
158+ {
159+ OutputDebugStringA (buffer);
160+ }
161+ }
162+
163+ #define SAFE_DEBUG_PRINT (buffer, ...) SafeDebugPrint((buffer), __VA_ARGS__)
164+ #define SAFE_DEBUG_PRINT_C (buffer, bufferSize, ...) SafeDebugPrintC((buffer), (bufferSize), __VA_ARGS__)
165+
166+ inline void SafeDebugPrintPrefixed (std::string_view prefix, const char * format, ...) noexcept
167+ {
168+ if (format == nullptr )
169+ return ;
170+
171+ char buffer[DEBUG_BUFFER_SIZE] = {};
172+
173+ std::size_t offset = 0 ;
174+ if (!prefix.empty ())
175+ {
176+ offset = std::min<std::size_t >(prefix.size (), DEBUG_BUFFER_SIZE - 1 );
177+ std::memcpy (buffer, prefix.data (), offset);
178+ }
179+
180+ if (offset >= DEBUG_BUFFER_SIZE - 1 )
181+ {
182+ buffer[DEBUG_BUFFER_SIZE - 1 ] = ' \0 ' ;
183+ OutputDebugStringA (buffer);
184+ return ;
185+ }
129186
187+ va_list args;
188+ va_start (args, format);
189+ const int written = _vsnprintf_s (buffer + offset, DEBUG_BUFFER_SIZE - offset, _TRUNCATE, format, args);
190+ va_end (args);
191+
192+ if (written > 0 || offset > 0 )
193+ {
194+ OutputDebugStringA (buffer);
195+ }
196+ }
130197#ifdef __cplusplus
131198extern " C"
132199{
0 commit comments