Click here to Skip to main content
15,896,542 members
Articles / Desktop Programming / MFC

Binary Data Marshaling

Rate me:
Please Sign up or sign in to vote.
4.63/5 (12 votes)
13 Jan 20055 min read 60.8K   1.9K   33  
Fast binary data marshaling using simple CMarshal class.
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include"String.h"
#include"Socket.h"
#include <vector>
using namespace std;

class CMarshalObject
{
public:
	virtual String Serialize() { return String(); };
	virtual void Deserialize(String&) {};
};

class CMarshal
{
public:
	CMarshal(void);
	~CMarshal(void);
public:
	String m_data;
	int m_nPopIndex;
// synchronization
	CMarshal *m_pClientMarshal;
	HANDLE m_hEvent;
// version
	float m_fVer;
public:
	void Attach(char* pBuffer, int nLength);
	void Assign(char* pBuffer, int nLength);
	void Append(char* pBuffer, int nLength);
	char* GetBuffer();
	char* Detach();
	int GetLength();
	void Clear();
// Marshal functions
	bool Marshal(LPCSTR lpcsFormat, ...);
	bool Marshal(LPCSTR& lpcsFormat, va_list &argList);
	template<class T> bool Marshal(LPCSTR lpcsFormat, ...)
	{
		va_list argList;
		va_start(argList, lpcsFormat);
		bool bSuccess = Marshal<T>(lpcsFormat, argList);
		va_end(argList);
		return bSuccess;
	}
	template<class T> bool Marshal(LPCSTR& lpcsFormat, va_list &argList)
	{
		bool bVector = false;
		for(; *lpcsFormat; lpcsFormat++)
		{
			if(*lpcsFormat == '%')
				continue;
			if(*lpcsFormat == '$')
				return true;
			m_data += (char)*lpcsFormat;
			// vector support
			if(*lpcsFormat == 'v' || *lpcsFormat == 'V')
			{
				bVector = true;
				continue;
			}
			switch (*lpcsFormat)
			{
			// single characters
			case 'c':
			case 'C':
				if(!bVector)
					m_data += (char)va_arg(argList, char);
				else
					PushVector<char>(va_arg(argList, void*));
				break;

			// object
			case 'o':
			case 'O':
				if(!bVector)
				{
					T* p = va_arg(argList, T*);
					if(p)
					{
						String str = p->Serialize();
						m_data += (short)str.GetLength();
						m_data += str;
					}
					else
						m_data += (short)0;
				}
				else
					PushObjectVector<T>(va_arg(argList, void *));
				break;
			case 'p':
			case 'P':
				if(bVector)
					PushObjectPointerVector<T*>(va_arg(argList, void *));
				break;

			// strings
			case 'S':
			case 's':
				if(!bVector)
				{
					if(*lpcsFormat == 'S')
					{
						String* pstrNextArg = va_arg(argList, String*);
						if(pstrNextArg)
						{
							m_data += (short)pstrNextArg->GetLength();
							m_data += *pstrNextArg;
						}
						else
							m_data += (short)0;
					}
					else
					{
						LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
						if(pstrNextArg)
						{
							m_data += (short)strlen(pstrNextArg);
							m_data += pstrNextArg;
						}
						else
							m_data += (short)0;
					}
				}
				else
					PushVector<String>(va_arg(argList, vector<String> *));
				break;
			// integers
			case 'd':
			case 'u':
			case 'x':
			case 'X':		
				if(!bVector)
					m_data += (int)va_arg(argList, int);
				else
					PushVector<int>(va_arg(argList, void*));
				break;
			case 'i':
				if(!bVector)
					m_data += (short)va_arg(argList, short);
				else
					PushVector<short>(va_arg(argList, void*));
				break;

			case 'e':
			case 'g':
			case 'G':
				if(!bVector)
					m_data += (double)va_arg(argList, double);
				else
					PushVector<double>(va_arg(argList, void*));
				break;

			case 'f':
				if(!bVector)
					m_data += (float)va_arg(argList, float);
				else
					PushVector<float>(va_arg(argList, void*));			
				break;
			// no output
			case 'n':
				break;
			}
			bVector = false;
		}
		
		return true;
	}
// Unmarshal functions
	bool Unmarshal(LPCSTR lpcsFormat, ...);
	bool Unmarshal(LPCSTR lpcsFormat, va_list &argList);
	template<class T> bool Unmarshal(LPCSTR lpcsFormat, va_list &argList)
	{
		bool bVector = false;
		for(LPCTSTR lpsz = lpcsFormat; *lpsz; lpsz++)
		{
			if(*lpsz == '$')
				continue;
			// vector support
			if(*lpsz == 'v' || *lpsz == 'V')
			{
				bVector = true;
				continue;
			}
			switch (*lpsz)
			{
			// single characters
			case 'c':
			case 'C':
				if(!bVector)
					*va_arg(argList, char*) = Pop<char>();
				else
					PopVector<char>(0, *va_arg(argList, vector<char> *));
				break;

			// object
			case 'o':
			case 'O':
				if(!bVector)
					va_arg(argList, CMarshalObject*)->Deserialize(Pop<String>(0));
				else
					PopObjectVector<T>(0, *va_arg(argList, vector<T> *));
				break;
			case 'p':
			case 'P':
				if(bVector)
					PopObjectPointerVector<T>(0, *va_arg(argList, vector<T*> *));
				break;
			// strings
			case 'S':
			case 's':
				if(!bVector)
					*va_arg(argList, String*) = Pop<String>(0);
				else
					PopVector<String>(0, *va_arg(argList, vector<String> *));
				break;
			// integers
			case 'd':
			case 'u':
			case 'x':
			case 'X':		
				if(!bVector)
					*va_arg(argList, int*) = Pop<int>();
				else
					PopVector<int>(0, *va_arg(argList, vector<int> *));
				break;
			case 'i':
				if(!bVector)
					*va_arg(argList, short*) = Pop<short>();
				else
					PopVector<short>(0, *va_arg(argList, vector<short> *));
				break;

			case 'e':
			case 'g':
			case 'G':
				if(!bVector)
					*va_arg(argList, double*) = Pop<double>();
				else
					PopVector<double>(0, *va_arg(argList, vector<double> *));
				break;

			case 'f':
				if(!bVector)
					*va_arg(argList, float*) = Pop<float>();
				else
					PopVector<float>(0, *va_arg(argList, vector<float> *));
				break;
			// no output
			case 'n':
				break;
			}
			bVector = false;
		}
		return true;
	}
	template<class T> bool Unmarshal(LPCSTR lpcsFormat, ...)
	{
		va_list argList;
		va_start(argList, lpcsFormat);
		bool bSuccess = Unmarshal<T>(lpcsFormat, argList);
		va_end(argList);
		return bSuccess;
	}


// Pop functions
	char PopType();
	template<class T> T Pop(BYTE byType = 0)
	{
		if(byType == 0)
			m_nPopIndex++;
		T t = *(T*)(GetBuffer()+m_nPopIndex);
		m_nPopIndex += sizeof(T);
		return t;
	}
	template<> String Pop<String>(BYTE byType)
	{
		if(byType == 0)
			m_nPopIndex++;
		char* pBuffer = GetBuffer();
		int nLength = *(short*)(pBuffer+m_nPopIndex);
		m_nPopIndex += sizeof(short);
		String str((char*)pBuffer+m_nPopIndex, nLength);
		m_nPopIndex += nLength;
		return str;
	}
	template<class T> T PopObject(BYTE byType)
	{
		T t;
		t.Deserialize(Pop<String>(byType));
		return t;
	}
	template<class T> vector<T*> PopObjectPointerVector(BYTE byType)
	{
		vector<T*> v;
		PopObjectPointerVector(byType, v);
		return v;
	}
	template<class T> void PopObjectPointerVector(BYTE byType, vector<T*>& v)
	{
		if(byType == 0)
			m_nPopIndex += 2;
		int nSize = *(int*)(m_data.GetBuffer(0)+m_nPopIndex);
		m_nPopIndex += sizeof(int);
		for(int n = 0; n < nSize; n++)
		{
			T *t = new T;
			t->Deserialize(Pop<String>('s'));
			v.push_back(t);
		}
	}
	template<class T> vector<T> PopObjectVector(BYTE byType)
	{
		vector<T> v;
		PopObjectVector(byType, v);
		return v;

	}
	template<class T> void PopObjectVector(BYTE byType, vector<T>& v)
	{
		if(byType == 0)
			m_nPopIndex += 2;
		int nSize = *(int*)(m_data.GetBuffer(0)+m_nPopIndex);
		m_nPopIndex += sizeof(int);
		for(int n = 0; n < nSize; n++)
		{
			T t;
			t.Deserialize(Pop<String>('s'));
			v.push_back(t);
		}
	}
	template<class T> vector<T> PopVector(BYTE byType = 0)
	{
		vector<T> v;
		PopVector(byType, v);
		return v;
	}
	template<class T> void PopVector(BYTE byType, vector<T>& v)
	{
		if(byType == 0)
			m_nPopIndex += 2;
		char* pBuffer = GetBuffer();
		int nSize = *(int*)(pBuffer+m_nPopIndex);
		m_nPopIndex += sizeof(int);
		v.resize(nSize);
		memcpy(&*v.begin(), pBuffer+m_nPopIndex, nSize*sizeof(T));
		m_nPopIndex += nSize*sizeof(T);
	}
	template<> vector<String> PopVector<String>(BYTE byType)
	{
		vector<String> v;
		PopVector<String>(byType, v);
		return v;
	}
	template<> void PopVector<String>(BYTE byType, vector<String>& v)
	{
		if(byType == 0)
			m_nPopIndex += 2;
		char* pBuffer = m_data.GetBuffer(0);
		int nSize = *(int*)(pBuffer+m_nPopIndex);
		m_nPopIndex += sizeof(int);
		for(int n = 0; n < nSize; n++)
			v.push_back(Pop<String>('s'));
	}

