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
This commit is contained in:
MediaPipe Team 2023-09-12 14:57:24 -07:00 committed by Copybara-Service
parent dbcdb44f7c
commit 5b08a09446

View File

@ -17,6 +17,9 @@
#ifdef _WIN32 #ifdef _WIN32
#include <Windows.h> #include <Windows.h>
#include <direct.h> #include <direct.h>
#include <codecvt>
#include <locale>
#else #else
#include <dirent.h> #include <dirent.h>
#endif // _WIN32 #endif // _WIN32
@ -86,11 +89,32 @@ class DirectoryListing {
struct dirent* next_entry_ = nullptr; struct dirent* next_entry_ = nullptr;
}; };
#else #else
#if defined(UNICODE)
using PathString = std::wstring;
PathString Utf8ToNative(const std::string& string) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
return converter.from_bytes(string.data(), string.data() + string.size());
}
std::string NativeToUtf8(const PathString& string) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, 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 { class DirectoryListing {
public: public:
explicit DirectoryListing(const std::string& directory) { explicit DirectoryListing(const std::string& directory)
directory_ = directory; : directory_(Utf8ToNative(directory)) {
std::string search_string = directory + "\\*.*"; PathString search_string = directory_ + Utf8ToNative("\\*.*");
find_handle_ = FindFirstFile(search_string.c_str(), &find_data_); find_handle_ = FindFirstFile(search_string.c_str(), &find_data_);
} }
@ -107,10 +131,10 @@ class DirectoryListing {
// after the one that is returned, if it exists. // after the one that is returned, if it exists.
std::string NextEntry() { std::string NextEntry() {
if (HasNextEntry()) { if (HasNextEntry()) {
std::string result = PathString result =
std::string(directory_ + "\\" + find_data_.cFileName); directory_ + Utf8ToNative("\\") + PathString(find_data_.cFileName);
ReadNextEntry(); ReadNextEntry();
return result; return NativeToUtf8(result);
} else { } else {
return std::string(); return std::string();
} }
@ -119,8 +143,9 @@ class DirectoryListing {
private: private:
void ReadNextEntry() { void ReadNextEntry() {
int find_result = FindNextFile(find_handle_, &find_data_); int find_result = FindNextFile(find_handle_, &find_data_);
while (find_result != 0 && (std::string(find_data_.cFileName) == "." || while (find_result != 0 &&
std::string(find_data_.cFileName) == "..")) { (PathString(find_data_.cFileName) == FILE_PATH_LITERAL(".") ||
PathString(find_data_.cFileName) == FILE_PATH_LITERAL(".."))) {
find_result = FindNextFile(find_handle_, &find_data_); 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; HANDLE find_handle_ = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA find_data_; 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::Status SetContents(absl::string_view file_name,
absl::string_view content) { absl::string_view content) {
FILE* fp = fopen(file_name.data(), "w"); FILE* fp = fopen(file_name.data(), "wb");
if (fp == NULL) { if (fp == NULL) {
return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC) return mediapipe::InvalidArgumentErrorBuilder(MEDIAPIPE_LOC)
<< "Can't open file: " << file_name; << "Can't open file: " << file_name;