3 #ifdef CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
5 #ifdef PLATFORM_WINDOWS
6 #include "../conversion/stringconversion.h"
10 #if defined(CPP_UTILITIES_USE_GNU_CXX_STDIO_FILEBUF)
11 #include <ext/stdio_filebuf.h>
12 #elif defined(CPP_UTILITIES_USE_BOOST_IOSTREAMS)
13 #include <boost/iostreams/device/file_descriptor.hpp>
14 #include <boost/iostreams/stream.hpp>
16 #error "Configuration for NativeFileStream backend insufficient."
20 #if defined(PLATFORM_UNIX)
24 #include <sys/types.h>
25 #elif defined(PLATFORM_WINDOWS)
38 #ifdef CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
40 #ifdef CPP_UTILITIES_USE_GNU_CXX_STDIO_FILEBUF
41 using StreamBuffer = __gnu_cxx::stdio_filebuf<char>;
42 #else // CPP_UTILITIES_USE_BOOST_IOSTREAMS
43 using StreamBuffer = boost::iostreams::stream_buffer<boost::iostreams::file_descriptor>;
46 struct NativeFileParams {
48 #ifdef PLATFORM_WINDOWS
49 NativeFileParams(ios_base::openmode cppOpenMode)
50 : openMode(cppOpenMode & ios_base::binary ? _O_BINARY : 0)
51 , flags(cppOpenMode & ios_base::binary ? 0 : _O_TEXT)
57 if ((cppOpenMode & ios_base::out) && (cppOpenMode & ios_base::in)) {
59 access = GENERIC_READ | GENERIC_WRITE;
60 shareMode = FILE_SHARE_READ;
61 creation = OPEN_EXISTING;
62 }
else if (cppOpenMode & ios_base::out) {
63 openMode |= _O_WRONLY | _O_CREAT;
64 permissions = _S_IREAD | _S_IWRITE;
65 access = GENERIC_WRITE;
66 creation = OPEN_ALWAYS;
67 }
else if (cppOpenMode & ios_base::in) {
68 openMode |= _O_RDONLY;
70 access = GENERIC_READ;
71 shareMode = FILE_SHARE_READ;
72 creation = OPEN_EXISTING;
74 if (cppOpenMode & ios_base::app) {
75 openMode |= _O_APPEND;
78 if (cppOpenMode & ios_base::trunc) {
80 creation = (cppOpenMode & ios_base::in) ? TRUNCATE_EXISTING : CREATE_ALWAYS;
91 NativeFileParams(ios_base::openmode cppOpenMode)
94 if ((cppOpenMode & ios_base::in) && (cppOpenMode & ios_base::out)) {
95 if (cppOpenMode & ios_base::app) {
97 openFlags = O_RDWR | O_APPEND;
98 }
else if (cppOpenMode & ios_base::trunc) {
100 openFlags = O_RDWR | O_TRUNC;
105 }
else if (cppOpenMode & ios_base::in) {
107 openFlags = O_RDONLY;
108 }
else if (cppOpenMode & ios_base::out) {
109 if (cppOpenMode & ios_base::app) {
111 openFlags = O_WRONLY | O_APPEND;
112 }
else if (cppOpenMode & ios_base::trunc) {
114 openFlags = O_WRONLY | O_TRUNC | O_CREAT;
117 openFlags = O_WRONLY | O_CREAT;
120 if (cppOpenMode & ios_base::binary) {
125 std::string openMode;
138 NativeFileStream::FileBuffer::FileBuffer(std::basic_streambuf<char> *buffer)
147 NativeFileStream::FileBuffer::FileBuffer(
const string &path, ios_base::openmode openMode)
149 #ifdef PLATFORM_WINDOWS
151 const auto widePath(makeWidePath(path));
155 const NativeFileParams nativeParams(openMode);
158 #ifdef CPP_UTILITIES_USE_GNU_CXX_STDIO_FILEBUF
159 #ifdef PLATFORM_WINDOWS
160 descriptor = _wopen(widePath.get(), nativeParams.openMode, nativeParams.permissions);
161 if (descriptor == -1) {
162 throw std::ios_base::failure(
"_wopen failed");
165 descriptor = ::open(path.data(), nativeParams.openFlags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
166 if (descriptor == -1) {
167 throw std::ios_base::failure(
"open failed");
170 buffer = make_unique<StreamBuffer>(descriptor, openMode);
171 #else // CPP_UTILITIES_USE_BOOST_IOSTREAMS
172 #ifdef PLATFORM_WINDOWS
173 handle = CreateFileW(widePath.get(), nativeParams.access, nativeParams.shareMode,
nullptr, nativeParams.creation, FILE_ATTRIBUTE_NORMAL,
nullptr);
174 if (handle == INVALID_HANDLE_VALUE) {
175 throw std::ios_base::failure(
"CreateFileW failed");
177 buffer = make_unique<StreamBuffer>(handle, boost::iostreams::close_handle);
180 descriptor = ::open(path.data(), nativeParams.openFlags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
181 if (descriptor == -1) {
182 throw std::ios_base::failure(
"open failed");
184 buffer = make_unique<StreamBuffer>(descriptor, boost::iostreams::close_handle);
195 NativeFileStream::FileBuffer::FileBuffer(
int fileDescriptor, ios_base::openmode openMode)
196 : descriptor(fileDescriptor)
198 #ifdef CPP_UTILITIES_USE_GNU_CXX_STDIO_FILEBUF
199 buffer = make_unique<StreamBuffer>(descriptor, openMode);
200 #else // CPP_UTILITIES_USE_BOOST_IOSTREAMS
202 #ifdef PLATFORM_WINDOWS
203 handle = reinterpret_cast<Handle>(_get_osfhandle(descriptor));
204 buffer = make_unique<StreamBuffer>(handle, boost::iostreams::close_handle);
206 buffer = make_unique<StreamBuffer>(descriptor, boost::iostreams::close_handle);
215 : iostream(new StreamBuffer)
224 : iostream(other.m_data.buffer.release())
227 #ifdef PLATFORM_WINDOWS
228 m_data.handle = other.m_data.handle;
230 m_data.descriptor = other.m_data.descriptor;
236 NativeFileStream::~NativeFileStream()
243 bool NativeFileStream::isOpen()
const
245 return m_data.buffer && static_cast<const StreamBuffer *>(m_data.buffer.get())->is_open();
261 void NativeFileStream::open(
const string &path, ios_base::openmode openMode)
263 setData(FileBuffer(path, openMode), openMode);
273 void NativeFileStream::open(
int fileDescriptor, ios_base::openmode openMode)
275 setData(FileBuffer(fileDescriptor, openMode), openMode);
281 void NativeFileStream::close()
284 static_cast<StreamBuffer *>(m_data.buffer.get())->close();
285 #ifdef PLATFORM_WINDOWS
286 m_data.handle =
nullptr;
288 m_data.descriptor = -1;
295 void NativeFileStream::setData(FileBuffer data, std::ios_base::openmode openMode)
297 rdbuf(data.buffer.get());
298 m_data = std::move(data);
299 m_openMode = openMode;
300 #if defined(PLATFORM_WINDOWS) && defined(CPP_UTILITIES_USE_BOOST_IOSTREAMS)
302 if (m_openMode & ios_base::app) {
303 seekp(0, ios_base::end);
308 #ifdef PLATFORM_WINDOWS
313 std::unique_ptr<wchar_t[]> NativeFileStream::makeWidePath(
const std::string &path)
315 auto widePath = ::CppUtilities::convertMultiByteToWide(path);
316 if (!widePath.first) {
317 throw std::ios_base::failure(
"Unable to convert path to UTF-16");
319 return std::move(widePath.first);