ArrayEncoder
ArrayEncoder is a simple example of a FilterWithBufferedInput
derived class. You can use it to quickly generate C style arrays and strings using a HexEncoder. The outputted strings will not exceed a chosen width
.
The ArrayEncoder
takes a pointer to a BufferedTransformation
. Because a pointer is taken, the ArrayEncoder
owns the attached transformation, and therefore will destroy it. See ownership for more details.
The ArrayEncoder
class appeared around Crypto++ 5.6.4 to help generate self tests. There is no ArrayDecoder
class.
ArrayEncoder
is not part of the Crypto++ library. If you want it, then paste it into a file like hex.h
below the HexEncoder
and HexDecoder
class definitions. ArrayEncoder
is a header-only definition so you don't need to modify source files. If you want to add it to the library, be sure its in the CryptoPP
namespace.
Construction
ArrayEncoder(BufferedTransformation *attachment=NULL, bool uppercase=true, unsigned int width=80, bool asString=true)
attachment
is a BufferedTransformation, such as another filter or sink. If attachment
is NULL
, then the ArrayEncoder
object will internally accumulate the output byte stream.
uppercase
is an output formatting option and determines if output is uppercase or lowercase.
width
is the maximum length of an output line. Lines may be shorter, but they will not be longer.
asString
is a flag indicating C-style strings. If asString
is true
then encoded bytes are prefixed with \x
and each line is quoted. Otherwise, encoded bytes are prefixed with 0x
and separated with commas.
Usage
SecByteBlock scratch(34); OS_GenerateRandomBlock(false, scratch, scratch.size()); ArraySource as(scratch, scratch.size(), true, new ArrayEncoder(new FileSink(cout)));
The result is as shown blow. You will have to add the opening and closing braces.
0x2A,0x5A,0x7D,0xC4,0x15,0x7F,0x78,0x2D,0xE4,0x65,0xDD,0x2F,0x2C,0xA8,0x01,0x5B, 0xA2,0x92,0xA1,0xCF,0x33,0x11,0xFF,0x12,0xAC,0x49,0x3D,0x1C,0x52,0x48,0xDC,0x72, 0xB0,0xF2
If you want a C style string, then set asString
to true
:
SecByteBlock scratch(34); OS_GenerateRandomBlock(false, scratch, scratch.size()); ArraySource as(scratch, scratch.size(), true, new ArrayEncoder(new FileSink(cout), true, 80, true));
It produces the result:
"\xCF\x75\xA2\x27\xD6\xD0\x1B\x2E\x9F\x44\x3C\x1C\x8B\x5C\x22\x62\x66\xA1\x23" "\x81\x6D\x15\x4F\xB4\x35\xDA\x01\xF2\xF8\x71\xAF\xFF\x86\xAA"
ArrayEncoder
class ArrayEncoder : public FilterWithBufferedInput { public: ArrayEncoder(BufferedTransformation *attachment=NULL, bool uppercase=true, unsigned int width=80, bool asString=true) : FilterWithBufferedInput(0, 1, 0, attachment), m_encoder(), m_width(width), m_firstPut(false), m_asString(asString) { AlgorithmParameters params; if (m_asString) { params = MakeParameters (Name::Uppercase(), uppercase) (Name::GroupSize(), 2) (Name::Terminator(), ConstByteArrayParameter("")) (Name::Separator(), ConstByteArrayParameter("\\x")); } else { params = MakeParameters (Name::Uppercase(), uppercase) (Name::GroupSize(), 2) (Name::Terminator(), ConstByteArrayParameter("")) (Name::Separator(), ConstByteArrayParameter(",0x")); } m_encoder.IsolatedInitialize(params); if (m_width < 40) m_width = 40; } virtual void FirstPut(const byte *inString) { // m_firstSize is from base class ArrayEncoder::Put2(inString, m_firstSize, 0, true); } virtual void LastPut(const byte *inString, size_t length) { ArrayEncoder::Put2(inString, length, -1, true); } virtual size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking) { // Allow member filter to process data and messageEnd if (inString && length) m_encoder.Put2(inString, length, messageEnd, blocking); // 8*m_width buffers for the output device. Push data if messageEnd if (m_encoder.MaxRetrievable() > 8*m_width || messageEnd) TransferEncoded(!!messageEnd); // Pass a messageEnd to the attached transformation if (messageEnd) AttachedTransformation()->MessageEnd(); return 0; } protected: void TransferEncodedLine(const SecByteBlock& str) { if (m_asString) // Opening quote AttachedTransformation()->Put((const byte*)"\"", 1); AttachedTransformation()->Put(str.data(), str.size()); if (m_asString) // Closing quote AttachedTransformation()->Put((const byte*)"\"", 1); AttachedTransformation()->Put((const byte*)"\n", 1); } void TransferEncoded(bool last=false) { if (last) m_encoder.MessageEnd(); if (!m_encoder.AnyRetrievable()) return; // m_asString and -2 due to quotes const size_t size = (m_asString ? ((m_width/4)*4-2): (m_width/5)*5); SecByteBlock scratch(size); ///////////////////////////////////////////////////////////////////////// // First Put (maybe last, too) if (!m_firstPut) { // First put needs the lead 0x or \x scratch[1] = 'x'; if (m_asString) scratch[0] = '\\'; else scratch[0] = '0'; size_t rem = m_encoder.Get(scratch.data()+2, size-2); scratch.resize(rem+2); TransferEncodedLine(scratch); m_firstPut = true; } // Middle Puts while (m_encoder.MaxRetrievable() >= m_width) { m_encoder.Get(scratch.data(), size); TransferEncodedLine(scratch); } // Last Put if (last) { if (m_encoder.AnyRetrievable()) { size_t rem = m_encoder.Get(scratch.data(), size); scratch.resize(rem); TransferEncodedLine(scratch); } m_firstPut = false; } } private: HexEncoder m_encoder; unsigned int m_width; bool m_firstPut, m_asString; };