refactor: update all modules for UTF8 string. waiting for debugging

This commit is contained in:
yyc12345 2024-06-28 15:46:58 +08:00
parent 44dbbb1c99
commit ccb729c718
15 changed files with 170 additions and 155 deletions

View File

@ -54,7 +54,7 @@ namespace YYCC::ConsoleHelper {
*/
template<bool _bIsConsole>
static std::string WinConsoleRead(HANDLE hStdIn) {
static yycc_u8string WinConsoleRead(HANDLE hStdIn) {
using _TChar = std::conditional_t<_bIsConsole, wchar_t, char>;
// Prepare an internal buffer because the read data may not be fully used.
@ -113,21 +113,21 @@ namespace YYCC::ConsoleHelper {
}
// post-process for return value
std::string real_return_buffer;
yycc_u8string real_return_buffer;
if constexpr (_bIsConsole) {
// console mode need convert wchar to utf8
YYCC::EncodingHelper::WcharToUTF8(return_buffer.c_str(), real_return_buffer);
YYCC::EncodingHelper::WcharToUTF8(return_buffer, real_return_buffer);
} else {
// non-console just copt the result
real_return_buffer = return_buffer;
real_return_buffer = EncodingHelper::ToUTF8(return_buffer);
}
// every mode need delete \r words
YYCC::StringHelper::Replace(real_return_buffer, "\r", "");
YYCC::StringHelper::Replace(real_return_buffer, YYCC_U8("\r"), YYCC_U8(""));
// return value
return real_return_buffer;
}
static void WinConsoleWrite(const std::string& strl, bool to_stderr) {
static void WinConsoleWrite(const yycc_u8string& strl, bool to_stderr) {
// Prepare some Win32 variables
// fetch stdout handle first
HANDLE hStdOut = GetStdHandle(to_stderr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE);
@ -139,7 +139,7 @@ namespace YYCC::ConsoleHelper {
if (GetConsoleMode(hStdOut, &dwConsoleMode)) {
// console handle, use WriteConsoleW.
// convert utf8 string to wide char first
std::wstring wstrl(YYCC::EncodingHelper::UTF8ToWchar(strl.c_str()));
std::wstring wstrl(YYCC::EncodingHelper::UTF8ToWchar(strl));
size_t wstrl_size = wstrl.size();
// write string with size check
if (wstrl_size <= std::numeric_limits<DWORD>::max()) {
@ -176,7 +176,7 @@ namespace YYCC::ConsoleHelper {
#endif
}
std::string ReadLine() {
yycc_u8string ReadLine() {
#if YYCC_OS == YYCC_OS_WINDOWS
// get stdin mode
@ -194,18 +194,18 @@ namespace YYCC::ConsoleHelper {
// in linux, directly use C++ function to fetch.
std::string cmd;
if (std::getline(std::cin, cmd).fail()) cmd.clear();
return cmd;
return EncodingHelper::ToUTF8(cmd);
#endif
}
template<bool bNeedFmt, bool bIsErr, bool bHasEOL>
static void RawWrite(const char* u8_fmt, va_list argptr) {
static void RawWrite(const yycc_char8_t* u8_fmt, va_list argptr) {
// Buiild string need to be written first
// If no format string or plain string for writing, return.
if (u8_fmt == nullptr) return;
// Build or simply copy string
std::string strl;
yycc_u8string strl;
if constexpr (bNeedFmt) {
// treat as format string
va_list argcpy;
@ -218,7 +218,7 @@ namespace YYCC::ConsoleHelper {
}
// Checkout whether add EOL
if constexpr (bHasEOL) {
strl += "\n";
strl += YYCC_U8("\n");
}
#if YYCC_OS == YYCC_OS_WINDOWS
@ -226,54 +226,54 @@ namespace YYCC::ConsoleHelper {
WinConsoleWrite(strl, bIsErr);
#else
// in linux, directly use C function to write.
std::fputs(strl.c_str(), bIsErr ? stderr : stdout);
std::fputs(EncodingHelper::ToNative(strl.c_str()), bIsErr ? stderr : stdout);
#endif
}
void Format(const char* u8_fmt, ...) {
void Format(const yycc_char8_t* u8_fmt, ...) {
va_list argptr;
va_start(argptr, u8_fmt);
RawWrite<true, false, false>(u8_fmt, argptr);
va_end(argptr);
}
void FormatLine(const char* u8_fmt, ...) {
void FormatLine(const yycc_char8_t* u8_fmt, ...) {
va_list argptr;
va_start(argptr, u8_fmt);
RawWrite<true, false, true>(u8_fmt, argptr);
va_end(argptr);
}
void Write(const char* u8_strl) {
void Write(const yycc_char8_t* u8_strl) {
va_list empty{};
RawWrite<false, false, false>(u8_strl, empty);
}
void WriteLine(const char* u8_strl) {
void WriteLine(const yycc_char8_t* u8_strl) {
va_list empty{};
RawWrite<false, false, true>(u8_strl, empty);
}
void ErrFormat(const char* u8_fmt, ...) {
void ErrFormat(const yycc_char8_t* u8_fmt, ...) {
va_list argptr;
va_start(argptr, u8_fmt);
RawWrite<true, true, false>(u8_fmt, argptr);
va_end(argptr);
}
void ErrFormatLine(const char* u8_fmt, ...) {
void ErrFormatLine(const yycc_char8_t* u8_fmt, ...) {
va_list argptr;
va_start(argptr, u8_fmt);
RawWrite<true, true, true>(u8_fmt, argptr);
va_end(argptr);
}
void ErrWrite(const char* u8_strl) {
void ErrWrite(const yycc_char8_t* u8_strl) {
va_list empty{};
RawWrite<false, true, false>(u8_strl, empty);
}
void ErrWriteLine(const char* u8_strl) {
void ErrWriteLine(const yycc_char8_t* u8_strl) {
va_list empty{};
RawWrite<false, true, true>(u8_strl, empty);
}

View File

@ -124,52 +124,52 @@ namespace YYCC::ConsoleHelper {
* This function also can be used as ordering user press Enter key by
* simply calling this function and ignoring its return value.
*/
std::string ReadLine();
yycc_u8string ReadLine();
/**
* @brief Universal console write function with format feature.
* @param[in] u8_fmt The format string.
* @param[in] ... The arguments to be formatted.
*/
void Format(const char* u8_fmt, ...);
void Format(const yycc_char8_t* u8_fmt, ...);
/**
* @brief Universal console write function with format and auto EOL feature.
* @param[in] u8_fmt The format string.
* @param[in] ... The arguments to be formatted.
*/
void FormatLine(const char* u8_fmt, ...);
void FormatLine(const yycc_char8_t* u8_fmt, ...);
/**
* @brief Universal console write function.
* @param[in] u8_strl The string to be written.
*/
void Write(const char* u8_strl);
void Write(const yycc_char8_t* u8_strl);
/**
* @brief Universal console write function with auto EOL feature.
* @param[in] u8_strl The string to be written.
*/
void WriteLine(const char* u8_strl);
void WriteLine(const yycc_char8_t* u8_strl);
/**
* @brief Universal console error write function with format and feature.
* @param[in] u8_fmt The format string.
* @param[in] ... The arguments to be formatted.
*/
void ErrFormat(const char* u8_fmt, ...);
void ErrFormat(const yycc_char8_t* u8_fmt, ...);
/**
* @brief Universal console error write function with format and auto EOL feature.
* @param[in] u8_fmt The format string.
* @param[in] ... The arguments to be formatted.
*/
void ErrFormatLine(const char* u8_fmt, ...);
void ErrFormatLine(const yycc_char8_t* u8_fmt, ...);
/**
* @brief Universal console error write function.
* @param[in] u8_strl The string to be written.
*/
void ErrWrite(const char* u8_strl);
void ErrWrite(const yycc_char8_t* u8_strl);
/**
* @brief Universal console error write function with auto EOL feature.
* @param[in] u8_strl The string to be written.
*/
void ErrWriteLine(const char* u8_strl);
void ErrWriteLine(const yycc_char8_t* u8_strl);
}

View File

@ -8,16 +8,16 @@ namespace YYCC::DialogHelper {
#pragma region FileFilters
bool FileFilters::Add(const char* filter_name, std::initializer_list<const char*> il) {
bool FileFilters::Add(const yycc_char8_t* filter_name, std::initializer_list<const yycc_char8_t*> il) {
// assign filter name
if (filter_name == nullptr) return false;
FilterName name(filter_name);
// assign filter patterns
FilterModes modes;
for (const char* pattern : il) {
for (const yycc_char8_t* pattern : il) {
if (pattern != nullptr)
modes.emplace_back(std::string(pattern));
modes.emplace_back(yycc_u8string(pattern));
}
// check filter patterns
@ -36,13 +36,13 @@ namespace YYCC::DialogHelper {
for (const auto& it : m_Filters) {
// convert name to wchar
WinFileFilters::WinFilterName name;
if (!YYCC::EncodingHelper::UTF8ToWchar(it.first.c_str(), name))
if (!YYCC::EncodingHelper::UTF8ToWchar(it.first, name))
return false;
// convert pattern and join them
std::string joined_modes(YYCC::StringHelper::Join(it.second, ";"));
yycc_u8string joined_modes(YYCC::StringHelper::Join(it.second, YYCC_U8(";")));
WinFileFilters::WinFilterModes modes;
if (!YYCC::EncodingHelper::UTF8ToWchar(joined_modes.c_str(), modes))
if (!YYCC::EncodingHelper::UTF8ToWchar(joined_modes, modes))
return false;
// append new pair
@ -94,12 +94,12 @@ namespace YYCC::DialogHelper {
// build title and init file name
if (m_HasTitle) {
if (!YYCC::EncodingHelper::UTF8ToWchar(m_Title.c_str(), win_result.m_WinTitle))
if (!YYCC::EncodingHelper::UTF8ToWchar(m_Title, win_result.m_WinTitle))
return false;
win_result.m_HasTitle = true;
}
if (m_HasInitFileName) {
if (!YYCC::EncodingHelper::UTF8ToWchar(m_InitFileName.c_str(), win_result.m_WinInitFileName))
if (!YYCC::EncodingHelper::UTF8ToWchar(m_InitFileName, win_result.m_WinInitFileName))
return false;
win_result.m_HasInitFileName = true;
}
@ -108,7 +108,7 @@ namespace YYCC::DialogHelper {
if (m_HasInitDirectory) {
// convert to wpath
std::wstring w_init_directory;
if (!YYCC::EncodingHelper::UTF8ToWchar(m_InitDirectory.c_str(), w_init_directory))
if (!YYCC::EncodingHelper::UTF8ToWchar(m_InitDirectory, w_init_directory))
return false;
// fetch IShellItem*
@ -143,7 +143,7 @@ namespace YYCC::DialogHelper {
* @return True if success, otherwise false.
* @remarks This is an assist function of CommonFileDialog.
*/
static bool ExtractDisplayName(IShellItem* item, std::string& ret) {
static bool ExtractDisplayName(IShellItem* item, yycc_u8string& ret) {
// fetch display name from IShellItem*
LPWSTR _name;
HRESULT hr = item->GetDisplayName(SIGDN_FILESYSPATH, &_name);
@ -168,7 +168,7 @@ namespace YYCC::DialogHelper {
* @remarks This function is the real underlying function of all dialog functions.
*/
template<CommonFileDialogType EDialogType>
static bool CommonFileDialog(const FileDialog& params, std::vector<std::string>& ret) {
static bool CommonFileDialog(const FileDialog& params, std::vector<yycc_u8string>& ret) {
// Reference: https://learn.microsoft.com/en-us/windows/win32/shell/common-file-dialog
// prepare result variable
HRESULT hr;
@ -289,7 +289,7 @@ namespace YYCC::DialogHelper {
COMHelper::SmartIShellItem result_item(_item);
// extract display name
std::string result_name;
yycc_u8string result_name;
if (!ExtractDisplayName(result_item.get(), result_name))
return false;
@ -326,7 +326,7 @@ namespace YYCC::DialogHelper {
COMHelper::SmartIShellItem result_item(_item);
// extract display name
std::string result_name;
yycc_u8string result_name;
if (!ExtractDisplayName(result_item.get(), result_name))
return false;
@ -347,24 +347,24 @@ namespace YYCC::DialogHelper {
#pragma region Wrapper Functions
bool OpenFileDialog(const FileDialog& params, std::string& ret) {
std::vector<std::string> cache;
bool OpenFileDialog(const FileDialog& params, yycc_u8string& ret) {
std::vector<yycc_u8string> cache;
bool isok = CommonFileDialog<CommonFileDialogType::OpenFile>(params, cache);
if (isok) ret = cache.front();
return isok;
}
bool OpenMultipleFileDialog(const FileDialog& params, std::vector<std::string>& ret) {
bool OpenMultipleFileDialog(const FileDialog& params, std::vector<yycc_u8string>& ret) {
return CommonFileDialog<CommonFileDialogType::OpenMultipleFiles>(params, ret);
}
bool SaveFileDialog(const FileDialog& params, std::string& ret) {
std::vector<std::string> cache;
bool SaveFileDialog(const FileDialog& params, yycc_u8string& ret) {
std::vector<yycc_u8string> cache;
bool isok = CommonFileDialog<CommonFileDialogType::SaveFile>(params, cache);
if (isok) ret = cache.front();
return isok;
}
bool OpenFolderDialog(const FileDialog& params, std::string& ret) {
std::vector<std::string> cache;
bool OpenFolderDialog(const FileDialog& params, yycc_u8string& ret) {
std::vector<yycc_u8string> cache;
bool isok = CommonFileDialog<CommonFileDialogType::OpenFolder>(params, cache);
if (isok) ret = cache.front();
return isok;

View File

@ -65,7 +65,7 @@ namespace YYCC::DialogHelper {
* @remarks This function allow you register multiple filter patterns for single friendly name.
* For example: `Add("Microsoft Word (*.doc; *.docx)", {"*.doc", "*.docx"})`
*/
bool Add(const char* filter_name, std::initializer_list<const char*> il);
bool Add(const yycc_char8_t* filter_name, std::initializer_list<const yycc_char8_t*> il);
/**
* @brief Clear filter pairs for following re-use.
*/
@ -85,8 +85,8 @@ namespace YYCC::DialogHelper {
bool Generate(WinFileFilters& win_result) const;
protected:
using FilterModes = std::vector<std::string>;
using FilterName = std::string;
using FilterModes = std::vector<yycc_u8string>;
using FilterName = yycc_u8string;
using FilterPair = std::pair<FilterName, FilterModes>;
std::vector<FilterPair> m_Filters;
@ -159,7 +159,7 @@ namespace YYCC::DialogHelper {
m_HasTitle(false), m_HasInitFileName(false), m_HasInitDirectory(false) {}
void SetOwner(HWND owner) { m_Owner = owner; }
void SetTitle(const char* title) {
void SetTitle(const yycc_char8_t* title) {
if (m_HasTitle = title != nullptr)
m_Title = title;
}
@ -167,11 +167,11 @@ namespace YYCC::DialogHelper {
return m_FileTypes;
}
void SetDefaultFileTypeIndex(size_t idx) { m_DefaultFileTypeIndex = idx; }
void SetInitFileName(const char* init_filename) {
void SetInitFileName(const yycc_char8_t* init_filename) {
if (m_HasInitFileName = init_filename != nullptr)
m_InitFileName = init_filename;
}
void SetInitDirectory(const char* init_dir) {
void SetInitDirectory(const yycc_char8_t* init_dir) {
if (m_HasInitDirectory = init_dir != nullptr)
m_InitDirectory = init_dir;
}
@ -200,7 +200,7 @@ namespace YYCC::DialogHelper {
protected:
HWND m_Owner;
bool m_HasTitle, m_HasInitFileName, m_HasInitDirectory;
std::string m_Title, m_InitFileName, m_InitDirectory;
yycc_u8string m_Title, m_InitFileName, m_InitDirectory;
FileFilters m_FileTypes;
/**
* @brief The default selected file type in dialog
@ -210,11 +210,11 @@ namespace YYCC::DialogHelper {
size_t m_DefaultFileTypeIndex;
};
bool OpenFileDialog(const FileDialog& params, std::string& ret);
bool OpenMultipleFileDialog(const FileDialog& params, std::vector<std::string>& ret);
bool SaveFileDialog(const FileDialog& params, std::string& ret);
bool OpenFileDialog(const FileDialog& params, yycc_u8string& ret);
bool OpenMultipleFileDialog(const FileDialog& params, std::vector<yycc_u8string>& ret);
bool SaveFileDialog(const FileDialog& params, yycc_u8string& ret);
bool OpenFolderDialog(const FileDialog& params, std::string& ret);
bool OpenFolderDialog(const FileDialog& params, yycc_u8string& ret);
}

View File

@ -50,7 +50,7 @@
*/
namespace YYCC::EncodingHelper {
#define YYCC_U8(strl) (reinterpret_cast<const yycc_char8_t*>(u8 ## strl))
#define YYCC_U8(strl) (reinterpret_cast<const ::YYCC::yycc_char8_t*>(u8 ## strl))
const yycc_char8_t* ToUTF8(const char* src);
yycc_char8_t* ToUTF8(char* src);

View File

@ -59,50 +59,50 @@ namespace YYCC::ExceptionHelper {
* @param[in] code Exception code
* @return The const string pointer to corresponding exception explanation string.
*/
static const char* UExceptionGetCodeName(DWORD code) {
static const yycc_char8_t* UExceptionGetCodeName(DWORD code) {
switch (code) {
case EXCEPTION_ACCESS_VIOLATION:
return "access violation";
return YYCC_U8("access violation");
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
return "array index out of bound";
return YYCC_U8("array index out of bound");
case EXCEPTION_BREAKPOINT:
return "breakpoint reached";
return YYCC_U8("breakpoint reached");
case EXCEPTION_DATATYPE_MISALIGNMENT:
return "misaligned data access";
return YYCC_U8("misaligned data access");
case EXCEPTION_FLT_DENORMAL_OPERAND:
return "operand had denormal value";
return YYCC_U8("operand had denormal value");
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
return "floating-point division by zero";
return YYCC_U8("floating-point division by zero");
case EXCEPTION_FLT_INEXACT_RESULT:
return "no decimal fraction representation for value";
return YYCC_U8("no decimal fraction representation for value");
case EXCEPTION_FLT_INVALID_OPERATION:
return "invalid floating-point operation";
return YYCC_U8("invalid floating-point operation");
case EXCEPTION_FLT_OVERFLOW:
return "floating-point overflow";
return YYCC_U8("floating-point overflow");
case EXCEPTION_FLT_STACK_CHECK:
return "floating-point stack corruption";
return YYCC_U8("floating-point stack corruption");
case EXCEPTION_FLT_UNDERFLOW:
return "floating-point underflow";
return YYCC_U8("floating-point underflow");
case EXCEPTION_ILLEGAL_INSTRUCTION:
return "illegal instruction";
return YYCC_U8("illegal instruction");
case EXCEPTION_IN_PAGE_ERROR:
return "inaccessible page";
return YYCC_U8("inaccessible page");
case EXCEPTION_INT_DIVIDE_BY_ZERO:
return "integer division by zero";
return YYCC_U8("integer division by zero");
case EXCEPTION_INT_OVERFLOW:
return "integer overflow";
return YYCC_U8("integer overflow");
case EXCEPTION_INVALID_DISPOSITION:
return "documentation says this should never happen";
return YYCC_U8("documentation says this should never happen");
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
return "can't continue after a noncontinuable exception";
return YYCC_U8("can't continue after a noncontinuable exception");
case EXCEPTION_PRIV_INSTRUCTION:
return "attempted to execute a privileged instruction";
return YYCC_U8("attempted to execute a privileged instruction");
case EXCEPTION_SINGLE_STEP:
return "one instruction has been executed";
return YYCC_U8("one instruction has been executed");
case EXCEPTION_STACK_OVERFLOW:
return "stack overflow";
return YYCC_U8("stack overflow");
default:
return "unknown exception";
return YYCC_U8("unknown exception");
}
}
@ -117,12 +117,12 @@ namespace YYCC::ExceptionHelper {
* @param[in] fmt The format string.
* @param[in] ... The argument to be formatted.
*/
static void UExceptionErrLogFormatLine(std::FILE* fs, const char* fmt, ...) {
static void UExceptionErrLogFormatLine(std::FILE* fs, const yycc_char8_t* fmt, ...) {
// write to file
if (fs != nullptr) {
va_list arg1;
va_start(arg1, fmt);
std::vfprintf(fs, fmt, arg1);
std::vfprintf(fs, EncodingHelper::ToNative(fmt), arg1);
std::fputs("\n", fs);
va_end(arg1);
}
@ -142,10 +142,10 @@ namespace YYCC::ExceptionHelper {
* If it is nullptr, function will skip writing for file stream.
* @param[in] strl The string to be written.
*/
static void UExceptionErrLogWriteLine(std::FILE* fs, const char* strl) {
static void UExceptionErrLogWriteLine(std::FILE* fs, const yycc_char8_t* strl) {
// write to file
if (fs != nullptr) {
std::fputs(strl, fs);
std::fputs(EncodingHelper::ToNative(strl), fs);
std::fputs("\n", fs);
}
// write to stderr
@ -163,7 +163,7 @@ namespace YYCC::ExceptionHelper {
// init symbol
if (!SymInitialize(process, 0, TRUE)) {
// fail to init. return
UExceptionErrLogWriteLine(fs, "Fail to initialize symbol handle for process!");
UExceptionErrLogWriteLine(fs, YYCC_U8("Fail to initialize symbol handle for process!"));
return;
}
@ -215,13 +215,13 @@ namespace YYCC::ExceptionHelper {
// depth breaker
--maxdepth;
if (maxdepth < 0) {
UExceptionErrLogWriteLine(fs, "..."); // indicate there are some frames not listed
UExceptionErrLogWriteLine(fs, YYCC_U8("...")); // indicate there are some frames not listed
break;
}
// get module name
const char* module_name = "<unknown module>";
std::string module_name_raw;
const yycc_char8_t* module_name = YYCC_U8("<unknown module>");
yycc_u8string module_name_raw;
DWORD64 module_base;
if (module_base = SymGetModuleBase64(process, frame.AddrPC.Offset)) {
if (WinFctHelper::GetModuleFileName((HINSTANCE)module_base, module_name_raw)) {
@ -230,18 +230,18 @@ namespace YYCC::ExceptionHelper {
}
// get source file and line
const char* source_file = "<unknown source>";
const yycc_char8_t* source_file = YYCC_U8("<unknown source>");
DWORD64 source_file_line = 0;
DWORD dwDisplacement;
IMAGEHLP_LINE64 winline;
winline.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &dwDisplacement, &winline)) {
source_file = winline.FileName;
source_file = EncodingHelper::ToUTF8(winline.FileName); // TODO: check whether there is UNICODE file name.
source_file_line = winline.LineNumber;
}
// write to file
UExceptionErrLogFormatLine(fs, "0x%" PRI_XPTR_LEFT_PADDING PRIXPTR "[%s+0x%" PRI_XPTR_LEFT_PADDING PRIXPTR "]\t%s#L%" PRIu64,
UExceptionErrLogFormatLine(fs, YYCC_U8("0x%" PRI_XPTR_LEFT_PADDING PRIXPTR "[%s+0x%" PRI_XPTR_LEFT_PADDING PRIXPTR "]\t%s#L%" PRIu64),
frame.AddrPC.Offset, // memory adress
module_name, frame.AddrPC.Offset - module_base, // module name + relative address
source_file, source_file_line // source file + source line
@ -255,16 +255,16 @@ namespace YYCC::ExceptionHelper {
SymCleanup(process);
}
static void UExceptionErrorLog(const std::string& u8_filename, LPEXCEPTION_POINTERS info) {
static void UExceptionErrorLog(const yycc_u8string& u8_filename, LPEXCEPTION_POINTERS info) {
// open file stream if we have file name
std::FILE* fs = nullptr;
if (!u8_filename.empty()) {
fs = IOHelper::UTF8FOpen(u8_filename.c_str(), "wb");
fs = IOHelper::UTF8FOpen(u8_filename.c_str(), YYCC_U8("wb"));
}
// record exception type first
PEXCEPTION_RECORD rec = info->ExceptionRecord;
UExceptionErrLogFormatLine(fs, "Unhandled exception occured at 0x%" PRI_XPTR_LEFT_PADDING PRIXPTR ": %s (%" PRIu32 ").",
UExceptionErrLogFormatLine(fs, YYCC_U8("Unhandled exception occured at 0x%" PRI_XPTR_LEFT_PADDING PRIXPTR ": %s (%" PRIu32 ")."),
rec->ExceptionAddress,
UExceptionGetCodeName(rec->ExceptionCode),
rec->ExceptionCode
@ -276,7 +276,7 @@ namespace YYCC::ExceptionHelper {
const char* op =
rec->ExceptionInformation[0] == 0 ? "read" :
rec->ExceptionInformation[0] == 1 ? "written" : "executed";
UExceptionErrLogFormatLine(fs, "The data at memory address 0x%" PRI_XPTR_LEFT_PADDING PRIxPTR " could not be %s.",
UExceptionErrLogFormatLine(fs, YYCC_U8("The data at memory address 0x%" PRI_XPTR_LEFT_PADDING PRIxPTR " could not be %s."),
rec->ExceptionInformation[1], op);
}
}
@ -290,12 +290,12 @@ namespace YYCC::ExceptionHelper {
}
}
static void UExceptionCoreDump(const std::string& u8_filename, LPEXCEPTION_POINTERS info) {
static void UExceptionCoreDump(const yycc_u8string& u8_filename, LPEXCEPTION_POINTERS info) {
// convert file encoding
std::wstring filename;
if (u8_filename.empty())
return; // if no given file name, return
if (!YYCC::EncodingHelper::UTF8ToWchar(u8_filename.c_str(), filename))
if (!YYCC::EncodingHelper::UTF8ToWchar(u8_filename, filename))
return; // if convertion failed, return
// open file and write
@ -315,18 +315,18 @@ namespace YYCC::ExceptionHelper {
}
}
static bool UExceptionFetchRecordPath(std::string& log_path, std::string& coredump_path) {
static bool UExceptionFetchRecordPath(yycc_u8string& log_path, yycc_u8string& coredump_path) {
// build two file names like: "module.dll.1234.log" and "module.dll.1234.dmp".
// "module.dll" is the name of current module. "1234" is current process id.
// get self module name
std::string u8_self_module_name;
yycc_u8string u8_self_module_name;
{
// get module handle
HMODULE hSelfModule = YYCC::WinFctHelper::GetCurrentModule();
if (hSelfModule == nullptr)
return false;
// get full path of self module
std::string u8_self_module_path;
yycc_u8string u8_self_module_path;
if (!YYCC::WinFctHelper::GetModuleFileName(hSelfModule, u8_self_module_path))
return false;
// extract file name from full path by std::filesystem::path
@ -336,22 +336,22 @@ namespace YYCC::ExceptionHelper {
// then get process id
DWORD process_id = GetCurrentProcessId();
// conbine them as a file name prefix
std::string u8_filename_prefix;
if (!YYCC::StringHelper::Printf(u8_filename_prefix, "%s.%" PRIu32, u8_self_module_name.c_str(), process_id))
yycc_u8string u8_filename_prefix;
if (!YYCC::StringHelper::Printf(u8_filename_prefix, YYCC_U8("%s.%" PRIu32), u8_self_module_name.c_str(), process_id))
return false;
// then get file name for log and minidump
std::string u8_log_filename = u8_filename_prefix + ".log";
std::string u8_coredump_filename = u8_filename_prefix + ".dmp";
yycc_u8string u8_log_filename = u8_filename_prefix + YYCC_U8(".log");
yycc_u8string u8_coredump_filename = u8_filename_prefix + YYCC_U8(".dmp");
// fetch crash report path
// get local appdata folder
std::string u8_localappdata_path;
yycc_u8string u8_localappdata_path;
if (!WinFctHelper::GetLocalAppData(u8_localappdata_path))
return false;
// convert to std::filesystem::path
std::filesystem::path crash_report_path(FsPathPatch::FromUTF8Path(u8_localappdata_path.c_str()));
// slash into crash report folder
crash_report_path /= FsPathPatch::FromUTF8Path("CrashDumps");
crash_report_path /= FsPathPatch::FromUTF8Path(YYCC_U8("CrashDumps"));
// use create function to make sure it is existing
std::filesystem::create_directories(crash_report_path);
@ -375,18 +375,18 @@ namespace YYCC::ExceptionHelper {
// core implementation
{
// fetch error report path first
std::string log_path, coredump_path;
yycc_u8string log_path, coredump_path;
if (!UExceptionFetchRecordPath(log_path, coredump_path)) {
// fail to fetch path, clear them.
// we still can handle crash without them
log_path.clear();
coredump_path.clear();
// and tell user we can not output file
ConsoleHelper::ErrWriteLine("Crash occurs, but we can not create crash log and coredump!");
ConsoleHelper::ErrWriteLine(YYCC_U8("Crash occurs, but we can not create crash log and coredump!"));
} else {
// okey. output file path to tell user the path where you can find.
ConsoleHelper::ErrFormatLine("Crash Log: %s", log_path.c_str());
ConsoleHelper::ErrFormatLine("Crash Coredump: %s", coredump_path.c_str());
ConsoleHelper::ErrFormatLine(YYCC_U8("Crash Log: %s"), log_path.c_str());
ConsoleHelper::ErrFormatLine(YYCC_U8("Crash Coredump: %s"), coredump_path.c_str());
}
// write crash log

View File

@ -6,7 +6,7 @@
namespace YYCC::FsPathPatch {
std::filesystem::path FromUTF8Path(const char* u8_path) {
std::filesystem::path FromUTF8Path(const yycc_char8_t* u8_path) {
#if YYCC_OS == YYCC_OS_WINDOWS
// convert path to wchar
@ -14,19 +14,19 @@ namespace YYCC::FsPathPatch {
if (!YYCC::EncodingHelper::UTF8ToWchar(u8_path, wpath))
throw std::invalid_argument("Fail to convert given UTF8 string.");
// call microsoft specified fopen which support wchar as argument.
// return path with wchar_t ctor
return std::filesystem::path(wpath);
#else
return std::filesystem::path(u8_path);
return std::filesystem::path(EncodingHelper::ToNative(u8_path));
#endif
}
std::string ToUTF8Path(const std::filesystem::path& path) {
yycc_u8string ToUTF8Path(const std::filesystem::path& path) {
#if YYCC_OS == YYCC_OS_WINDOWS
// get and convert to utf8
std::string u8_path;
yycc_u8string u8_path;
if (!YYCC::EncodingHelper::WcharToUTF8(path.c_str(), u8_path))
throw std::invalid_argument("Fail to convert to UTF8 string.");
@ -34,7 +34,7 @@ namespace YYCC::FsPathPatch {
return u8_path;
#else
return path.string();
return EncodingHelper::ToUTF8(path.string());
#endif
}

View File

@ -28,7 +28,7 @@ namespace YYCC::FsPathPatch {
* @return std::filesystem::path instance.
* @exception std::invalid_argument Fail to parse given UTF8 string (maybe invalid?).
*/
std::filesystem::path FromUTF8Path(const char* u8_path);
std::filesystem::path FromUTF8Path(const yycc_char8_t* u8_path);
/**
* @brief Returns the UTF8 representation of the pathname
@ -36,6 +36,6 @@ namespace YYCC::FsPathPatch {
* @return UTF8 encoded string representing given path.
* @exception std::invalid_argument Fail to parse to UTF8 string.
*/
std::string ToUTF8Path(const std::filesystem::path& path);
yycc_u8string ToUTF8Path(const std::filesystem::path& path);
}

View File

@ -14,7 +14,7 @@
namespace YYCC::IOHelper {
FILE* UTF8FOpen(const char* u8_filepath, const char* u8_mode) {
FILE* UTF8FOpen(const yycc_char8_t* u8_filepath, const yycc_char8_t* u8_mode) {
#if YYCC_OS == YYCC_OS_WINDOWS
// convert mode and file path to wchar

View File

@ -32,6 +32,6 @@ namespace YYCC::IOHelper {
* On other platforms, this function will delegate request directly to std::fopen.
* @return FILE* of the file to be opened, or nullptr if failed.
*/
FILE* UTF8FOpen(const char* u8_filepath, const char* u8_mode);
FILE* UTF8FOpen(const yycc_char8_t* u8_filepath, const yycc_char8_t* u8_mode);
}

View File

@ -14,11 +14,15 @@ namespace YYCC::ParserHelper {
// Reference: https://zh.cppreference.com/w/cpp/utility/from_chars
template<typename _Ty, std::enable_if_t<std::is_floating_point_v<_Ty>, int> = 0>
bool TryParse(const std::string& strl, _Ty& num) {
auto [ptr, ec] = std::from_chars(strl.c_str(), strl.c_str() + strl.size(), num, std::chars_format::general);
bool TryParse(const yycc_u8string_view& strl, _Ty& num) {
auto [ptr, ec] = std::from_chars(
EncodingHelper::ToNative(strl.data()),
EncodingHelper::ToNative(strl.data() + strl.size()),
num, std::chars_format::general
);
if (ec == std::errc()) {
// check whether the full string is matched
return ptr == strl.c_str() + strl.size();
return ptr == EncodingHelper::ToNative(strl.data() + strl.size());
} else if (ec == std::errc::invalid_argument) {
// given string is invalid
return false;
@ -31,11 +35,15 @@ namespace YYCC::ParserHelper {
}
}
template<typename _Ty, std::enable_if_t<std::is_integral_v<_Ty> && !std::is_same_v<_Ty, bool>, int> = 0>
bool TryParse(const std::string& strl, _Ty& num, int base = 10) {
auto [ptr, ec] = std::from_chars(strl.c_str(), strl.c_str() + strl.size(), num, base);
bool TryParse(const yycc_u8string_view& strl, _Ty& num, int base = 10) {
auto [ptr, ec] = std::from_chars(
EncodingHelper::ToNative(strl.data()),
EncodingHelper::ToNative(strl.data() + strl.size()),
num, base
);
if (ec == std::errc()) {
// check whether the full string is matched
return ptr == strl.c_str() + strl.size();
return ptr == EncodingHelper::ToNative(strl.data() + strl.size());
} else if (ec == std::errc::invalid_argument) {
// given string is invalid
return false;
@ -48,15 +56,15 @@ namespace YYCC::ParserHelper {
}
}
template<typename _Ty, std::enable_if_t<std::is_same_v<_Ty, bool>, int> = 0>
bool TryParse(const std::string& strl, _Ty& num) {
if (strl == "true") num = true;
else if (strl == "false") num = false;
bool TryParse(const yycc_u8string_view& strl, _Ty& num) {
if (strl == YYCC_U8("true")) num = true;
else if (strl == YYCC_U8("false")) num = false;
else return false;
return true;
}
template<typename _Ty, std::enable_if_t<std::is_arithmetic_v<_Ty>, int> = 0>
_Ty Parse(const std::string& strl) {
_Ty Parse(const yycc_u8string_view& strl) {
_Ty ret;
TryParse(strl, ret);
return ret;
@ -65,11 +73,15 @@ namespace YYCC::ParserHelper {
// Reference: https://en.cppreference.com/w/cpp/utility/to_chars
template<typename _Ty, std::enable_if_t<std::is_arithmetic_v<_Ty> && !std::is_same_v<_Ty, bool>, int> = 0>
std::string ToString(_Ty num) {
std::array<char, 64> buffer;
auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), num);
yycc_u8string ToString(_Ty num) {
std::array<yycc_char8_t, 64> buffer;
auto [ptr, ec] = std::to_chars(
EncodingHelper::ToNative(buffer.data()),
EncodingHelper::ToNative(buffer.data() + buffer.size()),
num
);
if (ec == std::errc()) {
return std::string(buffer.data(), ptr - buffer.data());
return yycc_u8string(buffer.data(), ptr - buffer.data());
} else if (ec == std::errc::value_too_large) {
// too short buffer
// this should not happend
@ -80,9 +92,9 @@ namespace YYCC::ParserHelper {
}
}
template<typename _Ty, std::enable_if_t<std::is_same_v<_Ty, bool>, int> = 0>
std::string ToString(_Ty num) {
if (num) return std::string("true");
else return std::string("false");
yycc_u8string ToString(_Ty num) {
if (num) return yycc_u8string(YYCC_U8("true"));
else return yycc_u8string(YYCC_U8("false"));
}
}

View File

@ -17,7 +17,7 @@ namespace YYCC::WinFctHelper {
return hModule;
}
bool GetTempDirectory(std::string& ret) {
bool GetTempDirectory(yycc_u8string& ret) {
// create wchar buffer for receiving the temp path.
std::wstring wpath(MAX_PATH + 1u, L'\0');
DWORD expected_size;
@ -41,10 +41,10 @@ namespace YYCC::WinFctHelper {
// resize result
wpath.resize(expected_size);
// convert to utf8 and return
return YYCC::EncodingHelper::WcharToUTF8(wpath.c_str(), ret);
return YYCC::EncodingHelper::WcharToUTF8(wpath, ret);
}
bool GetModuleFileName(HINSTANCE hModule, std::string& ret) {
bool GetModuleFileName(HINSTANCE hModule, yycc_u8string& ret) {
// create wchar buffer for receiving the temp path.
std::wstring wpath(MAX_PATH + 1u, L'\0');
DWORD copied_size;
@ -68,10 +68,13 @@ namespace YYCC::WinFctHelper {
// resize result
wpath.resize(copied_size);
// convert to utf8 and return
return YYCC::EncodingHelper::WcharToUTF8(wpath.c_str(), ret);
return YYCC::EncodingHelper::WcharToUTF8(wpath, ret);
}
bool GetLocalAppData(std::string& ret) {
bool GetLocalAppData(yycc_u8string& ret) {
// check whether com initialized
if (!COMHelper::IsInitialized()) return false;
// fetch path
LPWSTR _known_path;
HRESULT hr = SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &_known_path);

View File

@ -36,7 +36,7 @@ namespace YYCC::WinFctHelper {
* The variable receiving UTF8 encoded path to Windows temp folder.
* @return True if success, otherwise false.
*/
bool GetTempDirectory(std::string& ret);
bool GetTempDirectory(yycc_u8string& ret);
/**
* @brief Get the file name of given module HANDLE
@ -47,7 +47,7 @@ namespace YYCC::WinFctHelper {
* The variable receiving UTF8 encoded file name of given module.
* @return True if success, otherwise false.
*/
bool GetModuleFileName(HINSTANCE hModule, std::string& ret);
bool GetModuleFileName(HINSTANCE hModule, yycc_u8string& ret);
/**
* @brief Get the path to LOCALAPPDATA.
@ -56,7 +56,7 @@ namespace YYCC::WinFctHelper {
* The variable receiving UTF8 encoded path to LOCALAPPDATA.
* @return
*/
bool GetLocalAppData(std::string& ret);
bool GetLocalAppData(yycc_u8string& ret);
}

View File

@ -8,7 +8,7 @@
#include "COMHelper.hpp"
#include "DialogHelper.hpp"
#include "ParserHelper.hpp"
#include "ExceptionHelper.hpp"
#include "IOHelper.hpp"
#include "WinFctHelper.hpp"
#include "FsPathPatch.hpp"
#include "ExceptionHelper.hpp"

View File

@ -23,12 +23,12 @@ namespace YYCCTestbench {
#define TEST_UNICODE_STR_EMOJI "\U0001F363 \u2716 \U0001F37A" // sushi x beer mug
#define CONCAT(prefix, strl) prefix ## strl
#define CPP_U8_LITERAL(strl) reinterpret_cast<const char*>(CONCAT(u8, strl))
#define CPP_U8_LITERAL(strl) YYCC_U8(strl)
#define CPP_U16_LITERAL(strl) CONCAT(u, strl)
#define CPP_U32_LITERAL(strl) CONCAT(U, strl)
#define CPP_WSTR_LITERAL(strl) CONCAT(L, strl)
static std::vector<std::string> c_UTF8TestStrTable {
static std::vector<YYCC::yycc_u8string> c_UTF8TestStrTable {
CPP_U8_LITERAL(TEST_UNICODE_STR_JAPAN),
CPP_U8_LITERAL(TEST_UNICODE_STR_CHINA),
CPP_U8_LITERAL(TEST_UNICODE_STR_KOREA),