Since we have an ArraySink class I thought it would be good to have the
corresponding ArraySource and ArrayStore classes as well:

- Ron

filters.h:

class CRYPTOPP_DLL ArrayStore : public Store, private FilterPutSpaceHelper,
public NotCopyable
{
public:
   ArrayStore() : m_data(NULL), m_current(NULL), m_waiting(false),
m_space(NULL), m_len(0) { }
   ArrayStore( ArraySink * sink ) : m_waiting(false), m_space(NULL),
m_len(0) {
           StoreInitialize(MakeParameters("InputBuffer",
ConstByteArrayParameter(sink->GetBuffer(), sink->GetBufferLength())));
   }
   ArrayStore(byte *data, unsigned int dataLen) : m_data(NULL),
m_current(NULL), m_waiting(false), m_space(NULL), m_len(0)  {
           StoreInitialize(MakeParameters("InputBuffer",
ConstByteArrayParameter(data, dataLen)));
   }

   const byte * GetBuffer() { return m_data; };
   unsigned int GetBufferLength() { return m_dataLen; };

   unsigned long MaxRetrievable() const;
   unsigned int TransferTo2(BufferedTransformation &target, unsigned long
&transferBytes, const std::string &channel=NULL_CHANNEL, bool
blocking=true);
   unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long
&begin, unsigned long end=ULONG_MAX, const std::string
&channel=NULL_CHANNEL, bool blocking=true) const;
   unsigned long Skip(unsigned long skipMax=ULONG_MAX);

private:
   void StoreInitialize(const NameValuePairs &parameters) {
       ConstByteArrayParameter array;
       if (!parameters.GetValue(Name::InputBuffer(), array))
           throw InvalidArgument("StringStore: missing InputBuffer
argument");
       m_data= array.begin();
       m_current = (byte*) m_data;
       m_dataLen = array.size();
       m_waiting = false;
   };

   const byte *m_data;
   byte *m_current;
   unsigned int m_dataLen;


   byte *m_space;
   unsigned int m_len;
   bool m_waiting;
};

//! array-based implementation of Source interface
class CRYPTOPP_DLL ArraySource : public SourceTemplate<ArrayStore>
{
public:
   ArraySource(BufferedTransformation *attachment = NULL) :
SourceTemplate<ArrayStore>(attachment) {}
   ArraySource( ArraySink * sink, bool pumpAll, BufferedTransformation
*attachment = NULL ) : SourceTemplate<ArrayStore>(attachment) {
       SourceInitialize(pumpAll, MakeParameters("InputBuffer",
ConstByteArrayParameter(sink->GetBuffer(), sink->GetBufferLength())));
   }
   ArraySource(byte *data, unsigned int dataLen, bool pumpAll,
BufferedTransformation *attachment = NULL) :
SourceTemplate<ArrayStore>(attachment) {
       SourceInitialize(pumpAll, MakeParameters("InputBuffer",
ConstByteArrayParameter(data, dataLen)));
   }

};


filters.cpp

//! array-based implementation of Source interface
class CRYPTOPP_DLL ArraySource : public SourceTemplate<ArrayStore>
{
public:
   ArraySource(BufferedTransformation *attachment = NULL) :
SourceTemplate<ArrayStore>(attachment) {}
   ArraySource( ArraySink * sink, bool pumpAll, BufferedTransformation
*attachment = NULL ) : SourceTemplate<ArrayStore>(attachment) {
       SourceInitialize(pumpAll, MakeParameters("InputBuffer",
ConstByteArrayParameter(sink->GetBuffer(), sink->GetBufferLength())));
   }
   ArraySource(byte *data, unsigned int dataLen, bool pumpAll,
BufferedTransformation *attachment = NULL) :
SourceTemplate<ArrayStore>(attachment) {
       SourceInitialize(pumpAll, MakeParameters("InputBuffer",
ConstByteArrayParameter(data, dataLen)));
   }

};

unsigned long ArrayStore::MaxRetrievable() const
{
   if ( (m_dataLen < (m_current-m_data)))
       return 0;
   return m_dataLen - (m_current-m_data);
}

