Binary serialization

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
alexionne
Posts: 55
Joined: Fri Jun 22, 2007 9:55 am
Location: Novi Sad, Serbia

Binary serialization

Post by alexionne »

Hi, all!

Here are several files from the project I'm working on which I use to implement serialization of objects. So, what's in this post:

1. IrrCustomTypes.h - typedef's irr::wchar, also I use String, Char, STR, CHR so I can easily switch to irr::8/irr::core::stringc whenever I want :)

2. Stream.h/.cpp - implementation of infinite reading/writing stream. Note that you have to write something to Stream before you read from it.

3. IrrStreaming.h/.cpp - implementation of (de)serialization of basic Irrlicht types based on Stream. This is also an example of usage of Stream.

Hope you find this useful :-)

Code: Select all

CStream s;
// Serialization
String str(STR("Test"));
s << str;
// Deserialization:
String str2;
s >> str2;
// str2 is now "Test"

Code: Select all

/*
	IrrCustomTypes.h
	
	Custom Irrlicht-style types
*/

#ifndef IrrCustomTypes_h
#define IrrCustomTypes_h

#include <Irrlicht.h>

namespace irr
{
	typedef wchar_t wchar;
}

typedef irr::core::stringw String;
typedef irr::wchar Char;

#define STR(S) L##S
#define CHR(C) L##C

#endif // IrrCustomTypes_h

Code: Select all

/*
	Stream.h
*/

#ifndef Stream_h
#define Stream_h

#include <Irrlicht.h>

//! I/O stream, infinite read/write, without seeking
class CStream
{
private:
	//! Stream buffer
	irr::u8* Buffer;
	
	//! Stream buffer size
	irr::u32 BufferSize;

	//! Writing position
	irr::u32 WritePos;

	//! Reading position
	irr::u32 ReadPos;
	
	//! Can stream be written to?
	bool Writable;

public:
	//! Constructor
	CStream();
	
	//! Consturctor for read-only stream
	CStream(void* buffer, irr::u32 bufferSize);
	
	//! Pointer to readable area
	inline void* GetReadPtr()
	{
		return &Buffer[ReadPos];
	}
	
	//! Number of bytes which can be read
	inline irr::u32 GetReadSize()
	{
		return WritePos - ReadPos;
	}

	//! Pointer to writable area
	inline void* GetWritePtr()
	{
		return &Buffer[WritePos];
	}

	//! Ensures that spacified number of bytes can be written to GetWritePtr()
	void EnsureWriteSize(irr::u32 minWriteSize);

	//! Advance read position by specified number of bytes
	void AdvanceReadPos(irr::u32 delta);

	//! Advance write position by specified number of bytes
	void AdvanceWritePos(irr::u32 delta);

	//! General writing function, buffer can be NULL (skipping)
	irr::u32 Write(void *buffer, irr::u32 size);
	
	//! General reading function, buffer can be NULL (skipping)
	irr::u32 Read(void *buffer, irr::u32 size);
	
	//! Copies data from another stream to this
	irr::u32 Copy(CStream &source, irr::u32 size);
};

// Serialization declaration
#define DeclareSerialization_(T, REF) \
CStream& operator << (CStream& stream, T (REF obj));

#define DeclareSerialization(T) DeclareSerialization_(T,)
#define DeclareSerializationRef(T) DeclareSerialization_(T, &)
#define DeclareSerializationPtr(T) DeclareSerialization_(T, *)

// Serialization implementation
#define ImplementSerialization_(T, REF) \
CStream& operator << (CStream& stream, T (REF obj))

#define ImplementSerialization(T) ImplementSerialization_(T,)
#define ImplementSerializationRef(T) ImplementSerialization_(T, &)
#define ImplementSerializationPtr(T) ImplementSerialization_(T, *)

// Deserialization declaration
#define DeclareDeserialization_(T, REF) \
CStream& operator >> (CStream& stream, T (REF obj));

#define DeclareDeserialization(T) DeclareDeserialization_(T,)
#define DeclareDeserializationRef(T) DeclareDeserialization_(T, &)
#define DeclareDeserializationPtr(T) DeclareDeserialization_(T, *)

// Deserialization implementation
#define ImplementDeserialization_(T, REF) \
CStream& operator >> (CStream& stream, T (REF obj))

#define ImplementDeserialization(T) ImplementDeserialization_(T,)
#define ImplementDeserializationRef(T) ImplementDeserialization_(T, &)
#define ImplementDeserializationPtr(T) ImplementDeserialization_(T, *)

#endif // Stream_h

Code: Select all

/*
	Stream.cpp
*/

#include "Stream.h"

const irr::u32 MaxEmptyBufferSize = 1024;

//! Constructor
CStream::CStream() :
	Buffer(0),
	BufferSize(0),
	WritePos(0),
	ReadPos(0),
	Writable(true)
{
}

//! Consturctor for read-only stream
CStream::CStream(void* buffer, irr::u32 bufferSize) :
	Buffer((irr::u8*)buffer),
	BufferSize(bufferSize),
	WritePos(bufferSize),
	ReadPos(0),
	Writable(false)
{
}

//! Ensures that spacified number of bytes can be written to GetWritePtr()
void CStream::EnsureWriteSize(irr::u32 minWriteSize)
{
	if (!Writable)
		return;
	
	irr::u32 lastPos = WritePos + minWriteSize;
	if (lastPos > BufferSize)
	{
		if (BufferSize == 0)
			BufferSize = 16;
		
		while (lastPos > BufferSize)
			BufferSize *= 4;
		
		irr::u8* oldBuffer = Buffer;
		Buffer = new irr::u8[BufferSize];
		if (oldBuffer)
		{
			memcpy(&Buffer[ReadPos], &oldBuffer[ReadPos], WritePos - ReadPos);
			delete oldBuffer;
		}
	}
}

