0029081: With Mingw-w64 Unicode Paths Do Not Work
[occt.git] / src / OSD / OSD_OpenFile.hxx
index 378951e..24d3737 100644 (file)
 #include <TCollection_ExtendedString.hxx>
 #include <NCollection_UtfString.hxx>
 
+#if defined(_WIN32) && defined(__GLIBCXX__)
+  #include <ext/stdio_filebuf.h> // __gnu_cxx::stdio_filebuf
+#endif
+
 //! Function opens the file.
 //! @param theName name of file encoded in UTF-16
 //! @param theMode opening mode
@@ -37,21 +41,46 @@ __Standard_API FILE* OSD_OpenFile (const TCollection_ExtendedString& theName,
 //! @return stat.st_ctime value
 __Standard_API Standard_Time OSD_FileStatCTime (const char* theName);
 
-//! Function opens the file stream.
-//! @param theStream stream to open
-//! @param theName name of file encoded in UTF-8
+//! Open file descriptor for specified UTF-16 file path.
+//! @param theName name of file encoded in UTF-16
 //! @param theMode opening mode
-template <typename T>
-inline void OSD_OpenStream (T& theStream,
-                            const char* theName,
+//! @return file descriptor on success or -1 on error
+__Standard_API int OSD_OpenFileDescriptor (const TCollection_ExtendedString& theName,
+                                           ::std::ios_base::openmode theMode);
+
+//! Function opens the file buffer.
+//! @param theFileBuf file buffer to open
+//! @param theName name of file encoded in UTF-16
+//! @param theMode opening mode
+//! @return true if success, false otherwise
+inline bool OSD_OpenStream (::std::filebuf& theFileBuf,
+                            const TCollection_ExtendedString& theName,
                             const std::ios_base::openmode theMode)
 {
-#if defined(_WIN32) && defined(_MSC_VER)
-  // file name is treated as UTF-8 string and converted to UTF-16 one
-  const TCollection_ExtendedString aFileNameW (theName, Standard_True);
-  theStream.open (aFileNameW.ToWideString(), theMode);
+#if defined(_WIN32)
+  #if defined(__GLIBCXX__)
+  // if file buffer is already open, open() should fail according to C++ standard
+  if (theFileBuf.is_open())
+    return false;
+  // __gnu_cxx::stdio_filebuf is a std::filebuf providing extra constructor taking FILE* or file descriptor;
+  // It does not modify virtual methods or add any fields - so we can safely use swap (or move operator) here.
+  // MinGW does not provide open() methods taking wchar_t* or file descriptor - thus, creating __gnu_cxx::stdio_filebuf
+  // is the only way for opening such files since _wfopen()/_wsopen_s() from C world are available.
+  const int aFileDesc = OSD_OpenFileDescriptor (theName.ToWideString(), theMode);
+  __gnu_cxx::stdio_filebuf<char> aGccBuf (aFileDesc, theMode);
+  if (aGccBuf.is_open())
+  {
+    theFileBuf.swap (aGccBuf);
+    return true;
+  }
+  return false;
+  #else
+  return theFileBuf.open (theName.ToWideString(), theMode) != 0;
+  #endif
 #else
-  theStream.open (theName, theMode);
+  // conversion to UTF-8 for linux
+  NCollection_Utf8String aString (theName.ToExtString());
+  return theFileBuf.open (aString.ToCString(), theMode) != 0;
 #endif
 }
 
@@ -64,8 +93,22 @@ inline void OSD_OpenStream (T& theStream,
                             const TCollection_ExtendedString& theName,
                             const std::ios_base::openmode theMode)
 {
-#if defined(_WIN32) && defined(_MSC_VER)
+#if defined(_WIN32)
+  #if defined(__GLIBCXX__)
+  // Use hackish code for opening wchar_t* file paths on MinGW,
+  // which considers implementation details of std::filebuf within std::fstream/std::ifstream/std::ofstream.
+  // Should be removed when MinGW will be improved to support wchar_t file paths natively within C++ streams.
+  if (! OSD_OpenStream (*theStream.rdbuf(), theName, theMode))
+  {
+    theStream.setstate (std::ios_base::failbit);
+  }
+  else
+  {
+    theStream.clear();
+  }
+  #else
   theStream.open (theName.ToWideString(), theMode);
+  #endif
 #else
   // conversion in UTF-8 for linux
   NCollection_Utf8String aString (theName.ToExtString());
@@ -73,6 +116,24 @@ inline void OSD_OpenStream (T& theStream,
 #endif
 }
 
+//! Function opens the file stream.
+//! @param theStream stream to open
+//! @param theName name of file encoded in UTF-8
+//! @param theMode opening mode
+template <typename T>
+inline void OSD_OpenStream (T& theStream,
+                            const char* theName,
+                            const std::ios_base::openmode theMode)
+{
+#if defined(_WIN32)
+  // redirect to method taking UTF-16 string
+  const TCollection_ExtendedString aFileNameW (theName, Standard_True);
+  OSD_OpenStream (theStream, aFileNameW, theMode);
+#else
+  theStream.open (theName, theMode);
+#endif
+}
+
 extern "C" {
 #endif // __cplusplus