Add NativeFileStream to support unicode filenames under Windows

This commit is contained in:
Martchus 2016-12-19 23:29:54 +01:00
parent 59a8dfe833
commit 9d91cfca07
3 changed files with 129 additions and 0 deletions

View File

@ -25,6 +25,7 @@ set(HEADER_FILES
io/inifile.h
io/path.h
io/catchiofailure.h
io/nativefilestream.h
math/math.h
misc/memory.h
misc/random.h
@ -49,6 +50,7 @@ set(SRC_FILES
io/inifile.cpp
io/path.cpp
io/catchiofailure.cpp
io/nativefilestream.cpp
math/math.cpp
misc/random.cpp
tests/testutils.cpp
@ -119,6 +121,12 @@ set(META_VERSION_PATCH 0)
include(3rdParty)
use_iconv(AUTO_LINKAGE REQUIRED)
# configure use of native file buffer
option(USE_NATIVE_FILE_BUFFER "enables use of native file buffer under Windows, affects bc (required for unicode filenames under Windows)" OFF)
if(USE_NATIVE_FILE_BUFFER)
list(APPEND META_PUBLIC_COMPILE_DEFINITIONS ${META_PROJECT_VARNAME}_USE_NATIVE_FILE_BUFFER)
endif()
# include modules to apply configuration
include(BasicConfig)
include(WindowsResources)

73
io/nativefilestream.cpp Normal file
View File

@ -0,0 +1,73 @@
#include "./nativefilestream.h"
#ifdef PLATFORM_MINGW
# include <c++utilities/io/catchiofailure.h>
# include <windows.h>
# include <fcntl.h>
# include <sys/stat.h>
#endif
using namespace std;
namespace IoUtilities {
#if !defined(PLATFORM_MINGW) || !defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER)
// just use std::fstream
#else
NativeFileStream::NativeFileStream() :
m_filebuf(new __gnu_cxx::stdio_filebuf<char>)
{
rdbuf(m_filebuf.get());
}
NativeFileStream::~NativeFileStream()
{}
void NativeFileStream::open(const string &path, ios_base::openmode flags)
{
// convert path to UTF-16
int requiredSize = MultiByteToWideChar(CP_UTF8, 0, path.data(), -1, nullptr, 0);
if(requiredSize <= 0) {
::IoUtilities::throwIoFailure("Unable to calculate buffer size for conversion of path to UTF-16");
}
auto widePath = make_unique<wchar_t[]>(static_cast<size_t>(requiredSize));
requiredSize = MultiByteToWideChar(CP_UTF8, 0, path.data(), -1, widePath.get(), requiredSize);
if(requiredSize <= 0) {
::IoUtilities::throwIoFailure("Unable to convert path to UTF-16");
}
// translate flags
int nativeFlags = (flags & ios_base::binary ? _O_BINARY : 0);
int permissions = 0;
if((flags & ios_base::out) && (flags & ios_base::in)) {
nativeFlags |= _O_RDWR;
} else if(flags & ios_base::out) {
nativeFlags |= _O_WRONLY | _O_CREAT;
permissions = _S_IREAD | _S_IWRITE;
} else if(flags & ios_base::in) {
nativeFlags |= _O_RDONLY;
}
if(flags & ios_base::trunc) {
nativeFlags |= _O_TRUNC;
}
// initialize stdio_filebuf
int fd = _wopen(widePath.get(), nativeFlags, permissions);
if(fd == -1) {
::IoUtilities::throwIoFailure("_wopen failed");
}
m_filebuf = make_unique<__gnu_cxx::stdio_filebuf<char> >(fd, flags);
rdbuf(m_filebuf.get());
}
void NativeFileStream::close()
{
if(m_filebuf) {
m_filebuf->close();
}
}
#endif
}

48
io/nativefilestream.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef IOUTILITIES_NATIVE_FILE_STREAM
#define IOUTILITIES_NATIVE_FILE_STREAM
#include "../global.h"
#ifndef PLATFORM_MINGW
# include <fstream>
#else
# include "../misc/memory.h"
# include <string>
# include <iostream>
# include <ext/stdio_filebuf.h>
#endif
namespace IoUtilities {
#if !defined(PLATFORM_MINGW) || !defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER)
typedef std::fstream NativeFileStream;
#else
class CPP_UTILITIES_EXPORT NativeFileStream : public std::iostream
{
public:
NativeFileStream();
~NativeFileStream();
bool is_open() const;
void open(const std::string &path, std::ios_base::openmode flags);
void close();
private:
std::unique_ptr<__gnu_cxx::stdio_filebuf<char> > m_filebuf;
std::__c_file m_cfile;
};
inline bool NativeFileStream::is_open() const
{
return m_filebuf && m_filebuf->is_open();
}
#endif
}
#endif // IOUTILITIES_NATIVE_FILE_STREAM