#include <memory.h>
#include <stdio.h>
#include "BitStream.h"
const int MIN_FUNC_STACK_ALIGNMENT=4;
#define GET_OBJECT_MEMBER_PTR(_OUT_, _CLASS_, _FUNCTION_, _PARAMS_) \
{ \
union \
{ \
void (_cdecl _CLASS_::*__memberFunctionPtr)_PARAMS_; \
void* __voidFunc; \
}; \
__memberFunctionPtr=&_CLASS_::_FUNCTION_; \
(_OUT_) = __voidFunc; \
}
#define OBJECT_MEMBER_SIGNATURE(_CLASS_, _FUNCTION_, _PARAMS_) #_CLASS_ #_FUNCTION_ #_PARAMS_
template <class P1, class P2>
unsigned int SerializeParameters(char *out, unsigned int outMaxLen, P1 p1, P2 p2)
{
const unsigned char NUM_PARAMS=2;
unsigned int writeOffset=0;
unsigned int paramLength;
unsigned int bytesRequired = sizeof(unsigned char)+sizeof(unsigned int)*NUM_PARAMS+sizeof(P1)+sizeof(P2);
if (bytesRequired > outMaxLen)
return 0;
out[writeOffset]=NUM_PARAMS;
writeOffset+=sizeof(unsigned char);
paramLength=(unsigned int) sizeof(P1);
memcpy(out+writeOffset, ¶mLength, sizeof(unsigned int) );
writeOffset+=sizeof(unsigned int);
paramLength=(unsigned int) sizeof(P2);
memcpy(out+writeOffset, ¶mLength, sizeof(unsigned int) );
writeOffset+=sizeof(unsigned int);
memcpy(out+writeOffset,&p1,sizeof(P1));
writeOffset+=sizeof(P1);
memcpy(out+writeOffset,&p2,sizeof(P2));
writeOffset+=sizeof(P2);
return bytesRequired;
}
bool DeserializeParameters(char *out, unsigned int outLength, unsigned int *bytesWritten,
char *in, unsigned int inLength,
unsigned char *numParameters,
unsigned int *parameterLengths, unsigned int maxParameters)
{
unsigned int readOffset=0;
unsigned char parameterIndex;
unsigned int alignedBytesRequired;
*numParameters=in[0];
*bytesWritten=0;
readOffset+=sizeof(unsigned char);
if (*numParameters > maxParameters) return false;
if (readOffset+*numParameters*sizeof(unsigned int) > inLength) return false;
for (parameterIndex=0; parameterIndex < *numParameters; parameterIndex++)
{
memcpy(parameterLengths+parameterIndex, in+readOffset, sizeof(unsigned int));
readOffset+=sizeof(unsigned int);
}
for (parameterIndex=0; parameterIndex < *numParameters; parameterIndex++)
{
alignedBytesRequired = parameterLengths[parameterIndex];
if (alignedBytesRequired % MIN_FUNC_STACK_ALIGNMENT!=0)
{
alignedBytesRequired+=MIN_FUNC_STACK_ALIGNMENT-(alignedBytesRequired % MIN_FUNC_STACK_ALIGNMENT);
}
if (outLength < *bytesWritten + alignedBytesRequired )
return false;
if (RakNet::BitStream::IsBigEndian())
{
memcpy(out+*bytesWritten+alignedBytesRequired-parameterLengths[parameterIndex],in+readOffset,parameterLengths[parameterIndex]);
memset(out+*bytesWritten,0,alignedBytesRequired-parameterLengths[parameterIndex]);
}
else
{
memcpy(out+*bytesWritten,in+readOffset,parameterLengths[parameterIndex]);
memset(out+*bytesWritten+parameterLengths[parameterIndex],0,alignedBytesRequired-parameterLengths[parameterIndex]);
}
readOffset+=parameterLengths[parameterIndex];
*bytesWritten+=alignedBytesRequired;
}
return true;
}
void _cdecl func2(int a, char b)
{
printf("%i %i", a, b);
}
class MyClass
{
public:
virtual void _cdecl func6(int a, char b)
{
printf("func6 2 base\n");
}
};
class DerivedClass : public MyClass
{
public:
virtual void _cdecl func6(int a, char b)
{
printf("func6 2 derived\n");
}
};
bool DoFunctionCall(const char *inputStack, unsigned int numBytes, void *functionPtr, void *thisPtr)
{
if (numBytes > MAX_ALLOCA_STACK_ALLOCATION)
return false;
const int loopCount = numBytes/4;
__asm
{
sub esp,numBytes
mov ecx,loopCount
mov esi,inputStack
mov edi,esp
rep movs dword ptr es:[edi],dword ptr [esi]
cmp thisPtr,0
je no_this_ptr
push thisPtr
call functionPtr
pop thisPtr
jmp done
no_this_ptr:
call functionPtr
done:
add esp,numBytes
}
}
void main(void)
{
char in[256];
unsigned int inLength;
inLength=SerializeParameters(in, sizeof(in), 9, 6);
DerivedClass myClass;
char out[256];
unsigned int bytesWritten;
unsigned char numParameters;
unsigned int parameterLengths[10];
DeserializeParameters(out, sizeof(out), &bytesWritten,
in,inLength,
&numParameters,
parameterLengths, sizeof(parameterLengths)/sizeof(unsigned int));
void *v;
GET_OBJECT_MEMBER_PTR(v, MyClass, func6, (int a, char b));
printf("%s\n", OBJECT_MEMBER_SIGNATURE(MyClass, func6, (int a, char b)));
DoFunctionCall(out, bytesWritten, v, &myClass);
DoFunctionCall(out, bytesWritten, func2, 0);
}