Submitted for your approval.
IOW: couldn't find an implementation and had some spare time on my hands.
*The works:*
I basically duplicated files.h/.cpp and modified all the stream related code
to work with a CFile instead.
I had to bypass a few bumps on the way such as missing functionality
(namely: eof and peek), const pointers, etc.
I can't say that I made all possible tests and covered all bases, but all in
all it works for me.
Comments are most welcome.
Avi.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the "Crypto++ Users"
Google Group.
To unsubscribe, send an email to [email protected].
More information about Crypto++ and this group is available at
http://www.cryptopp.com.
-~----------~----~----~----~------~----~------~--~---
#ifndef CRYPTO_MFC_CFILE_H
#define CRYPTO_MFC_CFILE_H
#include "argnames.h"
#include "filters.h"
NAMESPACE_BEGIN(CryptoPP)
class CRYPTOPP_DLL MfcCFileStore : public Store, private FilterPutSpaceHelper,
public NotCopyable
{
public:
class Err : public Exception
{
public:
Err(const std::string &s) : Exception(IO_ERROR, s) {}
};
class OpenErr : public Err {public: OpenErr(const std::string
&filename) : Err("MfcCFileStore: error opening file for reading: " + filename)
{}};
class ReadErr : public Err {public: ReadErr() : Err("MfcCFileStore:
error reading file") {}};
MfcCFileStore() {}
MfcCFileStore(CFile* in)
{StoreInitialize(MakeParameters(Name::InputStreamPointer(),
in));}
MfcCFileStore(const char *filename)
{StoreInitialize(MakeParameters(Name::InputFileName(),
filename));}
lword MaxRetrievable() const;
size_t TransferTo2(BufferedTransformation &target, lword
&transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true);
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword
end=LWORD_MAX, const std::string &channel=NULL_CHANNEL, bool blocking=true)
const;
lword Skip(lword skipMax=ULONG_MAX);
private:
void StoreInitialize(const NameValuePairs ¶meters);
member_ptr<CFile> m_file;
byte *m_space;
UINT m_len;
bool m_waiting;
};
//! file-based implementation of Source interface
class CRYPTOPP_DLL MfcCFileSource : public SourceTemplate<MfcCFileStore>
{
public:
typedef MfcCFileStore::Err Err;
typedef MfcCFileStore::OpenErr OpenErr;
typedef MfcCFileStore::ReadErr ReadErr;
MfcCFileSource(BufferedTransformation *attachment = NULL)
: SourceTemplate<MfcCFileStore>(attachment) {}
MfcCFileSource(CFile* in, bool pumpAll, BufferedTransformation
*attachment = NULL)
: SourceTemplate<MfcCFileStore>(attachment)
{SourceInitialize(pumpAll, MakeParameters(Name::InputStreamPointer(), in));}
MfcCFileSource(const char *filename, bool pumpAll,
BufferedTransformation *attachment = NULL, bool binary=true)
: SourceTemplate<MfcCFileStore>(attachment)
{SourceInitialize(pumpAll, MakeParameters(Name::InputFileName(),
filename)(Name::InputBinaryMode(), binary));}
};
class CRYPTOPP_DLL MfcCFileSink : public Sink, public NotCopyable
{
public:
class Err : public Exception
{
public:
Err(const std::string &s) : Exception(IO_ERROR, s) {}
};
class OpenErr : public Err {public: OpenErr(const std::string
&filename) : Err("MfcCFileSink: error opening file for writing: " + filename)
{}};
class WriteErr : public Err {public: WriteErr() : Err("MfcCFileSink:
error writing file") {}};
MfcCFileSink() {}
MfcCFileSink(CFile* out)
{IsolatedInitialize(MakeParameters(Name::OutputStreamPointer(),
out));}
MfcCFileSink(const char *filename, bool binary=true)
{IsolatedInitialize(MakeParameters(Name::OutputFileName(),
filename)("OutputBinaryMode", binary));}
void IsolatedInitialize(const NameValuePairs ¶meters);
size_t Put2(const byte *inString, size_t length, int messageEnd, bool
blocking);
bool IsolatedFlush(bool hardFlush, bool blocking);
private:
member_ptr<CFile> m_file;
};
NAMESPACE_END
#endif CRYPTO_MFC_CFILE_H
#include "StdAfx.h"
#include "MfcCFile.h"
#include <limits>
#undef max // Macro defined in stdlib.h and windef.h; collides with
std::numeric_limits<std::streamsize>::max() below
NAMESPACE_BEGIN(CryptoPP)
void MfcCFiles_TestInstantiations()
{
MfcCFileStore f0;
MfcCFileSource f1;
MfcCFileSink f2;
}
inline bool IsCFileEOF( const CFile* pFile )
{
return pFile->GetPosition() == pFile->GetLength();
}
void MfcCFileStore::StoreInitialize(const NameValuePairs ¶meters)
{
m_file.reset(new CFile());
const char *fileName;
if (parameters.GetValue(Name::InputFileName(), fileName))
{
UINT fileType =
parameters.GetValueWithDefault(Name::OutputBinaryMode(), true) ?
CFile::typeBinary : CFile::typeText;
m_file->Open(fileName, CFile::modeRead | fileType);
if (!*m_file)
throw OpenErr(fileName);
}
else
{
CFile* pFile = NULL;
parameters.GetValue(Name::InputStreamPointer(), pFile);
m_file.reset(pFile);
}
m_waiting = false;
}
lword MfcCFileStore::MaxRetrievable() const
{
if (!m_file.get())
return 0;
DWORD current = m_file->GetPosition();
DWORD end = m_file->GetLength();
((CFile*)m_file.get())->Seek(current, CFile::begin);
return end-current;
}
size_t MfcCFileStore::TransferTo2(BufferedTransformation &target, lword
&transferBytes, const std::string &channel, bool blocking)
{
if (!m_file.get())
{
transferBytes = 0;
return 0;
}
lword size=transferBytes;
transferBytes = 0;
if (m_waiting)
goto output;
while ( size && ! IsCFileEOF(m_file.get()) )
{
{
size_t spaceSize = 1024;
m_space = HelpCreatePutSpace(target, channel, 1,
UnsignedMin(size_t(0)-1, size), spaceSize);
m_len = m_file->Read((char *)m_space, (unsigned
int)STDMIN(size, (lword)spaceSize));
}
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 MfcCFileStore::CopyRangeTo2(BufferedTransformation &target, lword
&begin, lword end, const std::string &channel, bool blocking) const
{
if (!m_file.get())
return 0;
if (begin == 0 && end == 1)
{
if ( IsCFileEOF( m_file.get() ) ) // EOF?
return 0;
else
{
byte c;
((CFile*)m_file.get())->Read(&c, 1);
((CFile*)m_file.get())->Seek(-1, CFile::current);
size_t blockedBytes = target.ChannelPut(channel, c,
blocking);
begin += 1-blockedBytes;
return blockedBytes;
}
}
// TODO: figure out what happens on cin
DWORD current = m_file->GetPosition();
DWORD endPosition = m_file->GetLength();
DWORD newPosition = current + (DWORD)begin;
if (newPosition >= endPosition)
{
((CFile*)m_file.get())->Seek(current, CFile::begin);
return 0; // don't try to seek beyond the end of file
}
((CFile*)m_file.get())->Seek(newPosition, CFile::begin);
try
{
assert(!m_waiting);
lword copyMax = end-begin;
size_t blockedBytes = const_cast<MfcCFileStore
*>(this)->TransferTo2(target, copyMax, channel, blocking);
begin += copyMax;
if (blockedBytes)
{
const_cast<MfcCFileStore *>(this)->m_waiting = false;
return blockedBytes;
}
}
catch(...)
{
((CFile*)m_file.get())->Seek(current, CFile::begin);
throw;
}
((CFile*)m_file.get())->Seek(current, CFile::begin);
return 0;
}
lword MfcCFileStore::Skip(lword skipMax)
{
lword oldPos = m_file->GetPosition();
std::istream::off_type offset;
if (!SafeConvert(skipMax, offset))
throw InvalidArgument("MfcCFileStore: maximum seek offset
exceeded");
m_file->Seek(offset, CFile::current);
return (lword)m_file->GetPosition() - oldPos;
}
//////////////////////////////////////////////////////////////////////////
void MfcCFileSink::IsolatedInitialize(const NameValuePairs ¶meters)
{
m_file.reset(new CFile());
const char *fileName;
if (parameters.GetValue(Name::OutputFileName(), fileName))
{
UINT fileType =
parameters.GetValueWithDefault(Name::OutputBinaryMode(), true) ?
CFile::typeBinary : CFile::typeText;
m_file->Open(fileName, CFile::modeWrite | CFile::modeCreate |
fileType);
if (!*m_file)
throw OpenErr(fileName);
}
else
{
CFile* pFile = NULL;
parameters.GetValue(Name::InputStreamPointer(), pFile);
m_file.reset(pFile);
}
}
bool MfcCFileSink::IsolatedFlush(bool hardFlush, bool blocking)
{
if (!m_file.get())
throw Err("MfcCFileSink: output stream not opened");
m_file->Flush();
// if (!m_stream->good())
// throw WriteErr();
return false;
}
size_t MfcCFileSink::Put2(const byte *inString, size_t length, int messageEnd,
bool blocking)
{
if (!m_file.get())
throw Err("MfcCFileSink: output stream not opened");
while (length > 0)
{
std::streamsize size;
if (!SafeConvert(length, size))
size = std::numeric_limits<std::streamsize>::max();
m_file->Write((const char *)inString, size);
inString += size;
length -= size;
}
if (messageEnd)
m_file->Flush();
// if (!m_stream->good())
// throw WriteErr();
return 0;
}
NAMESPACE_END