Skip to content

Commit

Permalink
Fixes Unicode paths on Windows
Browse files Browse the repository at this point in the history
Wraps "ifstream::ifstream", "ifstream::open", and "stat" with platform-aware
functions that automatically convert to wide char UTF-16 on Windows.
  • Loading branch information
itsmattkc committed Apr 8, 2021
1 parent 87d3109 commit 459bc74
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/OpenColorIO/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1180,7 +1180,7 @@ ConstConfigRcPtr Config::CreateFromEnv()

ConstConfigRcPtr Config::CreateFromFile(const char * filename)
{
std::ifstream istream(filename);
std::ifstream istream = Platform::CreateIfstream(filename);
if (istream.fail())
{
std::ostringstream os;
Expand Down
8 changes: 8 additions & 0 deletions src/OpenColorIO/PathUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "Mutex.h"
#include "PathUtils.h"
#include "Platform.h"
#include "pystring/pystring.h"
#include "utils/StringUtils.h"

Expand Down Expand Up @@ -37,8 +38,15 @@ namespace
// That's the default hash method implementation to compute a hash key based on a file content.
std::string DefaultComputeHash(const std::string &filename)
{
#ifdef _WIN32
struct _stat fileInfo;

if (_wstat(Platform::Utf8ToUtf16(filename).c_str(), &fileInfo) == 0)
#else
struct stat fileInfo;

if (stat(filename.c_str(), &fileInfo) == 0)
#endif
{
// Treat the st_dev (i.e. device) + st_ino (i.e. inode) as a proxy for the contents.

Expand Down
34 changes: 34 additions & 0 deletions src/OpenColorIO/Platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,40 @@ std::string CreateTempFilename(const std::string & filenameExt)
return filename;
}

std::ifstream CreateIfstream(const char * filename, std::ios_base::openmode mode)
{
#ifdef _WIN32
return std::ifstream(Utf8ToUtf16(filename).c_str(), mode);
#else
return std::ifstream(filename, mode);
#endif
}

void OpenIfstream(std::ifstream * stream, const char * filename, std::ios_base::openmode mode)
{
#ifdef _WIN32
stream->open(Utf8ToUtf16(filename).c_str(), mode);
#else
stream->open(filename, mode);
#endif
}

std::wstring Utf8ToUtf16(std::string str)
{
int sz = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
std::wstring wstr(sz, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstr[0], sz);
return wstr;
}

std::string Utf16ToUtf8(std::wstring wstr)
{
int sz = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
std::string str(sz, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &str[0], sz, NULL, NULL);
return str;
}



} // Platform
Expand Down
15 changes: 15 additions & 0 deletions src/OpenColorIO/Platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#endif // _WIN32


#include <fstream>
#include <string>


Expand Down Expand Up @@ -73,6 +74,20 @@ void AlignedFree(void * memBlock);
// the file if created.
std::string CreateTempFilename(const std::string & filenameExt);

// Platform-independent ifstream constructor based on UTF-8 input
std::ifstream CreateIfstream(const char * filename, std::ios_base::openmode mode = std::ios_base::in);

// Platform-independent ifstream open based on UTF-8 input
void OpenIfstream(std::ifstream * stream, const char * filename, std::ios_base::openmode mode = std::ios_base::in);

#ifdef _WIN32
// Convert UTF-8 string to Windows-friendly UTF-16 string
std::wstring Utf8ToUtf16(std::string str);

// Convert Windows-friendly UTF-16 string to UTF-8 string
std::string Utf16ToUtf8(std::wstring str);
#endif

}

} // namespace OCIO_NAMESPACE
Expand Down
2 changes: 1 addition & 1 deletion src/OpenColorIO/fileformats/FileFormatICC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ FileFormat * CreateFileFormatICC()

std::string GetProfileDescriptionFromICCProfile(const char * ICCProfileFilepath)
{
std::ifstream filestream(ICCProfileFilepath, std::ios_base::binary);
std::ifstream filestream = Platform::CreateIfstream(ICCProfileFilepath, std::ios_base::binary);
if (!filestream.good())
{
std::ostringstream os;
Expand Down
6 changes: 4 additions & 2 deletions src/OpenColorIO/transforms/FileTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,8 @@ void LoadFileUncached(FileFormat * & returnFormat,
try
{
// Open the filePath
filestream.open(
Platform::OpenIfstream(
&filestream,
filepath.c_str(),
tryFormat->isBinary()
? std::ios_base::binary : std::ios_base::in);
Expand Down Expand Up @@ -618,7 +619,8 @@ void LoadFileUncached(FileFormat * & returnFormat,
std::ifstream filestream;
try
{
filestream.open(filepath.c_str(), altFormat->isBinary()
Platform::OpenIfstream(
&filestream, filepath.c_str(), altFormat->isBinary()
? std::ios_base::binary : std::ios_base::in);
if (!filestream.good())
{
Expand Down
2 changes: 1 addition & 1 deletion tests/cpu/UnitTestUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ OCIO_SHARED_PTR<LocalCachedFile> LoadTestFile(

// Open the filePath
std::ifstream filestream;
filestream.open(filePath.c_str(), mode);
Platform::OpenIfstream(&filestream, filePath.c_str(), mode);

if (!filestream.is_open())
{
Expand Down
2 changes: 1 addition & 1 deletion vendor/aftereffects/OpenColorIO_AE_Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ bool Path::exists() const
if(path.empty())
return false;

std::ifstream f( path.c_str() );
std::ifstream f = Platform::CreateIfstream( path.c_str() );

return !!f;
}
Expand Down

0 comments on commit 459bc74

Please sign in to comment.