Chinaunix首页 | 论坛 | 博客
  • 博客访问: 187726
  • 博文数量: 89
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 828
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-08 10:44
文章分类
文章存档

2014年(9)

2013年(80)

我的朋友

分类: C/C++

2013-11-12 14:07:58

现在开始做序列化的读,也即是反序列化,本来为没个序列化的类设计了2个序列化接口函数:


//序列化接口
 virtual void GetObjectData(CJSerializationInfo* info) {}
 virtual void DeSerializationObjectData(CJSerializationInfo* info) {}


可突然发现,其实DeSerializationObjectData是没必要存在的,在.net中,每个对象都是引用,所以它可以为每个对象创建新的实例,然后再赋值,可C++中不可以啊,因为我有些对象包括上层类的实例中,它已经不需要再去实例化了。,所以在反序列化的时候,很多对象不能直接new,而必须从宿主对象中获取。只有哪些动态生成的对象才可以new。


中心思想有了,开始实现吧。


首先定义对象读取类


class CObjectRead
{
public:
 class ObjectMemberValue
 {
 public:
  juint32  TypeID;
  juint32  Valuetypeid;
  CJObject* pValue;
 };
 CObjectRead(CSerialization* pSer,jint32 id,CJStream* pStream);
 void Read(jbyte headercode);
 CJSerializationInfo* ReadObjectSerializationInfos();
 void ReadPrimitive(CJSerializationInfo* pSerInfo,CJSerializationInfo* currentObjSInfo,int index,jbyte typecode);
public:
 CSerialization* m_pSerialization;
 CJObject*  m_pObj;
 CJObject*  m_pParentObj;
 CJStream*  m_pStream;
 jint32   m_ObjID;
 CJList   m_ObjectMemberValues;


};
它的基本作用就是读取一个对象,并把它放到对象实例映射 表中去(在CSerialization对象中),具体过程:


反序列化入口函数:CSerialization的DeSerialize


