C++ Utilities  4.15.0
Useful C++ classes and routines such as argument parser, IO and conversion utilities
nativefilestream.cpp
Go to the documentation of this file.
1 #include "./nativefilestream.h"
2 
3 #if defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER) && (defined(PLATFORM_MINGW) || defined(PLATFORM_LINUX))
4 
5 #include "./catchiofailure.h"
6 
7 #ifdef PLATFORM_MINGW
8 #include <fcntl.h>
9 #include <io.h>
10 #include <sys/stat.h> // yes, this is needed under Windows (https://msdn.microsoft.com/en-US/library/5yhhz3y7.aspx)
11 #include <windows.h>
12 #endif
13 
14 #ifdef PLATFORM_LINUX
15 #include <cstdio>
16 #endif
17 
18 #endif
19 
20 using namespace std;
21 
22 namespace IoUtilities {
23 
24 #if defined(CPP_UTILITIES_USE_NATIVE_FILE_BUFFER) && (defined(PLATFORM_MINGW) || defined(PLATFORM_UNIX))
25 
26 struct NativeFileParams {
27 
28 #ifdef PLATFORM_MINGW
29  NativeFileParams(ios_base::openmode cppOpenMode)
30  : openMode(cppOpenMode & ios_base::binary ? _O_BINARY : 0)
31  , flags(cppOpenMode & ios_base::binary ? 0 : _O_TEXT)
32  , permissions(0)
33  {
34  if ((cppOpenMode & ios_base::out) && (cppOpenMode & ios_base::in)) {
35  openMode |= _O_RDWR;
36  } else if (cppOpenMode & ios_base::out) {
37  openMode |= _O_WRONLY | _O_CREAT;
38  permissions = _S_IREAD | _S_IWRITE;
39  } else if (cppOpenMode & ios_base::in) {
40  openMode |= _O_RDONLY;
41  flags |= _O_RDONLY;
42  }
43  if (cppOpenMode & ios_base::app) {
44  openMode |= _O_APPEND;
45  flags |= _O_APPEND;
46  }
47  if (cppOpenMode & ios_base::trunc) {
48  openMode |= _O_TRUNC;
49  }
50  }
51 
52  int openMode;
53  int flags;
54  int permissions;
55 
56 #else
57  NativeFileParams(ios_base::openmode cppOpenMode)
58  {
59  if ((cppOpenMode & ios_base::in) && (cppOpenMode & ios_base::out)) {
60  if (cppOpenMode & ios_base::app) {
61  openMode = "a+";
62  } else if (cppOpenMode & ios_base::trunc) {
63  openMode = "w+";
64  } else {
65  openMode = "r+";
66  }
67  } else if (cppOpenMode & ios_base::in) {
68  openMode = 'r';
69  } else if (cppOpenMode & ios_base::out) {
70  if (cppOpenMode & ios_base::app) {
71  openMode = 'a';
72  } else if (cppOpenMode & ios_base::trunc) {
73  openMode = 'w';
74  } else {
75  openMode = "r+";
76  }
77  }
78  if (cppOpenMode & ios_base::binary) {
79  openMode += 'b';
80  }
81  }
82 
83  std::string openMode;
84 #endif
85 };
86 
88  : m_filebuf(new __gnu_cxx::stdio_filebuf<char>)
89 {
90  rdbuf(m_filebuf.get());
91 }
92 
94  : m_filebuf(std::move(other.m_filebuf))
95  , m_cfile(other.m_cfile)
96 {
97 }
98 
99 NativeFileStream::~NativeFileStream()
100 {
101 }
102 
103 void NativeFileStream::open(const string &path, ios_base::openmode openMode)
104 {
105 #ifdef PLATFORM_MINGW
106  // convert path to UTF-16
107  int requiredSize = MultiByteToWideChar(CP_UTF8, 0, path.data(), -1, nullptr, 0);
108  if (requiredSize <= 0) {
109  ::IoUtilities::throwIoFailure("Unable to calculate buffer size for conversion of path to UTF-16");
110  }
111  auto widePath = make_unique<wchar_t[]>(static_cast<size_t>(requiredSize));
112  requiredSize = MultiByteToWideChar(CP_UTF8, 0, path.data(), -1, widePath.get(), requiredSize);
113  if (requiredSize <= 0) {
114  ::IoUtilities::throwIoFailure("Unable to convert path to UTF-16");
115  }
116 
117  // initialize stdio_filebuf
118  const NativeFileParams nativeParams(openMode);
119  const int fileHandle = _wopen(widePath.get(), nativeParams.openMode, nativeParams.permissions);
120  if (fileHandle == -1) {
121  ::IoUtilities::throwIoFailure("_wopen failed");
122  }
123 #else
124 
125  // initialize stdio_filebuf
126  const NativeFileParams nativeParams(openMode);
127  const auto fileHandle = fopen(path.data(), nativeParams.openMode.data());
128  if (!fileHandle) {
129  ::IoUtilities::throwIoFailure("fopen failed");
130  }
131 #endif
132  m_filebuf = make_unique<__gnu_cxx::stdio_filebuf<char>>(fileHandle, openMode);
133  rdbuf(m_filebuf.get());
134 }
135 
136 void NativeFileStream::openFromFileDescriptor(int fileDescriptor, ios_base::openmode openMode)
137 {
138  const NativeFileParams nativeParams(openMode);
139 #ifdef PLATFORM_MINGW
140  const auto fileHandle = _get_osfhandle(fileDescriptor);
141  if (fileHandle == -1) {
142  ::IoUtilities::throwIoFailure("_get_osfhandle failed");
143  }
144  const auto osFileHandle = _open_osfhandle(fileHandle, nativeParams.flags);
145  if (osFileHandle == -1) {
146  ::IoUtilities::throwIoFailure("_open_osfhandle failed");
147  }
148 #else
149  const auto fileHandle = fdopen(fileDescriptor, nativeParams.openMode.data());
150  if (!fileHandle) {
151  ::IoUtilities::throwIoFailure("fdopen failed");
152  }
153 #endif
154  m_filebuf = make_unique<__gnu_cxx::stdio_filebuf<char>>(fileHandle, openMode);
155  rdbuf(m_filebuf.get());
156 }
157 
158 void NativeFileStream::close()
159 {
160  if (m_filebuf) {
161  m_filebuf->close();
162  }
163 }
164 
165 #else
166 
167 // std::fstream is used
168 
169 #endif
170 } // namespace IoUtilities
CPP_UTILITIES_EXPORT void throwIoFailure(const char *what)
Throws an std::ios_base::failure with the specified message.
STL namespace.
std::fstream NativeFileStream
Contains utility classes helping to read and write streams.
Definition: binaryreader.h:10