Crypto++ 8.2 Free C++ class library of cryptographic schemes

files.cpp
1 // files.cpp - originally written and placed in the public domain by Wei Dai
2
3 #include "pch.h"
4
5 #ifndef CRYPTOPP_IMPORTS
6
7 #include "files.h"
8
9 #include <iostream>
10 #include <fstream>
11 #include <limits>
12
13 ANONYMOUS_NAMESPACE_BEGIN
14
15 /// \brief Disable badbit, failbit and eof exceptions
16 /// \sa https://github.com/weidai11/cryptopp/pull/968 and
17 /// https://www.cplusplus.com/reference/ios/ios/exceptions
18 class IosExceptionMask
19 {
20 public:
21 IosExceptionMask(std::istream& stream) : m_stream(stream) {
22 m_mask = m_stream.exceptions();
23 m_stream.exceptions(static_cast<std::ios::iostate>(0));
24 }
25
26 IosExceptionMask(std::istream& stream, std::ios::iostate newMask) : m_stream(stream) {
27 m_mask = m_stream.exceptions();
28 m_stream.exceptions(newMask);
29 }
30
31 ~IosExceptionMask() {
32 m_stream.exceptions(m_mask);
33 }
34
35 private:
36 std::istream& m_stream;
37 std::ios::iostate m_mask;
38 };
39
40 ANONYMOUS_NAMESPACE_END
41
42 NAMESPACE_BEGIN(CryptoPP)
43
44 #if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING)
45 void Files_TestInstantiations()
46 {
47 FileStore f0;
48 FileSource f1;
49 FileSink f2;
50 }
51 #endif
52
53 void FileStore::StoreInitialize(const NameValuePairs &parameters)
54 {
55 m_waiting = false;
56 m_stream = NULLPTR;
57 m_file.release();
58
59 const char *fileName = NULLPTR;
60 #if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400
61 const wchar_t *fileNameWide = NULLPTR;
62 if (!parameters.GetValue(Name::InputFileNameWide(), fileNameWide))
63 #endif
64 if (!parameters.GetValue(Name::InputFileName(), fileName))
65 {
66 parameters.GetValue(Name::InputStreamPointer(), m_stream);
67 return;
68 }
69
70 std::ios::openmode binary = parameters.GetValueWithDefault(Name::InputBinaryMode(), true) ? std::ios::binary : std::ios::openmode(0);
71 m_file.reset(new std::ifstream);
72 #ifdef CRYPTOPP_UNIX_AVAILABLE
73 std::string narrowed;
74 if (fileNameWide)
75 fileName = (narrowed = StringNarrow(fileNameWide)).c_str();
76 #endif
77 #if _MSC_VER >= 1400
78 if (fileNameWide)
79 {
80 m_file->open(fileNameWide, std::ios::in | binary);
81 if (!*m_file)
82 throw OpenErr(StringNarrow(fileNameWide, false));
83 }
84 #endif
85 if (fileName)
86 {
87 m_file->open(fileName, std::ios::in | binary);
88 if (!*m_file)
89 throw OpenErr(fileName);
90 }
91 m_stream = m_file.get();
92 }
93
94 lword FileStore::MaxRetrievable() const
95 {
96 if (!m_stream)
97 return 0;
98
99 // Disable badbit, failbit and eof exceptions
100 IosExceptionMask guard(*m_stream);
101
102 // Clear error bits due to seekg(). Also see
103 // https://github.com/weidai11/cryptopp/pull/968
104 std::streampos current = m_stream->tellg();
105 std::streampos end = m_stream->seekg(0, std::ios::end).tellg();
106 m_stream->clear();
107 m_stream->seekg(current);
108 m_stream->clear();
109
110 // Return max for a non-seekable stream
111 // https://www.cplusplus.com/reference/istream/istream/tellg
112 if (end == static_cast<std::streampos>(-1))
113 return LWORD_MAX;
114
115 return end-current;
116 }
117
118 size_t FileStore::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking)
119 {
120 if (!m_stream)
121 {
122 transferBytes = 0;
123 return 0;
124 }
125
126 lword size=transferBytes;
127 transferBytes = 0;
128
129 if (m_waiting)
130 goto output;
131
132 while (size && m_stream->good())
133 {
134 {
135 size_t spaceSize = 1024;
136 m_space = HelpCreatePutSpace(target, channel, 1, UnsignedMin(size_t(SIZE_MAX), size), spaceSize);
137
138 m_stream->read((char *)m_space, (unsigned int)STDMIN(size, (lword)spaceSize));
139 }
140 m_len = (size_t)m_stream->gcount();
141 size_t blockedBytes;
142 output:
143 blockedBytes = target.ChannelPutModifiable2(channel, m_space, m_len, 0, blocking);
144 m_waiting = blockedBytes > 0;
145 if (m_waiting)
146 return blockedBytes;
147 size -= m_len;
148 transferBytes += m_len;
149 }
150
151 if (!m_stream->good() && !m_stream->eof())
152 throw ReadErr();
153
154 return 0;
155 }
156
157 size_t FileStore::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const
158 {
159 if (!m_stream)
160 return 0;
161
162 if (begin == 0 && end == 1)
163 {
164 int result = m_stream->peek();
165 if (result == std::char_traits<char>::eof())
166 return 0;
167 else
168 {
169 size_t blockedBytes = target.ChannelPut(channel, byte(result), blocking);
170 begin += 1-blockedBytes;
171 return blockedBytes;
172 }
173 }
174
175 // TODO: figure out what happens on cin
176 std::streampos current = m_stream->tellg();
177 std::streampos endPosition = m_stream->seekg(0, std::ios::end).tellg();
178 std::streampos newPosition = current + static_cast<std::streamoff>(begin);
179
180 if (newPosition >= endPosition)
181 {
182 m_stream->seekg(current);
183 return 0; // don't try to seek beyond the end of file
184 }
185 m_stream->seekg(newPosition);
186 try
187 {
188 CRYPTOPP_ASSERT(!m_waiting);
189 lword copyMax = end-begin;
190 size_t blockedBytes = const_cast<FileStore *>(this)->TransferTo2(target, copyMax, channel, blocking);
191 begin += copyMax;
192 if (blockedBytes)
193 {
194 const_cast<FileStore *>(this)->m_waiting = false;
195 return blockedBytes;
196 }
197 }
198 catch(...)
199 {
200 m_stream->clear();
201 m_stream->seekg(current);
202 throw;
203 }
204 m_stream->clear();
205 m_stream->seekg(current);
206
207 return 0;
208 }
209
210 lword FileStore::Skip(lword skipMax)
211 {
212 if (!m_stream)
213 return 0;
214
215 lword oldPos = m_stream->tellg();
216 std::istream::off_type offset;
217 if (!SafeConvert(skipMax, offset))
218 throw InvalidArgument("FileStore: maximum seek offset exceeded");
219 m_stream->seekg(offset, std::ios::cur);
220 return (lword)m_stream->tellg() - oldPos;
221 }
222
223 void FileSink::IsolatedInitialize(const NameValuePairs &parameters)
224 {
225 m_stream = NULLPTR;
226 m_file.release();
227
228 const char *fileName = NULLPTR;
229 #if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400
230 const wchar_t *fileNameWide = NULLPTR;
231 if (!parameters.GetValue(Name::OutputFileNameWide(), fileNameWide))
232 #endif
233 if (!parameters.GetValue(Name::OutputFileName(), fileName))
234 {
235 parameters.GetValue(Name::OutputStreamPointer(), m_stream);
236 return;
237 }
238
239 std::ios::openmode binary = parameters.GetValueWithDefault(Name::OutputBinaryMode(), true) ? std::ios::binary : std::ios::openmode(0);
240 m_file.reset(new std::ofstream);
241 #ifdef CRYPTOPP_UNIX_AVAILABLE
242 std::string narrowed;
243 if (fileNameWide)
244 fileName = (narrowed = StringNarrow(fileNameWide)).c_str();
245 #elif (CRYPTOPP_MSC_VERSION >= 1400)
246 if (fileNameWide)
247 {
248 m_file->open(fileNameWide, std::ios::out | std::ios::trunc | binary);
249 if (!*m_file)
250 throw OpenErr(StringNarrow(fileNameWide, false));
251 }
252 #endif
253 if (fileName)
254 {
255 m_file->open(fileName, std::ios::out | std::ios::trunc | binary);
256 if (!*m_file)
257 throw OpenErr(fileName);
258 }
259 m_stream = m_file.get();
260 }
261
262 bool FileSink::IsolatedFlush(bool hardFlush, bool blocking)
263 {
264 CRYPTOPP_UNUSED(hardFlush), CRYPTOPP_UNUSED(blocking);
265 if (!m_stream)
266 throw Err("FileSink: output stream not opened");
267
268 m_stream->flush();
269 if (!m_stream->good())
270 throw WriteErr();
271
272 return false;
273 }
274
275 size_t FileSink::Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
276 {
277 CRYPTOPP_UNUSED(blocking);
278 if (!m_stream)
279 throw Err("FileSink: output stream not opened");
280
281 while (length > 0)
282 {
283 std::streamsize size;
284 if (!SafeConvert(length, size))
285 size = ((std::numeric_limits<std::streamsize>::max)());
286 m_stream->write((const char *)inString, size);
287 inString += size;
288 length -= (size_t)size;
289 }
290
291 if (messageEnd)
292 m_stream->flush();
293
294 if (!m_stream->good())
295 throw WriteErr();
296
297 return 0;
298 }
299
300 NAMESPACE_END
301
302 #endif
InvalidArgument
An invalid argument was detected.
Definition: cryptlib.h:202
BufferedTransformation::ChannelPutModifiable2
virtual size_t ChannelPutModifiable2(const std::string &channel, byte *inString, size_t length, int messageEnd, bool blocking)
Input multiple bytes that may be modified by callee on a channel.
Definition: cryptlib.cpp:475
StringNarrow
std::string StringNarrow(const wchar_t *str, bool throwOnError=true)
Converts a wide character C-string to a multibyte string.
Definition: misc.cpp:154
Name::InputFileNameWide
const char * InputFileNameWide()
const wchar_t *
Definition: argnames.h:59
SafeConvert
bool SafeConvert(T1 from, T2 &to)
Tests whether a conversion from -> to is safe to perform.
Definition: misc.h:690
NameValuePairs::GetValueWithDefault
T GetValueWithDefault(const char *name, T defaultValue) const
Get a named value.
Definition: cryptlib.h:392
BufferedTransformation::ChannelPut
size_t ChannelPut(const std::string &channel, byte inByte, bool blocking=true)
Input a byte for processing on a channel.
Definition: cryptlib.h:2173
FileStore::TransferTo2
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true)
Transfer bytes from this object to another BufferedTransformation.
Definition: files.cpp:118
FileSource
Implementation of Store interface.
Definition: files.h:86
Name::OutputStreamPointer
const char * OutputStreamPointer()
std::ostream *
Definition: argnames.h:64
Name::InputFileName
const char * InputFileName()
const char *
Definition: argnames.h:58
BufferedTransformation
Interface for buffered transformations.
Definition: cryptlib.h:1630
FileSink::Put2
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
Input multiple bytes for processing.
Definition: files.cpp:275
FileSink::IsolatedFlush
bool IsolatedFlush(bool hardFlush, bool blocking)
Flushes data buffered by this object, without signal propagation.
Definition: files.cpp:262
Name::InputStreamPointer
const char * InputStreamPointer()
std::istream *
Definition: argnames.h:60
Name::OutputBinaryMode
const char * OutputBinaryMode()
bool
Definition: argnames.h:65
FileStore::Skip
lword Skip(lword skipMax=ULONG_MAX)
Discard skipMax bytes from the output buffer.
Definition: files.cpp:210
Name::OutputFileName
const char * OutputFileName()
const char *
Definition: argnames.h:62
FileSink::WriteErr
Exception thrown when file-based write error is encountered.
Definition: files.h:142
pch.h
Precompiled header file.
FileSink::Err
Exception thrown when file-based error is encountered.
Definition: files.h:134
UnsignedMin
const T1 UnsignedMin(const T1 &a, const T2 &b)
Safe comparison of values that could be neagtive and incorrectly promoted.
Definition: misc.h:674
STDMIN
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:635
CRYPTOPP_ASSERT
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:68
FileStore
Implementation of Store interface.
Definition: files.h:22
FileSink::OpenErr
Exception thrown when file-based open error is encountered.
Definition: files.h:140
FileStore::CopyRangeTo2
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const
Copy bytes from this object to another BufferedTransformation.
Definition: files.cpp:157
FileSink::IsolatedInitialize
void IsolatedInitialize(const NameValuePairs &parameters)
Initialize or reinitialize this object, without signal propagation.
Definition: files.cpp:223
files.h
Classes providing file-based library services.
CryptoPP
Crypto++ library namespace.
NameValuePairs::GetValue
bool GetValue(const char *name, T &value) const
Get a named value.
Definition: cryptlib.h:379
Name::InputBinaryMode
const char * InputBinaryMode()
bool
Definition: argnames.h:61
FileStore::MaxRetrievable
lword MaxRetrievable() const
Provides the number of bytes ready for retrieval.
Definition: files.cpp:94
FileSink
Implementation of Store interface.
Definition: files.h:130
FileStore::ReadErr
Exception thrown when file-based read error is encountered.
Definition: files.h:34
Name::OutputFileNameWide
const char * OutputFileNameWide()
const wchar_t *
Definition: argnames.h:63
SIZE_MAX
#define SIZE_MAX
The maximum value of a machine word.
Definition: misc.h:116
NameValuePairs
Interface for retrieving values given their names.
Definition: cryptlib.h:321