unsigned int ArrayStore::TransferTo2(BufferedTransformation &target,
unsigned long &transferBytes, const std::string &channel, bool blocking)
{
   if (!m_data)
   {
       transferBytes = 0;
       return 0;
   }

   unsigned long size=transferBytes;
   transferBytes = 0;

   if (m_waiting)
       goto output;


   while (size &&  ( MaxRetrievable()>0 ))
   {
       unsigned int sz;
       {
           unsigned int spaceSize = 1024;
           m_space = HelpCreatePutSpace(target, channel, 1, (unsigned
int)STDMIN(size, (unsigned long)UINT_MAX), spaceSize);
           sz = STDMIN(size, (unsigned long)spaceSize);
           sz = STDMIN((unsigned long)sz, (unsigned long)
MaxRetrievable());
           memcpy(m_space, m_current, sz);
           m_current += sz;
       }

       m_len = sz;
       unsigned int 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;
   }

   return 0;
}

unsigned int ArrayStore::CopyRangeTo2(BufferedTransformation &target,
unsigned long &begin, unsigned long end, const std::string &channel, bool
blocking) const
{
   if (!m_data)
       return 0;

   if (begin == 0 && end == 1)
   {
       if ( MaxRetrievable()==0 )
           return 0;
       else
       {
           int result = m_current[0];
           unsigned int blockedBytes = target.ChannelPut(channel,
byte(result), blocking);
           begin += 1-blockedBytes;
           return blockedBytes;
       }
   }

   byte* current = m_current;
   byte* endPosition = (byte*)m_data + m_dataLen;
   byte* newPosition = current + begin;

   if (newPosition >= endPosition)
   {
       return 0;    // don't try to seek beyond the end of file
   }

   const_cast<ArrayStore *>(this)->Skip(begin);

   unsigned long total = 0;
   try
   {
       assert(!m_waiting);
       unsigned long copyMax = end-begin;
       unsigned int blockedBytes = const_cast<ArrayStore
*>(this)->TransferTo2(target, copyMax, channel, blocking);
       begin += copyMax;
       if (blockedBytes)
       {
           const_cast<ArrayStore *>(this)->m_waiting = false;
           return blockedBytes;
       }
   }
   catch(...)
   {
       throw;
   }

   const_cast<ArrayStore *>(this)->m_current = current;
   return 0;
}

unsigned long ArrayStore::Skip(unsigned long skipMax)
{
   unsigned long step;

   if ( skipMax > MaxRetrievable () )
       step = MaxRetrievable();
   else
       step = skipMax;

   m_current += step;

   return step;
}
// Contributed by Ron Bessems