	template<class T> static void VectorResize(vector<T> &v, int nSize)
	{
		v.resize(nSize);
	}
	template<class T> static void VectorClear(vector<T> &v)
	{
		v.clear();
	}
// Push functions
	template<class T> void Push(T t)
		{	m_data += (T)t;	}
	template<> void Push<String>(String str)
	{	
		m_data += (short)str.GetLength();
		m_data += str;
	}
	template<class V> void PushVector(void *v)
	{
		vector<V> *p = (vector<V> *)v;
		m_data += (int)p->size();
		m_data.Append((char*)&*p->begin(), (int)p->size()*sizeof(V));
	}
	template<> void PushVector<String>(void *v)
	{
		vector<String> *p = (vector<String> *)v;
		m_data += (int)p->size();
		for(vector<String>::iterator s = p->begin(); s != p->end(); s++)
		{
			m_data += (short)s->GetLength();
			m_data += *s;
		}
	}
	template<class T> void PushObjectPointerVector(void *p)
	{
		vector<T> *v = (vector<T> *)p;
		m_data += (int)v->size();
		for(vector<T>::iterator t = v->begin(); t != v->end(); t++)
		{
			String str = (*t)->Serialize();
			m_data += (short)str.GetLength();
			m_data += str;
		}
	}	
	template<class T> void PushObjectVector(void *p)
	{
		vector<T> *v = (vector<T> *)p;
		m_data += (int)v->size();
		for(vector<T>::iterator t = v->begin(); t != v->end(); t++)
		{
			String str = t->Serialize();
			m_data += (short)str.GetLength();
			m_data += str;
		}
	}	
	bool IsEOF()
	{
		return m_nPopIndex >= m_data.GetLength();
	}
// sockets functions
	int Send(SOCKET s, bool bSynchronize = false);
	int Recv(SOCKET s);
	int RecvData(SOCKET s);
};

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
Software Developer (Senior)
Egypt Egypt

Comments and Discussions