void ArchiveXML::DeserializeInstance(ObjectPtr& object) { // // If we don't have an object allocated for deserialization, pull one from the stream // if (!object.ReferencesObject()) { object = Allocate(); } // // We should now have an instance (unless data was skipped) // if (object.ReferencesObject()) { #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Get(stdout); Log::Print(TXT("Deserializing %s\n"), object->GetClass()->m_Name); m_Indent.Push(); #endif object->PreDeserialize( NULL ); Data* data = SafeCast<Data>(object); if ( data ) { #pragma TODO("Make sure this string copy goes away when replace the stl stream APIs") tstring body ( m_Iterator.GetCurrent()->m_Body.GetData(), m_Iterator.GetCurrent()->m_Body.GetSize() ); tstringstream stringStream ( body ); TCharStream stream ( &stringStream, false ); m_Body = &stream; data->Deserialize(*this); m_Body = NULL; m_Iterator.Advance( true ); } else { DeserializeFields(object); } object->PostDeserialize( NULL ); #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Pop(); #endif } }
void ArchiveXML::DeserializeArray( ArrayPusher& push, uint32_t flags ) { if ( m_Iterator.GetCurrent()->GetFirstChild() ) { // advance to the first child (the first array element) m_Iterator.Advance(); #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Get(stdout); Log::Print(TXT("Deserializing objects\n")); m_Indent.Push(); #endif for ( XMLElement* sibling = m_Iterator.GetCurrent(); sibling != NULL; sibling = sibling->GetNextSibling() ) { HELIUM_ASSERT( m_Iterator.GetCurrent() == sibling ); ObjectPtr object; DeserializeInstance(object); if (object.ReferencesObject()) { if ( object->IsClass( m_SearchClass ) ) { m_Skip = true; } if ( flags & ArchiveFlags::Status ) { ArchiveStatus info( *this, ArchiveStates::ObjectProcessed ); #pragma TODO("Update progress value for inter-array processing") //info.m_Progress = (int)(((float)(current - start_offset) / (float)m_Size) * 100.0f); e_Status.Raise( info ); m_Abort |= info.m_Abort; } } push( object ); } } else { // advance to the next element m_Iterator.Advance(); } #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Pop(); #endif if ( flags & ArchiveFlags::Status ) { ArchiveStatus info( *this, ArchiveStates::ObjectProcessed ); info.m_Progress = 100; e_Status.Raise( info ); } }
void ArchiveBinary::DeserializeInstance(ObjectPtr& object) { // // If we don't have an object allocated for deserialization, pull one from the stream // if (!object.ReferencesObject()) { object = Allocate(); } // // We should now have an instance (unless data was skipped) // if (object.ReferencesObject()) { #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Get(stdout); Log::Print(TXT("Deserializing %s\n"), object->GetClass()->m_Name); m_Indent.Push(); #endif object->PreDeserialize( NULL ); Data* data = SafeCast<Data>(object); if ( data ) { data->Deserialize(*this); } else { DeserializeFields(object); } object->PostDeserialize( NULL ); #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Pop(); #endif } }
ObjectPtr ArchiveBinary::Allocate() { ObjectPtr object; // read type string uint32_t typeCrc = Helium::BeginCrc32(); m_Stream->Read(&typeCrc); // A null type name CRC indicates that a null reference was serialized, so no type lookup needs to be performed. const Class* type = NULL; if ( typeCrc != 0 ) { type = Reflect::Registry::GetInstance()->GetClass( typeCrc ); } // read length info if we have it uint32_t length = 0; m_Stream->Read(&length); if ( m_Skip || typeCrc == 0 ) { // skip it, but account for already reading the length from the stream m_Stream->SeekRead(length - sizeof(uint32_t), std::ios_base::cur); } else { if (type) { // allocate instance by name object = Registry::GetInstance()->CreateInstance( type ); } // if we failed if (!object.ReferencesObject()) { // skip it, but account for already reading the length from the stream m_Stream->SeekRead(length - sizeof(uint32_t), std::ios_base::cur); // if you see this, then data is being lost because: // 1 - a type was completely removed from the codebase // 2 - a type was not found because its type library is not registered Log::Debug( TXT( "Unable to create object of type %s, size %d, skipping...\n" ), type ? type->m_Name : TXT("Unknown"), length); #pragma TODO("Support blind data") } } return object; }
DataPtr Field::CreateData() const { DataPtr data; if ( m_DataClass != NULL ) { ObjectPtr object = Registry::GetInstance()->CreateInstance( m_DataClass ); if (object.ReferencesObject()) { data = AssertCast<Data>(object); } } return data; }
ObjectPtr ArchiveXML::Allocate() { ObjectPtr object; // find type const String* typeStr = m_Iterator.GetCurrent()->GetAttributeValue( Name( TXT("Type") ) ); uint32_t typeCrc = typeStr ? Crc32( typeStr->GetData() ) : 0x0; // A null type name CRC indicates that a null reference was serialized, so no type lookup needs to be performed. const Class* type = NULL; if ( typeCrc != 0 ) { type = Reflect::Registry::GetInstance()->GetClass( typeCrc ); } if (type) { // allocate instance by name object = Registry::GetInstance()->CreateInstance( type ); } // if we failed if (!object.ReferencesObject()) { // if you see this, then data is being lost because: // 1 - a type was completely removed from the codebase // 2 - a type was not found because its type library is not registered Log::Debug( TXT( "Unable to create object of type %s, skipping...\n" ), type ? type->m_Name : TXT("Unknown") ); // skip past this object, skipping our children m_Iterator.Advance( true ); #pragma TODO("Support blind data") } return object; }
void ArchiveXML::DeserializeFields(Object* object) { if ( m_Iterator.GetCurrent()->GetFirstChild() ) { // advance to the first child m_Iterator.Advance(); for ( XMLElement* sibling = m_Iterator.GetCurrent(); sibling != NULL; sibling = sibling->GetNextSibling() ) { HELIUM_ASSERT( m_Iterator.GetCurrent() == sibling ); const String* fieldNameStr = sibling->GetAttributeValue( Name( TXT("Name") ) ); uint32_t fieldNameCrc = fieldNameStr ? Crc32( fieldNameStr->GetData() ) : 0x0; const Class* type = object->GetClass(); HELIUM_ASSERT( type ); ObjectPtr unknown; const Field* field = type->FindFieldByName(fieldNameCrc); if ( field ) { #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Get(stdout); Log::Print(TXT("Deserializing field %s\n"), field->m_Name); m_Indent.Push(); #endif // pull and object and downcast to data DataPtr latentData = SafeCast<Data>( Allocate() ); if (!latentData.ReferencesObject()) { // this should never happen, the type id read from the file is bogus throw Reflect::TypeInformationException( TXT( "Unknown data for field %s (%s)" ), field->m_Name, m_Path.c_str() ); #pragma TODO("Support blind data") } // if the types match we are a natural fit to just deserialize directly into the field data if ( field->m_DataClass == field->m_DataClass ) { // set data pointer latentData->ConnectField( object, field ); // process natively object->PreDeserialize( field ); DeserializeInstance( (ObjectPtr&)latentData ); object->PostDeserialize( field ); // disconnect latentData->Disconnect(); } else // else the type does not match, deserialize it into temp data then attempt to cast it into the field data { REFLECT_SCOPE_TIMER(("Casting")); // construct current serialization object ObjectPtr currentObject = Registry::GetInstance()->CreateInstance( field->m_DataClass ); // downcast to data DataPtr currentData = SafeCast<Data>(currentObject); if (!currentData.ReferencesObject()) { // this should never happen, the type id in the rtti data is bogus throw Reflect::TypeInformationException( TXT( "Invalid type id for field %s (%s)" ), field->m_Name, m_Path.c_str() ); } // process into temporary memory currentData->ConnectField(object, field); // process natively object->PreDeserialize( field ); DeserializeInstance( (ObjectPtr&)latentData ); // attempt cast data into new definition if ( !Data::CastValue( latentData, currentData, DataFlags::Shallow ) ) { // handle as unknown unknown = latentData; } else { // post process object->PostDeserialize( field ); } // disconnect currentData->Disconnect(); } } else // else the field does not exist in the current class anymore { try { DeserializeInstance( unknown ); } catch (Reflect::LogisticException& ex) { Log::Debug( TXT( "Unable to deserialize %s::%s, discarding: %s\n" ), type->m_Name, field->m_Name, ex.What()); } } if ( unknown.ReferencesObject() ) { // attempt processing object->ProcessUnknown( unknown, field ? Crc32( field->m_Name ) : 0 ); } #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Pop(); #endif } } else { // advance to the next element m_Iterator.Advance(); } }
void ArchiveBinary::DeserializeArray( ArrayPusher& push, uint32_t flags ) { uint32_t start_offset = (uint32_t)m_Stream->TellRead(); int32_t element_count = -1; m_Stream->Read(&element_count); #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Get(stdout); Log::Debug(TXT("Deserializing %d objects\n"), element_count); m_Indent.Push(); #endif if (element_count > 0) { for (int i=0; i<element_count && !m_Abort; i++) { ObjectPtr object; DeserializeInstance(object); if (object.ReferencesObject()) { if ( object->IsClass( m_SearchClass ) ) { m_Skip = true; } if ( flags & ArchiveFlags::Status ) { uint32_t current = (uint32_t)m_Stream->TellRead(); ArchiveStatus info( *this, ArchiveStates::ObjectProcessed ); info.m_Progress = (int)(((float)(current - start_offset) / (float)m_Size) * 100.0f); e_Status.Raise( info ); m_Abort |= info.m_Abort; } } push( object ); } } #ifdef REFLECT_ARCHIVE_VERBOSE m_Indent.Pop(); #endif if (!m_Abort) { int32_t terminator = -1; m_Stream->Read(&terminator); if (terminator != -1) { throw Reflect::DataFormatException( TXT( "Unterminated object array block (%s)" ), m_Path.c_str() ); } } if ( flags & ArchiveFlags::Status ) { ArchiveStatus info( *this, ArchiveStates::ObjectProcessed ); info.m_Progress = 100; e_Status.Raise( info ); } }