Sans Pareil Technologies, Inc.

Key To Your Business

Base64Decoder



Decoder for input streams that contain base64 encoded data.
Base64Decoder.h 
Definitions of the buffer, IO stream and decoder for base64 data.
/*
 * Base64Decoder.h
 *
 * $Id:  *poco/1.4/Foundation/include/Poco/Base64Decoder.h#2 $
 *
 * Library: Foundation
 * Package: Streams
 * Module:  Base64
 *
 * Definition of class Base64Decoder.
 *
 * Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
 * and Contributors.
 *
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 *
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer,
 * must be included in all copies of the Software, in whole or in part, and
 * all derivative works of the Software, unless such copies or derivative
 * works are solely in the form of machine-executable object code generated by
 * a source language processor.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */


#ifndef SPT_BASE64DECODER
#define SPT_BASE64DECODER


#include "UnbufferedStreamBuf.h"
#include "SPT.h"

#if defined( ARDUINO )
#include "../StandardCplusplus/istream"
#else
#include <istream>
#endif


namespace spt
{
  /// This streambuf base64-decodes all data read
  /// from the istream connected to it.
  ///
  /// Note: For performance reasons, the characters
  /// are read directly from the given istream's
  /// underlying streambuf, so the state
  /// of the istream will not reflect that of
  /// its streambuf.
  class Base64DecoderBuf: public UnbufferedStreamBuf
  {
  public:
    Base64DecoderBuf( std::istream& istr );
    ~Base64DecoderBuf();

  private:
    int_type readFromDevice();
    int readOne();

    Byte group[3];
    int32_t groupLength;
    int32_t groupIndex;
    std::streambuf& buf;

    static Byte IN_ENCODING[256];
    static bool IN_ENCODING_INIT;

  private:
    Base64DecoderBuf( const Base64DecoderBuf& );
    Base64DecoderBuf& operator = ( const Base64DecoderBuf& );
  };


  /// The base class for Base64Decoder.
  ///
  /// This class is needed to ensure the correct initialization
  /// order of the stream buffer and base classes.
  class Base64DecoderIOS: public virtual std::ios
  {
  public:
    Base64DecoderIOS( std::istream& istr );
    ~Base64DecoderIOS();
    Base64DecoderBuf* rdbuf();

  protected:
    Base64DecoderBuf buf;

  private:
    Base64DecoderIOS( const Base64DecoderIOS& );
    Base64DecoderIOS& operator = ( const Base64DecoderIOS& );
  };


  /// This istream base64-decodes all data
  /// read from the istream connected to it.
  ///
  /// Note: For performance reasons, the characters
  /// are read directly from the given istream's
  /// underlying streambuf, so the state
  /// of the istream will not reflect that of
  /// its streambuf.
  class Base64Decoder: public Base64DecoderIOS, public std::istream
  {
  public:
    Base64Decoder( std::istream& istr );
    ~Base64Decoder();

  private:
    Base64Decoder( const Base64Decoder& );
    Base64Decoder& operator = ( const Base64Decoder& );
  };


} // namespace spt


#endif // SPT_BASE64DECODER
Base64Decoder.cpp 
Implementation of the IO streams for base64 data.
/*
 * Base64Decoder.cpp
 *
 * $Id:  *poco/1.4/Foundation/src/Base64Decoder.cpp#2 $
 *
 * Library: Foundation
 * Package: Streams
 * Module:  Base64
 *
 * Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
 * and Contributors.
 *
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 *
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer,
 * must be included in all copies of the Software, in whole or in part, and
 * all derivative works of the Software, unless such copies or derivative
 * works are solely in the form of machine-executable object code generated by
 * a source language processor.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */


#include "Base64Decoder.h"
#include "Base64Encoder.h"


using spt::Byte;
using spt::Base64Decoder;
using spt::Base64DecoderBuf;
using spt::Base64DecoderIOS;
using spt::Base64Encoder;


Byte Base64DecoderBuf::IN_ENCODING[256];
bool Base64DecoderBuf::IN_ENCODING_INIT = false;


Base64DecoderBuf::Base64DecoderBuf( std::istream& istr ) :
  groupLength(0), groupIndex(0), buf( *istr.rdbuf() )
{
  if ( !IN_ENCODING_INIT )
    {
    for ( uint16_t i = 0; i < sizeof( IN_ENCODING ); ++i )
        {
            IN_ENCODING[i] = 0xFF;
        }

    for ( uint16_t i = 0; i < sizeof( Base64EncoderBuf::OUT_ENCODING ); ++i )
        {
            IN_ENCODING[Base64EncoderBuf::OUT_ENCODING[i]] = i;
        }

    IN_ENCODING[static_cast<Byte>( '=' )] = '\0';
        IN_ENCODING_INIT = true;
    }
}


