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 &parameters);
                
                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 &parameters);
        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 &parameters)
{
        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 &parameters)
{
        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

Reply via email to