cpp-utilities/io/nativefilestream.cpp

171 lines
4.8 KiB
C++
Raw Normal View History

#include "./nativefilestream.h"
#if defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER) && (defined(PLATFORM_MINGW) || defined(PLATFORM_LINUX))
#include "./catchiofailure.h"
#ifdef PLATFORM_MINGW
2017-05-01 03:13:11 +02:00
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h> // yes, this is needed under Windows (https://msdn.microsoft.com/en-US/library/5yhhz3y7.aspx)
2017-05-01 03:13:11 +02:00
#include <windows.h>
#endif
#ifdef PLATFORM_LINUX
#include <cstdio>
#endif
#endif
using namespace std;
namespace IoUtilities {
#if defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER) && (defined(PLATFORM_MINGW) || defined(PLATFORM_UNIX))
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
};
2017-05-01 03:13:11 +02:00
NativeFileStream::NativeFileStream()
: m_filebuf(new __gnu_cxx::stdio_filebuf<char>)
{
rdbuf(m_filebuf.get());
}
NativeFileStream::NativeFileStream(NativeFileStream &&other)
: m_filebuf(std::move(other.m_filebuf))
, m_cfile(other.m_cfile)
{
}
NativeFileStream::~NativeFileStream()
2017-05-01 03:13:11 +02:00
{
}
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);
2017-05-01 03:13:11 +02:00
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);
2017-05-01 03:13:11 +02:00
if (requiredSize <= 0) {
::IoUtilities::throwIoFailure("Unable to convert path to UTF-16");
}
// initialize stdio_filebuf
const NativeFileParams nativeParams(openMode);
const int fileHandle = _wopen(widePath.get(), nativeParams.openMode, nativeParams.permissions);
if (fileHandle == -1) {
::IoUtilities::throwIoFailure("_wopen failed");
}
#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());
}
void NativeFileStream::close()
{
2017-05-01 03:13:11 +02:00
if (m_filebuf) {
m_filebuf->close();
}
}
#else
// std::fstream is used
#endif
2018-03-24 17:00:30 +01:00
} // namespace IoUtilities