Crypto++
|
00001 // files.cpp - written and placed in the public domain by Wei Dai 00002 00003 #include "pch.h" 00004 00005 #ifndef CRYPTOPP_IMPORTS 00006 00007 #include "files.h" 00008 00009 #include <limits> 00010 00011 NAMESPACE_BEGIN(CryptoPP) 00012 00013 using namespace std; 00014 00015 #ifndef NDEBUG 00016 void Files_TestInstantiations() 00017 { 00018 FileStore f0; 00019 FileSource f1; 00020 FileSink f2; 00021 } 00022 #endif 00023 00024 void FileStore::StoreInitialize(const NameValuePairs ¶meters) 00025 { 00026 m_waiting = false; 00027 m_stream = NULL; 00028 m_file.release(); 00029 00030 const char *fileName = NULL; 00031 #if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400 00032 const wchar_t *fileNameWide = NULL; 00033 if (!parameters.GetValue(Name::InputFileNameWide(), fileNameWide)) 00034 #endif 00035 if (!parameters.GetValue(Name::InputFileName(), fileName)) 00036 { 00037 parameters.GetValue(Name::InputStreamPointer(), m_stream); 00038 return; 00039 } 00040 00041 ios::openmode binary = parameters.GetValueWithDefault(Name::InputBinaryMode(), true) ? ios::binary : ios::openmode(0); 00042 m_file.reset(new std::ifstream); 00043 #ifdef CRYPTOPP_UNIX_AVAILABLE 00044 std::string narrowed; 00045 if (fileNameWide) 00046 fileName = (narrowed = StringNarrow(fileNameWide)).c_str(); 00047 #endif 00048 #if _MSC_VER >= 1400 00049 if (fileNameWide) 00050 { 00051 m_file->open(fileNameWide, ios::in | binary); 00052 if (!*m_file) 00053 throw OpenErr(StringNarrow(fileNameWide, false)); 00054 } 00055 #endif 00056 if (fileName) 00057 { 00058 m_file->open(fileName, ios::in | binary); 00059 if (!*m_file) 00060 throw OpenErr(fileName); 00061 } 00062 m_stream = m_file.get(); 00063 } 00064 00065 lword FileStore::MaxRetrievable() const 00066 { 00067 if (!m_stream) 00068 return 0; 00069 00070 streampos current = m_stream->tellg(); 00071 streampos end = m_stream->seekg(0, ios::end).tellg(); 00072 m_stream->seekg(current); 00073 return end-current; 00074 } 00075 00076 size_t FileStore::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) 00077 { 00078 if (!m_stream) 00079 { 00080 transferBytes = 0; 00081 return 0; 00082 } 00083 00084 lword size=transferBytes; 00085 transferBytes = 0; 00086 00087 if (m_waiting) 00088 goto output; 00089 00090 while (size && m_stream->good()) 00091 { 00092 { 00093 size_t spaceSize = 1024; 00094 m_space = HelpCreatePutSpace(target, channel, 1, UnsignedMin(size_t(0)-1, size), spaceSize); 00095 00096 m_stream->read((char *)m_space, (unsigned int)STDMIN(size, (lword)spaceSize)); 00097 } 00098 m_len = (size_t)m_stream->gcount(); 00099 size_t blockedBytes; 00100 output: 00101 blockedBytes = target.ChannelPutModifiable2(channel, m_space, m_len, 0, blocking); 00102 m_waiting = blockedBytes > 0; 00103 if (m_waiting) 00104 return blockedBytes; 00105 size -= m_len; 00106 transferBytes += m_len; 00107 } 00108 00109 if (!m_stream->good() && !m_stream->eof()) 00110 throw ReadErr(); 00111 00112 return 0; 00113 } 00114 00115 size_t FileStore::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const 00116 { 00117 if (!m_stream) 00118 return 0; 00119 00120 if (begin == 0 && end == 1) 00121 { 00122 int result = m_stream->peek(); 00123 if (result == char_traits<char>::eof()) 00124 return 0; 00125 else 00126 { 00127 size_t blockedBytes = target.ChannelPut(channel, byte(result), blocking); 00128 begin += 1-blockedBytes; 00129 return blockedBytes; 00130 } 00131 } 00132 00133 // TODO: figure out what happens on cin 00134 streampos current = m_stream->tellg(); 00135 streampos endPosition = m_stream->seekg(0, ios::end).tellg(); 00136 streampos newPosition = current + (streamoff)begin; 00137 00138 if (newPosition >= endPosition) 00139 { 00140 m_stream->seekg(current); 00141 return 0; // don't try to seek beyond the end of file 00142 } 00143 m_stream->seekg(newPosition); 00144 try 00145 { 00146 assert(!m_waiting); 00147 lword copyMax = end-begin; 00148 size_t blockedBytes = const_cast<FileStore *>(this)->TransferTo2(target, copyMax, channel, blocking); 00149 begin += copyMax; 00150 if (blockedBytes) 00151 { 00152 const_cast<FileStore *>(this)->m_waiting = false; 00153 return blockedBytes; 00154 } 00155 } 00156 catch(...) 00157 { 00158 m_stream->clear(); 00159 m_stream->seekg(current); 00160 throw; 00161 } 00162 m_stream->clear(); 00163 m_stream->seekg(current); 00164 00165 return 0; 00166 } 00167 00168 lword FileStore::Skip(lword skipMax) 00169 { 00170 if (!m_stream) 00171 return 0; 00172 00173 lword oldPos = m_stream->tellg(); 00174 std::istream::off_type offset; 00175 if (!SafeConvert(skipMax, offset)) 00176 throw InvalidArgument("FileStore: maximum seek offset exceeded"); 00177 m_stream->seekg(offset, ios::cur); 00178 return (lword)m_stream->tellg() - oldPos; 00179 } 00180 00181 void FileSink::IsolatedInitialize(const NameValuePairs ¶meters) 00182 { 00183 m_stream = NULL; 00184 m_file.release(); 00185 00186 const char *fileName = NULL; 00187 #if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400 00188 const wchar_t *fileNameWide = NULL; 00189 if (!parameters.GetValue(Name::OutputFileNameWide(), fileNameWide)) 00190 #endif 00191 if (!parameters.GetValue(Name::OutputFileName(), fileName)) 00192 { 00193 parameters.GetValue(Name::OutputStreamPointer(), m_stream); 00194 return; 00195 } 00196 00197 ios::openmode binary = parameters.GetValueWithDefault(Name::OutputBinaryMode(), true) ? ios::binary : ios::openmode(0); 00198 m_file.reset(new std::ofstream); 00199 #ifdef CRYPTOPP_UNIX_AVAILABLE 00200 std::string narrowed; 00201 if (fileNameWide) 00202 fileName = (narrowed = StringNarrow(fileNameWide)).c_str(); 00203 #endif 00204 #if _MSC_VER >= 1400 00205 if (fileNameWide) 00206 { 00207 m_file->open(fileNameWide, ios::out | ios::trunc | binary); 00208 if (!*m_file) 00209 throw OpenErr(StringNarrow(fileNameWide, false)); 00210 } 00211 #endif 00212 if (fileName) 00213 { 00214 m_file->open(fileName, ios::out | ios::trunc | binary); 00215 if (!*m_file) 00216 throw OpenErr(fileName); 00217 } 00218 m_stream = m_file.get(); 00219 } 00220 00221 bool FileSink::IsolatedFlush(bool hardFlush, bool blocking) 00222 { 00223 if (!m_stream) 00224 throw Err("FileSink: output stream not opened"); 00225 00226 m_stream->flush(); 00227 if (!m_stream->good()) 00228 throw WriteErr(); 00229 00230 return false; 00231 } 00232 00233 size_t FileSink::Put2(const byte *inString, size_t length, int messageEnd, bool blocking) 00234 { 00235 if (!m_stream) 00236 throw Err("FileSink: output stream not opened"); 00237 00238 while (length > 0) 00239 { 00240 std::streamsize size; 00241 if (!SafeConvert(length, size)) 00242 size = numeric_limits<std::streamsize>::max(); 00243 m_stream->write((const char *)inString, size); 00244 inString += size; 00245 length -= (size_t)size; 00246 } 00247 00248 if (messageEnd) 00249 m_stream->flush(); 00250 00251 if (!m_stream->good()) 00252 throw WriteErr(); 00253 00254 return 0; 00255 } 00256 00257 NAMESPACE_END 00258 00259 #endif