1 // files.cpp - 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 <limits>
10 
NAMESPACE_BEGIN(CryptoPP)11 NAMESPACE_BEGIN(CryptoPP)
12 
13 #if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING)
14 void Files_TestInstantiations()
15 {
16 	FileStore f0;
17 	FileSource f1;
18 	FileSink f2;
19 }
20 #endif
21 
StoreInitialize(const NameValuePairs & parameters)22 void FileStore::StoreInitialize(const NameValuePairs &parameters)
23 {
24 	m_waiting = false;
25 	m_stream = NULL;
26 	m_file.release();
27 
28 	const char *fileName = NULL;
29 #if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400
30 	const wchar_t *fileNameWide = NULL;
31 	if (!parameters.GetValue(Name::InputFileNameWide(), fileNameWide))
32 #endif
33 		if (!parameters.GetValue(Name::InputFileName(), fileName))
34 		{
35 			parameters.GetValue(Name::InputStreamPointer(), m_stream);
36 			return;
37 		}
38 
39 	std::ios::openmode binary = parameters.GetValueWithDefault(Name::InputBinaryMode(), true) ? std::ios::binary : std::ios::openmode(0);
40 	m_file.reset(new std::ifstream);
41 #ifdef CRYPTOPP_UNIX_AVAILABLE
42 	std::string narrowed;
43 	if (fileNameWide)
44 		fileName = (narrowed = StringNarrow(fileNameWide)).c_str();
45 #endif
46 #if _MSC_VER >= 1400
47 	if (fileNameWide)
48 	{
49 		m_file->open(fileNameWide, std::ios::in | binary);
50 		if (!*m_file)
51 			throw OpenErr(StringNarrow(fileNameWide, false));
52 	}
53 #endif
54 	if (fileName)
55 	{
56 		m_file->open(fileName, std::ios::in | binary);
57 		if (!*m_file)
58 			throw OpenErr(fileName);
59 	}
60 	m_stream = m_file.get();
61 }
62 
MaxRetrievable() const63 lword FileStore::MaxRetrievable() const
64 {
65 	if (!m_stream)
66 		return 0;
67 
68 	std::streampos current = m_stream->tellg();
69 	std::streampos end = m_stream->seekg(0, std::ios::end).tellg();
70 	m_stream->seekg(current);
71 	return end-current;
72 }
73 
TransferTo2(BufferedTransformation & target,lword & transferBytes,const std::string & channel,bool blocking)74 size_t FileStore::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking)
75 {
76 	if (!m_stream)
77 	{
78 		transferBytes = 0;
79 		return 0;
80 	}
81 
82 	lword size=transferBytes;
83 	transferBytes = 0;
84 
85 	if (m_waiting)
86 		goto output;
87 
88 	while (size && m_stream->good())
89 	{
90 		{
91 		size_t spaceSize = 1024;
92 		m_space = HelpCreatePutSpace(target, channel, 1, UnsignedMin(size_t(SIZE_MAX), size), spaceSize);
93 
94 		m_stream->read((char *)m_space, (unsigned int)STDMIN(size, (lword)spaceSize));
95 		}
96 		m_len = (size_t)m_stream->gcount();
97 		size_t blockedBytes;
98 output:
99 		blockedBytes = target.ChannelPutModifiable2(channel, m_space, m_len, 0, blocking);
100 		m_waiting = blockedBytes > 0;
101 		if (m_waiting)
102 			return blockedBytes;
103 		size -= m_len;
104 		transferBytes += m_len;
105 	}
106 
107 	if (!m_stream->good() && !m_stream->eof())
108 		throw ReadErr();
109 
110 	return 0;
111 }
112 
CopyRangeTo2(BufferedTransformation & target,lword & begin,lword end,const std::string & channel,bool blocking) const113 size_t FileStore::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const
114 {
115 	if (!m_stream)
116 		return 0;
117 
118 	if (begin == 0 && end == 1)
119 	{
120 		int result = m_stream->peek();
121 		if (result == std::char_traits<char>::eof())
122 			return 0;
123 		else
124 		{
125 			size_t blockedBytes = target.ChannelPut(channel, byte(result), blocking);
126 			begin += 1-blockedBytes;
127 			return blockedBytes;
128 		}
129 	}
130 
131 	// TODO: figure out what happens on cin
132 	std::streampos current = m_stream->tellg();
133 	std::streampos endPosition = m_stream->seekg(0, std::ios::end).tellg();
134 	std::streampos newPosition = current + static_cast<std::streamoff>(begin);
135 
136 	if (newPosition >= endPosition)
137 	{
138 		m_stream->seekg(current);
139 		return 0;	// don't try to seek beyond the end of file
140 	}
141 	m_stream->seekg(newPosition);
142 	try
143 	{
144 		CRYPTOPP_ASSERT(!m_waiting);
145 		lword copyMax = end-begin;
146 		size_t blockedBytes = const_cast<FileStore *>(this)->TransferTo2(target, copyMax, channel, blocking);
147 		begin += copyMax;
148 		if (blockedBytes)
149 		{
150 			const_cast<FileStore *>(this)->m_waiting = false;
151 			return blockedBytes;
152 		}
153 	}
154 	catch(...)
155 	{
156 		m_stream->clear();
157 		m_stream->seekg(current);
158 		throw;
159 	}
160 	m_stream->clear();
161 	m_stream->seekg(current);
162 
163 	return 0;
164 }
165 
Skip(lword skipMax)166 lword FileStore::Skip(lword skipMax)
167 {
168 	if (!m_stream)
169 		return 0;
170 
171 	lword oldPos = m_stream->tellg();
172 	std::istream::off_type offset;
173 	if (!SafeConvert(skipMax, offset))
174 		throw InvalidArgument("FileStore: maximum seek offset exceeded");
175 	m_stream->seekg(offset, std::ios::cur);
176 	return (lword)m_stream->tellg() - oldPos;
177 }
178 
IsolatedInitialize(const NameValuePairs & parameters)179 void FileSink::IsolatedInitialize(const NameValuePairs &parameters)
180 {
181 	m_stream = NULL;
182 	m_file.release();
183 
184 	const char *fileName = NULL;
185 #if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400
186 	const wchar_t *fileNameWide = NULL;
187 	if (!parameters.GetValue(Name::OutputFileNameWide(), fileNameWide))
188 #endif
189 		if (!parameters.GetValue(Name::OutputFileName(), fileName))
190 		{
191 			parameters.GetValue(Name::OutputStreamPointer(), m_stream);
192 			return;
193 		}
194 
195 	std::ios::openmode binary = parameters.GetValueWithDefault(Name::OutputBinaryMode(), true) ? std::ios::binary : std::ios::openmode(0);
196 	m_file.reset(new std::ofstream);
197 #ifdef CRYPTOPP_UNIX_AVAILABLE
198 	std::string narrowed;
199 	if (fileNameWide)
200 		fileName = (narrowed = StringNarrow(fileNameWide)).c_str();
201 #elif (CRYPTOPP_MSC_VERSION >= 1400)
202 	if (fileNameWide)
203 	{
204 		m_file->open(fileNameWide, std::ios::out | std::ios::trunc | binary);
205 		if (!*m_file)
206 			throw OpenErr(StringNarrow(fileNameWide, false));
207 	}
208 #endif
209 	if (fileName)
210 	{
211 		m_file->open(fileName, std::ios::out | std::ios::trunc | binary);
212 		if (!*m_file)
213 			throw OpenErr(fileName);
214 	}
215 	m_stream = m_file.get();
216 }
217 
IsolatedFlush(bool hardFlush,bool blocking)218 bool FileSink::IsolatedFlush(bool hardFlush, bool blocking)
219 {
220 	CRYPTOPP_UNUSED(hardFlush), CRYPTOPP_UNUSED(blocking);
221 	if (!m_stream)
222 		throw Err("FileSink: output stream not opened");
223 
224 	m_stream->flush();
225 	if (!m_stream->good())
226 		throw WriteErr();
227 
228 	return false;
229 }
230 
Put2(const byte * inString,size_t length,int messageEnd,bool blocking)231 size_t FileSink::Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
232 {
233 	CRYPTOPP_UNUSED(blocking);
234 	if (!m_stream)
235 		throw Err("FileSink: output stream not opened");
236 
237 	while (length > 0)
238 	{
239 		std::streamsize size;
240 		if (!SafeConvert(length, size))
241 			size = ((std::numeric_limits<std::streamsize>::max)());
242 		m_stream->write((const char *)inString, size);
243 		inString += size;
244 		length -= (size_t)size;
245 	}
246 
247 	if (messageEnd)
248 		m_stream->flush();
249 
250 	if (!m_stream->good())
251 		throw WriteErr();
252 
253 	return 0;
254 }
255 
256 NAMESPACE_END
257 
258 #endif
259