refactor: update all modules for UTF8 string. waiting for debugging
This commit is contained in:
		| @ -54,7 +54,7 @@ namespace YYCC::ConsoleHelper { | |||||||
| 	*/ | 	*/ | ||||||
|  |  | ||||||
| 	template<bool _bIsConsole> | 	template<bool _bIsConsole> | ||||||
| 	static std::string WinConsoleRead(HANDLE hStdIn) { | 	static yycc_u8string WinConsoleRead(HANDLE hStdIn) { | ||||||
| 		using _TChar = std::conditional_t<_bIsConsole, wchar_t, char>; | 		using _TChar = std::conditional_t<_bIsConsole, wchar_t, char>; | ||||||
|  |  | ||||||
| 		// Prepare an internal buffer because the read data may not be fully used. | 		// 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 | 		// post-process for return value | ||||||
| 		std::string real_return_buffer; | 		yycc_u8string real_return_buffer; | ||||||
| 		if constexpr (_bIsConsole) { | 		if constexpr (_bIsConsole) { | ||||||
| 			// console mode need convert wchar to utf8 | 			// 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 { | 		} else { | ||||||
| 			// non-console just copt the result | 			// non-console just copt the result | ||||||
| 			real_return_buffer = return_buffer; | 			real_return_buffer = EncodingHelper::ToUTF8(return_buffer); | ||||||
| 		} | 		} | ||||||
| 		// every mode need delete \r words | 		// 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 value | ||||||
| 		return real_return_buffer; | 		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 | 		// Prepare some Win32 variables | ||||||
| 		// fetch stdout handle first | 		// fetch stdout handle first | ||||||
| 		HANDLE hStdOut = GetStdHandle(to_stderr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE); | 		HANDLE hStdOut = GetStdHandle(to_stderr ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE); | ||||||
| @ -139,7 +139,7 @@ namespace YYCC::ConsoleHelper { | |||||||
| 		if (GetConsoleMode(hStdOut, &dwConsoleMode)) { | 		if (GetConsoleMode(hStdOut, &dwConsoleMode)) { | ||||||
| 			// console handle, use WriteConsoleW. | 			// console handle, use WriteConsoleW. | ||||||
| 			// convert utf8 string to wide char first | 			// 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(); | 			size_t wstrl_size = wstrl.size(); | ||||||
| 			// write string with size check | 			// write string with size check | ||||||
| 			if (wstrl_size <= std::numeric_limits<DWORD>::max()) { | 			if (wstrl_size <= std::numeric_limits<DWORD>::max()) { | ||||||
| @ -176,7 +176,7 @@ namespace YYCC::ConsoleHelper { | |||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	std::string ReadLine() { | 	yycc_u8string ReadLine() { | ||||||
| #if YYCC_OS == YYCC_OS_WINDOWS | #if YYCC_OS == YYCC_OS_WINDOWS | ||||||
|  |  | ||||||
| 		// get stdin mode | 		// get stdin mode | ||||||
| @ -188,24 +188,24 @@ namespace YYCC::ConsoleHelper { | |||||||
| 		} else { | 		} else { | ||||||
| 			return WinConsoleRead<false>(hStdIn); | 			return WinConsoleRead<false>(hStdIn); | ||||||
| 		} | 		} | ||||||
|  | 		 | ||||||
| #else | #else | ||||||
|  |  | ||||||
| 		// in linux, directly use C++ function to fetch. | 		// in linux, directly use C++ function to fetch. | ||||||
| 		std::string cmd; | 		std::string cmd; | ||||||
| 		if (std::getline(std::cin, cmd).fail()) cmd.clear(); | 		if (std::getline(std::cin, cmd).fail()) cmd.clear(); | ||||||
| 		return cmd; | 		return EncodingHelper::ToUTF8(cmd); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template<bool bNeedFmt, bool bIsErr, bool bHasEOL> | 	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 | 		// Buiild string need to be written first | ||||||
| 		// If no format string or plain string for writing, return. | 		// If no format string or plain string for writing, return. | ||||||
| 		if (u8_fmt == nullptr) return; | 		if (u8_fmt == nullptr) return; | ||||||
| 		// Build or simply copy string | 		// Build or simply copy string | ||||||
| 		std::string strl; | 		yycc_u8string strl; | ||||||
| 		if constexpr (bNeedFmt) { | 		if constexpr (bNeedFmt) { | ||||||
| 			// treat as format string | 			// treat as format string | ||||||
| 			va_list argcpy; | 			va_list argcpy; | ||||||
| @ -218,62 +218,62 @@ namespace YYCC::ConsoleHelper { | |||||||
| 		} | 		} | ||||||
| 		// Checkout whether add EOL | 		// Checkout whether add EOL | ||||||
| 		if constexpr (bHasEOL) { | 		if constexpr (bHasEOL) { | ||||||
| 			strl += "\n"; | 			strl += YYCC_U8("\n"); | ||||||
| 		} | 		} | ||||||
|  | 		 | ||||||
| #if YYCC_OS == YYCC_OS_WINDOWS | #if YYCC_OS == YYCC_OS_WINDOWS | ||||||
| 		// call Windows specific writer | 		// call Windows specific writer | ||||||
| 		WinConsoleWrite(strl, bIsErr); | 		WinConsoleWrite(strl, bIsErr); | ||||||
| #else | #else | ||||||
| 		// in linux, directly use C function to write. | 		// 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 | #endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void Format(const char* u8_fmt, ...) { | 	void Format(const yycc_char8_t* u8_fmt, ...) { | ||||||
| 		va_list argptr; | 		va_list argptr; | ||||||
| 		va_start(argptr, u8_fmt); | 		va_start(argptr, u8_fmt); | ||||||
| 		RawWrite<true, false, false>(u8_fmt, argptr); | 		RawWrite<true, false, false>(u8_fmt, argptr); | ||||||
| 		va_end(argptr); | 		va_end(argptr); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void FormatLine(const char* u8_fmt, ...) { | 	void FormatLine(const yycc_char8_t* u8_fmt, ...) { | ||||||
| 		va_list argptr; | 		va_list argptr; | ||||||
| 		va_start(argptr, u8_fmt); | 		va_start(argptr, u8_fmt); | ||||||
| 		RawWrite<true, false, true>(u8_fmt, argptr); | 		RawWrite<true, false, true>(u8_fmt, argptr); | ||||||
| 		va_end(argptr); | 		va_end(argptr); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void Write(const char* u8_strl) { | 	void Write(const yycc_char8_t* u8_strl) { | ||||||
| 		va_list empty{}; | 		va_list empty{}; | ||||||
| 		RawWrite<false, false, false>(u8_strl, 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{}; | 		va_list empty{}; | ||||||
| 		RawWrite<false, false, true>(u8_strl, 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_list argptr; | ||||||
| 		va_start(argptr, u8_fmt); | 		va_start(argptr, u8_fmt); | ||||||
| 		RawWrite<true, true, false>(u8_fmt, argptr); | 		RawWrite<true, true, false>(u8_fmt, argptr); | ||||||
| 		va_end(argptr); | 		va_end(argptr); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void ErrFormatLine(const char* u8_fmt, ...) { | 	void ErrFormatLine(const yycc_char8_t* u8_fmt, ...) { | ||||||
| 		va_list argptr; | 		va_list argptr; | ||||||
| 		va_start(argptr, u8_fmt); | 		va_start(argptr, u8_fmt); | ||||||
| 		RawWrite<true, true, true>(u8_fmt, argptr); | 		RawWrite<true, true, true>(u8_fmt, argptr); | ||||||
| 		va_end(argptr); | 		va_end(argptr); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void ErrWrite(const char* u8_strl) { | 	void ErrWrite(const yycc_char8_t* u8_strl) { | ||||||
| 		va_list empty{}; | 		va_list empty{}; | ||||||
| 		RawWrite<false, true, false>(u8_strl, 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{}; | 		va_list empty{}; | ||||||
| 		RawWrite<false, true, true>(u8_strl, empty); | 		RawWrite<false, true, true>(u8_strl, empty); | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -124,52 +124,52 @@ namespace YYCC::ConsoleHelper { | |||||||
| 	 * This function also can be used as ordering user press Enter key by | 	 * This function also can be used as ordering user press Enter key by | ||||||
| 	 * simply calling this function and ignoring its return value. | 	 * simply calling this function and ignoring its return value. | ||||||
| 	*/ | 	*/ | ||||||
| 	std::string ReadLine(); | 	yycc_u8string ReadLine(); | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @brief Universal console write function with format feature. | 	 * @brief Universal console write function with format feature. | ||||||
| 	 * @param[in] u8_fmt The format string. | 	 * @param[in] u8_fmt The format string. | ||||||
| 	 * @param[in] ... The arguments to be formatted. | 	 * @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. | 	 * @brief Universal console write function with format and auto EOL feature. | ||||||
| 	 * @param[in] u8_fmt The format string. | 	 * @param[in] u8_fmt The format string. | ||||||
| 	 * @param[in] ... The arguments to be formatted. | 	 * @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. | 	 * @brief Universal console write function. | ||||||
| 	 * @param[in] u8_strl The string to be written. | 	 * @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. | 	 * @brief Universal console write function with auto EOL feature. | ||||||
| 	 * @param[in] u8_strl The string to be written. | 	 * @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. | 	 * @brief Universal console error write function with format and feature. | ||||||
| 	 * @param[in] u8_fmt The format string. | 	 * @param[in] u8_fmt The format string. | ||||||
| 	 * @param[in] ... The arguments to be formatted. | 	 * @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. | 	 * @brief Universal console error write function with format and auto EOL feature. | ||||||
| 	 * @param[in] u8_fmt The format string. | 	 * @param[in] u8_fmt The format string. | ||||||
| 	 * @param[in] ... The arguments to be formatted. | 	 * @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. | 	 * @brief Universal console error write function. | ||||||
| 	 * @param[in] u8_strl The string to be written. | 	 * @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. | 	 * @brief Universal console error write function with auto EOL feature. | ||||||
| 	 * @param[in] u8_strl The string to be written. | 	 * @param[in] u8_strl The string to be written. | ||||||
| 	*/ | 	*/ | ||||||
| 	void ErrWriteLine(const char* u8_strl); | 	void ErrWriteLine(const yycc_char8_t* u8_strl); | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,16 +8,16 @@ namespace YYCC::DialogHelper { | |||||||
|  |  | ||||||
| #pragma region FileFilters | #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 | 		// assign filter name | ||||||
| 		if (filter_name == nullptr) return false; | 		if (filter_name == nullptr) return false; | ||||||
| 		FilterName name(filter_name); | 		FilterName name(filter_name); | ||||||
|  |  | ||||||
| 		// assign filter patterns | 		// assign filter patterns | ||||||
| 		FilterModes modes; | 		FilterModes modes; | ||||||
| 		for (const char* pattern : il) { | 		for (const yycc_char8_t* pattern : il) { | ||||||
| 			if (pattern != nullptr) | 			if (pattern != nullptr) | ||||||
| 				modes.emplace_back(std::string(pattern)); | 				modes.emplace_back(yycc_u8string(pattern)); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// check filter patterns | 		// check filter patterns | ||||||
| @ -36,13 +36,13 @@ namespace YYCC::DialogHelper { | |||||||
| 		for (const auto& it : m_Filters) { | 		for (const auto& it : m_Filters) { | ||||||
| 			// convert name to wchar | 			// convert name to wchar | ||||||
| 			WinFileFilters::WinFilterName name; | 			WinFileFilters::WinFilterName name; | ||||||
| 			if (!YYCC::EncodingHelper::UTF8ToWchar(it.first.c_str(), name)) | 			if (!YYCC::EncodingHelper::UTF8ToWchar(it.first, name)) | ||||||
| 				return false; | 				return false; | ||||||
|  |  | ||||||
| 			// convert pattern and join them | 			// 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; | 			WinFileFilters::WinFilterModes modes; | ||||||
| 			if (!YYCC::EncodingHelper::UTF8ToWchar(joined_modes.c_str(), modes)) | 			if (!YYCC::EncodingHelper::UTF8ToWchar(joined_modes, modes)) | ||||||
| 				return false; | 				return false; | ||||||
|  |  | ||||||
| 			// append new pair | 			// append new pair | ||||||
| @ -94,12 +94,12 @@ namespace YYCC::DialogHelper { | |||||||
|  |  | ||||||
| 		// build title and init file name | 		// build title and init file name | ||||||
| 		if (m_HasTitle) { | 		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; | 				return false; | ||||||
| 			win_result.m_HasTitle = true; | 			win_result.m_HasTitle = true; | ||||||
| 		} | 		} | ||||||
| 		if (m_HasInitFileName) { | 		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; | 				return false; | ||||||
| 			win_result.m_HasInitFileName = true; | 			win_result.m_HasInitFileName = true; | ||||||
| 		} | 		} | ||||||
| @ -108,7 +108,7 @@ namespace YYCC::DialogHelper { | |||||||
| 		if (m_HasInitDirectory) { | 		if (m_HasInitDirectory) { | ||||||
| 			// convert to wpath | 			// convert to wpath | ||||||
| 			std::wstring w_init_directory; | 			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; | 				return false; | ||||||
|  |  | ||||||
| 			// fetch IShellItem* | 			// fetch IShellItem* | ||||||
| @ -143,7 +143,7 @@ namespace YYCC::DialogHelper { | |||||||
| 	 * @return True if success, otherwise false. | 	 * @return True if success, otherwise false. | ||||||
| 	 * @remarks This is an assist function of CommonFileDialog. | 	 * @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* | 		// fetch display name from IShellItem* | ||||||
| 		LPWSTR _name; | 		LPWSTR _name; | ||||||
| 		HRESULT hr = item->GetDisplayName(SIGDN_FILESYSPATH, &_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. | 	 * @remarks This function is the real underlying function of all dialog functions. | ||||||
| 	*/ | 	*/ | ||||||
| 	template<CommonFileDialogType EDialogType> | 	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 | 		// Reference: https://learn.microsoft.com/en-us/windows/win32/shell/common-file-dialog | ||||||
| 		// prepare result variable | 		// prepare result variable | ||||||
| 		HRESULT hr; | 		HRESULT hr; | ||||||
| @ -289,7 +289,7 @@ namespace YYCC::DialogHelper { | |||||||
| 				COMHelper::SmartIShellItem result_item(_item); | 				COMHelper::SmartIShellItem result_item(_item); | ||||||
|  |  | ||||||
| 				// extract display name | 				// extract display name | ||||||
| 				std::string result_name; | 				yycc_u8string result_name; | ||||||
| 				if (!ExtractDisplayName(result_item.get(), result_name)) | 				if (!ExtractDisplayName(result_item.get(), result_name)) | ||||||
| 					return false; | 					return false; | ||||||
|  |  | ||||||
| @ -326,7 +326,7 @@ namespace YYCC::DialogHelper { | |||||||
| 					COMHelper::SmartIShellItem result_item(_item); | 					COMHelper::SmartIShellItem result_item(_item); | ||||||
|  |  | ||||||
| 					// extract display name | 					// extract display name | ||||||
| 					std::string result_name; | 					yycc_u8string result_name; | ||||||
| 					if (!ExtractDisplayName(result_item.get(), result_name)) | 					if (!ExtractDisplayName(result_item.get(), result_name)) | ||||||
| 						return false; | 						return false; | ||||||
|  |  | ||||||
| @ -347,24 +347,24 @@ namespace YYCC::DialogHelper { | |||||||
|  |  | ||||||
| #pragma region Wrapper Functions | #pragma region Wrapper Functions | ||||||
|  |  | ||||||
| 	bool OpenFileDialog(const FileDialog& params, std::string& ret) { | 	bool OpenFileDialog(const FileDialog& params, yycc_u8string& ret) { | ||||||
| 		std::vector<std::string> cache; | 		std::vector<yycc_u8string> cache; | ||||||
| 		bool isok = CommonFileDialog<CommonFileDialogType::OpenFile>(params, cache); | 		bool isok = CommonFileDialog<CommonFileDialogType::OpenFile>(params, cache); | ||||||
| 		if (isok) ret = cache.front(); | 		if (isok) ret = cache.front(); | ||||||
| 		return isok; | 		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); | 		return CommonFileDialog<CommonFileDialogType::OpenMultipleFiles>(params, ret); | ||||||
| 	} | 	} | ||||||
| 	bool SaveFileDialog(const FileDialog& params, std::string& ret) { | 	bool SaveFileDialog(const FileDialog& params, yycc_u8string& ret) { | ||||||
| 		std::vector<std::string> cache; | 		std::vector<yycc_u8string> cache; | ||||||
| 		bool isok = CommonFileDialog<CommonFileDialogType::SaveFile>(params, cache); | 		bool isok = CommonFileDialog<CommonFileDialogType::SaveFile>(params, cache); | ||||||
| 		if (isok) ret = cache.front(); | 		if (isok) ret = cache.front(); | ||||||
| 		return isok; | 		return isok; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool OpenFolderDialog(const FileDialog& params, std::string& ret) { | 	bool OpenFolderDialog(const FileDialog& params, yycc_u8string& ret) { | ||||||
| 		std::vector<std::string> cache; | 		std::vector<yycc_u8string> cache; | ||||||
| 		bool isok = CommonFileDialog<CommonFileDialogType::OpenFolder>(params, cache); | 		bool isok = CommonFileDialog<CommonFileDialogType::OpenFolder>(params, cache); | ||||||
| 		if (isok) ret = cache.front(); | 		if (isok) ret = cache.front(); | ||||||
| 		return isok; | 		return isok; | ||||||
|  | |||||||
| @ -65,7 +65,7 @@ namespace YYCC::DialogHelper { | |||||||
| 		 * @remarks This function allow you register multiple filter patterns for single friendly name. | 		 * @remarks This function allow you register multiple filter patterns for single friendly name. | ||||||
| 		 * For example: `Add("Microsoft Word (*.doc; *.docx)", {"*.doc", "*.docx"})` | 		 * 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. | 		 * @brief Clear filter pairs for following re-use. | ||||||
| 		*/ | 		*/ | ||||||
| @ -85,8 +85,8 @@ namespace YYCC::DialogHelper { | |||||||
| 		bool Generate(WinFileFilters& win_result) const; | 		bool Generate(WinFileFilters& win_result) const; | ||||||
|  |  | ||||||
| 	protected: | 	protected: | ||||||
| 		using FilterModes = std::vector<std::string>; | 		using FilterModes = std::vector<yycc_u8string>; | ||||||
| 		using FilterName = std::string; | 		using FilterName = yycc_u8string; | ||||||
| 		using FilterPair = std::pair<FilterName, FilterModes>; | 		using FilterPair = std::pair<FilterName, FilterModes>; | ||||||
|  |  | ||||||
| 		std::vector<FilterPair> m_Filters; | 		std::vector<FilterPair> m_Filters; | ||||||
| @ -159,7 +159,7 @@ namespace YYCC::DialogHelper { | |||||||
| 			m_HasTitle(false), m_HasInitFileName(false), m_HasInitDirectory(false) {} | 			m_HasTitle(false), m_HasInitFileName(false), m_HasInitDirectory(false) {} | ||||||
|  |  | ||||||
| 		void SetOwner(HWND owner) { m_Owner = owner; } | 		void SetOwner(HWND owner) { m_Owner = owner; } | ||||||
| 		void SetTitle(const char* title) { | 		void SetTitle(const yycc_char8_t* title) { | ||||||
| 			if (m_HasTitle = title != nullptr) | 			if (m_HasTitle = title != nullptr) | ||||||
| 				m_Title = title; | 				m_Title = title; | ||||||
| 		} | 		} | ||||||
| @ -167,11 +167,11 @@ namespace YYCC::DialogHelper { | |||||||
| 			return m_FileTypes; | 			return m_FileTypes; | ||||||
| 		} | 		} | ||||||
| 		void SetDefaultFileTypeIndex(size_t idx) { m_DefaultFileTypeIndex = idx; } | 		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) | 			if (m_HasInitFileName = init_filename != nullptr) | ||||||
| 				m_InitFileName = init_filename; | 				m_InitFileName = init_filename; | ||||||
| 		} | 		} | ||||||
| 		void SetInitDirectory(const char* init_dir) { | 		void SetInitDirectory(const yycc_char8_t* init_dir) { | ||||||
| 			if (m_HasInitDirectory = init_dir != nullptr) | 			if (m_HasInitDirectory = init_dir != nullptr) | ||||||
| 				m_InitDirectory = init_dir; | 				m_InitDirectory = init_dir; | ||||||
| 		} | 		} | ||||||
| @ -200,7 +200,7 @@ namespace YYCC::DialogHelper { | |||||||
| 	protected: | 	protected: | ||||||
| 		HWND m_Owner; | 		HWND m_Owner; | ||||||
| 		bool m_HasTitle, m_HasInitFileName, m_HasInitDirectory; | 		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; | 		FileFilters m_FileTypes; | ||||||
| 		/** | 		/** | ||||||
| 		 * @brief The default selected file type in dialog | 		 * @brief The default selected file type in dialog | ||||||
| @ -210,11 +210,11 @@ namespace YYCC::DialogHelper { | |||||||
| 		size_t m_DefaultFileTypeIndex; | 		size_t m_DefaultFileTypeIndex; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	bool OpenFileDialog(const FileDialog& params, std::string& ret); | 	bool OpenFileDialog(const FileDialog& params, yycc_u8string& ret); | ||||||
| 	bool OpenMultipleFileDialog(const FileDialog& params, std::vector<std::string>& ret); | 	bool OpenMultipleFileDialog(const FileDialog& params, std::vector<yycc_u8string>& ret); | ||||||
| 	bool SaveFileDialog(const FileDialog& params, std::string& 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); | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -50,7 +50,7 @@ | |||||||
| */ | */ | ||||||
| namespace YYCC::EncodingHelper { | 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); | 	const yycc_char8_t* ToUTF8(const char* src); | ||||||
| 	yycc_char8_t* ToUTF8(char* src); | 	yycc_char8_t* ToUTF8(char* src); | ||||||
|  | |||||||
| @ -59,50 +59,50 @@ namespace YYCC::ExceptionHelper { | |||||||
| 	 * @param[in] code Exception code | 	 * @param[in] code Exception code | ||||||
| 	 * @return The const string pointer to corresponding exception explanation string. | 	 * @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) { | 		switch (code) { | ||||||
| 			case EXCEPTION_ACCESS_VIOLATION: | 			case EXCEPTION_ACCESS_VIOLATION: | ||||||
| 				return "access violation"; | 				return YYCC_U8("access violation"); | ||||||
| 			case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: | 			case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: | ||||||
| 				return "array index out of bound"; | 				return YYCC_U8("array index out of bound"); | ||||||
| 			case EXCEPTION_BREAKPOINT: | 			case EXCEPTION_BREAKPOINT: | ||||||
| 				return "breakpoint reached"; | 				return YYCC_U8("breakpoint reached"); | ||||||
| 			case EXCEPTION_DATATYPE_MISALIGNMENT: | 			case EXCEPTION_DATATYPE_MISALIGNMENT: | ||||||
| 				return "misaligned data access"; | 				return YYCC_U8("misaligned data access"); | ||||||
| 			case EXCEPTION_FLT_DENORMAL_OPERAND: | 			case EXCEPTION_FLT_DENORMAL_OPERAND: | ||||||
| 				return "operand had denormal value"; | 				return YYCC_U8("operand had denormal value"); | ||||||
| 			case EXCEPTION_FLT_DIVIDE_BY_ZERO: | 			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: | 			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: | 			case EXCEPTION_FLT_INVALID_OPERATION: | ||||||
| 				return "invalid floating-point operation"; | 				return YYCC_U8("invalid floating-point operation"); | ||||||
| 			case EXCEPTION_FLT_OVERFLOW: | 			case EXCEPTION_FLT_OVERFLOW: | ||||||
| 				return "floating-point overflow"; | 				return YYCC_U8("floating-point overflow"); | ||||||
| 			case EXCEPTION_FLT_STACK_CHECK: | 			case EXCEPTION_FLT_STACK_CHECK: | ||||||
| 				return "floating-point stack corruption"; | 				return YYCC_U8("floating-point stack corruption"); | ||||||
| 			case EXCEPTION_FLT_UNDERFLOW: | 			case EXCEPTION_FLT_UNDERFLOW: | ||||||
| 				return "floating-point underflow"; | 				return YYCC_U8("floating-point underflow"); | ||||||
| 			case EXCEPTION_ILLEGAL_INSTRUCTION: | 			case EXCEPTION_ILLEGAL_INSTRUCTION: | ||||||
| 				return "illegal instruction"; | 				return YYCC_U8("illegal instruction"); | ||||||
| 			case EXCEPTION_IN_PAGE_ERROR: | 			case EXCEPTION_IN_PAGE_ERROR: | ||||||
| 				return "inaccessible page"; | 				return YYCC_U8("inaccessible page"); | ||||||
| 			case EXCEPTION_INT_DIVIDE_BY_ZERO: | 			case EXCEPTION_INT_DIVIDE_BY_ZERO: | ||||||
| 				return "integer division by zero"; | 				return YYCC_U8("integer division by zero"); | ||||||
| 			case EXCEPTION_INT_OVERFLOW: | 			case EXCEPTION_INT_OVERFLOW: | ||||||
| 				return "integer overflow"; | 				return YYCC_U8("integer overflow"); | ||||||
| 			case EXCEPTION_INVALID_DISPOSITION: | 			case EXCEPTION_INVALID_DISPOSITION: | ||||||
| 				return "documentation says this should never happen"; | 				return YYCC_U8("documentation says this should never happen"); | ||||||
| 			case EXCEPTION_NONCONTINUABLE_EXCEPTION: | 			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: | 			case EXCEPTION_PRIV_INSTRUCTION: | ||||||
| 				return "attempted to execute a privileged instruction"; | 				return YYCC_U8("attempted to execute a privileged instruction"); | ||||||
| 			case EXCEPTION_SINGLE_STEP: | 			case EXCEPTION_SINGLE_STEP: | ||||||
| 				return "one instruction has been executed"; | 				return YYCC_U8("one instruction has been executed"); | ||||||
| 			case EXCEPTION_STACK_OVERFLOW: | 			case EXCEPTION_STACK_OVERFLOW: | ||||||
| 				return "stack overflow"; | 				return YYCC_U8("stack overflow"); | ||||||
| 			default: | 			default: | ||||||
| 				return "unknown exception"; | 				return YYCC_U8("unknown exception"); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -117,12 +117,12 @@ namespace YYCC::ExceptionHelper { | |||||||
| 	 * @param[in] fmt The format string. | 	 * @param[in] fmt The format string. | ||||||
| 	 * @param[in] ... The argument to be formatted. | 	 * @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 | 		// write to file | ||||||
| 		if (fs != nullptr) { | 		if (fs != nullptr) { | ||||||
| 			va_list arg1; | 			va_list arg1; | ||||||
| 			va_start(arg1, fmt); | 			va_start(arg1, fmt); | ||||||
| 			std::vfprintf(fs, fmt, arg1); | 			std::vfprintf(fs, EncodingHelper::ToNative(fmt), arg1); | ||||||
| 			std::fputs("\n", fs); | 			std::fputs("\n", fs); | ||||||
| 			va_end(arg1); | 			va_end(arg1); | ||||||
| 		} | 		} | ||||||
| @ -142,10 +142,10 @@ namespace YYCC::ExceptionHelper { | |||||||
| 	 * If it is nullptr, function will skip writing for file stream. | 	 * If it is nullptr, function will skip writing for file stream. | ||||||
| 	 * @param[in] strl The string to be written. | 	 * @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 | 		// write to file | ||||||
| 		if (fs != nullptr) { | 		if (fs != nullptr) { | ||||||
| 			std::fputs(strl, fs); | 			std::fputs(EncodingHelper::ToNative(strl), fs); | ||||||
| 			std::fputs("\n", fs); | 			std::fputs("\n", fs); | ||||||
| 		} | 		} | ||||||
| 		// write to stderr | 		// write to stderr | ||||||
| @ -163,7 +163,7 @@ namespace YYCC::ExceptionHelper { | |||||||
| 		// init symbol | 		// init symbol | ||||||
| 		if (!SymInitialize(process, 0, TRUE)) { | 		if (!SymInitialize(process, 0, TRUE)) { | ||||||
| 			// fail to init. return | 			// 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; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @ -215,13 +215,13 @@ namespace YYCC::ExceptionHelper { | |||||||
| 			// depth breaker | 			// depth breaker | ||||||
| 			--maxdepth; | 			--maxdepth; | ||||||
| 			if (maxdepth < 0) { | 			if (maxdepth < 0) { | ||||||
| 				UExceptionErrLogWriteLine(fs, "...");		// indicate there are some frames not listed | 				UExceptionErrLogWriteLine(fs, YYCC_U8("..."));		// indicate there are some frames not listed | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// get module name | 			// get module name | ||||||
| 			const char* module_name = "<unknown module>"; | 			const yycc_char8_t* module_name = YYCC_U8("<unknown module>"); | ||||||
| 			std::string module_name_raw; | 			yycc_u8string module_name_raw; | ||||||
| 			DWORD64 module_base; | 			DWORD64 module_base; | ||||||
| 			if (module_base = SymGetModuleBase64(process, frame.AddrPC.Offset)) { | 			if (module_base = SymGetModuleBase64(process, frame.AddrPC.Offset)) { | ||||||
| 				if (WinFctHelper::GetModuleFileName((HINSTANCE)module_base, module_name_raw)) { | 				if (WinFctHelper::GetModuleFileName((HINSTANCE)module_base, module_name_raw)) { | ||||||
| @ -230,18 +230,18 @@ namespace YYCC::ExceptionHelper { | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// get source file and line | 			// 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; | 			DWORD64 source_file_line = 0; | ||||||
| 			DWORD dwDisplacement; | 			DWORD dwDisplacement; | ||||||
| 			IMAGEHLP_LINE64 winline; | 			IMAGEHLP_LINE64 winline; | ||||||
| 			winline.SizeOfStruct = sizeof(IMAGEHLP_LINE64); | 			winline.SizeOfStruct = sizeof(IMAGEHLP_LINE64); | ||||||
| 			if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &dwDisplacement, &winline)) { | 			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; | 				source_file_line = winline.LineNumber; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// write to file | 			// 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 | 				frame.AddrPC.Offset, // memory adress | ||||||
| 				module_name, frame.AddrPC.Offset - module_base, // module name + relative address | 				module_name, frame.AddrPC.Offset - module_base, // module name + relative address | ||||||
| 				source_file, source_file_line // source file + source line | 				source_file, source_file_line // source file + source line | ||||||
| @ -255,16 +255,16 @@ namespace YYCC::ExceptionHelper { | |||||||
| 		SymCleanup(process); | 		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 | 		// open file stream if we have file name | ||||||
| 		std::FILE* fs = nullptr; | 		std::FILE* fs = nullptr; | ||||||
| 		if (!u8_filename.empty()) { | 		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 | 		// record exception type first | ||||||
| 		PEXCEPTION_RECORD rec = info->ExceptionRecord; | 		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, | 			rec->ExceptionAddress, | ||||||
| 			UExceptionGetCodeName(rec->ExceptionCode), | 			UExceptionGetCodeName(rec->ExceptionCode), | ||||||
| 			rec->ExceptionCode | 			rec->ExceptionCode | ||||||
| @ -276,7 +276,7 @@ namespace YYCC::ExceptionHelper { | |||||||
| 				const char* op = | 				const char* op = | ||||||
| 					rec->ExceptionInformation[0] == 0 ? "read" : | 					rec->ExceptionInformation[0] == 0 ? "read" : | ||||||
| 					rec->ExceptionInformation[0] == 1 ? "written" : "executed"; | 					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); | 					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 | 		// convert file encoding | ||||||
| 		std::wstring filename; | 		std::wstring filename; | ||||||
| 		if (u8_filename.empty()) | 		if (u8_filename.empty()) | ||||||
| 			return; // if no given file name, return | 			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 | 			return; // if convertion failed, return | ||||||
|  |  | ||||||
| 		// open file and write | 		// 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". | 		// 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. | 		// "module.dll" is the name of current module. "1234" is current process id. | ||||||
| 		// get self module name | 		// get self module name | ||||||
| 		std::string u8_self_module_name; | 		yycc_u8string u8_self_module_name; | ||||||
| 		{ | 		{ | ||||||
| 			// get module handle | 			// get module handle | ||||||
| 			HMODULE hSelfModule = YYCC::WinFctHelper::GetCurrentModule(); | 			HMODULE hSelfModule = YYCC::WinFctHelper::GetCurrentModule(); | ||||||
| 			if (hSelfModule == nullptr) | 			if (hSelfModule == nullptr) | ||||||
| 				return false; | 				return false; | ||||||
| 			// get full path of self module | 			// 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)) | 			if (!YYCC::WinFctHelper::GetModuleFileName(hSelfModule, u8_self_module_path)) | ||||||
| 				return false; | 				return false; | ||||||
| 			// extract file name from full path by std::filesystem::path | 			// extract file name from full path by std::filesystem::path | ||||||
| @ -336,22 +336,22 @@ namespace YYCC::ExceptionHelper { | |||||||
| 		// then get process id | 		// then get process id | ||||||
| 		DWORD process_id = GetCurrentProcessId(); | 		DWORD process_id = GetCurrentProcessId(); | ||||||
| 		// conbine them as a file name prefix | 		// conbine them as a file name prefix | ||||||
| 		std::string u8_filename_prefix; | 		yycc_u8string u8_filename_prefix; | ||||||
| 		if (!YYCC::StringHelper::Printf(u8_filename_prefix, "%s.%" PRIu32, u8_self_module_name.c_str(), process_id)) | 		if (!YYCC::StringHelper::Printf(u8_filename_prefix, YYCC_U8("%s.%" PRIu32), u8_self_module_name.c_str(), process_id)) | ||||||
| 			return false; | 			return false; | ||||||
| 		// then get file name for log and minidump | 		// then get file name for log and minidump | ||||||
| 		std::string u8_log_filename = u8_filename_prefix + ".log"; | 		yycc_u8string u8_log_filename = u8_filename_prefix + YYCC_U8(".log"); | ||||||
| 		std::string u8_coredump_filename = u8_filename_prefix + ".dmp"; | 		yycc_u8string u8_coredump_filename = u8_filename_prefix + YYCC_U8(".dmp"); | ||||||
|  |  | ||||||
| 		// fetch crash report path | 		// fetch crash report path | ||||||
| 		// get local appdata folder | 		// get local appdata folder | ||||||
| 		std::string u8_localappdata_path; | 		yycc_u8string u8_localappdata_path; | ||||||
| 		if (!WinFctHelper::GetLocalAppData(u8_localappdata_path)) | 		if (!WinFctHelper::GetLocalAppData(u8_localappdata_path)) | ||||||
| 			return false; | 			return false; | ||||||
| 		// convert to std::filesystem::path | 		// convert to std::filesystem::path | ||||||
| 		std::filesystem::path crash_report_path(FsPathPatch::FromUTF8Path(u8_localappdata_path.c_str())); | 		std::filesystem::path crash_report_path(FsPathPatch::FromUTF8Path(u8_localappdata_path.c_str())); | ||||||
| 		// slash into crash report folder | 		// 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 | 		// use create function to make sure it is existing | ||||||
| 		std::filesystem::create_directories(crash_report_path); | 		std::filesystem::create_directories(crash_report_path); | ||||||
|  |  | ||||||
| @ -375,18 +375,18 @@ namespace YYCC::ExceptionHelper { | |||||||
| 		// core implementation | 		// core implementation | ||||||
| 		{ | 		{ | ||||||
| 			// fetch error report path first | 			// fetch error report path first | ||||||
| 			std::string log_path, coredump_path; | 			yycc_u8string log_path, coredump_path; | ||||||
| 			if (!UExceptionFetchRecordPath(log_path, coredump_path)) { | 			if (!UExceptionFetchRecordPath(log_path, coredump_path)) { | ||||||
| 				// fail to fetch path, clear them. | 				// fail to fetch path, clear them. | ||||||
| 				// we still can handle crash without them | 				// we still can handle crash without them | ||||||
| 				log_path.clear(); | 				log_path.clear(); | ||||||
| 				coredump_path.clear(); | 				coredump_path.clear(); | ||||||
| 				// and tell user we can not output file | 				// 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 { | 			} else { | ||||||
| 				// okey. output file path to tell user the path where you can find. | 				// okey. output file path to tell user the path where you can find. | ||||||
| 				ConsoleHelper::ErrFormatLine("Crash Log: %s", log_path.c_str()); | 				ConsoleHelper::ErrFormatLine(YYCC_U8("Crash Log: %s"), log_path.c_str()); | ||||||
| 				ConsoleHelper::ErrFormatLine("Crash Coredump: %s", coredump_path.c_str()); | 				ConsoleHelper::ErrFormatLine(YYCC_U8("Crash Coredump: %s"), coredump_path.c_str()); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// write crash log | 			// write crash log | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ | |||||||
|  |  | ||||||
| namespace YYCC::FsPathPatch { | 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 | #if YYCC_OS == YYCC_OS_WINDOWS | ||||||
|  |  | ||||||
| 		// convert path to wchar | 		// convert path to wchar | ||||||
| @ -14,19 +14,19 @@ namespace YYCC::FsPathPatch { | |||||||
| 		if (!YYCC::EncodingHelper::UTF8ToWchar(u8_path, wpath)) | 		if (!YYCC::EncodingHelper::UTF8ToWchar(u8_path, wpath)) | ||||||
| 			throw std::invalid_argument("Fail to convert given UTF8 string."); | 			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); | 		return std::filesystem::path(wpath); | ||||||
|  | 		 | ||||||
| #else | #else | ||||||
| 		return std::filesystem::path(u8_path); | 		return std::filesystem::path(EncodingHelper::ToNative(u8_path)); | ||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	std::string ToUTF8Path(const std::filesystem::path& path) { | 	yycc_u8string ToUTF8Path(const std::filesystem::path& path) { | ||||||
| #if YYCC_OS == YYCC_OS_WINDOWS | #if YYCC_OS == YYCC_OS_WINDOWS | ||||||
|  |  | ||||||
| 		// get and convert to utf8 | 		// get and convert to utf8 | ||||||
| 		std::string u8_path; | 		yycc_u8string u8_path; | ||||||
| 		if (!YYCC::EncodingHelper::WcharToUTF8(path.c_str(), u8_path)) | 		if (!YYCC::EncodingHelper::WcharToUTF8(path.c_str(), u8_path)) | ||||||
| 			throw std::invalid_argument("Fail to convert to UTF8 string."); | 			throw std::invalid_argument("Fail to convert to UTF8 string."); | ||||||
|  |  | ||||||
| @ -34,7 +34,7 @@ namespace YYCC::FsPathPatch { | |||||||
| 		return u8_path; | 		return u8_path; | ||||||
|  |  | ||||||
| #else | #else | ||||||
| 		return path.string(); | 		return EncodingHelper::ToUTF8(path.string()); | ||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ namespace YYCC::FsPathPatch { | |||||||
| 	 * @return std::filesystem::path instance. | 	 * @return std::filesystem::path instance. | ||||||
| 	 * @exception std::invalid_argument Fail to parse given UTF8 string (maybe invalid?). | 	 * @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 | 	 * @brief Returns the UTF8 representation of the pathname | ||||||
| @ -36,6 +36,6 @@ namespace YYCC::FsPathPatch { | |||||||
| 	 * @return UTF8 encoded string representing given path. | 	 * @return UTF8 encoded string representing given path. | ||||||
| 	 * @exception std::invalid_argument Fail to parse to UTF8 string. | 	 * @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); | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ | |||||||
|  |  | ||||||
| namespace YYCC::IOHelper { | 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 | #if YYCC_OS == YYCC_OS_WINDOWS | ||||||
|  |  | ||||||
| 		// convert mode and file path to wchar | 		// convert mode and file path to wchar | ||||||
|  | |||||||
| @ -32,6 +32,6 @@ namespace YYCC::IOHelper { | |||||||
| 	 * On other platforms, this function will delegate request directly to std::fopen. | 	 * On other platforms, this function will delegate request directly to std::fopen. | ||||||
| 	 * @return FILE* of the file to be opened, or nullptr if failed. | 	 * @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); | ||||||
| 	 | 	 | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,11 +14,15 @@ namespace YYCC::ParserHelper { | |||||||
| 	// Reference: https://zh.cppreference.com/w/cpp/utility/from_chars | 	// 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> | 	template<typename _Ty, std::enable_if_t<std::is_floating_point_v<_Ty>, int> = 0> | ||||||
| 	bool TryParse(const std::string& strl, _Ty& num) { | 	bool TryParse(const yycc_u8string_view& strl, _Ty& num) { | ||||||
| 		auto [ptr, ec] = std::from_chars(strl.c_str(), strl.c_str() + strl.size(), num, std::chars_format::general); | 		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()) { | 		if (ec == std::errc()) { | ||||||
| 			// check whether the full string is matched | 			// 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) { | 		} else if (ec == std::errc::invalid_argument) { | ||||||
| 			// given string is invalid | 			// given string is invalid | ||||||
| 			return false; | 			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> | 	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) { | 	bool TryParse(const yycc_u8string_view& strl, _Ty& num, int base = 10) { | ||||||
| 		auto [ptr, ec] = std::from_chars(strl.c_str(), strl.c_str() + strl.size(), num, base); | 		auto [ptr, ec] = std::from_chars( | ||||||
|  | 			EncodingHelper::ToNative(strl.data()),  | ||||||
|  | 			EncodingHelper::ToNative(strl.data() + strl.size()),  | ||||||
|  | 			num, base | ||||||
|  | 		); | ||||||
| 		if (ec == std::errc()) { | 		if (ec == std::errc()) { | ||||||
| 			// check whether the full string is matched | 			// 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) { | 		} else if (ec == std::errc::invalid_argument) { | ||||||
| 			// given string is invalid | 			// given string is invalid | ||||||
| 			return false; | 			return false; | ||||||
| @ -48,15 +56,15 @@ namespace YYCC::ParserHelper { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	template<typename _Ty, std::enable_if_t<std::is_same_v<_Ty, bool>, int> = 0> | 	template<typename _Ty, std::enable_if_t<std::is_same_v<_Ty, bool>, int> = 0> | ||||||
| 	bool TryParse(const std::string& strl, _Ty& num) { | 	bool TryParse(const yycc_u8string_view& strl, _Ty& num) { | ||||||
| 		if (strl == "true") num = true; | 		if (strl == YYCC_U8("true")) num = true; | ||||||
| 		else if (strl == "false") num = false; | 		else if (strl == YYCC_U8("false")) num = false; | ||||||
| 		else return false; | 		else return false; | ||||||
| 		return true; | 		return true; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	template<typename _Ty, std::enable_if_t<std::is_arithmetic_v<_Ty>, int> = 0> | 	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; | 		_Ty ret; | ||||||
| 		TryParse(strl, ret); | 		TryParse(strl, ret); | ||||||
| 		return ret; | 		return ret; | ||||||
| @ -65,11 +73,15 @@ namespace YYCC::ParserHelper { | |||||||
| 	// Reference: https://en.cppreference.com/w/cpp/utility/to_chars | 	// 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> | 	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) { | 	yycc_u8string ToString(_Ty num) { | ||||||
| 		std::array<char, 64> buffer; | 		std::array<yycc_char8_t, 64> buffer; | ||||||
| 		auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), num); | 		auto [ptr, ec] = std::to_chars( | ||||||
|  | 			EncodingHelper::ToNative(buffer.data()),  | ||||||
|  | 			EncodingHelper::ToNative(buffer.data() + buffer.size()),  | ||||||
|  | 			num | ||||||
|  | 		); | ||||||
| 		if (ec == std::errc()) { | 		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) { | 		} else if (ec == std::errc::value_too_large) { | ||||||
| 			// too short buffer | 			// too short buffer | ||||||
| 			// this should not happend | 			// 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> | 	template<typename _Ty, std::enable_if_t<std::is_same_v<_Ty, bool>, int> = 0> | ||||||
| 	std::string ToString(_Ty num) { | 	yycc_u8string ToString(_Ty num) { | ||||||
| 		if (num) return std::string("true"); | 		if (num) return yycc_u8string(YYCC_U8("true")); | ||||||
| 		else return std::string("false"); | 		else return yycc_u8string(YYCC_U8("false")); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ namespace YYCC::WinFctHelper { | |||||||
| 		return hModule; | 		return hModule; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool GetTempDirectory(std::string& ret) { | 	bool GetTempDirectory(yycc_u8string& ret) { | ||||||
| 		// create wchar buffer for receiving the temp path. | 		// create wchar buffer for receiving the temp path. | ||||||
| 		std::wstring wpath(MAX_PATH + 1u, L'\0'); | 		std::wstring wpath(MAX_PATH + 1u, L'\0'); | ||||||
| 		DWORD expected_size; | 		DWORD expected_size; | ||||||
| @ -41,10 +41,10 @@ namespace YYCC::WinFctHelper { | |||||||
| 		// resize result | 		// resize result | ||||||
| 		wpath.resize(expected_size); | 		wpath.resize(expected_size); | ||||||
| 		// convert to utf8 and return | 		// 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. | 		// create wchar buffer for receiving the temp path. | ||||||
| 		std::wstring wpath(MAX_PATH + 1u, L'\0'); | 		std::wstring wpath(MAX_PATH + 1u, L'\0'); | ||||||
| 		DWORD copied_size; | 		DWORD copied_size; | ||||||
| @ -68,10 +68,13 @@ namespace YYCC::WinFctHelper { | |||||||
| 		// resize result | 		// resize result | ||||||
| 		wpath.resize(copied_size); | 		wpath.resize(copied_size); | ||||||
| 		// convert to utf8 and return | 		// 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 | 		// fetch path | ||||||
| 		LPWSTR _known_path; | 		LPWSTR _known_path; | ||||||
| 		HRESULT hr = SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &_known_path); | 		HRESULT hr = SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, NULL, &_known_path); | ||||||
|  | |||||||
| @ -36,7 +36,7 @@ namespace YYCC::WinFctHelper { | |||||||
| 	 * The variable receiving UTF8 encoded path to Windows temp folder. | 	 * The variable receiving UTF8 encoded path to Windows temp folder. | ||||||
| 	 * @return True if success, otherwise false. | 	 * @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 | 	 * @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. | 	 * The variable receiving UTF8 encoded file name of given module. | ||||||
| 	 * @return True if success, otherwise false. | 	 * @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. | 	 * @brief Get the path to LOCALAPPDATA. | ||||||
| @ -56,7 +56,7 @@ namespace YYCC::WinFctHelper { | |||||||
| 	 * The variable receiving UTF8 encoded path to LOCALAPPDATA. | 	 * The variable receiving UTF8 encoded path to LOCALAPPDATA. | ||||||
| 	 * @return  | 	 * @return  | ||||||
| 	*/ | 	*/ | ||||||
| 	bool GetLocalAppData(std::string& ret); | 	bool GetLocalAppData(yycc_u8string& ret); | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
| #include "COMHelper.hpp" | #include "COMHelper.hpp" | ||||||
| #include "DialogHelper.hpp" | #include "DialogHelper.hpp" | ||||||
| #include "ParserHelper.hpp" | #include "ParserHelper.hpp" | ||||||
| #include "ExceptionHelper.hpp" |  | ||||||
| #include "IOHelper.hpp" | #include "IOHelper.hpp" | ||||||
| #include "WinFctHelper.hpp" | #include "WinFctHelper.hpp" | ||||||
| #include "FsPathPatch.hpp" | #include "FsPathPatch.hpp" | ||||||
|  | #include "ExceptionHelper.hpp" | ||||||
|  | |||||||
| @ -23,12 +23,12 @@ namespace YYCCTestbench { | |||||||
| #define TEST_UNICODE_STR_EMOJI "\U0001F363 \u2716 \U0001F37A" // sushi x beer mug | #define TEST_UNICODE_STR_EMOJI "\U0001F363 \u2716 \U0001F37A" // sushi x beer mug | ||||||
|  |  | ||||||
| #define CONCAT(prefix, strl) prefix ## strl | #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_U16_LITERAL(strl) CONCAT(u, strl) | ||||||
| #define CPP_U32_LITERAL(strl) CONCAT(U, strl) | #define CPP_U32_LITERAL(strl) CONCAT(U, strl) | ||||||
| #define CPP_WSTR_LITERAL(strl) CONCAT(L, 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_JAPAN), | ||||||
| 		CPP_U8_LITERAL(TEST_UNICODE_STR_CHINA), | 		CPP_U8_LITERAL(TEST_UNICODE_STR_CHINA), | ||||||
| 		CPP_U8_LITERAL(TEST_UNICODE_STR_KOREA), | 		CPP_U8_LITERAL(TEST_UNICODE_STR_KOREA), | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user