mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-08-10 00:52:16 +00:00
128 lines
3.7 KiB
C++
128 lines
3.7 KiB
C++
/**
|
|
* @file src/platform/windows/tools/helper.h
|
|
* @brief Helpers for tools.
|
|
*/
|
|
#pragma once
|
|
|
|
// standard includes
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
// lib includes
|
|
#include <boost/locale.hpp>
|
|
|
|
// platform includes
|
|
#include <Windows.h>
|
|
|
|
/**
|
|
* @brief Safe console output utilities for Windows
|
|
* These functions prevent crashes when outputting strings with special characters.
|
|
* This is only used in tools/audio-info and tools/dxgi-info.
|
|
*/
|
|
namespace output {
|
|
// ASCII character range constants for safe output, https://www.ascii-code.com/
|
|
static constexpr int ASCII_PRINTABLE_START = 32;
|
|
static constexpr int ASCII_PRINTABLE_END = 127;
|
|
|
|
/**
|
|
* @brief Return a non-null wide string, defaulting to "Unknown" if null
|
|
* @param str The wide string to check
|
|
* @return A non-null wide string
|
|
*/
|
|
inline const wchar_t *no_null(const wchar_t *str) {
|
|
return str ? str : L"Unknown";
|
|
}
|
|
|
|
/**
|
|
* @brief Safely convert a wide string to console output using Windows API
|
|
* @param wstr The wide string to output
|
|
*/
|
|
inline void safe_wcout(const std::wstring &wstr) {
|
|
if (wstr.empty()) {
|
|
return;
|
|
}
|
|
|
|
// Try to use the Windows console API for proper Unicode output
|
|
if (const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); hConsole != INVALID_HANDLE_VALUE) {
|
|
DWORD written;
|
|
if (WriteConsoleW(hConsole, wstr.c_str(), wstr.length(), &written, nullptr)) {
|
|
return; // Success with WriteConsoleW
|
|
}
|
|
}
|
|
|
|
// Fallback: convert to narrow string and output to std::cout
|
|
try {
|
|
const std::string narrow_str = boost::locale::conv::utf_to_utf<char>(wstr);
|
|
std::cout << narrow_str;
|
|
} catch (const boost::locale::conv::conversion_error &) {
|
|
// Final fallback: output character by character, replacing non-ASCII
|
|
for (const wchar_t wc : wstr) {
|
|
if (wc >= ASCII_PRINTABLE_START && wc < ASCII_PRINTABLE_END) { // Printable ASCII
|
|
std::cout << static_cast<char>(wc);
|
|
} else {
|
|
std::cout << '?';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Safely convert a wide string literal to console encoding and output it
|
|
* @param wstr The wide string literal to output
|
|
*/
|
|
inline void safe_wcout(const wchar_t *wstr) {
|
|
if (wstr) {
|
|
safe_wcout(std::wstring(wstr));
|
|
} else {
|
|
std::cout << "Unknown";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Safely convert a string to wide string and then to console output
|
|
* @param str The string to output
|
|
*/
|
|
inline void safe_cout(const std::string &str) {
|
|
if (str.empty()) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Convert string to wide string first, then to console output
|
|
const std::wstring wstr = boost::locale::conv::utf_to_utf<wchar_t>(str);
|
|
safe_wcout(wstr);
|
|
} catch (const boost::locale::conv::conversion_error &) {
|
|
// Fallback: output string directly, replacing problematic characters
|
|
for (const char c : str) {
|
|
if (c >= ASCII_PRINTABLE_START && c < ASCII_PRINTABLE_END) { // Printable ASCII
|
|
std::cout << c;
|
|
} else {
|
|
std::cout << '?';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Output a label and value pair safely
|
|
* @param label The label to output
|
|
* @param value The wide string value to output
|
|
*/
|
|
inline void output_field(const std::string &label, const wchar_t *value) {
|
|
std::cout << label << " : ";
|
|
safe_wcout(value ? value : L"Unknown");
|
|
std::cout << std::endl;
|
|
}
|
|
|
|
/**
|
|
* @brief Output a label and string value pair
|
|
* @param label The label to output
|
|
* @param value The string value to output
|
|
*/
|
|
inline void output_field(const std::string &label, const std::string &value) {
|
|
std::cout << label << " : ";
|
|
safe_cout(value);
|
|
std::cout << std::endl;
|
|
}
|
|
} // namespace output
|