Click here to Skip to main content
15,895,746 members
Articles / Programming Languages / C++

IoBind, a serializer code factory.

Rate me:
Please Sign up or sign in to vote.
4.89/5 (10 votes)
29 Jun 20037 min read 79.1K   763   29  
IoBind proposes a new approach to object serialization.
/*
IoBind Library License:
--------------------------

The zlib/libpng License Copyright (c) 2003 Jonathan de Halleux

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.

3. This notice may not be removed or altered from any source distribution
*/

//  base64.hpp 
//  Autor Konstantin Pilipchuk
//  mailto:lostd@ukr.net
//
//

#ifndef IOBIND_BASE64_HPP
#define IOBIND_BASE64_HPP

#include <iterator>
#include <sstream>

static
int _base64Chars[]= {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
				     'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
			         '0','1','2','3','4','5','6','7','8','9',
			         '+','/' };


#define _0000_0011 0x03
#define _1111_1100 0xFC
#define _1111_0000 0xF0
#define _0011_0000 0x30
#define _0011_1100 0x3C
#define _0000_1111 0x0F
#define _1100_0000 0xC0
#define _0011_1111 0x3F

#define _EQUAL_CHAR   (-1)
#define _UNKNOWN_CHAR (-2)

#define _IOS_FAILBIT   std::ios_base::failbit
#define _IOS_EOFBIT    std::ios_base::eofbit
#define _IOS_BADBIT    std::ios_base::badbit
#define _IOS_GOODBIT   std::ios_base::goodbit

namespace iobind{
namespace base64{

// TEMPLATE CLASS base64_put
template<class _E = char, class _Tr = std::char_traits<_E> >
class base64
{
public:

	typedef unsigned char byte_t;
	typedef _E            char_type;
	typedef _Tr           traits_type; 

	// base64 requires max line length <= 72 characters
	// you can fill end of line
	// it may be crlf, crlfsp, noline or other class like it

	struct crlf
	{
		template<class _OI>
			_OI operator()(_OI _To) const{
			*_To = _Tr::to_char_type('\r'); ++_To;
			*_To = _Tr::to_char_type('\n'); ++_To;

			return (_To);
		}
	};


	struct crlfsp
	{
		template<class _OI>
			_OI operator()(_OI _To) const{
			*_To = _Tr::to_char_type('\r'); ++_To;
			*_To = _Tr::to_char_type('\n'); ++_To;
			*_To = _Tr::to_char_type(' '); ++_To;

			return (_To);
		}
	};

	struct noline
	{
		template<class _OI>
			_OI operator()(_OI _To) const{
			return (_To);
		}
	};

	struct three2four
	{
		void zero()
		{
			_data[0] = 0;
			_data[1] = 0;
			_data[2] = 0;
		}

		byte_t get_0()	const
		{
			return _data[0];
		}
		byte_t get_1()	const
		{
			return _data[1];
		}
		byte_t get_2()	const
		{
			return _data[2];
		}

		void set_0(byte_t _ch)
		{
			_data[0] = _ch;
		}

		void set_1(byte_t _ch)
		{
			_data[1] = _ch;
		}

		void set_2(byte_t _ch)
		{
			_data[2] = _ch;
		}

		// 0000 0000  1111 1111  2222 2222
		// xxxx xxxx  xxxx xxxx  xxxx xxxx
		// 0000 0011  1111 2222  2233 3333

		int b64_0()	const	{return (_data[0] & _1111_1100) >> 2;}
		int b64_1()	const	{return ((_data[0] & _0000_0011) << 4) + ((_data[1] & _1111_0000)>>4);}
		int b64_2()	const	{return ((_data[1] & _0000_1111) << 2) + ((_data[2] & _1100_0000)>>6);}
		int b64_3()	const	{return (_data[2] & _0011_1111);}

		void b64_0(int _ch)	{_data[0] = ((_ch & _0011_1111) << 2) | (_0000_0011 & _data[0]);}

		void b64_1(int _ch)	{
			_data[0] = ((_ch & _0011_0000) >> 4) | (_1111_1100 & _data[0]);
			_data[1] = ((_ch & _0000_1111) << 4) | (_0000_1111 & _data[1]);	}

