uint32_t BasicBuffer::AddBuffer( const SmartBufferPtr& buffer, bool add_fixups ) { // platform types have to match HELIUM_ASSERT(buffer->GetByteOrder() == m_ByteOrder); // first bring in all the data from the incoming buffer uint32_t return_val = AddBuffer( buffer->GetData(), buffer->GetSize() ); if (add_fixups) { // inherit all the incoming / outgoing fixups from this buffer with out new offset InheritFixups( buffer, return_val ); } return return_val; }
void SmartBuffer::InheritFixups( const SmartBufferPtr& buffer, u32 offset ) { // inherit all the incoming fixups if ( !buffer->GetIncomingFixups().Empty() ) { // first we copy the incoming fixups, since we are messing with that map S_DumbBufferLocation incoming_fixup_copy = buffer->GetIncomingFixups(); S_DumbBufferLocation::Iterator itr = incoming_fixup_copy.Begin(); S_DumbBufferLocation::Iterator end = incoming_fixup_copy.End(); for( ; itr != end; ++itr ) { // this is the old incoming fixup data DumbBufferLocation source_location = (*itr); // get the target location from the source buffer M_OffsetToFixup::iterator i = source_location.second->m_OutgoingFixups.find( source_location.first ); HELIUM_ASSERT( i != source_location.second->m_OutgoingFixups.end() ); // get a pointer to the fixup FixupPtr fixup = (*i).second; // get the previous destination, we know this fixup must have one or else there // wouldn't be an incoming entry for it BufferLocation old_destination; bool found_destination = fixup->GetDestination( old_destination ); HELIUM_ASSERT( found_destination && old_destination.second == buffer ); // null out the old fixup AddFixup( source_location, NULL ); // now change the fixup to have the right Helium::SmartPtr BufferLocation new_destination (old_destination.first + offset, this); fixup->ChangeDestination( new_destination ); // optimization just incase this fixup is completely internal to buffer if ( source_location.second == buffer.Ptr() ) { source_location.first += offset; source_location.second = this; } // restore the fixup with the correct destination AddFixup( source_location, fixup ); } } // inherit all the outgoing fixups from the buffer if ( !buffer->m_OutgoingFixups.empty() ) { M_OffsetToFixup outgoing_fixups_copy = buffer->m_OutgoingFixups; SmartBuffer::M_OffsetToFixup::const_iterator itr = outgoing_fixups_copy.begin(); SmartBuffer::M_OffsetToFixup::const_iterator end = outgoing_fixups_copy.end(); for( ; itr != end; ++itr ) { // get a pointer to the fixup FixupPtr fixup = (*itr).second; // first remove the old fixup DumbBufferLocation old_source_location ( (*itr).first, buffer ); AddFixup( old_source_location, NULL ); // we need to offset the previous fixup by the correct offset in the current buffer DumbBufferLocation new_source_location ( offset + (*itr).first, this ); AddFixup( new_source_location, fixup ); } } }
bool BufferSerializer::ReadFromStream( tistream& strm ) { //uint32_t starting_offset = strm.tellp(); // read a ChunkFileHeader ChunkFileHeader file_header; strm.read( (tchar_t*)&file_header, sizeof( ChunkFileHeader ) ); uint32_t test1 = (uint32_t)strm.tellg(); bool swizzle = false; // check that the header looks valid if ( file_header.m_Magic != CHUNK_MAGIC_LITTLE_ENDIAN ) { uint32_t magic = ConvertEndian(file_header.m_Magic, true); if ( magic == CHUNK_MAGIC_BIG_ENDIAN ) { swizzle = true; } else { return false; } } file_header.m_Version = ConvertEndian(file_header.m_Version, swizzle); file_header.m_ChunkCount = ConvertEndian(file_header.m_ChunkCount, swizzle); uint32_t alignment; switch( file_header.m_Version ) { case CHUNK_VERSION_128_ALIGN: alignment = 128; break; case CHUNK_VERSION_16_ALIGN: alignment = 16; break; default: return false; } // std::vector< ChunkHeader > chunk_headers( file_header.m_ChunkCount ); std::vector< SmartBufferPtr > chunks( file_header.m_ChunkCount ); std::map< uint32_t, uint32_t, std::greater<uint32_t> > chunk_map; // read each chunk header for ( uint32_t chunk_index = 0; chunk_index < file_header.m_ChunkCount; ++chunk_index ) { strm.read( (tchar_t*)&chunk_headers[ chunk_index ], sizeof( ChunkHeader ) ); chunk_headers[ chunk_index ].m_Type = ConvertEndian(chunk_headers[ chunk_index ].m_Type, swizzle); chunk_headers[ chunk_index ].m_Offset = ConvertEndian(chunk_headers[ chunk_index ].m_Offset, swizzle); chunk_headers[ chunk_index ].m_Size = ConvertEndian(chunk_headers[ chunk_index ].m_Size, swizzle); } // create and read each chunk for ( uint32_t chunk_index = 0; chunk_index < file_header.m_ChunkCount; ++chunk_index ) { const ChunkHeader& header = chunk_headers[ chunk_index ]; SmartBufferPtr buffer = new SmartBuffer(); buffer->SetByteOrder( swizzle ? ByteOrders::BigEndian : ByteOrders::LittleEndian ); //HELIUM_ASSERT( header.m_Offset == ( strm.tellp() - starting_offset ) ); chunks[ chunk_index ] = buffer; buffer->Resize( header.m_Size ); buffer->SetType( header.m_Type ); strm.read( (tchar_t*)buffer->GetData(), buffer->GetSize() ); HELIUM_ASSERT( chunk_map.find( header.m_Offset ) == chunk_map.end() ); chunk_map[ header.m_Offset ] = chunk_index; // is the buffer aligned? if ( swizzle && (buffer->GetSize() & ( alignment - 1 )) != 0 ) { uint32_t pad = alignment - (buffer->GetSize() & ( alignment - 1 ) ); strm.seekg( pad, std::ios_base::cur ); } } uint32_t test = (uint32_t)strm.tellg(); // read the fixups uint32_t num_fixups; strm.read( (tchar_t*)&num_fixups, sizeof( num_fixups ) ); num_fixups = ConvertEndian(num_fixups, swizzle); for ( uint32_t fixup_index = 0; fixup_index < num_fixups; ++fixup_index ) { uint32_t source_offset; strm.read( (tchar_t*)&source_offset, sizeof( source_offset ) ); source_offset = ConvertEndian(source_offset, swizzle); // figure out which buffer this fixup starts in std::map< uint32_t, uint32_t, std::greater<uint32_t> >::iterator source_itr = chunk_map.lower_bound( source_offset ); HELIUM_ASSERT( source_itr != chunk_map.end() ); // get the necessary source data const ChunkHeader& source_header = chunk_headers[ (*source_itr).second ]; SmartBufferPtr source_buffer = chunks[ (*source_itr).second ]; uint32_t* source_data = (uint32_t*)(source_buffer->GetData() + ( source_offset - source_header.m_Offset ) ); uint32_t dest_offset = *source_data; dest_offset = ConvertEndian(dest_offset, swizzle); // figure out which buffer this fixup ends in std::map< uint32_t, uint32_t, std::greater<uint32_t> >::iterator dest_itr = chunk_map.lower_bound( dest_offset ); HELIUM_ASSERT( dest_itr != chunk_map.end() ); // get the necessary dest data const ChunkHeader& dest_header = chunk_headers[ (*dest_itr).second ]; SmartBufferPtr dest_buffer = chunks[ (*dest_itr).second ]; // do the fixup SmartBuffer::AddPointerFixup( source_buffer->GetOffsetLocation( source_offset - source_header.m_Offset ), dest_buffer->GetOffsetLocation ( dest_offset - dest_header.m_Offset ), 4 ); } // read the fixups uint32_t num_fixups_64; strm.read( (tchar_t*)&num_fixups_64, sizeof( num_fixups_64 ) ); num_fixups_64 = ConvertEndian(num_fixups_64, swizzle); if (!strm.eof()) { for ( uint32_t fixup_index = 0; fixup_index < num_fixups_64; ++fixup_index ) { uint32_t source_offset; strm.read( (tchar_t*)&source_offset, sizeof( source_offset ) ); source_offset = ConvertEndian(source_offset, swizzle); // figure out which buffer this fixup starts in std::map< uint32_t, uint32_t, std::greater<uint32_t> >::iterator source_itr = chunk_map.lower_bound( source_offset ); HELIUM_ASSERT( source_itr != chunk_map.end() ); // get the necessary source data const ChunkHeader& source_header = chunk_headers[ (*source_itr).second ]; SmartBufferPtr source_buffer = chunks[ (*source_itr).second ]; uint32_t* source_data = (uint32_t*)(source_buffer->GetData() + ( source_offset - source_header.m_Offset ) ); uint32_t dest_offset = *source_data; dest_offset = ConvertEndian(dest_offset, swizzle); // figure out which buffer this fixup ends in std::map< uint32_t, uint32_t, std::greater<uint32_t> >::iterator dest_itr = chunk_map.lower_bound( dest_offset ); HELIUM_ASSERT( dest_itr != chunk_map.end() ); // get the necessary dest data const ChunkHeader& dest_header = chunk_headers[ (*dest_itr).second ]; SmartBufferPtr dest_buffer = chunks[ (*dest_itr).second ]; // do the fixup SmartBuffer::AddPointerFixup( source_buffer->GetOffsetLocation( source_offset - source_header.m_Offset - 4), dest_buffer->GetOffsetLocation ( dest_offset - dest_header.m_Offset ), 8 ); } } // store the chunks m_Buffers.clear(); { std::vector< SmartBufferPtr >::const_iterator itr = chunks.begin(); std::vector< SmartBufferPtr >::const_iterator end = chunks.end(); for ( ; itr != end; ++itr ) { if ( std::find( m_Buffers.begin(), m_Buffers.end(), *itr ) == m_Buffers.end() ) { m_Buffers.push_back( *itr ); } } } return true; }