#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);
};