Implement NativeFileStream under Unix/Linux/Android as well
* Like the Windows implementation this is disabled by default and can be enabled via compile-time switch which will affect the ABI. * Add support for opening a file from a file descriptor.
This commit is contained in:
parent
826c43ef8b
commit
5c9a834236
|
@ -1,21 +1,88 @@
|
||||||
#include "./nativefilestream.h"
|
#include "./nativefilestream.h"
|
||||||
|
|
||||||
|
#if defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER) && (defined(PLATFORM_MINGW) || defined(PLATFORM_LINUX))
|
||||||
|
|
||||||
|
#include "./catchiofailure.h"
|
||||||
|
|
||||||
#ifdef PLATFORM_MINGW
|
#ifdef PLATFORM_MINGW
|
||||||
#include "catchiofailure.h"
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/stat.h>
|
#include <io.h>
|
||||||
|
#include <sys/stat.h> // yes, this is needed under Windows (https://msdn.microsoft.com/en-US/library/5yhhz3y7.aspx)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PLATFORM_LINUX
|
||||||
|
#include <cstdio>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace IoUtilities {
|
namespace IoUtilities {
|
||||||
|
|
||||||
#if !defined(PLATFORM_MINGW) || !defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER)
|
#if defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER) && (defined(PLATFORM_MINGW) || defined(PLATFORM_UNIX))
|
||||||
|
|
||||||
// just use std::fstream
|
struct NativeFileParams {
|
||||||
|
|
||||||
|
#ifdef PLATFORM_MINGW
|
||||||
|
NativeFileParams(ios_base::openmode cppOpenMode)
|
||||||
|
: openMode(cppOpenMode & ios_base::binary ? _O_BINARY : 0)
|
||||||
|
, flags(cppOpenMode & ios_base::binary ? 0 : _O_TEXT)
|
||||||
|
, permissions(0)
|
||||||
|
{
|
||||||
|
if ((cppOpenMode & ios_base::out) && (cppOpenMode & ios_base::in)) {
|
||||||
|
openMode |= _O_RDWR;
|
||||||
|
} else if (cppOpenMode & ios_base::out) {
|
||||||
|
openMode |= _O_WRONLY | _O_CREAT;
|
||||||
|
permissions = _S_IREAD | _S_IWRITE;
|
||||||
|
} else if (cppOpenMode & ios_base::in) {
|
||||||
|
openMode |= _O_RDONLY;
|
||||||
|
flags |= _O_RDONLY;
|
||||||
|
}
|
||||||
|
if (cppOpenMode & ios_base::app) {
|
||||||
|
openMode |= _O_APPEND;
|
||||||
|
flags |= _O_APPEND;
|
||||||
|
}
|
||||||
|
if (cppOpenMode & ios_base::trunc) {
|
||||||
|
openMode |= _O_TRUNC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int openMode;
|
||||||
|
int flags;
|
||||||
|
int permissions;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
NativeFileParams(ios_base::openmode cppOpenMode)
|
||||||
|
{
|
||||||
|
if ((cppOpenMode & ios_base::in) && (cppOpenMode & ios_base::out)) {
|
||||||
|
if (cppOpenMode & ios_base::app) {
|
||||||
|
openMode = "a+";
|
||||||
|
} else if (cppOpenMode & ios_base::trunc) {
|
||||||
|
openMode = "w+";
|
||||||
|
} else {
|
||||||
|
openMode = "r+";
|
||||||
|
}
|
||||||
|
} else if (cppOpenMode & ios_base::in) {
|
||||||
|
openMode = 'r';
|
||||||
|
} else if (cppOpenMode & ios_base::out) {
|
||||||
|
if (cppOpenMode & ios_base::app) {
|
||||||
|
openMode = 'a';
|
||||||
|
} else if (cppOpenMode & ios_base::trunc) {
|
||||||
|
openMode = 'w';
|
||||||
|
} else {
|
||||||
|
openMode = "r+";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cppOpenMode & ios_base::binary) {
|
||||||
|
openMode += 'b';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string openMode;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
NativeFileStream::NativeFileStream()
|
NativeFileStream::NativeFileStream()
|
||||||
: m_filebuf(new __gnu_cxx::stdio_filebuf<char>)
|
: m_filebuf(new __gnu_cxx::stdio_filebuf<char>)
|
||||||
|
@ -23,12 +90,19 @@ NativeFileStream::NativeFileStream()
|
||||||
rdbuf(m_filebuf.get());
|
rdbuf(m_filebuf.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NativeFileStream::NativeFileStream(NativeFileStream &&other)
|
||||||
|
: m_filebuf(std::move(other.m_filebuf))
|
||||||
|
, m_cfile(other.m_cfile)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
NativeFileStream::~NativeFileStream()
|
NativeFileStream::~NativeFileStream()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeFileStream::open(const string &path, ios_base::openmode flags)
|
void NativeFileStream::open(const string &path, ios_base::openmode openMode)
|
||||||
{
|
{
|
||||||
|
#ifdef PLATFORM_MINGW
|
||||||
// convert path to UTF-16
|
// convert path to UTF-16
|
||||||
int requiredSize = MultiByteToWideChar(CP_UTF8, 0, path.data(), -1, nullptr, 0);
|
int requiredSize = MultiByteToWideChar(CP_UTF8, 0, path.data(), -1, nullptr, 0);
|
||||||
if (requiredSize <= 0) {
|
if (requiredSize <= 0) {
|
||||||
|
@ -39,26 +113,45 @@ void NativeFileStream::open(const string &path, ios_base::openmode flags)
|
||||||
if (requiredSize <= 0) {
|
if (requiredSize <= 0) {
|
||||||
::IoUtilities::throwIoFailure("Unable to convert path to UTF-16");
|
::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
|
// initialize stdio_filebuf
|
||||||
int fd = _wopen(widePath.get(), nativeFlags, permissions);
|
const NativeFileParams nativeParams(openMode);
|
||||||
if (fd == -1) {
|
const int fileHandle = _wopen(widePath.get(), nativeParams.openMode, nativeParams.permissions);
|
||||||
|
if (fileHandle == -1) {
|
||||||
::IoUtilities::throwIoFailure("_wopen failed");
|
::IoUtilities::throwIoFailure("_wopen failed");
|
||||||
}
|
}
|
||||||
m_filebuf = make_unique<__gnu_cxx::stdio_filebuf<char>>(fd, flags);
|
#else
|
||||||
|
|
||||||
|
// initialize stdio_filebuf
|
||||||
|
const NativeFileParams nativeParams(openMode);
|
||||||
|
const auto fileHandle = fopen(path.data(), nativeParams.openMode.data());
|
||||||
|
if (!fileHandle) {
|
||||||
|
::IoUtilities::throwIoFailure("fopen failed");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
m_filebuf = make_unique<__gnu_cxx::stdio_filebuf<char>>(fileHandle, openMode);
|
||||||
|
rdbuf(m_filebuf.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeFileStream::openFromFileDescriptor(int fileDescriptor, ios_base::openmode openMode)
|
||||||
|
{
|
||||||
|
const NativeFileParams nativeParams(openMode);
|
||||||
|
#ifdef PLATFORM_MINGW
|
||||||
|
const auto fileHandle = _get_osfhandle(fileDescriptor);
|
||||||
|
if (fileHandle == -1) {
|
||||||
|
::IoUtilities::throwIoFailure("_get_osfhandle failed");
|
||||||
|
}
|
||||||
|
const auto osFileHandle = _open_osfhandle(fileHandle, nativeParams.flags);
|
||||||
|
if (osFileHandle == -1) {
|
||||||
|
::IoUtilities::throwIoFailure("_open_osfhandle failed");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
const auto fileHandle = fdopen(fileDescriptor, nativeParams.openMode.data());
|
||||||
|
if (!fileHandle) {
|
||||||
|
::IoUtilities::throwIoFailure("fdopen failed");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
m_filebuf = make_unique<__gnu_cxx::stdio_filebuf<char>>(fileHandle, openMode);
|
||||||
rdbuf(m_filebuf.get());
|
rdbuf(m_filebuf.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,5 +162,9 @@ void NativeFileStream::close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// std::fstream is used
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
} // namespace IoUtilities
|
} // namespace IoUtilities
|
||||||
|
|
|
@ -3,31 +3,35 @@
|
||||||
|
|
||||||
#include "../global.h"
|
#include "../global.h"
|
||||||
|
|
||||||
#ifndef PLATFORM_MINGW
|
#if defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER)
|
||||||
#include <fstream>
|
#if defined(PLATFORM_MINGW) || defined(PLATFORM_LINUX)
|
||||||
#else
|
|
||||||
#include <ext/stdio_filebuf.h>
|
#include <ext/stdio_filebuf.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#else
|
||||||
|
#error "Platform not supported by NativeFileStream."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <fstream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace IoUtilities {
|
namespace IoUtilities {
|
||||||
|
|
||||||
#if !defined(PLATFORM_MINGW) || !defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER)
|
#if defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER) && (defined(PLATFORM_MINGW) || defined(PLATFORM_UNIX))
|
||||||
|
|
||||||
typedef std::fstream NativeFileStream;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
class CPP_UTILITIES_EXPORT NativeFileStream : public std::iostream {
|
class CPP_UTILITIES_EXPORT NativeFileStream : public std::iostream {
|
||||||
public:
|
public:
|
||||||
NativeFileStream();
|
NativeFileStream();
|
||||||
|
NativeFileStream(NativeFileStream &&);
|
||||||
~NativeFileStream();
|
~NativeFileStream();
|
||||||
|
|
||||||
bool is_open() const;
|
bool is_open() const;
|
||||||
void open(const std::string &path, std::ios_base::openmode flags);
|
void open(const std::string &path, std::ios_base::openmode openMode);
|
||||||
|
void openFromFileDescriptor(int fileDescriptor, std::ios_base::openmode openMode);
|
||||||
void close();
|
void close();
|
||||||
|
std::__c_file fileHandle();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<__gnu_cxx::stdio_filebuf<char>> m_filebuf;
|
std::unique_ptr<__gnu_cxx::stdio_filebuf<char>> m_filebuf;
|
||||||
|
@ -39,7 +43,17 @@ inline bool NativeFileStream::is_open() const
|
||||||
return m_filebuf && m_filebuf->is_open();
|
return m_filebuf && m_filebuf->is_open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::__c_file NativeFileStream::fileHandle()
|
||||||
|
{
|
||||||
|
return m_cfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef std::fstream NativeFileStream;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace IoUtilities
|
} // namespace IoUtilities
|
||||||
|
|
||||||
#endif // IOUTILITIES_NATIVE_FILE_STREAM
|
#endif // IOUTILITIES_NATIVE_FILE_STREAM
|
||||||
|
|
Loading…
Reference in New Issue