#include "Utils.hpp" #ifdef _WIN32 # include #endif #ifdef _WIN32 # define BRUSSEL_MODE_STRING(string) L##string #else # define BRUSSEL_MODE_STRING(string) string #endif #if _WIN32 using FopenModeString = const wchar_t*; #else using FopenModeString = const char*; #endif static FopenModeString GetModeString(Utils::IoMode mode, bool binary) { using namespace Utils; if (binary) { switch (mode) { case Read: return BRUSSEL_MODE_STRING("r"); case WriteTruncate: return BRUSSEL_MODE_STRING("w"); case WriteAppend: return BRUSSEL_MODE_STRING("a"); } } else { switch (mode) { case Read: return BRUSSEL_MODE_STRING("rb"); case WriteTruncate: return BRUSSEL_MODE_STRING("wb"); case WriteAppend: return BRUSSEL_MODE_STRING("ab"); } } return nullptr; } FILE* Utils::OpenCstdioFile(const std::filesystem::path& path, IoMode mode, bool binary) { #ifdef _WIN32 // std::filesystem::path::c_str() returns `const wchar_t*` under Windows, because NT uses UTF-16 natively // NOTE: _wfopen() only affects the type of path parameter, otherwise the file stream created is identical to the one by fopen() return _wfopen(path.c_str(), ::GetModeString(mode, binary)); #else return fopen(path.c_str(), ::GetModeString(mode, binary)); #endif } FILE* Utils::OpenCstdioFile(const char* path, IoMode mode, bool binary) { #ifdef _WIN32 // On Windows, fopen() accepts ANSI codepage encoded path, convert our UTF-8 string to UTF-16 to ensure that no matter what the locale is, the path continues to work WCHAR platformPath[MAX_PATH]; if (MultiByteToWideChar(CP_UTF8, 0, path, -1, platformPath, MAX_PATH) == 0) { return nullptr; } return _wfopen(platformPath, ::GetModeString(mode, binary)); #else return fopen(path, ::GetModeString(mode, binary)); #endif }