		void b64_2(int _ch)	{
			_data[1] = ((_ch & _0011_1100) >> 2) | (_1111_0000 & _data[1]);
			_data[2] = ((_ch & _0000_0011) << 6) | (_0011_1111 & _data[2]);	}

		void b64_3(int _ch){
			_data[2] = (_ch & _0011_1111) | (_1100_0000 & _data[2]);}

	private:
		byte_t _data[3];

	};

	template<class _II, class _OI, class _State, class _Endline>
		_II put(_II _First, _II _Last, _OI _To, _State& _St, _Endline _Endl)  const
	{
		three2four _3to4;
		int line_octets = 0;

		while(_First != _Last)
		{
			_3to4.zero();

			// ���� �� 3 �������
			_3to4.set_0(*_First);
			_First++;

			if(_First == _Last)
			{
				*_To = _Tr::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
				*_To = _Tr::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
				*_To = _Tr::to_char_type('='); ++_To;
				*_To = _Tr::to_char_type('='); ++_To;
				goto __end;
			}

			_3to4.set_1(*_First);
			_First++;

			if(_First == _Last)
			{
				*_To = _Tr::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
				*_To = _Tr::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
				*_To = _Tr::to_char_type(_base64Chars[_3to4.b64_2()]); ++_To;
				*_To = _Tr::to_char_type('='); ++_To;
				goto __end;
			}

			_3to4.set_2(*_First);
			_First++;

			*_To = _Tr::to_char_type(_base64Chars[_3to4.b64_0()]); ++_To;
			*_To = _Tr::to_char_type(_base64Chars[_3to4.b64_1()]); ++_To;
			*_To = _Tr::to_char_type(_base64Chars[_3to4.b64_2()]); ++_To;
			*_To = _Tr::to_char_type(_base64Chars[_3to4.b64_3()]); ++_To;

			if(line_octets == 17) // base64 ��������� ����� ������ �� ����� 72 ��������
			{
				_To = _Endl(_To);

				line_octets = 0;
			}
			else
				++line_octets;
		}

		__end: ;

		return (_First);

	}

	template<class _II, class _OI, class _State>
		_II get(_II _First, _II _Last, _OI _To, _State& _St) const
	{
		three2four _3to4;
		int _Char;

		while(_First != _Last)
		{

			// Take octet
			_3to4.zero();

			// -- 0 --
			// Search next valid char... 
			while((_Char =  get_char_type(*_First)) < 0 && _Char == _UNKNOWN_CHAR)
			{
				if(++_First == _Last)
				{
					_St |= _IOS_FAILBIT|_IOS_EOFBIT; return _First; // unexpected EOF
				}
			}

			if(_Char == _EQUAL_CHAR){
				// Error! First character in octet can't be '='
				_St |= _IOS_FAILBIT; 
				return _First; 
			}
			else
				_3to4.b64_0(_Char);


			// -- 1 --
			// Search next valid char... 
			while(++_First != _Last)
				if((_Char = get_char_type(*_First)) != _UNKNOWN_CHAR)
					break;

			if(_First == _Last)	{
				_St |= _IOS_FAILBIT|_IOS_EOFBIT; // unexpected EOF 
				return _First;
			}

			if(_Char == _EQUAL_CHAR){
				// Error! Second character in octet can't be '='
				_St |= _IOS_FAILBIT; 
				return _First; 
			}
			else
				_3to4.b64_1(_Char);


			// -- 2 --
			// Search next valid char... 
			while(++_First != _Last)
				if((_Char = get_char_type(*_First)) != _UNKNOWN_CHAR)
					break;

			if(_First == _Last)	{
				// Error! Unexpected EOF. Must be '=' or base64 character
				_St |= _IOS_FAILBIT|_IOS_EOFBIT; 
				return _First; 
			}

			if(_Char == _EQUAL_CHAR){
				// OK!
				_3to4.b64_2(0); 
				_3to4.b64_3(0); 

				// chek for EOF
				if(++_First == _Last)
				{
					// Error! Unexpected EOF. Must be '='. Ignore it.
					//_St |= _IOS_BADBIT|_IOS_EOFBIT;
					_St |= _IOS_EOFBIT;
				}
				else 
					if(get_char_type(*_First) != _EQUAL_CHAR)
					{
						// Error! Must be '='. Ignore it.
						//_St |= _IOS_BADBIT;
					}
				else
					++_First; // Skip '='

				// write 1 byte to output
				*_To = (byte_t) _3to4.get_0();
				return _First;
			}
			else
				_3to4.b64_2(_Char);


			// -- 3 --
			// Search next valid char... 
			while(++_First != _Last)
				if((_Char = get_char_type(*_First)) != _UNKNOWN_CHAR)
					break;

			if(_First == _Last)	{
				// Unexpected EOF. It's error. But ignore it.
				//_St |= _IOS_FAILBIT|_IOS_EOFBIT; 
					_St |= _IOS_EOFBIT; 
				
				return _First; 
			}

			if(_Char == _EQUAL_CHAR)
			{
				// OK!
				_3to4.b64_3(0); 

				// write to output 2 bytes
				*_To = (byte_t) _3to4.get_0();
				*_To = (byte_t) _3to4.get_1();

				++_First; // set position to next character

				return _First;
			}
			else
				_3to4.b64_3(_Char);


			// write to output 3 bytes
			*_To = (byte_t) _3to4.get_0();
			*_To = (byte_t) _3to4.get_1();
			*_To = (byte_t) _3to4.get_2();

			++_First;
			

		} // while(_First != _Last)

		return (_First);
	};

protected:

