diff --git a/src/ConsoleHelper.cpp b/src/ConsoleHelper.cpp index 4bd25dc..bd16e27 100644 --- a/src/ConsoleHelper.cpp +++ b/src/ConsoleHelper.cpp @@ -54,7 +54,7 @@ namespace YYCC::ConsoleHelper { */ template - 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::max()) { @@ -176,7 +176,7 @@ namespace YYCC::ConsoleHelper { #endif } - std::string ReadLine() { + yycc_u8string ReadLine() { #if YYCC_OS == YYCC_OS_WINDOWS // get stdin mode @@ -188,24 +188,24 @@ namespace YYCC::ConsoleHelper { } else { return WinConsoleRead(hStdIn); } - + #else // 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 - 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,62 +218,62 @@ namespace YYCC::ConsoleHelper { } // Checkout whether add EOL if constexpr (bHasEOL) { - strl += "\n"; + strl += YYCC_U8("\n"); } - + #if YYCC_OS == YYCC_OS_WINDOWS // call Windows specific writer 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(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(u8_fmt, argptr); va_end(argptr); } - void Write(const char* u8_strl) { + void Write(const yycc_char8_t* u8_strl) { va_list empty{}; RawWrite(u8_strl, empty); } - void WriteLine(const char* u8_strl) { + void WriteLine(const yycc_char8_t* u8_strl) { va_list empty{}; RawWrite(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(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(u8_fmt, argptr); va_end(argptr); } - void ErrWrite(const char* u8_strl) { + void ErrWrite(const yycc_char8_t* u8_strl) { va_list empty{}; RawWrite(u8_strl, empty); } - void ErrWriteLine(const char* u8_strl) { + void ErrWriteLine(const yycc_char8_t* u8_strl) { va_list empty{}; RawWrite(u8_strl, empty); } diff --git a/src/ConsoleHelper.hpp b/src/ConsoleHelper.hpp index 683dbbc..5e7eb35 100644 --- a/src/ConsoleHelper.hpp +++ b/src/ConsoleHelper.hpp @@ -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); } diff --git a/src/DialogHelper.cpp b/src/DialogHelper.cpp index 8c807e9..7aad925 100644 --- a/src/DialogHelper.cpp +++ b/src/DialogHelper.cpp @@ -8,16 +8,16 @@ namespace YYCC::DialogHelper { #pragma region FileFilters - bool FileFilters::Add(const char* filter_name, std::initializer_list il) { + bool FileFilters::Add(const yycc_char8_t* filter_name, std::initializer_list 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 - static bool CommonFileDialog(const FileDialog& params, std::vector& ret) { + static bool CommonFileDialog(const FileDialog& params, std::vector& 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 cache; + bool OpenFileDialog(const FileDialog& params, yycc_u8string& ret) { + std::vector cache; bool isok = CommonFileDialog(params, cache); if (isok) ret = cache.front(); return isok; } - bool OpenMultipleFileDialog(const FileDialog& params, std::vector& ret) { + bool OpenMultipleFileDialog(const FileDialog& params, std::vector& ret) { return CommonFileDialog(params, ret); } - bool SaveFileDialog(const FileDialog& params, std::string& ret) { - std::vector cache; + bool SaveFileDialog(const FileDialog& params, yycc_u8string& ret) { + std::vector cache; bool isok = CommonFileDialog(params, cache); if (isok) ret = cache.front(); return isok; } - bool OpenFolderDialog(const FileDialog& params, std::string& ret) { - std::vector cache; + bool OpenFolderDialog(const FileDialog& params, yycc_u8string& ret) { + std::vector cache; bool isok = CommonFileDialog(params, cache); if (isok) ret = cache.front(); return isok; diff --git a/src/DialogHelper.hpp b/src/DialogHelper.hpp index b5bc554..6dbe54a 100644 --- a/src/DialogHelper.hpp +++ b/src/DialogHelper.hpp @@ -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 il); + bool Add(const yycc_char8_t* filter_name, std::initializer_list 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; - using FilterName = std::string; + using FilterModes = std::vector; + using FilterName = yycc_u8string; using FilterPair = std::pair; std::vector 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& ret); - bool SaveFileDialog(const FileDialog& params, std::string& ret); + bool OpenFileDialog(const FileDialog& params, yycc_u8string& ret); + bool OpenMultipleFileDialog(const FileDialog& params, std::vector& 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); } diff --git a/src/EncodingHelper.hpp b/src/EncodingHelper.hpp index 0267f96..f310afc 100644 --- a/src/EncodingHelper.hpp +++ b/src/EncodingHelper.hpp @@ -50,7 +50,7 @@ */ namespace YYCC::EncodingHelper { -#define YYCC_U8(strl) (reinterpret_cast(u8 ## strl)) +#define YYCC_U8(strl) (reinterpret_cast(u8 ## strl)) const yycc_char8_t* ToUTF8(const char* src); yycc_char8_t* ToUTF8(char* src); diff --git a/src/ExceptionHelper.cpp b/src/ExceptionHelper.cpp index 5201f46..388f093 100644 --- a/src/ExceptionHelper.cpp +++ b/src/ExceptionHelper.cpp @@ -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 = ""; - std::string module_name_raw; + const yycc_char8_t* module_name = YYCC_U8(""); + 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 = ""; + const yycc_char8_t* source_file = YYCC_U8(""); 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 diff --git a/src/FsPathPatch.cpp b/src/FsPathPatch.cpp index 37f33f6..5977db9 100644 --- a/src/FsPathPatch.cpp +++ b/src/FsPathPatch.cpp @@ -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 } diff --git a/src/FsPathPatch.hpp b/src/FsPathPatch.hpp index 799d585..87fa0cd 100644 --- a/src/FsPathPatch.hpp +++ b/src/FsPathPatch.hpp @@ -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); } diff --git a/src/IOHelper.cpp b/src/IOHelper.cpp index e2b0f52..6c7d57e 100644 --- a/src/IOHelper.cpp +++ b/src/IOHelper.cpp @@ -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 diff --git a/src/IOHelper.hpp b/src/IOHelper.hpp index ab77694..d56925e 100644 --- a/src/IOHelper.hpp +++ b/src/IOHelper.hpp @@ -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); } diff --git a/src/ParserHelper.hpp b/src/ParserHelper.hpp index b23dba7..4722249 100644 --- a/src/ParserHelper.hpp +++ b/src/ParserHelper.hpp @@ -14,11 +14,15 @@ namespace YYCC::ParserHelper { // Reference: https://zh.cppreference.com/w/cpp/utility/from_chars template, 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 && !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, 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, 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 && !std::is_same_v<_Ty, bool>, int> = 0> - std::string ToString(_Ty num) { - std::array buffer; - auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), num); + yycc_u8string ToString(_Ty num) { + std::array 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, 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")); } } diff --git a/src/WinFctHelper.cpp b/src/WinFctHelper.cpp index eedf280..130662d 100644 --- a/src/WinFctHelper.cpp +++ b/src/WinFctHelper.cpp @@ -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); diff --git a/src/WinFctHelper.hpp b/src/WinFctHelper.hpp index f4c7651..a66f430 100644 --- a/src/WinFctHelper.hpp +++ b/src/WinFctHelper.hpp @@ -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); } diff --git a/src/YYCCommonplace.hpp b/src/YYCCommonplace.hpp index c85e045..865c191 100644 --- a/src/YYCCommonplace.hpp +++ b/src/YYCCommonplace.hpp @@ -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" diff --git a/testbench/main.cpp b/testbench/main.cpp index 82dd606..b893ce4 100644 --- a/testbench/main.cpp +++ b/testbench/main.cpp @@ -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(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 c_UTF8TestStrTable { + static std::vector c_UTF8TestStrTable { CPP_U8_LITERAL(TEST_UNICODE_STR_JAPAN), CPP_U8_LITERAL(TEST_UNICODE_STR_CHINA), CPP_U8_LITERAL(TEST_UNICODE_STR_KOREA),