//! Advance read position by specified number of bytes
void CStream::AdvanceReadPos(irr::u32 delta)
{
	ReadPos += delta;
	if (ReadPos > WritePos)
		ReadPos = WritePos;

	if ((ReadPos == WritePos) || ((ReadPos < WritePos) && (ReadPos >= MaxEmptyBufferSize)))
	{
		irr::u32 writtenSize = WritePos - ReadPos;
		if (writtenSize > 0)
			memcpy(&Buffer[0], &Buffer[ReadPos], writtenSize);

		ReadPos = 0;
		WritePos = writtenSize;
	}
}

//! Advance write position by specified number of bytes
void CStream::AdvanceWritePos(irr::u32 delta)
{
	if (!Writable)
		return;

	WritePos += delta;

	/*
	if ((WritePos == ReadPos) || ((WritePos < ReadPos) && (WritePos >= MaxEmptyBufferSize)))
	{
		irr::u32 bufferSize = ReadPos - WritePos;
		if (bufferSize > 0)
			memcpy(&Buffer[0], &Buffer[WritePos], bufferSize);

		WritePos = 0;
		ReadPos = bufferSize;
	}
	*/
}

//! General writing function
irr::u32 CStream::Write(void *buffer, irr::u32 size)
{
	if (!Writable)
		return 0;

	EnsureWriteSize(size);
	
	memcpy(&Buffer[WritePos], buffer, size);
	AdvanceWritePos(size);
	
	return size;
}

//! General reading function
irr::u32 CStream::Read(void *buffer, irr::u32 size)
{
	irr::u32 readSize = GetReadSize();
	if (readSize > size)
		readSize = size;
	
	memcpy(buffer, &Buffer[ReadPos], readSize);
	AdvanceReadPos(readSize);

	return readSize;
}


//! Copies data from another stream to this
irr::u32 CStream::Copy(CStream &source, irr::u32 size)
{
	if (!Writable)
		return 0;

	EnsureWriteSize(size);
	return Read(source.GetReadPtr(), size);
}

Code: Select all

/*
	IrrStreaming.h
*/

#ifndef IrrStreaming_h
#define IrrStreaming_h

#include "Stream.h"

#include "IrrCustomTypes.h"

//! Serialization of Irrlicht basic types
inline ImplementSerialization(irr::u8) { stream.Write(&obj, 1); }
inline ImplementSerialization(irr::s8) { stream.Write(&obj, 1); }
inline ImplementSerialization(irr::u16) { stream.Write(&obj, 2); }
inline ImplementSerialization(irr::s16) { stream.Write(&obj, 2); }
inline ImplementSerialization(irr::u32) { stream.Write(&obj, 4); }
inline ImplementSerialization(irr::s32) { stream.Write(&obj, 4); }
inline ImplementSerialization(irr::f32) { stream.Write(&obj, 4); }
inline ImplementSerializationRef(irr::f64) { stream.Write(&obj, 8); }
inline ImplementSerialization(irr::c8) { stream.Write(&obj, 1); }
inline ImplementSerialization(irr::wchar) { stream.Write(&obj, 2); }
DeclareSerializationRef(irr::core::stringc);
DeclareSerializationRef(irr::core::stringw);

//! Deserialization of Irrlicht basic types
inline ImplementDeserializationRef(irr::u8) { stream.Read(&obj, 1); }
inline ImplementDeserializationRef(irr::s8) { stream.Read(&obj, 1); }
inline ImplementDeserializationRef(irr::u16) { stream.Read(&obj, 2); }
inline ImplementDeserializationRef(irr::s16) { stream.Read(&obj, 2); }
inline ImplementDeserializationRef(irr::u32) { stream.Read(&obj, 4); }
inline ImplementDeserializationRef(irr::s32) { stream.Read(&obj, 4); }
inline ImplementDeserializationRef(irr::f32) { stream.Read(&obj, 4); }
inline ImplementDeserializationRef(irr::f64) { stream.Read(&obj, 8); }
inline ImplementDeserializationRef(irr::c8) { stream.Read(&obj, 1); }
inline ImplementDeserializationRef(irr::wchar) { stream.Read(&obj, 2); }
DeclareDeserializationRef(irr::core::stringc);
DeclareDeserializationRef(irr::core::stringw);

#endif // IrrStreaming_h

Code: Select all

/*
	IrrStreaming.cpp
*/

#include "IrrStreaming.h"

//! Serialization of irr::core::stringc
ImplementSerializationRef(irr::core::stringc)
{
	irr::u32 len = obj.size();
	stream << len;
	for (irr::u32 i = 0; i < len; i++)
		stream << obj[i];
	return stream;
}

//! Deserialization of irr::core::stringc
ImplementDeserializationRef(irr::core::stringc)
{
	irr::u32 len;
	irr::c8 ch;
	stream >> len;
	obj = "";
	obj.reserve(len);
	for (irr::u32 i = 0; i < len; i++)
	{
		stream >> ch;
		obj.append(ch);
	}
	return stream;
}

//! Serialization of irr::core::stringw
ImplementSerializationRef(irr::core::stringw)
{
	irr::u32 len = obj.size();
	stream << len;
	for (irr::u32 i = 0; i < len; i++)
		stream << obj[i];
	return stream;
}

//! Deserialization of irr::core::stringw
ImplementDeserializationRef(irr::core::stringw)
{
	irr::u32 len;
	irr::wchar ch;
	stream >> len;
	obj = "";
	obj.reserve(len);
	for (irr::u32 i = 0; i < len; i++)
	{
		stream >> ch;
		obj.append(ch);
	}
	return stream;
}
Post Reply