diff options
Diffstat (limited to 'lib/cryptopp/files.cpp')
-rw-r--r-- | lib/cryptopp/files.cpp | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/lib/cryptopp/files.cpp b/lib/cryptopp/files.cpp new file mode 100644 index 000000000..453b56248 --- /dev/null +++ b/lib/cryptopp/files.cpp @@ -0,0 +1,259 @@ +// files.cpp - written and placed in the public domain by Wei Dai + +#include "pch.h" + +#ifndef CRYPTOPP_IMPORTS + +#include "files.h" + +#include <limits> + +NAMESPACE_BEGIN(CryptoPP) + +using namespace std; + +#ifndef NDEBUG +void Files_TestInstantiations() +{ + FileStore f0; + FileSource f1; + FileSink f2; +} +#endif + +void FileStore::StoreInitialize(const NameValuePairs ¶meters) +{ + m_waiting = false; + m_stream = NULL; + m_file.release(); + + const char *fileName = NULL; +#if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400 + const wchar_t *fileNameWide = NULL; + if (!parameters.GetValue(Name::InputFileNameWide(), fileNameWide)) +#endif + if (!parameters.GetValue(Name::InputFileName(), fileName)) + { + parameters.GetValue(Name::InputStreamPointer(), m_stream); + return; + } + + ios::openmode binary = parameters.GetValueWithDefault(Name::InputBinaryMode(), true) ? ios::binary : ios::openmode(0); + m_file.reset(new std::ifstream); +#ifdef CRYPTOPP_UNIX_AVAILABLE + std::string narrowed; + if (fileNameWide) + fileName = (narrowed = StringNarrow(fileNameWide)).c_str(); +#endif +#if _MSC_VER >= 1400 + if (fileNameWide) + { + m_file->open(fileNameWide, ios::in | binary); + if (!*m_file) + throw OpenErr(StringNarrow(fileNameWide, false)); + } +#endif + if (fileName) + { + m_file->open(fileName, ios::in | binary); + if (!*m_file) + throw OpenErr(fileName); + } + m_stream = m_file.get(); +} + +lword FileStore::MaxRetrievable() const +{ + if (!m_stream) + return 0; + + streampos current = m_stream->tellg(); + streampos end = m_stream->seekg(0, ios::end).tellg(); + m_stream->seekg(current); + return end-current; +} + +size_t FileStore::TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel, bool blocking) +{ + if (!m_stream) + { + transferBytes = 0; + return 0; + } + + lword size=transferBytes; + transferBytes = 0; + + if (m_waiting) + goto output; + + while (size && m_stream->good()) + { + { + size_t spaceSize = 1024; + m_space = HelpCreatePutSpace(target, channel, 1, UnsignedMin(size_t(0)-1, size), spaceSize); + + m_stream->read((char *)m_space, (unsigned int)STDMIN(size, (lword)spaceSize)); + } + m_len = (size_t)m_stream->gcount(); + size_t blockedBytes; +output: + blockedBytes = target.ChannelPutModifiable2(channel, m_space, m_len, 0, blocking); + m_waiting = blockedBytes > 0; + if (m_waiting) + return blockedBytes; + size -= m_len; + transferBytes += m_len; + } + + if (!m_stream->good() && !m_stream->eof()) + throw ReadErr(); + + return 0; +} + +size_t FileStore::CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end, const std::string &channel, bool blocking) const +{ + if (!m_stream) + return 0; + + if (begin == 0 && end == 1) + { + int result = m_stream->peek(); + if (result == char_traits<char>::eof()) + return 0; + else + { + size_t blockedBytes = target.ChannelPut(channel, byte(result), blocking); + begin += 1-blockedBytes; + return blockedBytes; + } + } + + // TODO: figure out what happens on cin + streampos current = m_stream->tellg(); + streampos endPosition = m_stream->seekg(0, ios::end).tellg(); + streampos newPosition = current + (streamoff)begin; + + if (newPosition >= endPosition) + { + m_stream->seekg(current); + return 0; // don't try to seek beyond the end of file + } + m_stream->seekg(newPosition); + try + { + assert(!m_waiting); + lword copyMax = end-begin; + size_t blockedBytes = const_cast<FileStore *>(this)->TransferTo2(target, copyMax, channel, blocking); + begin += copyMax; + if (blockedBytes) + { + const_cast<FileStore *>(this)->m_waiting = false; + return blockedBytes; + } + } + catch(...) + { + m_stream->clear(); + m_stream->seekg(current); + throw; + } + m_stream->clear(); + m_stream->seekg(current); + + return 0; +} + +lword FileStore::Skip(lword skipMax) +{ + if (!m_stream) + return 0; + + lword oldPos = m_stream->tellg(); + std::istream::off_type offset; + if (!SafeConvert(skipMax, offset)) + throw InvalidArgument("FileStore: maximum seek offset exceeded"); + m_stream->seekg(offset, ios::cur); + return (lword)m_stream->tellg() - oldPos; +} + +void FileSink::IsolatedInitialize(const NameValuePairs ¶meters) +{ + m_stream = NULL; + m_file.release(); + + const char *fileName = NULL; +#if defined(CRYPTOPP_UNIX_AVAILABLE) || _MSC_VER >= 1400 + const wchar_t *fileNameWide = NULL; + if (!parameters.GetValue(Name::OutputFileNameWide(), fileNameWide)) +#endif + if (!parameters.GetValue(Name::OutputFileName(), fileName)) + { + parameters.GetValue(Name::OutputStreamPointer(), m_stream); + return; + } + + ios::openmode binary = parameters.GetValueWithDefault(Name::OutputBinaryMode(), true) ? ios::binary : ios::openmode(0); + m_file.reset(new std::ofstream); +#ifdef CRYPTOPP_UNIX_AVAILABLE + std::string narrowed; + if (fileNameWide) + fileName = (narrowed = StringNarrow(fileNameWide)).c_str(); +#endif +#if _MSC_VER >= 1400 + if (fileNameWide) + { + m_file->open(fileNameWide, ios::out | ios::trunc | binary); + if (!*m_file) + throw OpenErr(StringNarrow(fileNameWide, false)); + } +#endif + if (fileName) + { + m_file->open(fileName, ios::out | ios::trunc | binary); + if (!*m_file) + throw OpenErr(fileName); + } + m_stream = m_file.get(); +} + +bool FileSink::IsolatedFlush(bool hardFlush, bool blocking) +{ + if (!m_stream) + throw Err("FileSink: output stream not opened"); + + m_stream->flush(); + if (!m_stream->good()) + throw WriteErr(); + + return false; +} + +size_t FileSink::Put2(const byte *inString, size_t length, int messageEnd, bool blocking) +{ + if (!m_stream) + throw Err("FileSink: output stream not opened"); + + while (length > 0) + { + std::streamsize size; + if (!SafeConvert(length, size)) + size = numeric_limits<std::streamsize>::max(); + m_stream->write((const char *)inString, size); + inString += size; + length -= (size_t)size; + } + + if (messageEnd) + m_stream->flush(); + + if (!m_stream->good()) + throw WriteErr(); + + return 0; +} + +NAMESPACE_END + +#endif |