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"
|
||||
|
||||
#if defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER) && (defined(PLATFORM_MINGW) || defined(PLATFORM_LINUX))
|
||||
|
||||
#include "./catchiofailure.h"
|
||||
|
||||
#ifdef PLATFORM_MINGW
|
||||
#include "catchiofailure.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>
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_LINUX
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
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
|
||||
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()
|
||||
: m_filebuf(new __gnu_cxx::stdio_filebuf<char>)
|
||||
|
@ -23,12 +90,19 @@ NativeFileStream::NativeFileStream()
|
|||
rdbuf(m_filebuf.get());
|
||||
}
|
||||
|
||||
NativeFileStream::NativeFileStream(NativeFileStream &&other)
|
||||
: m_filebuf(std::move(other.m_filebuf))
|
||||
, m_cfile(other.m_cfile)
|
||||
{
|
||||
}
|
||||
|
||||
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
|
||||
int requiredSize = MultiByteToWideChar(CP_UTF8, 0, path.data(), -1, nullptr, 0);
|
||||
if (requiredSize <= 0) {
|
||||
|
@ -39,26 +113,45 @@ void NativeFileStream::open(const string &path, ios_base::openmode flags)
|
|||
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) {
|
||||
const NativeFileParams nativeParams(openMode);
|
||||
const int fileHandle = _wopen(widePath.get(), nativeParams.openMode, nativeParams.permissions);
|
||||
if (fileHandle == -1) {
|
||||
::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());
|
||||
}
|
||||
|
||||
|
@ -69,5 +162,9 @@ void NativeFileStream::close()
|
|||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// std::fstream is used
|
||||
|
||||
#endif
|
||||
} // namespace IoUtilities
|
||||
|
|
|
@ -3,31 +3,35 @@
|
|||
|
||||
#include "../global.h"
|
||||
|
||||
#ifndef PLATFORM_MINGW
|
||||
#include <fstream>
|
||||
#else
|
||||
#if defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER)
|
||||
#if defined(PLATFORM_MINGW) || defined(PLATFORM_LINUX)
|
||||
#include <ext/stdio_filebuf.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#else
|
||||
#error "Platform not supported by NativeFileStream."
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
namespace IoUtilities {
|
||||
|
||||
#if !defined(PLATFORM_MINGW) || !defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER)
|
||||
|
||||
typedef std::fstream NativeFileStream;
|
||||
|
||||
#else
|
||||
#if defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER) && (defined(PLATFORM_MINGW) || defined(PLATFORM_UNIX))
|
||||
|
||||
class CPP_UTILITIES_EXPORT NativeFileStream : public std::iostream {
|
||||
public:
|
||||
NativeFileStream();
|
||||
NativeFileStream(NativeFileStream &&);
|
||||
~NativeFileStream();
|
||||
|
||||
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();
|
||||
std::__c_file fileHandle();
|
||||
|
||||
private:
|
||||
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();
|
||||
}
|
||||
|
||||
inline std::__c_file NativeFileStream::fileHandle()
|
||||
{
|
||||
return m_cfile;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef std::fstream NativeFileStream;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace IoUtilities
|
||||
|
||||
#endif // IOUTILITIES_NATIVE_FILE_STREAM
|
||||
|
|
Loading…
Reference in New Issue