From 5b08a09446e2766d61f1a11999011a37e71df225 Mon Sep 17 00:00:00 2001 From: MediaPipe Team Date: Tue, 12 Sep 2023 14:57:24 -0700 Subject: [PATCH] Fixes two issues with file handling on windows: . If UNICODE is set, then win32 functions taking file paths use wide (utf-16) strings. For example, FindFirstFile really calls to FindFirstFileW, which takes a wchar_t*. This adds support for the unicode path. . SetContents() changes from "w" to "wb". This is necessary as windows will do some amount of encoding without "b", which results in much different values being written. PiperOrigin-RevId: 564842317 --- mediapipe/framework/deps/file_helpers.cc | 45 ++++++++++++++++++------ 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/mediapipe/framework/deps/file_helpers.cc b/mediapipe/framework/deps/file_helpers.cc index 23b50310f..b5c2bae81 100644 --- a/mediapipe/framework/deps/file_helpers.cc +++ b/mediapipe/framework/deps/file_helpers.cc @@ -17,6 +17,9 @@ #ifdef _WIN32 #include #include + +#include +#include #else #include #endif // _WIN32 @@ -86,11 +89,32 @@ class DirectoryListing { struct dirent* next_entry_ = nullptr; }; #else +#if defined(UNICODE) +using PathString = std::wstring; + +PathString Utf8ToNative(const std::string& string) { + std::wstring_convert, wchar_t> converter; + return converter.from_bytes(string.data(), string.data() + string.size()); +} +std::string NativeToUtf8(const PathString& string) { + std::wstring_convert, wchar_t> converter; + return converter.to_bytes(string.data(), string.data() + string.size()); +} +#define FILE_PATH_LITERAL_INTERNAL(x) L##x +#define FILE_PATH_LITERAL(x) FILE_PATH_LITERAL_INTERNAL(x) +#else +using PathString = std::string; +PathString Utf8ToNative(const std::string& string) { return string; } +std::string NativeToUtf8(const PathString& string) { return string; } +#define FILE_PATH_LITERAL_INTERNAL(x) ##x +#define FILE_PATH_LITERAL(x) FILE_PATH_LITERAL_INTERNAL(x) +#endif + class DirectoryListing { public: - explicit DirectoryListing(const std::string& directory) { - directory_ = directory; - std::string search_string = directory + "\\*.*"; + explicit DirectoryListing(const std::string& directory) + : directory_(Utf8ToNative(directory)) { + PathString search_string = directory_ + Utf8ToNative("\\*.*"); find_handle_ = FindFirstFile(search_string.c_str(), &find_data_); } @@ -107,10 +131,10 @@ class DirectoryListing { // after the one that is returned, if it exists. std::string NextEntry() { if (HasNextEntry()) { - std::string result = - std::string(directory_ + "\\" + find_data_.cFileName); + PathString result = + directory_ + Utf8ToNative("\\") + PathString(find_data_.cFileName); ReadNextEntry(); - return result; + return NativeToUtf8(result); } else { return std::string(); } @@ -119,8 +143,9 @@ class DirectoryListing { private: void ReadNextEntry() { int find_result = FindNextFile(find_handle_, &find_data_); - while (find_result != 0 && (std::string(find_data_.cFileName) == "." || - std::string(find_data_.cFileName) == "..")) { + while (find_result != 0 && + (PathString(find_data_.cFileName) == FILE_PATH_LITERAL(".") || + PathString(find_data_.cFileName) == FILE_PATH_LITERAL(".."))) { find_result = FindNextFile(find_handle_, &find_data_); } @@ -130,7 +155,7 @@ class DirectoryListing { } } - std::string directory_; + const PathString directory_; HANDLE find_handle_ = INVALID_HANDLE_VALUE; WIN32_FIND_DATA find_data_; }; @@ -162,7 +187,7 @@ absl::Status GetContents(absl::string_view file_name, std::string* output, absl::Status SetContents(absl::string_view file_name, absl::string_view content) { - FILE* fp = fopen(file_name.data(), "w"); + FILE* fp = fopen(file_name.data(), "wb"); if (fp == NULL) { return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC) << "Can't open file: " << file_name;