feat: move std::filesystem::path related function to independent namespace.

- create FsPathPatch namespace to hold std::filesystem::path related functions.
- add corresponding testbench code for it.
This commit is contained in:
2024-06-15 17:57:33 +08:00
parent e7b13768ec
commit 5481898ad9
7 changed files with 143 additions and 61 deletions

View File

@ -9,6 +9,7 @@ PRIVATE
${CMAKE_CURRENT_LIST_DIR}/DialogHelper.hpp
${CMAKE_CURRENT_LIST_DIR}/EncodingHelper.hpp
${CMAKE_CURRENT_LIST_DIR}/ExceptionHelper.hpp
${CMAKE_CURRENT_LIST_DIR}/FsPathPatch.hpp
${CMAKE_CURRENT_LIST_DIR}/IOHelper.hpp
${CMAKE_CURRENT_LIST_DIR}/ParserHelper.hpp
${CMAKE_CURRENT_LIST_DIR}/StringHelper.hpp
@ -25,6 +26,7 @@ PRIVATE
${CMAKE_CURRENT_LIST_DIR}/DialogHelper.cpp
${CMAKE_CURRENT_LIST_DIR}/EncodingHelper.cpp
${CMAKE_CURRENT_LIST_DIR}/ExceptionHelper.cpp
${CMAKE_CURRENT_LIST_DIR}/FsPathPatch.cpp
${CMAKE_CURRENT_LIST_DIR}/IOHelper.cpp
${CMAKE_CURRENT_LIST_DIR}/ParserHelper.cpp
${CMAKE_CURRENT_LIST_DIR}/StringHelper.cpp
@ -72,9 +74,11 @@ FILES
${CMAKE_CURRENT_LIST_DIR}/DialogHelper.hpp
${CMAKE_CURRENT_LIST_DIR}/EncodingHelper.hpp
${CMAKE_CURRENT_LIST_DIR}/ExceptionHelper.hpp
${CMAKE_CURRENT_LIST_DIR}/FsPathPatch.hpp
${CMAKE_CURRENT_LIST_DIR}/IOHelper.hpp
${CMAKE_CURRENT_LIST_DIR}/ParserHelper.hpp
${CMAKE_CURRENT_LIST_DIR}/StringHelper.hpp
${CMAKE_CURRENT_LIST_DIR}/WinFctHelper.hpp
# Windows including guard pair
${CMAKE_CURRENT_LIST_DIR}/WinImportPrefix.hpp
${CMAKE_CURRENT_LIST_DIR}/WinImportSuffix.hpp

41
src/FsPathPatch.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "FsPathPatch.hpp"
#include "EncodingHelper.hpp"
#include <string>
#include <stdexcept>
namespace YYCC::FsPathPatch {
std::filesystem::path FromUTF8Path(const char* u8_path) {
#if YYCC_OS == YYCC_OS_WINDOWS
// convert path to wchar
std::wstring wpath;
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 std::filesystem::path(wpath);
#else
return std::filesystem::path(u8_path);
#endif
}
std::string ToUTF8Path(const std::filesystem::path& path) {
#if YYCC_OS == YYCC_OS_WINDOWS
// get and convert to utf8
std::string u8_path;
if (!YYCC::EncodingHelper::WcharToUTF8(path.c_str(), u8_path))
throw std::invalid_argument("Fail to convert to UTF8 string.");
// return utf8 path
return u8_path;
#else
return path.string();
#endif
}
}

41
src/FsPathPatch.hpp Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include "YYCCInternal.hpp"
#include <filesystem>
/**
* @brief The patch namespace resolving \c std::filesystem::path encoding issue.
* @details
* This patch is Windows oriented.
* If you are in Windows, this patch will perform extra operations to achieve goals,
* and in other platforms, they just redirect request to corresponding vanilla C++ functions.
*
* As you know, the underlying char type of \c std::filesystem::path is \c wchar_t on Windows,
* and in other platforms, it is simple \c char.
* Due to this, if you passing UTF8 char sequence to \c std::filesystem::path on Windows,
* the library implementation will assume your input is based on current Windows code page, not UTF8.
* And the final path stored in \c std::filesystem::path is not what you expcected.
*
* This patch namespace always use UTF8 as its argument. There is no ambiguous issue.
* You should use the functions provided by this namespace on any platforms
* instead of vanilla \c std::filesystem::path functions.
*/
namespace YYCC::FsPathPatch {
/**
* @brief Constructs the path from a UTF8 character sequence
* @param[in] u8_path UTF8 path string for building this std::filesystem::path.
* @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);
/**
* @brief Returns the UTF8 representation of the pathname
* @param path[in] The string to be output.
* @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);
}

View File

@ -32,22 +32,5 @@ namespace YYCC::IOHelper {
#endif
}
std::filesystem::path UTF8Path(const char* u8_path) {
#if YYCC_OS == YYCC_OS_WINDOWS
// convert path to wchar
std::wstring wpath;
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 std::filesystem::path(wpath);
#else
return std::filesystem::path(u8_path);
#endif
}
}

View File

@ -34,15 +34,4 @@ namespace YYCC::IOHelper {
*/
FILE* UTF8FOpen(const char* u8_filepath, const char* u8_mode);
/**
* @brief Build std::filesystem::path from UTF8 string.
* @param[in] u8_path UTF8 path string for building this std::filesystem::path.
* @return std::filesystem::path instance.
* @exception std::invalid_argument Fail to parse given UTF8 string (maybe invalid?).
* @remarks
* This function is suit for Windows.
* On other platforms, it will simply call the constructor of std::filesystem::path.
*/
std::filesystem::path UTF8Path(const char* u8_path);
}

View File

@ -10,3 +10,4 @@
#include "ExceptionHelper.hpp"
#include "IOHelper.hpp"
#include "WinFctHelper.hpp"
#include "FsPathPatch.hpp"