Base64DecoderBuf::~Base64DecoderBuf() {}


Base64DecoderBuf::int_type Base64DecoderBuf::readFromDevice()
{
  if ( groupIndex <  groupLength ) return group[groupIndex++];
    else
    {
    Byte buffer[4];

        int c;
    if ( ( c = readOne() ) == -1 ) return -1;

    buffer[0] = static_cast<Byte>( c );
    if ( IN_ENCODING[buffer[0]] == 0xFF ) return -1;
    if ( ( c = readOne() ) == -1 ) return -1;

    buffer[1] = static_cast<Byte>( c );
    if ( IN_ENCODING[buffer[1]] == 0xFF ) return -1;
    if ( ( c = readOne() ) == -1 ) return -1;

    buffer[2] = static_cast<Byte>( c );
    if ( IN_ENCODING[buffer[2]] == 0xFF ) return -1;
    if ( ( c = readOne() ) == -1 ) return -1;

        buffer[3] = c;
    if ( IN_ENCODING[buffer[3]] == 0xFF ) return -1;
        
    group[0] = ( IN_ENCODING[buffer[0]] << 2 ) | ( IN_ENCODING[buffer[1]] >> 4 );
    group[1] = ( ( IN_ENCODING[buffer[1]] & 0x0F ) << 4 ) | ( IN_ENCODING[buffer[2]] >> 2 );
    group[2] = ( IN_ENCODING[buffer[2]] << 6 ) | IN_ENCODING[buffer[3]];

    if ( buffer[2] == '=' ) groupLength = 1;
    else if ( buffer[3] == '=' )  groupLength = 2;
    else groupLength = 3;

    groupIndex = 1;
    return group[0];
    }
}