CJObject* CSerialization::DeSerialize(CJStream* pStream)
{
 jint32 head;
 CJObject* pTopObj = JNULL;
 if(!pStream->ReadInt32(&head))return JNULL;
 if(head != 0xFF78FF78)return JNULL;
 char c;
 pStream->ReadChar(&c);if(c != 'J')return JNULL;
 pStream->ReadChar(&c);if(c != 'H')return JNULL;
 pStream->ReadChar(&c);if(c != 'M')return JNULL;
 pStream->ReadChar(&c);if(c != 'F')return JNULL;
 //确认是我们的序列化数据
 jbool readend = FALSE;
 jbyte headtype;
 while(pStream->ReadByte(&headtype))
 {
  switch(headtype)
  {
  case SER_HRADERTYPE_OBJINFO:
   {
    CObjectRead obread(this,-1,pStream);
    AddObjectSerializationInfos(obread.ReadObjectSerializationInfos());
   }
   break;
  case SER_HRADERTYPE_BASEDATA:
  case SER_HRADERTYPE_ARRAY:
  case SER_HRADERTYPE_OBJHEADER:
   {
    CObjectRead obread(this,-1,pStream);
    obread.Read(headtype);
   }
   break;
  case SER_HRADERTYPE_END:
   readend = TRUE;
   goto DeSerializeEnd;
   break;
  default:
   if(headtype >= SER_HRADERTYPE_OBJMEMBER && headtype <= SER_HRADERTYPE_String)
   {
   }
   else
   {
    JThrowSerialException("序列化数据被破坏");
   }
   break;
  }
 }
DeSerializeEnd:
 if(readend)
 {
  CHasReadedObject* pTopReadObj = GetHasReadedObject(topID);
  JASSERT(pTopReadObj != JNULL);
  pTopObj = pTopReadObj->m_pObject;
  //修复所有对象
  CJListT* keys = this->m_FixingObjects.GetKeys();
  for(int i = 0;i < keys->GetCount();i++)
  {
   CHasReadedObject* pReadObj = (CHasReadedObject*)m_FixingObjects.GetHashObject(0,(*keys)[i]);
   JASSERT(pReadObj != JNULL && pReadObj->m_pObject != JNULL);
   if(pReadObj->m_pObject->GetType().IsArray())
   {
    //指针数组需要特殊处理
    CJObjectArray* pArray = (CJObjectArray*)pReadObj->m_pObject;
    for(int j = 0;j < pArray->GetLength();j++)
    {
     CJObject* pitem = pArray->GetItem(j);
     if(pitem->GetType() == JTYPEOF(CFixObject))
     {
      CFixObject* pfix = (CFixObject*)pitem;
      CHasReadedObject* preaded = GetHasReadedObject(pfix->m_ObjectID);
      JASSERT(preaded != JNULL);
      pArray->SetItem(preaded->m_pObject,j);
      delete pitem;
     }
    }
   }
   else
   {
    //首先获取序列化信息
    CJSerializationInfo* currentObjSInfo = GetCurrentObjectSerializationInfos(pReadObj->m_typeID,pReadObj->m_pObject);
    JASSERT(currentObjSInfo != JNULL);
    for(int i = 0;i < currentObjSInfo->GetStatisticsCount();i++)
    {
     if(((SerializationInfoField*)currentObjSInfo->m_fields[i])->fieldTypeID == FIELDTYPE_OBJPTR)
     {
      CJObject** pfObj = (CJObject**)currentObjSInfo->GetFieldObject(pReadObj->m_pObject,i);
      if(pfObj == JNULL)continue;
      if(*pfObj == JNULL)continue;
      if((*pfObj)->GetType() == JTYPEOF(CFixObject))
      {
       //修复引用
       CFixObject* pfix = (CFixObject*)*pfObj;
       CHasReadedObject* preaded = GetHasReadedObject(pfix->m_ObjectID);
       JASSERT(preaded == JNULL);
       *pfObj = preaded->m_pObject;
       delete pfix;
      }
     }
    }
   }
  }
 }
 //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&资源清除&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
 //删除当前库类型序列化信息
 //删除文件库类型序列化信息
 //删除读取对象实例映射表
 return pTopObj;


 
}


这个函数目的很简单,首先做格式判断,然后开始一个一个的读取对象(和对象序列化格式信息),真正读取对象:


void CObjectRead::Read(jbyte headercode)
{
 jint64 ll = m_pStream->GetPosition();
 jint32 typeID,id,parentid,findex;
 if(!m_pStream->ReadInt32(&typeID))JThrowSerialException("序列化数据被破坏");
 if(!m_pStream->ReadInt32(&id))JThrowSerialException("序列化数据被破坏");
 if(!m_pStream->ReadInt32(&parentid))JThrowSerialException("序列化数据被破坏");
 if(!m_pStream->ReadInt32(&findex))JThrowSerialException("序列化数据被破坏");
 //根据类型ID此时可以确认对象类型了,而且对象类型信息应该已经存在于映射表中了
 CJSerializationInfo* pObSerInfos = m_pSerialization->GetObjectSerializationInfos(typeID);
 if(pObSerInfos == JNULL)JThrowSerialException("序列化内核异常:对象类型信息丢失,数据被破坏");
 //此时比较复杂,处理需反复斟酌
 if(parentid > 0)
 {
  //有父对象,此时,父对象已经产生,从父对象中获取实例
  CHasReadedObject* pParentObj = m_pSerialization->GetHasReadedObject(parentid);
  if(pParentObj == JNULL || pParentObj->m_pObject == JNULL)JThrowSerialException("序列化内核错误:无法找到父对象");
  CJSerializationInfo* parentSinfo = m_pSerialization->GetObjectSerializationInfos(pParentObj->m_typeID);
  if(parentSinfo == JNULL)JThrowSerialException("序列化内核错误:无法找到父对象序列化信息(此时程序应该已经保证父对象类型序列化信息已经被读取)");
  CJSerializationInfo* currentParentSInfo = m_pSerialization->GetCurrentObjectSerializationInfos(pParentObj->m_typeID,pParentObj->m_pObject);
  m_pObj = currentParentSInfo->GetFieldObject(pParentObj->m_pObject,parentSinfo->GetFieldInfo(findex)->name);
  if(m_pObj == JNULL)
  {
   //有父对象,但确找不到自己的实例,唯一的可能是版本不一致,用户程序去除了该字段的序列化
  }
 }
 else
 {
  //创建该对象
  
  CJObject* pnewObj = CJActivator::CreateInstance(pObSerInfos->m_Name);
  //需要做外部实例化处理,现在不做,待续
  if(pnewObj == JNULL)JThrowSerialException(CJString::FormatString("序列化异常:无法创建%s对象",pObSerInfos->m_Name));
  m_pObj = pnewObj;
 }
 
 CHasReadedObject* pObjRead = m_pSerialization->AddReadedInstances(m_pObj,typeID,id,parentid);
 if(headercode == SER_HRADERTYPE_OBJHEADER)
 {
  //增加到对象映射表
  CJSerializationInfo* currentObjSInfo = m_pSerialization->GetCurrentObjectSerializationInfos(typeID,m_pObj);
  
  jbool objectconplete = TRUE;
  //开始读取成员
  if(pObSerInfos->GetStatisticsCount() > 0)
  {
   //强制性初始化,将对象中的参与反序列化的引用(指针)初始化为空
   if(m_pObj != JNULL)
   {
    for(int i = 0;i < currentObjSInfo->GetStatisticsCount();i++)
    {
     if(((SerializationInfoField*)currentObjSInfo->m_fields[i])->fieldTypeID == FIELDTYPE_OBJPTR)
     {
      CJObject** pfObj = (CJObject**)currentObjSInfo->GetFieldObject(m_pObj,i);
      if(pfObj == JNULL)continue;
      *pfObj = JNULL;
     }
    }
   }
   jbyte membetype;
   for(int i = 0;i < pObSerInfos->GetStatisticsCount();i++)
   {
    jint64 ll1 = m_pStream->GetPosition();
    if(!m_pStream->ReadByte(&membetype))JThrowSerialException("序列化内核异常:对象成员读取失败,数据被破坏");
    while(membetype == SER_HRADERTYPE_OBJINFO)
    {
     m_pSerialization->AddObjectSerializationInfos(ReadObjectSerializationInfos());
     if(!m_pStream->ReadByte(&membetype))JThrowSerialException("序列化内核异常:对象成员读取失败,数据被破坏");
    }
    switch(membetype)
    {
    case SER_HRADERTYPE_OBJMEMBER:
     {
      //对象,该对象存储在其他地方,此时,该对象已经被实例化了
     }
     break;
    case SER_HRADERTYPE_OBJMEMBERPTR:
     {
      jint32 memberid,memberindex;
      m_pStream->ReadInt32(&memberid);
      m_pStream->ReadInt32(&memberindex);     
      if(m_pObj != JNULL)
      {
       CJObject* pMemberObj = JNULL;
       pMemberObj = currentObjSInfo->GetFieldObject(m_pObj,pObSerInfos->GetFieldInfo(memberindex)->name);
       if(pMemberObj != JNULL)
       {
        CJObject** ppMemberObj = (CJObject**)pMemberObj;
        CHasReadedObject* pReadedMembetObj= m_pSerialization->GetHasReadedObject(memberid);
        if(pReadedMembetObj != JNULL)
        {
         //如果对象已经存在
         *ppMemberObj = pReadedMembetObj->m_pObject;
        }
        else
        {
         CFixObject* fixObj = new CFixObject();
         fixObj->m_ObjectID = memberid;
         *ppMemberObj = fixObj;
         //增加到待修复队列
         if(objectconplete)
         {
          m_pSerialization->AddToFix(pObjRead);
         }
         objectconplete = FALSE;
        }
       }//确定该字段存在
      }//确定该对象实例存在
     }
     break;
    default:
     if(membetype >= SER_HRADERTYPE_Boolean && membetype <= SER_HRADERTYPE_String)
     {
      ReadPrimitive(pObSerInfos,currentObjSInfo,i,membetype);
     }
     else
     {
      JThrowSerialException("序列化异常:不识别的头类型");
     }
     break;
    }


   }
  }
 }
 else if(headercode == SER_HRADERTYPE_ARRAY)
 {
  CJObjectArray* pArray = (CJObjectArray*)m_pObj;
  jint32 length;
  if(!m_pStream->ReadInt32(&length))JThrowSerialException("序列化数据被破坏");
  if(length > 0)
  {
   for(int i = 0;i < length;i++)
   {
    jint32 id;
    if(!m_pStream->ReadInt32(&id))JThrowSerialException("序列化数据被破坏");
    if(pArray == JNULL)continue;
    CFixObject* fixObj = new CFixObject();
    fixObj->m_ObjectID = id;
    pArray->AddItem(fixObj);
   }
   if(m_pObj != JNULL)
   {
    m_pSerialization->AddToFix(pObjRead);
   }
  }
 }
 else if(headercode == SER_HRADERTYPE_BASEDATA)
 {
  CJBaseDataType* pBaseObj = (CJBaseDataType*)m_pObj;
  jbool bnew = FALSE;
  if(pBaseObj == JNULL)
  {
   //也许该对象不存在,也许该字段不存在了,此时读取,只为兼容格式,不保存信息
   pBaseObj =  (CJBaseDataType*)CJActivator::CreateInstance(pObSerInfos->m_Name);
   if(pBaseObj == JNULL)JThrowSerialException(CJString::FormatString("序列化异常:无法创建%s对象",pObSerInfos->m_Name));
   bnew = TRUE;
  }
  CJArchive ar(m_pStream);
  pBaseObj->DeSerialize(&ar);
  if(bnew)
  {
   CJActivator::ReleaseInstance(pBaseObj);
  }


 }
 else
 {
  JThrowSerialException("序列化异常:不识别的对象类型头");
 }
}