	int get_char_type(int C_) const
	{
		if(_base64Chars[62] == C_)
			return 62;

		if(_base64Chars[63] == C_)
			return 63;

		if((_base64Chars[0] <= C_) && (_base64Chars[25] >= C_))
			return C_ - _base64Chars[0];

		if((_base64Chars[26] <= C_) && (_base64Chars[51] >= C_))
			return C_ - _base64Chars[26] + 26;

		if((_base64Chars[52] <= C_) && (_base64Chars[61] >= C_))
			return C_ - _base64Chars[52] + 52;

		if(C_ == _Tr::to_int_type('='))
			return _EQUAL_CHAR;

		return _UNKNOWN_CHAR;
	};
};

}; // base64

// base64 encode
template<typename T>
std::string base64_encode( T const& value_)
{
		int _State = 0;
		base64::base64<char> encoder;

		// converting value to string
		std::ostringstream ostr;
		ostr<<value_;

		// get istream
		std::istringstream istr(ostr.str());
		std::istreambuf_iterator<char> _From(istr.rdbuf());
		std::istreambuf_iterator<char> _To(0);

		// encode to output string
		std::ostringstream ostr_64;
		std::ostreambuf_iterator<char> _Out(ostr_64);

		// encoding string
		encoder.put(_From, _To, _Out, _State, base64::base64<>::crlf());

		return ostr_64.str();
};

// base64 encode
template<typename IteratorT>
std::string base64_encode( IteratorT const& begin_, IteratorT const& end_)
{
		int _State = 0;
		base64::base64<char> encoder;

		// converting value to string
		std::ostringstream ostr;
		IteratorT it = begin_;
		while (it != end_)
			ostr<<*(it++);

		// get istream
		std::istringstream istr(ostr.str());
		std::istreambuf_iterator<char> _From(istr.rdbuf());
		std::istreambuf_iterator<char> _To(0);

		// encode to output string
		std::ostringstream ostr_64;
		std::ostreambuf_iterator<char> _Out(ostr_64);

		// encoding string
		encoder.put(_From, _To, _Out, _State, base64::base64<>::crlf());

		return ostr_64.str();
};

// base64 decode
template<typename T>
std::string base64_decode( T const& value_)
{
		int _State = 0;
		base64::base64<char> encoder;

		// converting value to string
		std::ostringstream ostr;
		ostr<<value_;

		// get istream
		std::istringstream istr(ostr.str());
		std::istreambuf_iterator<char> _From(istr.rdbuf());
		std::istreambuf_iterator<char> _To(0);

		// encode to output string
		std::ostringstream ostr_64;
		std::ostreambuf_iterator<char> _Out(ostr_64);

		// encoding string
		encoder.get(_From, _To, _Out, _State);

		return ostr_64.str();
};

}; //iobind
#endif


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Engineer
United States United States
Jonathan de Halleux is Civil Engineer in Applied Mathematics. He finished his PhD in 2004 in the rainy country of Belgium. After 2 years in the Common Language Runtime (i.e. .net), he is now working at Microsoft Research on Pex (http://research.microsoft.com/pex).

Comments and Discussions