790 lines
20 KiB
C++
790 lines
20 KiB
C++
/**
|
|
* @file ObjArchive.h
|
|
* @brief 二进制文件的序列化,支持版本兼容机制
|
|
* @date 2014-5-23
|
|
* @author: liyonggang
|
|
*/
|
|
#ifndef PAI_FRAME_COSGARCHIVE_H__
|
|
#define PAI_FRAME_COSGARCHIVE_H__
|
|
#pragma warning( push ,0)
|
|
#include <stdio.h>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <set>
|
|
#ifdef _WINDOWS
|
|
#include <typeinfo.h>
|
|
#endif
|
|
|
|
#include <QString>
|
|
#include <QDataStream>
|
|
#include <QAction>
|
|
#include <QSet>
|
|
#include <QMap>
|
|
#include <QMessageBox>
|
|
#include <QBuffer>
|
|
#include <QVariant>
|
|
#include <QUuid>
|
|
#include <QVector>
|
|
//#include "Turtle.h"
|
|
#pragma warning( pop )
|
|
|
|
//bool CXXClass::Serialize(CObjectArchive &ar)
|
|
//{
|
|
// if(ar.IsStoring())
|
|
// {
|
|
// /**
|
|
// * begin Archive one object
|
|
// * note :
|
|
// * if you add some member variable, please add new block
|
|
// * if you del some member variable, please use temp variable replace the member variable
|
|
// * more detail ,please reference CObjectArchive in the "GmArchive.h" file
|
|
// */
|
|
// BEGIN_WRITE_OBJECT( ar,1 );
|
|
//
|
|
// BEGIN_WRITE_BLOCK( ar, 1);
|
|
// //write your code
|
|
// END_WRITE_BLOCK( ar, 1 );
|
|
//
|
|
// END_WRITE_OBJECT( ar );
|
|
// }
|
|
// else
|
|
// {
|
|
// BEGIN_READ_OBJECT( ar,1 );
|
|
//
|
|
// BEGIN_READ_BLOCK( 1 );
|
|
// //write your code
|
|
// END_READ_BLOCK( 1 );
|
|
//
|
|
// END_READ_OBJECT( ar );
|
|
// }
|
|
// return true;
|
|
//}
|
|
|
|
|
|
|
|
extern int g_nSerializeErrorMsgBoxMaxCount ; /*error occur when Serialize,the max MessageBox count */
|
|
|
|
//#ifndef NDEBUG
|
|
|
|
// debug and release version ,when read block, ensure block size is right,help debug
|
|
#define BEGIN_RECORD_BLOCKBEGINPOS(ar) \
|
|
int nBlockBeginPos_archive = static_cast<int> ( (ar).GetDevice()->pos() ) ;\
|
|
CObjectArchive &ar_RecordBlockPos = (ar);\
|
|
|
|
// debug version ,when read block, ensure block size is right,help debug
|
|
#define END_RECORD_BLOCKBEGINPOS() if( ( ar_RecordBlockPos.GetDevice()->pos() - nBlockBeginPos_archive ) != BlockDatasize_archive )\
|
|
{\
|
|
/*get error msg */\
|
|
QString strErrorMsg = "read block error :" ;\
|
|
strErrorMsg = strErrorMsg + "\nfile: " + __FILE__ + ":" + QString::number(__LINE__) ;\
|
|
/*strErrorMsg = strErrorMsg + "\ntypename: " + typeid( *pObject ).name() ;*/ \
|
|
if( g_nSerializeErrorMsgBoxMaxCount<1 )\
|
|
{\
|
|
/*QMessageBox::critical(NULL, "load data", strErrorMsg);*/ \
|
|
QMessageBox msgBox;\
|
|
msgBox.setIcon(QMessageBox::Critical);\
|
|
msgBox.setWindowTitle("load data");\
|
|
msgBox.setText(strErrorMsg);\
|
|
msgBox.setWindowFlags(msgBox.windowFlags()|Qt::WindowStaysOnTopHint);\
|
|
msgBox.exec();\
|
|
++g_nSerializeErrorMsgBoxMaxCount;\
|
|
}\
|
|
ar_RecordBlockPos.SeekPos( static_cast<int>( nBlockBeginPos_archive + BlockDatasize_archive ) ,CObjectArchive::SEEKFROM_BEGIN );\
|
|
}\
|
|
|
|
//#else
|
|
//#define BEGIN_RECORD_BLOCKBEGINPOS(ar)
|
|
//#define END_RECORD_BLOCKBEGINPOS()
|
|
//#endif
|
|
|
|
#ifndef NDEBUG // debug version, don't try exception
|
|
#define BEGIN_TRY_SERIALIZE( ar,msg,pObject )
|
|
#define END_TRY_SERIALIZE( ar, bWrite , Msg,pObject )
|
|
#else
|
|
/* begin try exception when serialize */
|
|
#ifdef _WINDOWS
|
|
#define BEGIN_TRY_SERIALIZE( ar,msg,pObject ) \
|
|
{\
|
|
/*record object's first pos */\
|
|
qint64 nObjectBeginPos_archive = ( ar ).GetDevice()->pos() ;\
|
|
try\
|
|
{\
|
|
|
|
#define END_TRY_SERIALIZE( ar, bWrite , Msg,pObject ) \
|
|
}catch(...)\
|
|
{ \
|
|
/*get error msg */\
|
|
QString strErrorMsg = Msg ;\
|
|
strErrorMsg = strErrorMsg + "\nfile: " + __FILE__ + ":" + QString::number(__LINE__) ;\
|
|
strErrorMsg = strErrorMsg + "\ntypename: " + typeid( *pObject ).name() ;\
|
|
/*10 msgbox is max*/ \
|
|
if( g_nSerializeErrorMsgBoxMaxCount<1 )\
|
|
{ \
|
|
QMessageBox::critical(NULL, Msg, strErrorMsg);\
|
|
++g_nSerializeErrorMsgBoxMaxCount;\
|
|
}\
|
|
/*record log */\
|
|
/*DEBUG_LOG( strErrorMsg );*/\
|
|
/*rollback operate */\
|
|
bool bWriteValue = bWrite;\
|
|
if( bWriteValue )\
|
|
{\
|
|
(ar).RollbackWriteObject( ( int )nObjectBeginPos_archive );\
|
|
}else\
|
|
{\
|
|
(ar).RollbackReadObject( ( int )nObjectBeginPos_archive );\
|
|
}\
|
|
}\
|
|
}
|
|
#else
|
|
#define BEGIN_TRY_SERIALIZE( ar,Msg,pObject )
|
|
#define END_TRY_SERIALIZE( ar, bWrite , Msg,pObject )
|
|
#endif
|
|
#endif
|
|
|
|
|
|
/** "Serializatioin macro" **/
|
|
//* begin to Read Object
|
|
//* @param ar ; CObjectArchive object
|
|
//* @param ver : the least version we expect Read
|
|
//* @author : yonggang
|
|
#define BEGIN_READ_OBJECT_EX(ar,ver,pObj )\
|
|
BEGIN_TRY_SERIALIZE( ar,"load",pObj );\
|
|
{\
|
|
qint64 nObjectBeginPos_archiveSeek = ( ar ).GetDevice()->pos() ;\
|
|
/* Read Block Number in One Object */\
|
|
unsigned short nBlockNumber_archive = 0;\
|
|
unsigned short verRead_archive = 0;\
|
|
(ar).ReadObject( nBlockNumber_archive ,verRead_archive );\
|
|
/*if Less than ver then skip this Object */\
|
|
if( verRead_archive < ver )\
|
|
{ \
|
|
(ar).SeekPos( ( int )nObjectBeginPos_archiveSeek ,CObjectArchive::SEEKFROM_BEGIN );\
|
|
(ar).SkipObject();\
|
|
return nBlockNumber_archive >0 ;\
|
|
}\
|
|
/* loop all block */ \
|
|
for( int iBlock_archive = 0;iBlock_archive < nBlockNumber_archive ; ++iBlock_archive )\
|
|
{ \
|
|
/* Read Block ID and Block Data's Size */ \
|
|
unsigned short BlockID_archive = 0 ;\
|
|
unsigned int BlockDatasize_archive = 0 ;\
|
|
(ar).ReadBlock( BlockID_archive,BlockDatasize_archive ) ;\
|
|
BEGIN_RECORD_BLOCKBEGINPOS(ar);\
|
|
/* Read One Block */ \
|
|
switch( BlockID_archive )\
|
|
{
|
|
|
|
|
|
|
|
//* Read the end of object
|
|
//* @param ar ; CObjectArchive object
|
|
//* @author : yonggang
|
|
#define END_READ_OBJECT_EX(ar,pObj )\
|
|
default :\
|
|
{\
|
|
/* if not recognise the Block , Then Skip */\
|
|
/* this will frequently happen when Lower Version software open the higher File */\
|
|
(ar).SeekPos( BlockDatasize_archive,CObjectArchive::SEEKFROM_CUR );\
|
|
}\
|
|
break;\
|
|
}\
|
|
}\
|
|
}\
|
|
END_TRY_SERIALIZE( ar, false,"LOAD_DATA",pObj );
|
|
|
|
|
|
#define BEGIN_READ_OBJECT(ar,ver ) BEGIN_READ_OBJECT_EX( ar,ver,this )
|
|
#define END_READ_OBJECT( ar ) END_READ_OBJECT_EX(ar,this )
|
|
|
|
|
|
//* begin to Read One Block
|
|
//* @param BlockId ; Block ID
|
|
//* @author : yonggang
|
|
#define BEGIN_READ_BLOCK( BlockId )\
|
|
case BlockId:\
|
|
{ \
|
|
|
|
|
|
//* End Read One Block
|
|
//* @param id ; Block ID
|
|
//* @author : yonggang
|
|
#define END_READ_BLOCK( BlockId )\
|
|
END_RECORD_BLOCKBEGINPOS();\
|
|
}\
|
|
break;\
|
|
|
|
|
|
//* Begin to Write One Object
|
|
//* @param ar ; CObjectArchive Object
|
|
/** @param ver ; the Object's version,
|
|
usually, we should not change the version,we should add new Block for add new member variable,
|
|
i think the version shouled a big version for business,perhaps it is Unchange at least one year
|
|
*/
|
|
//* @param pObj: the object of write
|
|
//* @author : yonggang
|
|
#define BEGIN_WRITE_OBJECT_EX( ar,ver,pObj)\
|
|
BEGIN_TRY_SERIALIZE( ar,"write",pObj )\
|
|
{\
|
|
void *pObjWriteObjectVoidPointer = ( void * )(ar).CreateNewObjectID();\
|
|
(ar).BeginWriteObject( pObjWriteObjectVoidPointer ,ver );\
|
|
{\
|
|
|
|
|
|
|
|
//* end Write Object,this will correct the Object's Block Number
|
|
//* @param ar : CObjectArchive Object
|
|
//* @author : yonggang
|
|
#define END_WRITE_OBJECT_EX( ar,pObj )\
|
|
}\
|
|
(ar).EndWriteObject( pObjWriteObjectVoidPointer );\
|
|
}\
|
|
END_TRY_SERIALIZE(ar, true ,"SAVE_DATA",pObj )\
|
|
|
|
#define BEGIN_WRITE_OBJECT( ar,ver) BEGIN_WRITE_OBJECT_EX( ar,ver,this )
|
|
#define END_WRITE_OBJECT(ar) END_WRITE_OBJECT_EX( ar,this )
|
|
|
|
|
|
//* end Write Object,this will correct the Object's Block Number
|
|
//* @param ar : CObjectArchive Object
|
|
//* @param BlockID : block id
|
|
//* @author : yonggang
|
|
#define BEGIN_WRITE_BLOCK( ar, BlockID ) \
|
|
(ar).BeginWriteBlock( BlockID , pObjWriteObjectVoidPointer );\
|
|
{
|
|
|
|
|
|
//* end Write Object,this will correct the Object's Block Data size
|
|
//* @param ar : CObjectArchive Object
|
|
//* @parma BlockID : block id
|
|
//* @author : yonggang
|
|
#define END_WRITE_BLOCK( ar,BlockID ) \
|
|
}\
|
|
(ar).EndWriteBlock( BlockID , pObjWriteObjectVoidPointer ) ;
|
|
|
|
/** "Serializatioin macro" end **/
|
|
|
|
class QFile;
|
|
enum EGmArchiveMode
|
|
{
|
|
eStore = 1,
|
|
eLoad = 2,
|
|
ebNoFlushOnDelete = 4,
|
|
ebNoByteSwap = 8 ,
|
|
};
|
|
|
|
#define CONSTRUCT_GMARCHIVE( strPath,eState )\
|
|
CObjectArchive ar( strPath, eState );\
|
|
if( !ar.IsOpened() ) return false;\
|
|
|
|
#define CONSTRUCT_GMARCHIVE_VOID( strPath,eState )\
|
|
CObjectArchive ar( strPath, eState );\
|
|
if( !ar.IsOpened() ) return ;\
|
|
|
|
/*define a emtyp value */
|
|
#define NULLVALUE
|
|
|
|
/* if you want "return" when Store Data at special block,if must use this macro*/
|
|
#define RETURN_WRITE( ar, BlockID,retValue ) \
|
|
(ar).EndWriteBlock( BlockID , pObjWriteObjectVoidPointer ) ;\
|
|
(ar).EndWriteObject( pObjWriteObjectVoidPointer );\
|
|
return retValue;\
|
|
|
|
|
|
class CObjectArchive: public QDataStream
|
|
{
|
|
|
|
private:
|
|
/**
|
|
* Cache of information when Serialization
|
|
*/
|
|
struct CObjectArchivePos
|
|
{
|
|
public:
|
|
qint64 m_uCurrentBlockSizePos ; //the Byte Pos of The Current Block size
|
|
qint64 m_uCurrentBlockDataPos ; //the Byte Pos of The Current Block Data
|
|
qint64 m_uBlockNumPos ; //the Byte Pos of One Object's Block Number
|
|
unsigned short m_nBlockNumInObject; // Block Number of One Object
|
|
#ifndef NDEBUG
|
|
QSet< unsigned short > m_setBlockId ; //When Debug, Record one Object's all Block ID
|
|
#endif
|
|
};
|
|
|
|
|
|
/**
|
|
* Get Current Positon of the File
|
|
* @param pos [out]: currnet position of the file
|
|
*/
|
|
inline void GetCurPos( qint64 &pos );
|
|
|
|
/**
|
|
* write Data at specially file's postion
|
|
* @param pos : the position of write Data
|
|
* @param pDwordSize : data .if this is not NULL , then write this data.other wize write pShortSize
|
|
* @param pShortSize : data .if pDwordSize is NULL, then write this data
|
|
*/
|
|
inline void WriteSize ( const qint64 &pos , const unsigned int *pDwordSize,unsigned short *pShortSize );
|
|
|
|
/**
|
|
* when Debug ,Assert the Block id
|
|
* @param id : block Id
|
|
* @param bHave : Assert the Block id whether have
|
|
*/
|
|
inline void Q_ASSERTBlockID( unsigned short id,bool bHave );
|
|
|
|
/**
|
|
* all object's information that is writting
|
|
*/
|
|
std::map< const void * ,CObjectArchivePos > m_mapObjectPos;
|
|
|
|
/**
|
|
* the current Object's Information that is writting
|
|
*/
|
|
CObjectArchivePos * m_pCurObjectPos ;
|
|
qint64 m_nObjectID;
|
|
|
|
#ifndef NDEBUG
|
|
int m_nBlockNumber; // when debug,Record the Block Number
|
|
int m_nPackNumber ; // when Debug, Record the Object Number
|
|
#endif
|
|
|
|
/**
|
|
* Init All Archive's Information ,is used the construct CObjectArchive Object
|
|
*/
|
|
void InitArchivePosData();
|
|
|
|
/**
|
|
* Set The Current Object that is Writting
|
|
* @param pObject : the Object
|
|
*/
|
|
void SetActiveObject( const void *pObject ) ;
|
|
|
|
/**
|
|
* separate block function
|
|
*/
|
|
public:
|
|
/**
|
|
* Begin Postion when Seek
|
|
*/
|
|
enum SEEKFROM
|
|
{
|
|
SEEKFROM_CUR, //the current postion
|
|
SEEKFROM_BEGIN, //the beginning of the file
|
|
};
|
|
|
|
/**
|
|
* Skip One Object when Read
|
|
*/
|
|
void SkipObject();
|
|
|
|
/**
|
|
* Read Block Number and Data size
|
|
* @param blockId [out] : Block Id
|
|
* @param datasize [out] : Block Data size
|
|
*/
|
|
void ReadBlock ( unsigned short &blockcid ,unsigned int &datasize );
|
|
|
|
/**
|
|
* Read One Object's Block Number and Version
|
|
* @param nBlockNumber :[out] Block Number
|
|
* @param ver :[out] version
|
|
*/
|
|
void ReadObject( unsigned short& nBlockNumber,unsigned short &ver ) ;
|
|
|
|
/**
|
|
* Begin write one Block
|
|
* @param id : block id
|
|
* @parma pObject : the object of the block
|
|
*/
|
|
void BeginWriteBlock( unsigned short id,const void *pObj ) ;
|
|
|
|
/**
|
|
* end write the block,this will correct the block's data size
|
|
* @param id : block id
|
|
* @parma pObject : the object of this block
|
|
*/
|
|
void EndWriteBlock( unsigned short id , const void *pObj ) ;
|
|
|
|
/**
|
|
* begin write one Object
|
|
* @param pObj : the object
|
|
* @param ver : versioin
|
|
*/
|
|
void BeginWriteObject( const void *pObj,unsigned short ver );
|
|
|
|
/**
|
|
* end write one object ,this will correct the block number of the object
|
|
* @parma pObj: the object
|
|
*/
|
|
void EndWriteObject( const void *pObj ) ;
|
|
|
|
/**
|
|
* seek to specially positon
|
|
* @param pos : the postion relative "from"
|
|
* @parma from : the beginning of seek pos
|
|
*/
|
|
void SeekPos( int Pos ,SEEKFROM from ) ;
|
|
|
|
|
|
/**
|
|
* when Debug ,we can use this function to examine if we match "beginObject " and "endObject",Block ID etc.
|
|
*/
|
|
bool IsWriteDataOK( ) ;
|
|
|
|
/**
|
|
* Write a empty Object ,only write version and block Numer( blockNumer is 0 )
|
|
* it is used when we delete a object ,then we can Write and Read Empty object ,
|
|
* thus ,the lower version software can successly open the Higer file
|
|
*/
|
|
bool WriteEmptyObject( ) ;
|
|
|
|
/**
|
|
* Read a empty Object , Only Read version and Block Number ( after read ,Block Number shoudle be 0 )
|
|
* it is used when we delete a object ,then we can Write and Read Empty object ,
|
|
* thus ,the lower version software can successly open the Higer file
|
|
*/
|
|
bool ReadEmptyObject( ) ;
|
|
|
|
/**
|
|
* Create a new Object ID
|
|
*/
|
|
qint64 CreateNewObjectID( ) ;
|
|
|
|
/**
|
|
* rollback to write a emtpy object
|
|
* when error occur during save object
|
|
*/
|
|
void RollbackWriteObject( int nObjctBeginPos);
|
|
|
|
/**
|
|
* rollback to skip this object
|
|
* when error occur during load object
|
|
*/
|
|
void RollbackReadObject(int nObjectBeginPos );
|
|
|
|
public:
|
|
|
|
/**
|
|
* memery archive construct
|
|
* @param byteArray : byte array
|
|
* @param eMode : store or load mode
|
|
*/
|
|
CObjectArchive( QByteArray& byteArray,EGmArchiveMode eMode );
|
|
/**
|
|
* construct a CObjectArchive object
|
|
* @param sFile : file full path
|
|
* @param eMode : store or load mode
|
|
* @param nWriteOffSet : if eMode = store,then set the write offset
|
|
* <0, append to the end of file.
|
|
* =0 ,then truncate.
|
|
* >0 ,then set the write offset.if file size is not enougth large,then extend it
|
|
*/
|
|
CObjectArchive(QString sFile, EGmArchiveMode eMode ,qint64 nWriteOffSet = 0);
|
|
|
|
/**
|
|
* attach a QFile object to CObjectArchive object ,
|
|
* @param pFile : QFile Object,when destructor,pFile Don't Close.
|
|
* @param eMode : store or load mode
|
|
*/
|
|
void Attatch(QIODevice *pDevice,EGmArchiveMode eMode );
|
|
|
|
bool IsOpened();
|
|
~CObjectArchive();
|
|
// QString m_strLastClassName; yonggang comment,don't need now
|
|
bool IsLoading() ;
|
|
bool IsStoring() ;
|
|
|
|
/**
|
|
* get byteArray.if this is not a memory archive, return NULL
|
|
*/
|
|
QByteArray* GetByteArray();
|
|
|
|
QIODevice* GetDevice();
|
|
void Read(void* lpBuf, unsigned int nMax);
|
|
void Write(const void* lpBuf, unsigned int nMax);
|
|
void Close();
|
|
void WriteString(char * lpsz);
|
|
char * ReadString(char * lpsz, unsigned int nMax);
|
|
int ReadString(QString& rString);
|
|
unsigned long ReadCount();
|
|
void WriteCount(unsigned long dwCount);
|
|
/**
|
|
* @brief save filename in current archive and create a new archive(derive) on the filename
|
|
* @param strFilePathName the file name which is connected with new archive
|
|
* @return the new archive handle
|
|
* @author haidong
|
|
* @see PopArchive
|
|
*/
|
|
CObjectArchive& PushArchive(QString& strFilePathName);
|
|
/**
|
|
* @brief close specified archive and return to current archive
|
|
* @param archive2 the derived archive handle,will be closed.
|
|
* @return
|
|
* @author haidong
|
|
* @see PushArchive
|
|
*/
|
|
void PopArchive(CObjectArchive& archive2);
|
|
CObjectArchive& operator<<(char ch);
|
|
CObjectArchive& operator<<(unsigned char by);
|
|
CObjectArchive& operator<<(bool b );
|
|
CObjectArchive& operator<<(short w);
|
|
CObjectArchive& operator<<(unsigned short w);
|
|
CObjectArchive& operator<<(int i);
|
|
CObjectArchive& operator<<(unsigned int u);
|
|
CObjectArchive& operator<<(long l);
|
|
CObjectArchive& operator<<(unsigned long dw);
|
|
CObjectArchive& operator<<(float f);
|
|
CObjectArchive& operator<<(double d);
|
|
CObjectArchive& operator<<(qint64 n);
|
|
CObjectArchive& operator<<(const QString & s );
|
|
CObjectArchive& operator<<(QAction *pAction);
|
|
CObjectArchive& operator<<( QUuid id );
|
|
|
|
// extraction operations
|
|
CObjectArchive& operator>>(char& ch);
|
|
CObjectArchive& operator>>(unsigned char& by);
|
|
CObjectArchive& operator>>(bool & b );
|
|
CObjectArchive& operator>>(short& w);
|
|
CObjectArchive& operator>>(unsigned short& w);
|
|
CObjectArchive& operator>>(int& i);
|
|
CObjectArchive& operator>>(unsigned int & u);
|
|
CObjectArchive& operator>>(long& l);
|
|
CObjectArchive& operator>>(unsigned long & dw);
|
|
CObjectArchive& operator>>(float& f);
|
|
CObjectArchive& operator>>(double& d);
|
|
CObjectArchive& operator>>(qint64 &n);
|
|
CObjectArchive& operator>>( QString & s );
|
|
CObjectArchive& operator>>( QAction *pAction );
|
|
CObjectArchive& operator>>( QUuid& id );
|
|
public:
|
|
QString filename;
|
|
protected:
|
|
QIODevice* m_pDevice;
|
|
EGmArchiveMode m_eMode;
|
|
bool m_bOpened;
|
|
bool m_bQFileOpenedByMe;
|
|
int m_currLength;
|
|
};
|
|
|
|
/**
|
|
* @brief : clone object general,use T1,and T1's Write function,T2 and T2's Load function
|
|
* @param src : the source object( pls use pointer )
|
|
* @param pWrite : static function pointer or function object ,the signature should be like function1( T1 t, CObjectArchive & )
|
|
* @param dest :the dest object,that will same with source object( pls use pointer )
|
|
* @param pLoad : static function pointer or function object ,the signature should be like function2( T2 t, CObjectArchive & )
|
|
*/
|
|
template< class T1, class _Pr1Write,class T2,class _Pr2Load >
|
|
void CloneObjectGeneral( T1 src ,_Pr1Write pWrite, T2 dest,_Pr2Load pLoad )
|
|
{
|
|
QByteArray byteArray;
|
|
|
|
/* write object data to byteArray use src "write" function */
|
|
{
|
|
CObjectArchive ar( byteArray,eStore);
|
|
pWrite( src, ar );
|
|
}
|
|
|
|
/* read object data from byteArray use dest "Load" function */
|
|
{
|
|
CObjectArchive ar( byteArray,eLoad );
|
|
pLoad( dest,ar );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* save object srcWrite to a BLOB variant by function pWrite
|
|
*/
|
|
template< class T ,class _Pr1Write>
|
|
QVariant SaveObjectToVtBLOB( T *srcWrite,_Pr1Write pWrite )
|
|
{
|
|
/* write object data to byteArray use src "write" function */
|
|
QByteArray byteArray;
|
|
{
|
|
CObjectArchive ar( byteArray,eStore);
|
|
pWrite( srcWrite, ar );
|
|
}
|
|
|
|
// set to vtBLOB
|
|
QVariant vtBLOB(byteArray);
|
|
|
|
// return the vtBLOB
|
|
return vtBLOB;
|
|
};
|
|
|
|
/**
|
|
* save object srcWrite to a BLOB variant
|
|
*/
|
|
template< class T >
|
|
QVariant SaveObjectToVtBLOB2(T *srcWrite)
|
|
{
|
|
/* write object data to byteArray use src "Serialize" function */
|
|
QByteArray byteArray;
|
|
{
|
|
CObjectArchive ar( byteArray,eStore);
|
|
srcWrite->Serialize(ar );
|
|
}
|
|
|
|
// set to vtBLOB
|
|
QVariant vtBLOB(byteArray);
|
|
|
|
// return the vtBLOB
|
|
return vtBLOB;
|
|
};
|
|
/**
|
|
* load object ObjectLoad from a BLOB variant by function pLoad
|
|
*/
|
|
template< class T ,class _Pr2Load>
|
|
void LoadObjectFromVtBLOB(T *ObjectLoad ,QVariant &vtBLOB, _Pr2Load pLoad )
|
|
{
|
|
// get byteArray from vtBLOB
|
|
QByteArray byteArray = vtBLOB.toByteArray();
|
|
|
|
/* read object data from byteArray use src "_Pr2Load" function */
|
|
if( byteArray.size() >0 )
|
|
{
|
|
CObjectArchive ar( byteArray,eLoad );
|
|
pLoad( ObjectLoad, ar );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* load object ObjectLoad from a BLOB variant
|
|
*/
|
|
template< class T >
|
|
void LoadObjectFromVtBLOB2( T *ObjectLoad ,QVariant &vtBLOB )
|
|
{
|
|
// get byteArray from vtBLOB
|
|
QByteArray byteArray = vtBLOB.toByteArray();
|
|
|
|
/* read object data from byteArray use src "Serialize" function */
|
|
if( byteArray.size() >0 )
|
|
{
|
|
CObjectArchive ar( byteArray,eLoad );
|
|
ObjectLoad->Serialize( ar );
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* use Serialize function to clone object from one to other
|
|
* object must have "Serialize(CObjectArchive &ar)"function
|
|
* @param src : source object
|
|
* @param dest : destination object.destination object will fully equal source object
|
|
( deep copy,all of children and pointer content will be copied )
|
|
*/
|
|
template< typename T>
|
|
void CloneObject( const T &src , T &dest )
|
|
{
|
|
QByteArray byteArray;
|
|
|
|
/* write object data to byteArray use src "Serialize" function */
|
|
{
|
|
CObjectArchive ar(byteArray,eStore);
|
|
T &tmp = const_cast< T & >( src );
|
|
tmp.Serialize( ar );
|
|
}
|
|
|
|
/* read object data from byteArray use dest "Serialize" function */
|
|
{
|
|
CObjectArchive ar( byteArray,eLoad);
|
|
dest.Serialize( ar );
|
|
}
|
|
}
|
|
|
|
template<class T>
|
|
CObjectArchive & operator <<( CObjectArchive &ar,std::vector<T>& v )
|
|
{
|
|
int nSize = (int )v.size();
|
|
ar << nSize;
|
|
for( long i = 0 ; i < nSize ; ++i )
|
|
{
|
|
ar << v[i];
|
|
}
|
|
|
|
return ar;
|
|
};
|
|
|
|
template<class T>
|
|
CObjectArchive & operator >>( CObjectArchive &ar,std::vector<T>& v )
|
|
{
|
|
v.clear();
|
|
|
|
int nSize(0);
|
|
ar >> nSize;
|
|
for( long i = 0 ; i < nSize ; ++i )
|
|
{
|
|
T a;
|
|
ar >> a;
|
|
v.push_back( a );
|
|
}
|
|
return ar;
|
|
};
|
|
|
|
|
|
template<class T>
|
|
CObjectArchive & operator <<( CObjectArchive &ar,std::set<T>& v )
|
|
{
|
|
int nSize = (int )v.size();
|
|
ar << nSize;
|
|
|
|
typename std::set<T>::iterator it = v.begin();
|
|
for( ; it!=v.end() ; ++it )
|
|
{
|
|
ar << *it;
|
|
}
|
|
|
|
return ar;
|
|
};
|
|
|
|
template<class T>
|
|
CObjectArchive & operator >>( CObjectArchive &ar,std::set<T>& v )
|
|
{
|
|
v.clear();
|
|
|
|
int nSize(0);
|
|
ar >> nSize;
|
|
for( long i = 0 ; i < nSize ; ++i )
|
|
{
|
|
T a;
|
|
ar >> a;
|
|
v.insert( a );
|
|
}
|
|
return ar;
|
|
};
|
|
|
|
/**
|
|
* @brief 序列化一个QVector到二进制流
|
|
*/
|
|
template <typename T>
|
|
CObjectArchive& operator<< (CObjectArchive& ar,const QVector<T>& vec)
|
|
{
|
|
ar << (int)vec.size();
|
|
typename QVector<T>::const_iterator it = vec.constBegin();
|
|
for(;it != vec.constEnd(); ++it)
|
|
{
|
|
ar << *it;
|
|
}
|
|
return ar;
|
|
}
|
|
/**
|
|
* @brief 从二进制流反序列化到一个QVector
|
|
*/
|
|
template <typename T>
|
|
CObjectArchive& operator >> (CObjectArchive& ar, QVector<T>& vec)
|
|
{
|
|
assert(vec.size()==0);
|
|
|
|
int vecSize = 0;
|
|
ar >> vecSize;
|
|
|
|
T value;
|
|
for(int i = 0; i<vecSize; ++i)
|
|
{
|
|
ar >> value;
|
|
vec.push_back(value);
|
|
}
|
|
return ar;
|
|
}
|
|
|
|
#endif
|