OpenBarnyard
 
Loading...
Searching...
No Matches
PTRB.h
Go to the documentation of this file.
1#pragma once
2//-----------------------------------------------------------------------------
3// This plugin helps writing your own TRB (Toshi Relocatable Binary) files
4// using easy API that takes care of everything needed to make working TRB.
5// Also, supports BTEC compressing algorithm when reading or writing.
6// Note: does not work on x64 and was not tested on big endian systems!
7//-----------------------------------------------------------------------------
8
9#include <File/TTSF.h>
10#include <Toshi/TString8.h>
11#include <Toshi/T2String8.h>
12
13// TODO: replace STL classes with native TOSHI classes
14#include <vector>
15#include <string>
16
17#ifndef __TOSHI_TTRB_H__
18# error Include TTRB.h to use this extension
19#endif
20
21#ifndef __TOSHI_PLUGIN_PTRB_H__
22# define __TOSHI_PLUGIN_PTRB_H__
23#endif
24
25class PTRBHeader;
26class PTRBSections;
27class PTRBRelocations;
28class PTRBSymbols;
29
31{
32public:
33 PTRBHeader( Toshi::TVersion version );
34
35 void SetVersion( Toshi::TVersion version );
36 void SetSectionCount( int32_t count );
37 void Write( Toshi::TTSFO& ttsfo, PTRBSections& sect, Endianess eEndianess );
38 void Read( Toshi::TTSFI& ttsfi, PTRBSections& sect, Endianess eEndianess );
39
40private:
41 Toshi::TTRB::Header m_Header;
42};
43
45{
46public:
47 PTRBRelocations() = default;
48
49 void Write( Toshi::TTSFO& ttsfo, PTRBSections& sect, Endianess eEndianess );
50 void Read( Toshi::TTSFI& ttsfi, PTRBSections& sect, Endianess eEndianess );
51};
52
54{
55public:
57 {
58 public:
62
63 static constexpr TUINT BUFFER_GROW_SIZE = 4096;
64
65 template <class T>
66 class Ptr
67 {
68 public:
70 : m_Stack( TNULL ), m_Offset( 0 ) {}
72 : m_Stack( stack ), m_Offset( offset ) {}
74 : m_Stack( stack ), m_Offset( stack->GetOffset( ptr ) ) {}
75
76 T* get()
77 {
78 TASSERT( this->operator TBOOL() == TTRUE, "Pointer is null" );
79 return TREINTERPRETCAST( T*, m_Stack->GetBuffer() + m_Offset );
80 }
81
82 const T* get() const
83 {
84 TASSERT( this->operator TBOOL() == TTRUE, "Pointer is null" );
85 return TREINTERPRETCAST( const T*, m_Stack->GetBuffer() + m_Offset );
86 }
87
89 {
90 return m_Stack;
91 }
92
93 TUINT offset() const
94 {
95 return m_Offset;
96 }
97
99 {
100 TASSERT( this->operator TBOOL() == TTRUE, "Pointer is null" );
101 return *TREINTERPRETCAST( T*, m_Stack->GetBuffer() + m_Offset );
102 }
103
105 {
106 TASSERT( this->operator TBOOL() == TTRUE, "Pointer is null" );
107 return TREINTERPRETCAST( T*, m_Stack->GetBuffer() + m_Offset );
108 }
109
110 template <typename N>
111 Ptr<T> operator+( const N& a_iValue )
112 {
113 return Ptr<T>{ m_Stack, m_Offset + sizeof( T ) * a_iValue };
114 }
115
116 template <typename N>
117 Ptr<T> operator-( const N& a_iValue )
118 {
119 return Ptr<T>{ m_Stack, m_Offset - sizeof( T ) * a_iValue };
120 }
121
122 operator TBOOL() const
123 {
124 return m_Stack != TNULL;
125 }
126
127 private:
129 TUINT m_Offset;
130 };
131
138
139 public:
140 MemoryStream( TUINT32 index, Endianess eEndianess )
141 {
142 m_Index = index;
143 m_eEndianess = eEndianess;
144 m_Buffer = TNULL;
145 m_BufferPos = TNULL;
146 m_BufferSize = 0;
147 m_ExpectedSize = 0;
148 m_PtrList.reserve( 32 );
149 GrowBuffer( 0 );
150 }
151
153 {
154 TASSERT( other.m_DependentStacks.size() == 0, "Cross pointers are not supported" );
155
156 m_Index = other.m_Index;
157 m_eEndianess = other.m_eEndianess;
158 m_Buffer = TNULL;
159 m_BufferSize = 0;
160 m_ExpectedSize = other.m_ExpectedSize;
161 Resize( other.m_BufferSize );
162 m_BufferPos = m_Buffer + other.GetUsedSize();
163 Toshi::TUtil::MemCopy( m_Buffer, other.m_Buffer, other.GetUsedSize() );
164
165 m_PtrList.reserve( other.m_PtrList.size() );
166 for ( TUINT i = 0; i < other.m_PtrList.size(); i++ )
167 {
168 m_PtrList.emplace_back(
169 other.m_PtrList[ i ].Offset,
170 other.m_PtrList[ i ].DataPtr,
171 this // TODO: support cross pointers
172 );
173 }
174 }
175
177 {
178 if ( m_Buffer != TNULL )
179 {
180 delete[] m_Buffer;
181 }
182 }
183
184 TUINT Tell() { return GetUsedSize(); }
185
186 void Seek( TUINT newPos )
187 {
188 TASSERT( newPos < m_BufferSize, "Trying to seek out of buffer" );
189 m_BufferPos = m_Buffer + newPos;
190 }
191
193 {
194 TUINT32 oldIndex = m_Index;
195 m_Index = index;
196 return oldIndex;
197 }
198
199 void SetExpectedSize( TUINT32 expectedSize ) { m_ExpectedSize = expectedSize; }
200
201 TUINT32 GetExpectedSize() const { return m_ExpectedSize; }
202
203 TUINT32 GetIndex() const { return m_Index; }
204
205 TUINT GetPointerCount() const { return m_PtrList.size(); }
206
207 TCHAR* GetBuffer() const { return m_Buffer; }
208
209 TCHAR* GetBufferPos() const { return m_BufferPos; }
210
211 TUINT GetBufferSize() const { return m_BufferSize; }
212
213 TUINT GetUsedSize() const { return (TUINT)m_BufferPos - (TUINT)m_Buffer; }
214
215 TUINT GetOffset( const void* ptr ) const
216 {
217 TASSERT( (TUINT)ptr >= (TUINT)m_Buffer && (TUINT)ptr < (TUINT)m_Buffer + m_BufferSize, "Pointer is out of buffer" );
218 return (TUINT)ptr - (TUINT)m_Buffer;
219 }
220
221 template <class T>
222 void SetCrossPointer( T** outPtr, Ptr<T> ptr );
223
224 template <class T>
225 T* Write( TUINT offset, const T& value )
226 {
227 TASSERT( offset >= 0 && offset < m_BufferSize, "Offset is out of buffer" );
228 *(T*)( &m_Buffer[ offset ] ) = value;
229 return TREINTERPRETCAST( T*, &m_Buffer[ offset ] );
230 }
231
232 void Write( TUINT offset, TCHAR* value, TINT size )
233 {
234 TASSERT( offset >= 0 && offset < m_BufferSize, "Offset is out of buffer" );
235 Toshi::TUtil::MemCopy( &m_Buffer[ offset ], value, size );
236 }
237
238 template <class T>
239 Ptr<T> Alloc();
240
241 template <class T>
242 Ptr<T> Alloc( TUINT count );
243
244 Ptr<TCHAR> AllocBytes( TUINT Size );
245
246 template <class T>
247 void WritePointer( T** outPtr, const T* ptr );
248
249 template <class T>
250 void WritePointer( T** outPtr, const Ptr<T>& ptr );
251
252 template <class T>
253 Ptr<T> Alloc( T** outPtr, TUINT count );
254
255 template <class T, TUINT Count = 1>
256 Ptr<T> Alloc( T** outPtr );
257
258 void Link();
259 void Unlink();
260
261 std::vector<RelcPtr>::iterator begin() { return m_PtrList.begin(); }
262 std::vector<RelcPtr>::iterator end() { return m_PtrList.end(); }
263
264 void GrowBuffer( TUINT requiredSize );
265
266 private:
267 void Resize( TUINT size );
268
269 void AddRelocationPtr( TUINT offset, TUINT dataPtr, MemoryStream* pDataStack = TNULL )
270 {
271 m_PtrList.emplace_back( offset, dataPtr, pDataStack == TNULL ? this : pDataStack );
272 }
273
274 private:
275 TUINT32 m_Index;
276 TCHAR* m_Buffer;
277 TCHAR* m_BufferPos;
278 TUINT m_BufferSize;
279 TUINT32 m_ExpectedSize;
280 std::vector<RelcPtr> m_PtrList;
281 std::vector<MemoryStream*> m_DependentStacks;
282 Endianess m_eEndianess;
283 };
284
285public:
287 : m_eEndianess( a_eEndianess )
288 {}
289
291 {
292 Reset();
293 }
294
295 void Reset()
296 {
297 for ( auto stack : m_Stacks )
298 delete stack;
299
300 m_Stacks.clear();
301 m_eEndianess = Endianess_Little;
302 }
303
305 {
306 return m_Stacks.size();
307 }
308
310 {
311 if ( m_Stacks.size() == 0 )
312 {
313 m_eEndianess = a_eEndianess;
314 return TTRUE;
315 }
316
317 return TFALSE;
318 }
319
323
325
326 void Write( Toshi::TTSFO& ttsfo, TBOOL compress );
327 void Read( Toshi::TTSFI& ttsfi, TBOOL compressed = TFALSE, Endianess eEndianess = Endianess_Little );
328
329 std::vector<PTRBSections::MemoryStream*>::iterator begin() { return m_Stacks.begin(); }
330 std::vector<PTRBSections::MemoryStream*>::iterator end() { return m_Stacks.end(); }
331
332private:
333 std::vector<PTRBSections::MemoryStream*> m_Stacks;
334 Endianess m_eEndianess;
335};
336
338{
339public:
341 {
342 Reset();
343 }
344
345 void Reset()
346 {
347 m_Symbols.clear();
348 m_SymbolNames.clear();
349 m_Symbols.reserve( 5 );
350 m_SymbolNames.reserve( 5 );
351 }
352
353 TBOOL Is( TUINT index, const TCHAR* name )
354 {
355 TASSERT( index >= 0 && index < m_Symbols.size() );
356 auto hash = Toshi::TTRB::HashString( name );
357
358 if ( m_Symbols[ index ].NameHash == hash )
359 {
360 if ( m_SymbolNames[ index ] == name )
361 {
362 return TTRUE;
363 }
364 }
365
366 return TFALSE;
367 }
368
369 TINT FindIndex( PTRBSections& sect, const TCHAR* name )
370 {
371 auto hash = Toshi::TTRB::HashString( name );
372
373 for ( TUINT i = 0; i < m_Symbols.size(); i++ )
374 {
375 if ( m_Symbols[ i ].NameHash == hash )
376 {
377 if ( m_SymbolNames[ i ] == name )
378 {
379 return i;
380 }
381 }
382 }
383
384 return -1;
385 }
386
387 TINT FindIndex( PTRBSections* sect, const TCHAR* name )
388 {
389 return FindIndex( *sect, name );
390 }
391
392 template <class T>
394 {
395 if ( index != -1 && (TINT)m_Symbols.size() > index )
396 {
397 auto stack = sect.GetStack( m_Symbols[ index ].HDRX );
398 return { stack, m_Symbols[ index ].DataOffset };
399 }
400
401 return { TNULL, (TUINT)0 };
402 }
403
404 template <class T>
406 {
407 TINT index = FindIndex( sect, name );
408
409 if ( index != -1 )
410 {
411 auto stack = sect.GetStack( m_Symbols[ index ].HDRX );
412 return { stack, m_Symbols[ index ].DataOffset };
413 }
414
415 return { TNULL, (TUINT)0 };
416 }
417
418 template <class T>
420 {
421 return Find<T>( *sect, name );
422 }
423
425 {
426 TINT index = FindIndex( sect, name );
427
428 if ( index != -1 )
429 {
430 auto stack = sect.GetStack( m_Symbols[ index ].HDRX );
431 return stack;
432 }
433
434 return TNULL;
435 }
436
438 {
439 return FindStack( *sect, name );
440 }
441
442 template <class T>
444 {
445 TASSERT( index < m_Symbols.size() );
446
447 return {
448 sect.GetStack( m_Symbols[ index ].HDRX ),
449 m_Symbols[ index ].DataOffset
450 };
451 }
452
453 template <class T>
455 {
456 return GetByIndex<T>( *sect, index );
457 }
458
460 {
461 TASSERT( index < m_Symbols.size() );
462 return sect.GetStack( m_Symbols[ index ].HDRX );
463 }
464
466 {
467 return GetStack( *sect, index );
468 }
469
470 Toshi::T2StringView GetName( TUINT index )
471 {
472 return m_SymbolNames[ index ].GetString();
473 }
474
476 {
477 return m_Symbols.size();
478 }
479
480 void Add( PTRBSections::MemoryStream* pStream, const TCHAR* name, void* ptr )
481 {
482 m_Symbols.emplace_back( pStream->GetIndex(), 0, 0, 0, pStream->GetOffset( ptr ) );
483 m_SymbolNames.push_back( name );
484 }
485
487 {
488 auto stackIndex = pStream->GetIndex();
489
490 for ( TUINT i = 0; i < m_Symbols.size(); i++ )
491 {
492 if ( m_Symbols[ i ].HDRX == stackIndex )
493 {
494 m_Symbols[ i ].HDRX = newIndex;
495 }
496 }
497
498 pStream->SetIndex( newIndex );
499 }
500
501 void Remove( TUINT index )
502 {
503 TASSERT( index >= 0 && index < m_Symbols.size() );
504
505 m_Symbols.erase( m_Symbols.begin() + index );
506 m_SymbolNames.erase( m_SymbolNames.begin() + index );
507 }
508
509 void RemoveAllWithStackIndex( TINT stackIndex )
510 {
511 for ( TUINT i = 0; i < m_Symbols.size(); )
512 {
513 if ( m_Symbols[ i ].HDRX == stackIndex )
514 {
515 Remove( i );
516 }
517 else
518 {
519 i++;
520 }
521 }
522 }
523
524 void Write( Toshi::TTSFO& ttsfo, Endianess eEndianess )
525 {
526 TASSERT( m_Symbols.size() == m_SymbolNames.size(), "" );
527
528 TUINT32 nameOffset = 0;
529 TUINT32 symbolCount = m_Symbols.size();
530 ttsfo.Write( CONVERTENDIANESS( eEndianess, symbolCount ) );
531
532 for ( TUINT i = 0; i < m_Symbols.size(); i++ )
533 {
534 m_Symbols[ i ].NameHash = Toshi::TTRB::HashString( m_SymbolNames[ i ] );
535 m_Symbols[ i ].NameOffset = nameOffset;
536 nameOffset += m_SymbolNames[ i ].Length() + 1;
537
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 );
545 }
546
547 for ( auto& name : m_SymbolNames )
548 {
549 ttsfo.WriteRaw( name, name.Length() );
550 ttsfo.Write( (TUINT8)0 );
551 }
552 }
553
554 void Read( Toshi::TTSFI& ttsfi, PTRBSections& sect, Endianess eEndianess )
555 {
556 TUINT32 symbolCount = 0;
557 ttsfi.Read( &symbolCount );
558 symbolCount = CONVERTENDIANESS( eEndianess, symbolCount );
559
560 // Read symbols
561 TUINT symbolsSize = sizeof( Toshi::TTRB::TTRBSymbol ) * symbolCount;
562 m_Symbols.resize( symbolCount );
563 ttsfi.ReadRaw( m_Symbols.data(), symbolsSize );
564
565 // Read symbol names
566 TUINT namesSize = ttsfi.GetCurrentHunk().Size - symbolsSize;
567 m_SymbolNames.reserve( symbolCount );
568 TCHAR* namesBuffer = new TCHAR[ namesSize ];
569 ttsfi.ReadRaw( namesBuffer, namesSize );
570
571 for ( auto& symbol : m_Symbols )
572 {
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 );
578
579 const TCHAR* symbolName = &namesBuffer[ symbol.NameOffset ];
580 m_SymbolNames.push_back( symbolName );
581 }
582
583 delete[] namesBuffer;
584 }
585
586 std::vector<Toshi::TString8>::iterator begin() { return m_SymbolNames.begin(); }
587 std::vector<Toshi::TString8>::iterator end() { return m_SymbolNames.end(); }
588
589private:
590 std::vector<Toshi::TTRB::TTRBSymbol> m_Symbols;
591 std::vector<Toshi::TString8> m_SymbolNames;
592};
593
594class PTRB
595{
596public:
597 static constexpr Toshi::TVersion VERSION = { TVERSION( 1, 1 ) };
598
599public:
601 : m_HDRX( VERSION )
602 , m_eEndianess( a_eEndianess )
603 {
604 m_SECT.SetEndianess( m_eEndianess );
605 }
606
607 PTRB( Toshi::T2StringView filepath )
608 : m_HDRX( VERSION ) { ReadFromFile( filepath ); }
609
610 void Reset()
611 {
612 m_SECT.Reset();
613 m_SYMB.Reset();
614 m_SECT.SetEndianess( m_eEndianess );
615 }
616
617 TBOOL ReadFromFile( Toshi::T2StringView filepath )
618 {
619 Reset();
620
621 Toshi::TTSFI ttsfi;
622 auto pFile = Toshi::TFile::Create( filepath.Get() );
623
624 m_eEndianess = -1;
625 if ( pFile && ttsfi.Open( pFile ) == Toshi::TTRB::ERROR_OK )
626 {
627 m_eEndianess = ttsfi.GetEndianess();
628 int32_t leftSize = ttsfi.GetCurrentHunk().Size - 4;
629
630 m_SECT.SetEndianess( m_eEndianess );
631
632 while ( leftSize > sizeof( Toshi::TTSF::Hunk ) )
633 {
634 if ( ttsfi.ReadHunk() != Toshi::TTRB::ERROR_OK ) break;
635 leftSize -= ttsfi.GetCurrentHunk().Size + sizeof( Toshi::TTSF::Hunk );
636
637 switch ( ttsfi.GetCurrentHunk().Name )
638 {
639 case TFourCC( "HDRX" ):
640 m_HDRX.Read( ttsfi, m_SECT, m_eEndianess );
641 break;
642 case TFourCC( "SECT" ):
643 m_SECT.Read( ttsfi, TFALSE, m_eEndianess );
644 break;
645 case TFourCC( "SECC" ):
646 m_SECT.Read( ttsfi, TTRUE, m_eEndianess );
647 break;
648 case TFourCC( "RELC" ):
649 m_RELC.Read( ttsfi, m_SECT, m_eEndianess );
650 break;
651 case TFourCC( "SYMB" ):
652 m_SYMB.Read( ttsfi, m_SECT, m_eEndianess );
653 break;
654 }
655
656 ttsfi.SkipHunk();
657 }
658
659 ttsfi.Close( TFALSE );
660 pFile->Destroy();
661 return TTRUE;
662 }
663
664 if ( pFile != TNULL )
665 {
666 ttsfi.Close( TFALSE );
667 pFile->Destroy();
668 }
669
670 return TFALSE;
671 }
672
673 TBOOL WriteToFile( Toshi::T2StringView filepath, TBOOL compress = TFALSE )
674 {
675 if ( m_eEndianess != -1 )
676 {
677 Toshi::TTSFO ttsfo;
678 Toshi::TTSFO::HunkMark mark;
679 ttsfo.Create( filepath, ( m_eEndianess == Endianess_Big ) ? "FBRT" : "TRBF", m_eEndianess );
680
681 // HDRX
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 );
686
687 // SECT
688 if ( compress )
689 Toshi::TCompress::ms_bIsBigEndian = ( m_eEndianess == Endianess_Big );
690
691 ttsfo.OpenHunk( &mark, compress ? "SECC" : "SECT" );
692 m_SECT.Write( ttsfo, compress );
693 ttsfo.CloseHunk( &mark );
694
695 // RELC
696 ttsfo.OpenHunk( &mark, "RELC" );
697 m_RELC.Write( ttsfo, m_SECT, m_eEndianess );
698 ttsfo.CloseHunk( &mark );
699
700 // SYMB
701 ttsfo.OpenHunk( &mark, "SYMB" );
702 m_SYMB.Write( ttsfo, m_eEndianess );
703 ttsfo.CloseHunk( &mark );
704
705 ttsfo.Close();
706
707 return TTRUE;
708 }
709
710 return TFALSE;
711 }
712
713 template <typename T>
714 T ConvertEndianess( T a_numValue )
715 {
716 return CONVERTENDIANESS( m_eEndianess, a_numValue );
717 }
718
719 PTRBSymbols* GetSymbols() { return &m_SYMB; }
720 PTRBSections* GetSections() { return &m_SECT; }
721 Endianess GetEndianess() const { return m_eEndianess; }
722
723private:
724 PTRBHeader m_HDRX;
725 PTRBSections m_SECT;
726 PTRBRelocations m_RELC;
727 PTRBSymbols m_SYMB;
728 Endianess m_eEndianess;
729};
730
731inline PTRBHeader::PTRBHeader( Toshi::TVersion version )
732{
733 m_Header.m_ui32Version = version;
734 m_Header.m_i32SectionCount = 0;
735}
736
737inline void PTRBHeader::SetVersion( Toshi::TVersion version )
738{
739 m_Header.m_ui32Version = version;
740}
741
742inline void PTRBHeader::SetSectionCount( int32_t count )
743{
744 m_Header.m_i32SectionCount = count;
745}
746
747inline void PTRBHeader::Write( Toshi::TTSFO& ttsfo, PTRBSections& sect, Endianess eEndianess )
748{
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 );
752
753 ttsfo.Write( oFixedHeader );
754
755 for ( PTRBSections::MemoryStream* stack : sect )
756 {
757 Toshi::TTRB::SecInfo sectionInfo = {};
758 sectionInfo.m_Size = CONVERTENDIANESS( eEndianess, TAlignNumUp( stack->GetUsedSize() ) );
759 ttsfo.Write( sectionInfo );
760 }
761}
762
763inline void PTRBHeader::Read( Toshi::TTSFI& ttsfi, PTRBSections& sect, Endianess eEndianess )
764{
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 );
768
769 for ( TINT i = 0; i < m_Header.m_i32SectionCount; i++ )
770 {
771 Toshi::TTRB::SecInfo sectionInfo;
772 ttsfi.Read( &sectionInfo );
773
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 );
779
780 auto stack = sect.CreateStream();
781 stack->SetExpectedSize( sectionInfo.m_Size );
782 }
783}
784
785inline void PTRBRelocations::Write( Toshi::TTSFO& ttsfo, PTRBSections& sect, Endianess eEndianess )
786{
787 TUINT32 ptrCount = 0;
788 for ( auto section : sect )
789 {
790 ptrCount += section->GetPointerCount();
791 }
792
793 ttsfo.Write( CONVERTENDIANESS( eEndianess, ptrCount ) );
794
795 for ( TUINT i = 0; i < sect.GetStackCount(); i++ )
796 {
797 auto section = sect.GetStack( i );
798
799 for ( auto& ptr : *section )
800 {
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 );
806 }
807 }
808}
809
810inline void PTRBRelocations::Read( Toshi::TTSFI& ttsfi, PTRBSections& sect, Endianess eEndianess )
811{
812 TUINT32 ptrCount = 0;
813 ttsfi.Read( &ptrCount );
814
815 ptrCount = CONVERTENDIANESS( eEndianess, ptrCount );
816
817 Toshi::TTRB::RELCEntry entry;
818 for ( TUINT32 i = 0; i < ptrCount; i++ )
819 {
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 );
824
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 );
829 }
830
831 for ( auto stack : sect )
832 {
833 stack->Link();
834 }
835}
836
837template <class T>
839{
840 TASSERT( (TUINT)outPtr >= (TUINT)m_Buffer && (TUINT)outPtr < (TUINT)m_Buffer + (TUINT)m_BufferSize, "Out pointer is out of buffer" );
841 TASSERT( TNULL != ptr.stack() );
842 TASSERT( this != ptr.stack() );
843
844 TUINT outPtrOffset = GetOffset( outPtr );
845 Write<T*>( outPtrOffset, ptr.get() );
846
847 AddRelocationPtr( outPtrOffset, ptr.offset(), ptr.stack() );
848
849 // Set current stack as dependent from ptr.stack()
850 auto crossStack = ptr.stack();
851 auto it = std::find( crossStack->m_DependentStacks.begin(), crossStack->m_DependentStacks.end(), this );
852
853 if ( it == crossStack->m_DependentStacks.end() )
854 {
855 // Add this stack
856 crossStack->m_DependentStacks.push_back( this );
857 }
858}
859
860template <class T>
862{
863 m_BufferPos = TREINTERPRETCAST( TCHAR*, TAlignPointerUp( m_BufferPos ) );
864
865 constexpr TUINT TSize = sizeof( T );
866 GrowBuffer( GetUsedSize() + TSize );
867
868 T* allocated = TREINTERPRETCAST( T*, m_BufferPos );
869 m_BufferPos += TSize;
870
871 return { this, allocated };
872}
873
874template <class T>
876{
877 m_BufferPos = TREINTERPRETCAST( TCHAR*, TAlignPointerUp( m_BufferPos ) );
878
879 const TUINT TSize = sizeof( T ) * count;
880 GrowBuffer( GetUsedSize() + TSize );
881
882 T* allocated = TREINTERPRETCAST( T*, m_BufferPos );
883 m_BufferPos += TSize;
884
885 return { this, allocated };
886}
887
888template <class T>
890{
891 TASSERT( (TUINT)outPtr >= (TUINT)m_Buffer && (TUINT)outPtr < (TUINT)m_Buffer + (TUINT)m_BufferSize, "Out pointer is out of buffer" );
892 m_BufferPos = TREINTERPRETCAST( TCHAR*, TAlignPointerUp( m_BufferPos ) );
893
894 const TUINT TSize = sizeof( T ) * count;
895 TUINT outPtrOffset = GetOffset( outPtr );
896 GrowBuffer( GetUsedSize() + TSize );
897
898 T* allocated = TREINTERPRETCAST( T*, m_BufferPos );
899 m_BufferPos += TSize;
900
901 Write<T*>( outPtrOffset, allocated );
902 AddRelocationPtr( outPtrOffset, CONVERTENDIANESS( m_eEndianess, GetOffset( allocated ) ) );
903
904 return { this, allocated };
905}
906
907template <class T, TUINT Count>
909{
910 TASSERT( (TUINT)outPtr >= (TUINT)m_Buffer && (TUINT)outPtr < (TUINT)m_Buffer + (TUINT)m_BufferSize, "Out pointer is out of buffer" );
911 m_BufferPos = TREINTERPRETCAST( TCHAR*, TAlignPointerUp( m_BufferPos ) );
912
913 constexpr TUINT TSize = sizeof( T ) * Count;
914 TUINT outPtrOffset = GetOffset( outPtr );
915 GrowBuffer( GetUsedSize() + TSize );
916
917 T* allocated = TREINTERPRETCAST( T*, m_BufferPos );
918 m_BufferPos += TSize;
919
920 Write<T*>( outPtrOffset, allocated );
921 AddRelocationPtr( outPtrOffset, CONVERTENDIANESS( m_eEndianess, GetOffset( allocated ) ) );
922
923 return { this, allocated };
924}
925
926template <class T>
927inline void PTRBSections::MemoryStream::WritePointer( T** outPtr, const T* ptr )
928{
929 TASSERT( (TUINT)outPtr >= (TUINT)m_Buffer && (TUINT)outPtr < (TUINT)m_Buffer + (TUINT)m_BufferSize, "Out pointer is out of buffer" );
930 TASSERT( (TUINT)ptr >= (TUINT)m_Buffer && (TUINT)ptr < (TUINT)m_Buffer + (TUINT)m_BufferSize, "Pointer is out of buffer" );
931
932 TUINT outPtrOffset = GetOffset( outPtr );
933 Write<TUINT32>( outPtrOffset, TREINTERPRETCAST( TUINT32, ptr ) );
934 AddRelocationPtr( outPtrOffset, CONVERTENDIANESS( m_eEndianess, GetOffset( ptr ) ) );
935}
936
937template <class T>
939{
940 TASSERT( (TUINT)outPtr >= (TUINT)m_Buffer && (TUINT)outPtr < (TUINT)m_Buffer + (TUINT)m_BufferSize, "Out pointer is out of buffer" );
941
942 TUINT outPtrOffset = GetOffset( outPtr );
943 Write<TUINT32>( outPtrOffset, TREINTERPRETCAST( TUINT32, ptr.get() ) );
944 AddRelocationPtr( outPtrOffset, CONVERTENDIANESS( m_eEndianess, ptr.offset() ) );
945}
946
948{
949 GrowBuffer( GetUsedSize() + Size );
950
951 TCHAR* allocated = reinterpret_cast<TCHAR*>( m_BufferPos );
952 m_BufferPos += Size;
953
954 return { this, allocated };
955}
956
958{
959 for ( auto& ptr : m_PtrList )
960 {
961 Write<void*>( ptr.Offset, ptr.DataStack->GetBuffer() + CONVERTENDIANESS( m_eEndianess, ptr.DataPtr ) );
962 }
963}
964
966{
967 for ( auto& ptr : m_PtrList )
968 {
969 Write<void*>( ptr.Offset, (void*)ptr.DataPtr );
970 }
971}
972
974{
975 TUINT newSize = ( ( requiredSize / BUFFER_GROW_SIZE ) + 1 ) * BUFFER_GROW_SIZE;
976
977 if ( newSize != m_BufferSize )
978 {
979 Resize( newSize );
980 }
981}
982
983inline void PTRBSections::MemoryStream::Resize( TUINT size )
984{
985 TASSERT( size > 0, "Size should be positive" );
986 //TASSERT(size != m_BufferSize, "Size is the same");
987 //TASSERT(size > m_BufferSize, "Buffer can't shrink");
988
989 TCHAR* oldBuffer = m_Buffer;
990 TUINT usedSize = GetUsedSize();
991 m_Buffer = new TCHAR[ size ];
992 m_BufferSize = size;
993
994 Toshi::TUtil::MemClear( m_Buffer, size );
995
996 if ( oldBuffer != TNULL )
997 {
998 Toshi::TUtil::MemCopy( m_Buffer, oldBuffer, usedSize );
999 m_BufferPos = m_Buffer + usedSize;
1000 delete[] oldBuffer;
1001 }
1002 else
1003 {
1004 m_BufferPos = m_Buffer;
1005 }
1006
1007 Link();
1008}
1009
1011{
1012 PTRBSections::MemoryStream* stack = new PTRBSections::MemoryStream( m_Stacks.size(), m_eEndianess );
1013 m_Stacks.push_back( stack );
1014 return stack;
1015}
1016
1018{
1020 stack->SetIndex( m_Stacks.size() );
1021 m_Stacks.push_back( stack );
1022 return stack;
1023}
1024
1026{
1027 auto result = std::find( m_Stacks.begin(), m_Stacks.end(), pStream );
1028
1029 if ( result != m_Stacks.end() )
1030 {
1031 pSymb->RemoveAllWithStackIndex( pStream->GetIndex() );
1032
1033 m_Stacks.erase( result );
1034 delete pStream;
1035
1036 // Update indexes
1037 TUINT32 index = 0;
1038 for ( auto it = m_Stacks.begin(); it != m_Stacks.end(); it++ )
1039 {
1040 auto stack = *it;
1041 pSymb->UpdateSymbolsIndexes( stack, index++ );
1042 }
1043
1044 return TTRUE;
1045 }
1046 else
1047 {
1048 return TFALSE;
1049 }
1050}
1051
1053{
1054 TASSERT( index >= 0 && index < GetStackCount(), "Index is out of bounds" );
1055 return m_Stacks[ index ];
1056}
1057
1058inline void PTRBSections::Write( Toshi::TTSFO& ttsfo, TBOOL compress )
1059{
1060 TUINT ready = 0;
1061 TUINT count = m_Stacks.size();
1062
1063 if ( compress )
1064 {
1065 if ( count > 1 )
1066 {
1067 TTRACE( "Compressing progress: 0%\n" );
1068 }
1069 else
1070 {
1071 TTRACE( "Started BTEC compression...\n" );
1072 }
1073 }
1074
1075 for ( auto stack : m_Stacks )
1076 {
1077 stack->Unlink();
1078
1079 if ( compress )
1080 {
1081 ttsfo.WriteCompressed( stack->GetBuffer(), stack->GetUsedSize() );
1082 ready += 1;
1083
1084 if ( count > 1 )
1085 {
1086 TTRACE( "Compressing progress: %.1f\n", (double)ready / count * 100 );
1087 }
1088 else
1089 {
1090 TTRACE( "BTEC compression completed...\n" );
1091 }
1092 }
1093 else
1094 {
1095 ttsfo.WriteRaw( stack->GetBuffer(), stack->GetUsedSize() );
1096 }
1097
1098 ttsfo.WriteAlignmentPad();
1099 stack->Link();
1100 }
1101}
1102
1103inline void PTRBSections::Read( Toshi::TTSFI& ttsfi, TBOOL compressed, Endianess eEndianess )
1104{
1105 m_eEndianess = eEndianess;
1106
1107 for ( auto stack : m_Stacks )
1108 {
1109 TUINT expectedSize = stack->GetExpectedSize();
1110
1111 if ( expectedSize > 0 )
1112 {
1113 stack->GrowBuffer( expectedSize );
1114
1115 if ( compressed )
1116 {
1117 Toshi::TCompress::ms_bIsBigEndian = ( eEndianess == Endianess_Big );
1118 ttsfi.ReadCompressed( stack->GetBuffer(), expectedSize );
1119 }
1120 else
1121 {
1122 ttsfi.ReadRaw( stack->GetBuffer(), expectedSize );
1123 }
1124
1125 stack->Seek( expectedSize );
1126 stack->SetExpectedSize( 0 );
1127 }
1128 }
1129}
#define TASSERT(X,...)
Definition Defines.h:138
#define TREINTERPRETCAST(TYPE, VALUE)
Definition Defines.h:68
#define TVERSION(VER_MAJOR, VER_MINOR)
Definition Defines.h:14
#define TTRACE(...)
Definition Defines.h:155
@ Endianess_Big
Definition Endianness.h:9
@ Endianess_Little
Definition Endianness.h:8
TUINT8 Endianess
Definition Endianness.h:5
TFORCEINLINE constexpr T * TAlignPointerUp(T *a_pMem, TSIZE a_uiAlignment=sizeof(T *))
Definition Helpers.h:41
TFORCEINLINE constexpr T TAlignNumUp(T a_iValue, TSIZE a_uiAlignment=4)
Definition Helpers.h:66
TFORCEINLINE constexpr TUINT32 TFourCC(const TCHAR str[4])
Definition Helpers.h:15
Char string implementation for the Toshi engine.
unsigned int TUINT
Definition Typedefs.h:8
int16_t TINT16
Definition Typedefs.h:14
char TCHAR
Definition Typedefs.h:20
uint8_t TUINT8
Definition Typedefs.h:17
#define TNULL
Definition Typedefs.h:23
uint32_t TUINT32
Definition Typedefs.h:13
int TINT
Definition Typedefs.h:7
#define TFALSE
Definition Typedefs.h:24
#define TTRUE
Definition Typedefs.h:25
bool TBOOL
Definition Typedefs.h:6
void SetSectionCount(int32_t count)
Definition PTRB.h:742
PTRBHeader(Toshi::TVersion version)
Definition PTRB.h:731
void Read(Toshi::TTSFI &ttsfi, PTRBSections &sect, Endianess eEndianess)
Definition PTRB.h:763
void Write(Toshi::TTSFO &ttsfo, PTRBSections &sect, Endianess eEndianess)
Definition PTRB.h:747
void SetVersion(Toshi::TVersion version)
Definition PTRB.h:737
void Read(Toshi::TTSFI &ttsfi, PTRBSections &sect, Endianess eEndianess)
Definition PTRB.h:810
void Write(Toshi::TTSFO &ttsfo, PTRBSections &sect, Endianess eEndianess)
Definition PTRB.h:785
PTRBRelocations()=default
~PTRBSections()
Definition PTRB.h:290
std::vector< PTRBSections::MemoryStream * >::iterator end()
Definition PTRB.h:330
TBOOL DeleteStack(PTRBSymbols *pSymb, PTRBSections::MemoryStream *pStream)
Definition PTRB.h:1025
std::vector< PTRBSections::MemoryStream * >::iterator begin()
Definition PTRB.h:329
TBOOL SetEndianess(Endianess a_eEndianess)
Definition PTRB.h:309
PTRBSections::MemoryStream * CreateStream()
Definition PTRB.h:1010
void Reset()
Definition PTRB.h:295
void Read(Toshi::TTSFI &ttsfi, TBOOL compressed=false, Endianess eEndianess=Endianess_Little)
Definition PTRB.h:1103
void Write(Toshi::TTSFO &ttsfo, TBOOL compress)
Definition PTRB.h:1058
PTRBSections(Endianess a_eEndianess=Endianess_Little)
Definition PTRB.h:286
PTRBSections::MemoryStream * GetStack(TUINT index)
Definition PTRB.h:1052
TUINT GetStackCount() const
Definition PTRB.h:304
TUINT32 SetIndex(TUINT32 index)
Definition PTRB.h:192
TUINT32 GetExpectedSize() const
Definition PTRB.h:201
void WritePointer(T **outPtr, const T *ptr)
Definition PTRB.h:927
MemoryStream(const MemoryStream &other)
Definition PTRB.h:152
void Seek(TUINT newPos)
Definition PTRB.h:186
TUINT32 GetIndex() const
Definition PTRB.h:203
std::vector< RelcPtr >::iterator end()
Definition PTRB.h:262
TUINT GetPointerCount() const
Definition PTRB.h:205
static constexpr TUINT BUFFER_GROW_SIZE
Definition PTRB.h:63
void SetCrossPointer(T **outPtr, Ptr< T > ptr)
Definition PTRB.h:838
T * Write(TUINT offset, const T &value)
Definition PTRB.h:225
std::vector< RelcPtr >::iterator begin()
Definition PTRB.h:261
void GrowBuffer(TUINT requiredSize)
Definition PTRB.h:973
TUINT GetOffset(const void *ptr) const
Definition PTRB.h:215
TCHAR * GetBufferPos() const
Definition PTRB.h:209
MemoryStream(TUINT32 index, Endianess eEndianess)
Definition PTRB.h:140
TUINT GetUsedSize() const
Definition PTRB.h:213
Ptr< TCHAR > AllocBytes(TUINT Size)
Definition PTRB.h:947
void SetExpectedSize(TUINT32 expectedSize)
Definition PTRB.h:199
TCHAR * GetBuffer() const
Definition PTRB.h:207
void Write(TUINT offset, TCHAR *value, TINT size)
Definition PTRB.h:232
TUINT GetBufferSize() const
Definition PTRB.h:211
Ptr(PTRBSections::MemoryStream *stack, TUINT offset)
Definition PTRB.h:71
Ptr(PTRBSections::MemoryStream *stack, T *ptr)
Definition PTRB.h:73
Ptr< T > operator-(const N &a_iValue)
Definition PTRB.h:117
Ptr< T > operator+(const N &a_iValue)
Definition PTRB.h:111
const T * get() const
Definition PTRB.h:82
PTRBSections::MemoryStream * stack()
Definition PTRB.h:88
PTRBSections::MemoryStream * DataStack
Definition PTRB.h:136
PTRBSections::MemoryStream::Ptr< T > Find(PTRBSections *sect, const TCHAR *name)
Definition PTRB.h:419
PTRBSections::MemoryStream * FindStack(PTRBSections *sect, const TCHAR *name)
Definition PTRB.h:437
TINT FindIndex(PTRBSections &sect, const TCHAR *name)
Definition PTRB.h:369
std::vector< Toshi::TString8 >::iterator end()
Definition PTRB.h:587
void Add(PTRBSections::MemoryStream *pStream, const TCHAR *name, void *ptr)
Definition PTRB.h:480
void Remove(TUINT index)
Definition PTRB.h:501
PTRBSections::MemoryStream * GetStack(PTRBSections *sect, TUINT index)
Definition PTRB.h:465
PTRBSections::MemoryStream * FindStack(PTRBSections &sect, const TCHAR *name)
Definition PTRB.h:424
TINT FindIndex(PTRBSections *sect, const TCHAR *name)
Definition PTRB.h:387
void UpdateSymbolsIndexes(PTRBSections::MemoryStream *pStream, TUINT32 newIndex)
Definition PTRB.h:486
PTRBSymbols()
Definition PTRB.h:340
void Write(Toshi::TTSFO &ttsfo, Endianess eEndianess)
Definition PTRB.h:524
PTRBSections::MemoryStream::Ptr< T > GetByIndex(PTRBSections &sect, TUINT index)
Definition PTRB.h:443
PTRBSections::MemoryStream::Ptr< T > Find(PTRBSections &sect, const TCHAR *name)
Definition PTRB.h:405
TBOOL Is(TUINT index, const TCHAR *name)
Definition PTRB.h:353
void Reset()
Definition PTRB.h:345
PTRBSections::MemoryStream::Ptr< T > Get(PTRBSections &sect, TINT index)
Definition PTRB.h:393
std::vector< Toshi::TString8 >::iterator begin()
Definition PTRB.h:586
Toshi::T2StringView GetName(TUINT index)
Definition PTRB.h:470
void RemoveAllWithStackIndex(TINT stackIndex)
Definition PTRB.h:509
PTRBSections::MemoryStream * GetStack(PTRBSections &sect, TUINT index)
Definition PTRB.h:459
PTRBSections::MemoryStream::Ptr< T > GetByIndex(PTRBSections *sect, TUINT index)
Definition PTRB.h:454
void Read(Toshi::TTSFI &ttsfi, PTRBSections &sect, Endianess eEndianess)
Definition PTRB.h:554
TUINT GetCount()
Definition PTRB.h:475
TBOOL ReadFromFile(Toshi::T2StringView filepath)
Definition PTRB.h:617
PTRBSymbols * GetSymbols()
Definition PTRB.h:719
T ConvertEndianess(T a_numValue)
Definition PTRB.h:714
PTRBSections * GetSections()
Definition PTRB.h:720
static constexpr Toshi::TVersion VERSION
Definition PTRB.h:597
Endianess GetEndianess() const
Definition PTRB.h:721
TBOOL WriteToFile(Toshi::T2StringView filepath, TBOOL compress=false)
Definition PTRB.h:673
PTRB(Toshi::T2StringView filepath)
Definition PTRB.h:607
void Reset()
Definition PTRB.h:610
PTRB(Endianess a_eEndianess=Endianess_Little)
Definition PTRB.h:600