//! array-based implementation of Store interface
class CRYPTOPP_DLL ArrayStore : public Store, private FilterPutSpaceHelper, 
public NotCopyable
{
public:
        ArrayStore() : m_data(NULL), m_current(NULL), m_waiting(false), 
m_space(NULL), m_len(0) { }
        ArrayStore( ArraySink * sink ) : m_waiting(false), m_space(NULL), 
m_len(0) {
                        StoreInitialize(MakeParameters("InputBuffer", 
ConstByteArrayParameter(sink->GetBuffer(), sink->GetBufferLength())));    
        }
        ArrayStore(byte *data, unsigned int dataLen) : m_data(NULL), 
m_current(NULL), m_waiting(false), m_space(NULL), m_len(0)  {
                        StoreInitialize(MakeParameters("InputBuffer", 
ConstByteArrayParameter(data, dataLen)));
        }

        const byte * GetBuffer() { return m_data; };
        unsigned int GetBufferLength() { return m_dataLen; };

        unsigned long MaxRetrievable() const;
        unsigned int TransferTo2(BufferedTransformation &target, unsigned long 
&transferBytes, const std::string &channel=NULL_CHANNEL, bool blocking=true);
        unsigned int CopyRangeTo2(BufferedTransformation &target, unsigned long 
&begin, unsigned long end=ULONG_MAX, const std::string &channel=NULL_CHANNEL, 
bool blocking=true) const;
        unsigned long Skip(unsigned long skipMax=ULONG_MAX);

private:
        void StoreInitialize(const NameValuePairs &parameters) {
                ConstByteArrayParameter array;
                if (!parameters.GetValue(Name::InputBuffer(), array))
                        throw InvalidArgument("StringStore: missing InputBuffer 
argument");
                m_data= array.begin();
                m_current = (byte*) m_data;
                m_dataLen = array.size();
                m_waiting = false;
        };      

        const byte *m_data;
        byte *m_current;
        unsigned int m_dataLen;
        

        byte *m_space;  
        unsigned int m_len;
        bool m_waiting;
};

//! array-based implementation of Source interface
class CRYPTOPP_DLL ArraySource : public SourceTemplate<ArrayStore>
{
public:
        ArraySource(BufferedTransformation *attachment = NULL) : 
SourceTemplate<ArrayStore>(attachment) {}
        ArraySource( ArraySink * sink, bool pumpAll, BufferedTransformation 
*attachment = NULL ) : SourceTemplate<ArrayStore>(attachment) {
                SourceInitialize(pumpAll, MakeParameters("InputBuffer", 
ConstByteArrayParameter(sink->GetBuffer(), sink->GetBufferLength())));
        }       
        ArraySource(byte *data, unsigned int dataLen, bool pumpAll, 
BufferedTransformation *attachment = NULL) : 
SourceTemplate<ArrayStore>(attachment) {
                SourceInitialize(pumpAll, MakeParameters("InputBuffer", 
ConstByteArrayParameter(data, dataLen)));
        }

};

unsigned long ArrayStore::MaxRetrievable() const
{       
        if ( (m_dataLen < (m_current-m_data)))
                return 0;
        return m_dataLen - (m_current-m_data);
}

unsigned int ArrayStore::TransferTo2(BufferedTransformation &target, unsigned 
long &transferBytes, const std::string &channel, bool blocking)
{
        if (!m_data)
        {
                transferBytes = 0;
                return 0;
        }

        unsigned long size=transferBytes;
        transferBytes = 0;

        if (m_waiting)
                goto output;
        

        while (size &&  ( MaxRetrievable()>0 ))
        {
                unsigned int sz;
                {
                        unsigned int spaceSize = 1024;
                        m_space = HelpCreatePutSpace(target, channel, 1, 
(unsigned int)STDMIN(size, (unsigned long)UINT_MAX), spaceSize);
                        sz = STDMIN(size, (unsigned long)spaceSize);
                        sz = STDMIN((unsigned long)sz, (unsigned long) 
MaxRetrievable());
                        memcpy(m_space, m_current, sz);
                        m_current += sz;
                }

                m_len = sz;
                unsigned int 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;
        }

        return 0;
}

unsigned int ArrayStore::CopyRangeTo2(BufferedTransformation &target, unsigned 
long &begin, unsigned long end, const std::string &channel, bool blocking) const
{
        if (!m_data)
                return 0;

        if (begin == 0 && end == 1)
        {
                if ( MaxRetrievable()==0 ) 
                        return 0;
                else
                {
                        int result = m_current[0];
                        unsigned int blockedBytes = target.ChannelPut(channel, 
byte(result), blocking);
                        begin += 1-blockedBytes;
                        return blockedBytes;
                }
        }

        byte* current = m_current;
        byte* endPosition = (byte*)m_data + m_dataLen;
        byte* newPosition = current + begin;

        if (newPosition >= endPosition)
        {
                return 0;       // don't try to seek beyond the end of file
        }

        const_cast<ArrayStore *>(this)->Skip(begin);

        unsigned long total = 0;
        try
        {
                assert(!m_waiting);
                unsigned long copyMax = end-begin;
                unsigned int blockedBytes = const_cast<ArrayStore 
*>(this)->TransferTo2(target, copyMax, channel, blocking);
                begin += copyMax;
                if (blockedBytes)
                {
                        const_cast<ArrayStore *>(this)->m_waiting = false;
                        return blockedBytes;
                }
        }
        catch(...)
        {
                throw;
        }

        const_cast<ArrayStore *>(this)->m_current = current;
        return 0;
}

unsigned long ArrayStore::Skip(unsigned long skipMax)
{
        unsigned long step;

        if ( skipMax > MaxRetrievable () )
                step = MaxRetrievable();
        else
                step = skipMax;

        m_current += step;

        return step;
}

Reply via email to