这个函数有点长了,看注释基本上可以明白内容,看看读取对象序列化类型信息


CJSerializationInfo* CObjectRead::ReadObjectSerializationInfos()
{
 CJSerializationInfo* pObjSerinfos = new CJSerializationInfo();
 jint32 fieldcount;
 if(!m_pStream->ReadString(&pObjSerinfos->m_Name))JThrowSerialException("序列化数据被破坏");
 if(!m_pStream->ReadInt32(&pObjSerinfos->m_typeID))JThrowSerialException("序列化数据被破坏");
 if(!m_pStream->ReadInt32(&fieldcount))JThrowSerialException("序列化数据被破坏");
 if(fieldcount > 0)
 {
  for(int i = 0;i < fieldcount;i++)
  {
   SerializationInfoField* field = new SerializationInfoField;
   m_pStream->ReadUInt32(&field->fieldTypeID);
   m_pStream->ReadUInt32(&field->valuetypeid);
   m_pStream->ReadString(&field->name);
   pObjSerinfos->m_fields.Add(field);
  }
 }
 return pObjSerinfos;
}


 


对于CJSerializationInfo对象,我们有2个,一个是从文件(二进制)中获取,一个是从程序中调用对象的GetObjectData获取,


为什么会有2个呢,因为他们可能不一致,所以在读取的时候是以文件(二进制)中保存的信息为准,而在赋值的时候是以GetObjectData获取的为准,这样可以解决版本兼容问题,而且反序列化程序不会因为格式变换而乱。


以上工作,基本上完成了序列化所有主要的工作,其他工作(如资源释放等)以后做.下次要开始调试,测试工作了。
阅读(939) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~