int Base64DecoderBuf::readOne()
{
  int ch = buf.sbumpc();
  while ( ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n' ) ch = buf.sbumpc();
    return ch;
}


Base64DecoderIOS::Base64DecoderIOS( std::istream& istr ): buf( istr )
{
  init( &buf );
}


Base64DecoderIOS::~Base64DecoderIOS() {}


Base64DecoderBuf* Base64DecoderIOS::rdbuf() { return &buf; }


Base64Decoder::Base64Decoder( std::istream& istr ) :
  Base64DecoderIOS( istr ), std::istream( &buf ) {}


Base64Decoder::~Base64Decoder() {}
Base64Test.cpp 
Unit test suite for base64 encoding and decoding.
#if defined( ARDUINO )
#include "tut.hpp"
#include "SPT.h"
#include "Base64Encoder.h"
#include "Base64Decoder.h"
#else
#include <tut/tut.hpp>
#include <SPT.h>
#include <Base64Encoder.h>
#include <Base64Decoder.h>
#endif

using spt::Base64Encoder;
using spt::Base64Decoder;

namespace tut
{
  struct Base64TestData {};

  typedef test_group<Base64TestData> Base64TestGroup;
  typedef Base64TestGroup::object Base64Test;
  Base64TestGroup base64TestGroup( "Base64 test suite" );


  template<>
  template<>
  void Base64Test::test<1>()
  {
    set_test_name( "encode1" );

    std::ostringstream str;
    Base64Encoder encoder( str );
    encoder << std::string( "\00\01\02\03\04\05", 6 );
    encoder.close();
    ensure( "Encode1", str.str() == "AAECAwQF" );
    spt::printFreeRam();
  }


  template<>
  template<>
  void Base64Test::test<2>()
  {
    set_test_name( "encode2" );

    std::ostringstream str;
    Base64Encoder encoder( str );
    encoder << std::string( "\00\01\02\03", 4 );
    encoder.close();
    ensure( "Encode2", str.str() == "AAECAw==" );
    spt::printFreeRam();
  }


  template<>
  template<>
  void Base64Test::test<3>()
  {
    set_test_name( "encode3" );

    std::ostringstream str;
    Base64Encoder encoder( str );
    encoder << "ABCDEF";
    encoder.close();
    ensure( "Encode 3", str.str() == "QUJDREVG" );
    spt::printFreeRam();
  }


  template<>
  template<>
  void Base64Test::test<4>()
  {
    set_test_name( "decode1" );

    std::istringstream istr( "AAECAwQF" );
    Base64Decoder decoder( istr );
    ensure( "Decode 1-1", decoder.good() && decoder.get() == 0 );
    ensure( "Decode 1-2", decoder.good() && decoder.get() == 1 );
    ensure( "Decode 1-3", decoder.good() && decoder.get() == 2 );
    ensure( "Decode 1-4", decoder.good() && decoder.get() == 3 );
    ensure( "Decode 1-5", decoder.good() && decoder.get() == 4 );
    ensure( "Decode 1-6", decoder.good() && decoder.get() == 5 );
    ensure( "Decode 1-7", decoder.good() && decoder.get() == -1 );
    spt::printFreeRam();
  }


  template<>
  template<>
  void Base64Test::test<5>()
  {
    set_test_name( "decode2" );

    std::istringstream istr( "AAECAwQ=" );
    Base64Decoder decoder( istr );
    ensure( "Decode 2-1", decoder.good() && decoder.get() == 0 );
    ensure( "Decode 2-2", decoder.good() && decoder.get() == 1 );
    ensure( "Decode 2-3", decoder.good() && decoder.get() == 2 );
    ensure( "Decode 2-4", decoder.good() && decoder.get() == 3 );
    ensure( "Decode 2-5", decoder.good() && decoder.get() == 4 );
    ensure( "Decode 2-6", decoder.good() && decoder.get() == -1 );
    spt::printFreeRam();
  }


  template<>
  template<>
  void Base64Test::test<6>()
  {
    set_test_name( "decode3" );

    std::istringstream istr( "AAECAw==" );
    Base64Decoder decoder( istr );
    ensure( "Decode 3-1", decoder.good() && decoder.get() == 0 );
    ensure( "Decode 3-2", decoder.good() && decoder.get() == 1 );
    ensure( "Decode 3-3", decoder.good() && decoder.get() == 2 );
    ensure( "Decode 3-4", decoder.good() && decoder.get() == 3 );
    ensure( "Decode 3-5", decoder.good() && decoder.get() == -1 );
    spt::printFreeRam();
  }


  template<>
  template<>
  void Base64Test::test<7>()
  {
    set_test_name( "decode4" );

    std::istringstream istr( "QUJDREVG" );
    Base64Decoder decoder( istr );
    std::string s;
    decoder >> s;
    ensure( "Decode 4-1", s == "ABCDEF" );
    ensure( "Decode 4-2", decoder.eof() );
    spt::printFreeRam();
  }


  template<>
  template<>
  void Base64Test::test<8>()
  {
    set_test_name( "decode5" );

    std::istringstream istr( "QUJ\r\nDRE\r\nVG" );
    Base64Decoder decoder( istr );
    std::string s;
    decoder >> s;
    ensure( "Decode 5-1", s == "ABCDEF" );
    ensure( "Decode 5-2", decoder.eof() );
    spt::printFreeRam();
  }


  template<>
  template<>
  void Base64Test::test<9>()
  {
    set_test_name( "decode6" );

    std::istringstream istr( "QUJD#REVG" );
    Base64Decoder decoder( istr );
    std::string s;
    decoder >> s;
    ensure( "Decode 6-1", decoder.eof() );
    spt::printFreeRam();
  }


  template<>
  template<>
  void Base64Test::test<10>()
  {
    set_test_name( "encodeDecode1" );

    std::stringstream str;
    Base64Encoder encoder( str );
    encoder << "The quick brown fox ";
    encoder << "jumped over the lazy dog.";
    encoder.close();

    Base64Decoder decoder( str );
    std::string s;
    int c = decoder.get();
    while ( c != -1 ) { s += char(c); c = decoder.get(); }
    ensure( "EncodeDecode1", s == "The quick brown fox jumped over the lazy dog." );
    spt::printFreeRam();
  }


  template<>
  template<>
  void Base64Test::test<11>()
  {
    set_test_name( "encodeDecode2" );

    std::string src;
    for ( int i = 0; i < 255; ++i ) src += char( i );
    std::stringstream str;
    Base64Encoder encoder(str);
    encoder.write( src.data(), static_cast<std::streamsize>( src.size() ) );
    encoder.close();

    Base64Decoder decoder( str );
    std::string s;
    int c = decoder.get();
    while ( c != -1 ) { s += char(c); c = decoder.get(); }
    ensure( "EncodeDecode2", s == src );
    spt::printFreeRam();
  }
}
Adapted for use on Arduino from Poco.