17#ifndef __TOSHI_TTRB_H__
18# error Include TTRB.h to use this extension
21#ifndef __TOSHI_PLUGIN_PTRB_H__
22# define __TOSHI_PLUGIN_PTRB_H__
41 Toshi::TTRB::Header m_Header;
70 : m_Stack(
TNULL ), m_Offset( 0 ) {}
110 template <
typename N>
113 return Ptr<T>{ m_Stack, m_Offset +
sizeof( T ) * a_iValue };
116 template <
typename N>
119 return Ptr<T>{ m_Stack, m_Offset -
sizeof( T ) * a_iValue };
124 return m_Stack !=
TNULL;
143 m_eEndianess = eEndianess;
148 m_PtrList.reserve( 32 );
154 TASSERT( other.m_DependentStacks.size() == 0,
"Cross pointers are not supported" );
156 m_Index = other.m_Index;
157 m_eEndianess = other.m_eEndianess;
160 m_ExpectedSize = other.m_ExpectedSize;
161 Resize( other.m_BufferSize );
163 Toshi::TUtil::MemCopy( m_Buffer, other.m_Buffer, other.
GetUsedSize() );
165 m_PtrList.reserve( other.m_PtrList.size() );
166 for (
TUINT i = 0; i < other.m_PtrList.size(); i++ )
168 m_PtrList.emplace_back(
169 other.m_PtrList[ i ].Offset,
170 other.m_PtrList[ i ].DataPtr,
178 if ( m_Buffer !=
TNULL )
188 TASSERT( newPos < m_BufferSize,
"Trying to seek out of buffer" );
189 m_BufferPos = m_Buffer + newPos;
227 TASSERT( offset >= 0 && offset < m_BufferSize,
"Offset is out of buffer" );
228 *(T*)( &m_Buffer[ offset ] ) = value;
234 TASSERT( offset >= 0 && offset < m_BufferSize,
"Offset is out of buffer" );
235 Toshi::TUtil::MemCopy( &m_Buffer[ offset ], value, size );
255 template <
class T, TUINT Count = 1>
256 Ptr<T>
Alloc( T** outPtr );
261 std::vector<RelcPtr>::iterator
begin() {
return m_PtrList.begin(); }
262 std::vector<RelcPtr>::iterator
end() {
return m_PtrList.end(); }
267 void Resize(
TUINT size );
271 m_PtrList.emplace_back( offset, dataPtr, pDataStack ==
TNULL ?
this : pDataStack );
280 std::vector<RelcPtr> m_PtrList;
281 std::vector<MemoryStream*> m_DependentStacks;
287 : m_eEndianess( a_eEndianess )
297 for (
auto stack : m_Stacks )
306 return m_Stacks.size();
311 if ( m_Stacks.size() == 0 )
313 m_eEndianess = a_eEndianess;
326 void Write( Toshi::TTSFO& ttsfo,
TBOOL compress );
329 std::vector<PTRBSections::MemoryStream*>::iterator
begin() {
return m_Stacks.begin(); }
330 std::vector<PTRBSections::MemoryStream*>::iterator
end() {
return m_Stacks.end(); }
333 std::vector<PTRBSections::MemoryStream*> m_Stacks;
348 m_SymbolNames.clear();
349 m_Symbols.reserve( 5 );
350 m_SymbolNames.reserve( 5 );
355 TASSERT( index >= 0 && index < m_Symbols.size() );
356 auto hash = Toshi::TTRB::HashString( name );
358 if ( m_Symbols[ index ].NameHash == hash )
360 if ( m_SymbolNames[ index ] == name )
371 auto hash = Toshi::TTRB::HashString( name );
373 for (
TUINT i = 0; i < m_Symbols.size(); i++ )
375 if ( m_Symbols[ i ].NameHash == hash )
377 if ( m_SymbolNames[ i ] == name )
395 if ( index != -1 && (
TINT)m_Symbols.size() > index )
397 auto stack = sect.
GetStack( m_Symbols[ index ].HDRX );
398 return { stack, m_Symbols[ index ].DataOffset };
411 auto stack = sect.
GetStack( m_Symbols[ index ].HDRX );
412 return { stack, m_Symbols[ index ].DataOffset };
430 auto stack = sect.
GetStack( m_Symbols[ index ].HDRX );
445 TASSERT( index < m_Symbols.size() );
448 sect.
GetStack( m_Symbols[ index ].HDRX ),
449 m_Symbols[ index ].DataOffset
461 TASSERT( index < m_Symbols.size() );
462 return sect.
GetStack( m_Symbols[ index ].HDRX );
472 return m_SymbolNames[ index ].GetString();
477 return m_Symbols.size();
482 m_Symbols.emplace_back( pStream->
GetIndex(), 0, 0, 0, pStream->
GetOffset( ptr ) );
483 m_SymbolNames.push_back( name );
488 auto stackIndex = pStream->
GetIndex();
490 for (
TUINT i = 0; i < m_Symbols.size(); i++ )
492 if ( m_Symbols[ i ].HDRX == stackIndex )
494 m_Symbols[ i ].HDRX = newIndex;
503 TASSERT( index >= 0 && index < m_Symbols.size() );
505 m_Symbols.erase( m_Symbols.begin() + index );
506 m_SymbolNames.erase( m_SymbolNames.begin() + index );
511 for (
TUINT i = 0; i < m_Symbols.size(); )
513 if ( m_Symbols[ i ].HDRX == stackIndex )
526 TASSERT( m_Symbols.size() == m_SymbolNames.size(),
"" );
529 TUINT32 symbolCount = m_Symbols.size();
530 ttsfo.Write( CONVERTENDIANESS( eEndianess, symbolCount ) );
532 for (
TUINT i = 0; i < m_Symbols.size(); i++ )
534 m_Symbols[ i ].NameHash = Toshi::TTRB::HashString( m_SymbolNames[ i ] );
535 m_Symbols[ i ].NameOffset = nameOffset;
536 nameOffset += m_SymbolNames[ i ].Length() + 1;
538 Toshi::TTRB::TTRBSymbol oFixedSymbol;
539 oFixedSymbol.HDRX = CONVERTENDIANESS( eEndianess, m_Symbols[ i ].HDRX );
540 oFixedSymbol.NameHash = CONVERTENDIANESS( eEndianess, m_Symbols[ i ].NameHash );
541 oFixedSymbol.NameOffset = CONVERTENDIANESS( eEndianess, m_Symbols[ i ].NameOffset );
542 oFixedSymbol.Padding = CONVERTENDIANESS( eEndianess, m_Symbols[ i ].Padding );
543 oFixedSymbol.DataOffset = CONVERTENDIANESS( eEndianess, m_Symbols[ i ].DataOffset );
544 ttsfo.Write( oFixedSymbol );
547 for (
auto& name : m_SymbolNames )
549 ttsfo.WriteRaw( name, name.Length() );
557 ttsfi.Read( &symbolCount );
558 symbolCount = CONVERTENDIANESS( eEndianess, symbolCount );
561 TUINT symbolsSize =
sizeof( Toshi::TTRB::TTRBSymbol ) * symbolCount;
562 m_Symbols.resize( symbolCount );
563 ttsfi.ReadRaw( m_Symbols.data(), symbolsSize );
566 TUINT namesSize = ttsfi.GetCurrentHunk().Size - symbolsSize;
567 m_SymbolNames.reserve( symbolCount );
569 ttsfi.ReadRaw( namesBuffer, namesSize );
571 for (
auto& symbol : m_Symbols )
573 symbol.HDRX = CONVERTENDIANESS( eEndianess, symbol.HDRX );
574 symbol.NameHash = CONVERTENDIANESS( eEndianess, symbol.NameHash );
575 symbol.NameOffset = CONVERTENDIANESS( eEndianess, symbol.NameOffset );
576 symbol.Padding = CONVERTENDIANESS( eEndianess, symbol.Padding );
577 symbol.DataOffset = CONVERTENDIANESS( eEndianess, symbol.DataOffset );
579 const TCHAR* symbolName = &namesBuffer[ symbol.NameOffset ];
580 m_SymbolNames.push_back( symbolName );
583 delete[] namesBuffer;
586 std::vector<Toshi::TString8>::iterator
begin() {
return m_SymbolNames.begin(); }
587 std::vector<Toshi::TString8>::iterator
end() {
return m_SymbolNames.end(); }
590 std::vector<Toshi::TTRB::TTRBSymbol> m_Symbols;
591 std::vector<Toshi::TString8> m_SymbolNames;
602 , m_eEndianess( a_eEndianess )
604 m_SECT.SetEndianess( m_eEndianess );
607 PTRB( Toshi::T2StringView filepath )
614 m_SECT.SetEndianess( m_eEndianess );
622 auto pFile = Toshi::TFile::Create( filepath.Get() );
625 if ( pFile && ttsfi.Open( pFile ) == Toshi::TTRB::ERROR_OK )
627 m_eEndianess = ttsfi.GetEndianess();
628 int32_t leftSize = ttsfi.GetCurrentHunk().Size - 4;
630 m_SECT.SetEndianess( m_eEndianess );
632 while ( leftSize >
sizeof( Toshi::TTSF::Hunk ) )
634 if ( ttsfi.ReadHunk() != Toshi::TTRB::ERROR_OK )
break;
635 leftSize -= ttsfi.GetCurrentHunk().Size +
sizeof( Toshi::TTSF::Hunk );
637 switch ( ttsfi.GetCurrentHunk().Name )
640 m_HDRX.Read( ttsfi, m_SECT, m_eEndianess );
643 m_SECT.Read( ttsfi,
TFALSE, m_eEndianess );
646 m_SECT.Read( ttsfi,
TTRUE, m_eEndianess );
649 m_RELC.Read( ttsfi, m_SECT, m_eEndianess );
652 m_SYMB.Read( ttsfi, m_SECT, m_eEndianess );
664 if ( pFile !=
TNULL )
675 if ( m_eEndianess != -1 )
678 Toshi::TTSFO::HunkMark mark;
679 ttsfo.Create( filepath, ( m_eEndianess ==
Endianess_Big ) ?
"FBRT" :
"TRBF", m_eEndianess );
682 ttsfo.OpenHunk( &mark,
"HDRX" );
683 m_HDRX.SetSectionCount( m_SECT.GetStackCount() );
684 m_HDRX.Write( ttsfo, m_SECT, m_eEndianess );
685 ttsfo.CloseHunk( &mark );
689 Toshi::TCompress::ms_bIsBigEndian = ( m_eEndianess ==
Endianess_Big );
691 ttsfo.OpenHunk( &mark, compress ?
"SECC" :
"SECT" );
692 m_SECT.Write( ttsfo, compress );
693 ttsfo.CloseHunk( &mark );
696 ttsfo.OpenHunk( &mark,
"RELC" );
697 m_RELC.Write( ttsfo, m_SECT, m_eEndianess );
698 ttsfo.CloseHunk( &mark );
701 ttsfo.OpenHunk( &mark,
"SYMB" );
702 m_SYMB.Write( ttsfo, m_eEndianess );
703 ttsfo.CloseHunk( &mark );
713 template <
typename T>
716 return CONVERTENDIANESS( m_eEndianess, a_numValue );
733 m_Header.m_ui32Version = version;
734 m_Header.m_i32SectionCount = 0;
739 m_Header.m_ui32Version = version;
744 m_Header.m_i32SectionCount = count;
749 Toshi::TTRB::Header oFixedHeader;
750 oFixedHeader.m_ui32Version = CONVERTENDIANESS( eEndianess, m_Header.m_ui32Version.Value );
751 oFixedHeader.m_i32SectionCount = CONVERTENDIANESS( eEndianess, m_Header.m_i32SectionCount );
753 ttsfo.Write( oFixedHeader );
757 Toshi::TTRB::SecInfo sectionInfo = {};
758 sectionInfo.m_Size = CONVERTENDIANESS( eEndianess,
TAlignNumUp( stack->GetUsedSize() ) );
759 ttsfo.Write( sectionInfo );
765 ttsfi.Read( &m_Header );
766 m_Header.m_i32SectionCount = CONVERTENDIANESS( eEndianess, m_Header.m_i32SectionCount );
767 m_Header.m_ui32Version = CONVERTENDIANESS( eEndianess, m_Header.m_ui32Version.Value );
769 for (
TINT i = 0; i < m_Header.m_i32SectionCount; i++ )
771 Toshi::TTRB::SecInfo sectionInfo;
772 ttsfi.Read( §ionInfo );
774 sectionInfo.m_Data = CONVERTENDIANESS( eEndianess, sectionInfo.m_Data );
775 sectionInfo.m_Size = CONVERTENDIANESS( eEndianess, sectionInfo.m_Size );
776 sectionInfo.m_Unk1 = CONVERTENDIANESS( eEndianess, sectionInfo.m_Unk1 );
777 sectionInfo.m_Unk2 = CONVERTENDIANESS( eEndianess, sectionInfo.m_Unk2 );
778 sectionInfo.m_Unused = CONVERTENDIANESS( eEndianess, sectionInfo.m_Unused );
788 for (
auto section : sect )
790 ptrCount += section->GetPointerCount();
793 ttsfo.Write( CONVERTENDIANESS( eEndianess, ptrCount ) );
799 for (
auto& ptr : *section )
801 Toshi::TTRB::RELCEntry entry = {};
802 entry.HDRX1 = CONVERTENDIANESS( eEndianess, (
TINT16)i );
803 entry.HDRX2 = CONVERTENDIANESS( eEndianess, (
TINT16)ptr.DataStack->GetIndex() );
804 entry.Offset = CONVERTENDIANESS( eEndianess, ptr.Offset );
805 ttsfo.Write( entry );
813 ttsfi.Read( &ptrCount );
815 ptrCount = CONVERTENDIANESS( eEndianess, ptrCount );
817 Toshi::TTRB::RELCEntry entry;
818 for (
TUINT32 i = 0; i < ptrCount; i++ )
820 ttsfi.Read( &entry );
821 entry.HDRX1 = CONVERTENDIANESS( eEndianess, entry.HDRX1 );
822 entry.HDRX2 = CONVERTENDIANESS( eEndianess, entry.HDRX2 );
823 entry.Offset = CONVERTENDIANESS( eEndianess, entry.Offset );
825 auto stack = sect.
GetStack( entry.HDRX1 );
826 auto dataStack = sect.
GetStack( entry.HDRX2 );
827 TUINT32 dataPtr = *(
TUINT32*)( &stack->GetBuffer()[ entry.Offset ] );
828 stack->AddRelocationPtr( entry.Offset, dataPtr, dataStack );
831 for (
auto stack : sect )
847 AddRelocationPtr( outPtrOffset, ptr.
offset(), ptr.
stack() );
850 auto crossStack = ptr.
stack();
851 auto it = std::find( crossStack->m_DependentStacks.begin(), crossStack->m_DependentStacks.end(),
this );
853 if ( it == crossStack->m_DependentStacks.end() )
856 crossStack->m_DependentStacks.push_back(
this );
865 constexpr TUINT TSize =
sizeof( T );
869 m_BufferPos += TSize;
871 return {
this, allocated };
879 const TUINT TSize =
sizeof( T ) * count;
883 m_BufferPos += TSize;
885 return {
this, allocated };
894 const TUINT TSize =
sizeof( T ) * count;
899 m_BufferPos += TSize;
902 AddRelocationPtr( outPtrOffset, CONVERTENDIANESS( m_eEndianess,
GetOffset( allocated ) ) );
904 return {
this, allocated };
907template <
class T, TUINT Count>
913 constexpr TUINT TSize =
sizeof( T ) * Count;
918 m_BufferPos += TSize;
921 AddRelocationPtr( outPtrOffset, CONVERTENDIANESS( m_eEndianess,
GetOffset( allocated ) ) );
923 return {
this, allocated };
934 AddRelocationPtr( outPtrOffset, CONVERTENDIANESS( m_eEndianess,
GetOffset( ptr ) ) );
944 AddRelocationPtr( outPtrOffset, CONVERTENDIANESS( m_eEndianess, ptr.
offset() ) );
951 TCHAR* allocated =
reinterpret_cast<TCHAR*
>( m_BufferPos );
954 return {
this, allocated };
959 for (
auto& ptr : m_PtrList )
961 Write<void*>( ptr.Offset, ptr.DataStack->GetBuffer() + CONVERTENDIANESS( m_eEndianess, ptr.DataPtr ) );
967 for (
auto& ptr : m_PtrList )
977 if ( newSize != m_BufferSize )
983inline void PTRBSections::MemoryStream::Resize(
TUINT size )
985 TASSERT( size > 0,
"Size should be positive" );
989 TCHAR* oldBuffer = m_Buffer;
990 TUINT usedSize = GetUsedSize();
991 m_Buffer =
new TCHAR[ size ];
994 Toshi::TUtil::MemClear( m_Buffer, size );
996 if ( oldBuffer !=
TNULL )
998 Toshi::TUtil::MemCopy( m_Buffer, oldBuffer, usedSize );
999 m_BufferPos = m_Buffer + usedSize;
1004 m_BufferPos = m_Buffer;
1013 m_Stacks.push_back( stack );
1020 stack->
SetIndex( m_Stacks.size() );
1021 m_Stacks.push_back( stack );
1027 auto result = std::find( m_Stacks.begin(), m_Stacks.end(), pStream );
1029 if ( result != m_Stacks.end() )
1033 m_Stacks.erase( result );
1038 for (
auto it = m_Stacks.begin(); it != m_Stacks.end(); it++ )
1055 return m_Stacks[ index ];
1061 TUINT count = m_Stacks.size();
1067 TTRACE(
"Compressing progress: 0%\n" );
1071 TTRACE(
"Started BTEC compression...\n" );
1075 for (
auto stack : m_Stacks )
1081 ttsfo.WriteCompressed( stack->GetBuffer(), stack->GetUsedSize() );
1086 TTRACE(
"Compressing progress: %.1f\n", (
double)ready / count * 100 );
1090 TTRACE(
"BTEC compression completed...\n" );
1095 ttsfo.WriteRaw( stack->GetBuffer(), stack->GetUsedSize() );
1098 ttsfo.WriteAlignmentPad();
1105 m_eEndianess = eEndianess;
1107 for (
auto stack : m_Stacks )
1109 TUINT expectedSize = stack->GetExpectedSize();
1111 if ( expectedSize > 0 )
1113 stack->GrowBuffer( expectedSize );
1117 Toshi::TCompress::ms_bIsBigEndian = ( eEndianess ==
Endianess_Big );
1118 ttsfi.ReadCompressed( stack->GetBuffer(), expectedSize );
1122 ttsfi.ReadRaw( stack->GetBuffer(), expectedSize );
1125 stack->Seek( expectedSize );
1126 stack->SetExpectedSize( 0 );
#define TREINTERPRETCAST(TYPE, VALUE)
#define TVERSION(VER_MAJOR, VER_MINOR)
TFORCEINLINE constexpr T * TAlignPointerUp(T *a_pMem, TSIZE a_uiAlignment=sizeof(T *))
TFORCEINLINE constexpr T TAlignNumUp(T a_iValue, TSIZE a_uiAlignment=4)
TFORCEINLINE constexpr TUINT32 TFourCC(const TCHAR str[4])
Char string implementation for the Toshi engine.
void SetSectionCount(int32_t count)
PTRBHeader(Toshi::TVersion version)
void Read(Toshi::TTSFI &ttsfi, PTRBSections §, Endianess eEndianess)
void Write(Toshi::TTSFO &ttsfo, PTRBSections §, Endianess eEndianess)
void SetVersion(Toshi::TVersion version)
void Read(Toshi::TTSFI &ttsfi, PTRBSections §, Endianess eEndianess)
void Write(Toshi::TTSFO &ttsfo, PTRBSections §, Endianess eEndianess)
PTRBRelocations()=default
std::vector< PTRBSections::MemoryStream * >::iterator end()
TBOOL DeleteStack(PTRBSymbols *pSymb, PTRBSections::MemoryStream *pStream)
std::vector< PTRBSections::MemoryStream * >::iterator begin()
TBOOL SetEndianess(Endianess a_eEndianess)
PTRBSections::MemoryStream * CreateStream()
void Read(Toshi::TTSFI &ttsfi, TBOOL compressed=false, Endianess eEndianess=Endianess_Little)
void Write(Toshi::TTSFO &ttsfo, TBOOL compress)
PTRBSections(Endianess a_eEndianess=Endianess_Little)
PTRBSections::MemoryStream * GetStack(TUINT index)
TUINT GetStackCount() const
TUINT32 SetIndex(TUINT32 index)
TUINT32 GetExpectedSize() const
void WritePointer(T **outPtr, const T *ptr)
MemoryStream(const MemoryStream &other)
std::vector< RelcPtr >::iterator end()
TUINT GetPointerCount() const
static constexpr TUINT BUFFER_GROW_SIZE
void SetCrossPointer(T **outPtr, Ptr< T > ptr)
T * Write(TUINT offset, const T &value)
std::vector< RelcPtr >::iterator begin()
void GrowBuffer(TUINT requiredSize)
TUINT GetOffset(const void *ptr) const
TCHAR * GetBufferPos() const
MemoryStream(TUINT32 index, Endianess eEndianess)
TUINT GetUsedSize() const
Ptr< TCHAR > AllocBytes(TUINT Size)
void SetExpectedSize(TUINT32 expectedSize)
TCHAR * GetBuffer() const
void Write(TUINT offset, TCHAR *value, TINT size)
TUINT GetBufferSize() const
Ptr(PTRBSections::MemoryStream *stack, TUINT offset)
Ptr(PTRBSections::MemoryStream *stack, T *ptr)
Ptr< T > operator-(const N &a_iValue)
Ptr< T > operator+(const N &a_iValue)
PTRBSections::MemoryStream * stack()
PTRBSections::MemoryStream * DataStack
PTRBSections::MemoryStream::Ptr< T > Find(PTRBSections *sect, const TCHAR *name)
PTRBSections::MemoryStream * FindStack(PTRBSections *sect, const TCHAR *name)
TINT FindIndex(PTRBSections §, const TCHAR *name)
std::vector< Toshi::TString8 >::iterator end()
void Add(PTRBSections::MemoryStream *pStream, const TCHAR *name, void *ptr)
PTRBSections::MemoryStream * GetStack(PTRBSections *sect, TUINT index)
PTRBSections::MemoryStream * FindStack(PTRBSections §, const TCHAR *name)
TINT FindIndex(PTRBSections *sect, const TCHAR *name)
void UpdateSymbolsIndexes(PTRBSections::MemoryStream *pStream, TUINT32 newIndex)
void Write(Toshi::TTSFO &ttsfo, Endianess eEndianess)
PTRBSections::MemoryStream::Ptr< T > GetByIndex(PTRBSections §, TUINT index)
PTRBSections::MemoryStream::Ptr< T > Find(PTRBSections §, const TCHAR *name)
TBOOL Is(TUINT index, const TCHAR *name)
PTRBSections::MemoryStream::Ptr< T > Get(PTRBSections §, TINT index)
std::vector< Toshi::TString8 >::iterator begin()
Toshi::T2StringView GetName(TUINT index)
void RemoveAllWithStackIndex(TINT stackIndex)
PTRBSections::MemoryStream * GetStack(PTRBSections §, TUINT index)
PTRBSections::MemoryStream::Ptr< T > GetByIndex(PTRBSections *sect, TUINT index)
void Read(Toshi::TTSFI &ttsfi, PTRBSections §, Endianess eEndianess)
TBOOL ReadFromFile(Toshi::T2StringView filepath)
PTRBSymbols * GetSymbols()
T ConvertEndianess(T a_numValue)
PTRBSections * GetSections()
static constexpr Toshi::TVersion VERSION
Endianess GetEndianess() const
TBOOL WriteToFile(Toshi::T2StringView filepath, TBOOL compress=false)
PTRB(Toshi::T2StringView filepath)
PTRB(Endianess a_eEndianess=Endianess_Little)