diff --git a/CMakeLists.txt b/CMakeLists.txt index f55dae5..0365013 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/io/nativefilestream.cpp b/io/nativefilestream.cpp new file mode 100644 index 0000000..aa1069b --- /dev/null +++ b/io/nativefilestream.cpp @@ -0,0 +1,73 @@ +#include "./nativefilestream.h" + +#ifdef PLATFORM_MINGW +# include +# include +# include +# include +#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) +{ + 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(static_cast(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 >(fd, flags); + rdbuf(m_filebuf.get()); +} + +void NativeFileStream::close() +{ + if(m_filebuf) { + m_filebuf->close(); + } +} + +#endif + +} diff --git a/io/nativefilestream.h b/io/nativefilestream.h new file mode 100644 index 0000000..91d8dc2 --- /dev/null +++ b/io/nativefilestream.h @@ -0,0 +1,48 @@ +#ifndef IOUTILITIES_NATIVE_FILE_STREAM +#define IOUTILITIES_NATIVE_FILE_STREAM + +#include "../global.h" + +#ifndef PLATFORM_MINGW +# include +#else +# include "../misc/memory.h" +# include +# include +# include +#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 > 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 +