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