1+ using System ;
2+ using System . IO ;
3+ using System . Collections . Generic ;
4+ using Newtonsoft . Json ;
5+ using System . ComponentModel . DataAnnotations ;
6+ using System . Reflection . Emit ;
7+ using System . Reflection . Metadata ;
8+ using Newtonsoft . Json . Converters ;
9+
10+ namespace DC2AP
11+ {
12+ static class Program
13+ {
14+ static void Main ( string [ ] args )
15+ {
16+ Console . WriteLine ( "SB2 File Parser" ) ;
17+ Console . WriteLine ( "Written by ArsonAssassin" ) ;
18+ var sb2Path = "" ;
19+ if ( args . Length > 0 )
20+ {
21+ sb2Path = args [ 0 ] ;
22+ }
23+ else
24+ {
25+ Console . WriteLine ( "Please input SB2 file path" ) ;
26+ sb2Path = Console . ReadLine ( ) ;
27+ }
28+ SB2 fullFile = new SB2 ( ) ;
29+ using ( var fileStream = new FileStream ( sb2Path , FileMode . Open , FileAccess . Read ) )
30+ using ( var reader = new BinaryReader ( fileStream ) )
31+ {
32+ //Parse Header
33+ fullFile . Header = new SB2Header ( ) ;
34+ var magic = new string ( reader . ReadChars ( 4 ) ) ;
35+ if ( magic != "SB2\0 " )
36+ throw new InvalidDataException ( "Invalid magic number in header." ) ;
37+ fullFile . Header . Magic = magic ;
38+ fullFile . Header . unk_function_data_offset = ReadUint ( reader ) ;
39+ fullFile . Header . codeStartByteOffset = ReadUint ( reader ) ;
40+ fullFile . Header . header_byte_count = ReadUint ( reader ) ;
41+ fullFile . Header . external_function_count = ReadUint ( reader ) ;
42+ fullFile . Header . unk0 = ReadUint ( reader ) ;
43+ fullFile . Header . global_variable_count = ReadUint ( reader ) ;
44+
45+ fullFile . Header . unk1 = ReadUint ( reader ) ;
46+ fullFile . Header . unk2 = ReadUint ( reader ) ;
47+ fullFile . Header . unk3 = ReadUint ( reader ) ;
48+ fullFile . Header . unk4 = ReadUint ( reader ) ;
49+ fullFile . Header . unk5 = ReadUint ( reader ) ;
50+ fullFile . Header . unk6 = ReadUint ( reader ) ;
51+ fullFile . Header . unk7 = ReadUint ( reader ) ;
52+ fullFile . Header . unk8 = ReadUint ( reader ) ;
53+ fullFile . Header . unk9 = ReadUint ( reader ) ;
54+
55+ Console . WriteLine ( "Header Parsed successfully" ) ;
56+ Console . WriteLine ( JsonConvert . SerializeObject ( fullFile . Header , Formatting . Indented ) ) ;
57+ fullFile . ExternalFunctionTable = new List < SB2ExternalFunctionTableEntry > ( ) ;
58+ for ( int i = 0 ; i < fullFile . Header . external_function_count ; i ++ )
59+ {
60+ SB2ExternalFunctionTableEntry sB2ExternalFunctionTableEntry = new SB2ExternalFunctionTableEntry ( ) ;
61+ sB2ExternalFunctionTableEntry . Id = ReadUint ( reader ) ;
62+ sB2ExternalFunctionTableEntry . function_data_byte_offset = ReadUint ( reader ) ;
63+ fullFile . ExternalFunctionTable . Add ( sB2ExternalFunctionTableEntry ) ;
64+ }
65+ Console . WriteLine ( "External Function Table Parsed successfully" ) ;
66+ Console . WriteLine ( JsonConvert . SerializeObject ( fullFile . ExternalFunctionTable , Formatting . Indented ) ) ;
67+ fullFile . Functions = new List < SB2Function > ( ) ;
68+ for ( int i = 0 ; i < fullFile . ExternalFunctionTable . Count ; i ++ )
69+ {
70+ var functionEntry = fullFile . ExternalFunctionTable [ i ] ;
71+ SB2Function func = new SB2Function ( ) ;
72+ func . Instructions = new List < Sb2Instruction > ( ) ;
73+ reader . BaseStream . Seek ( functionEntry . function_data_byte_offset , SeekOrigin . Begin ) ;
74+ func . CodeStartOffset = ReadUint ( reader ) ;
75+ func . NameByteOffset = ReadUint ( reader ) ;
76+ func . StackSize = ReadUint ( reader ) ;
77+ func . ArgumentCount = ReadUint ( reader ) ;
78+ func . unk0 = ReadUint ( reader ) ;
79+ func . unk1 = ReadUint ( reader ) ;
80+ func . unk2 = ReadUint ( reader ) ;
81+ func . unk3 = ReadUint ( reader ) ;
82+ func . unk4 = ReadUint ( reader ) ;
83+ func . unk5 = ReadUint ( reader ) ;
84+ func . unk6 = ReadUint ( reader ) ;
85+ func . unk7 = ReadUint ( reader ) ;
86+ func . unk8 = ReadUint ( reader ) ;
87+ func . unk9 = ReadUint ( reader ) ;
88+
89+ reader . BaseStream . Seek ( func . CodeStartOffset , SeekOrigin . Begin ) ;
90+ OpCode currentOpCode = OpCode . count ;
91+ while ( ! ( currentOpCode == OpCode . _end ) )
92+ {
93+ var instruction = ReadInstruction ( reader ) ;
94+ func . Instructions . Add ( instruction ) ;
95+ currentOpCode = instruction . OpCode ;
96+ }
97+ if ( fullFile . ExternalFunctionTable . Last ( ) . Id != functionEntry . Id )
98+ {
99+ var nextFuncStart = fullFile . ExternalFunctionTable [ i + 1 ] . function_data_byte_offset ;
100+ var currentLocation = reader . BaseStream . Position ;
101+ var currentDataSize = nextFuncStart - reader . BaseStream . Position ;
102+ byte [ ] localData = new byte [ currentDataSize ] ;
103+ reader . BaseStream . Read ( localData , 0 , localData . Length ) ;
104+ func . LocalData = localData ;
105+ }
106+ else
107+ {
108+ var currentLocation = reader . BaseStream . Position ;
109+ var currentDataSize = reader . BaseStream . Length - reader . BaseStream . Position ;
110+ byte [ ] localData = new byte [ currentDataSize ] ;
111+ reader . BaseStream . Read ( localData , 0 , localData . Length ) ;
112+ func . LocalData = localData ;
113+ }
114+
115+ fullFile . Functions . Add ( func ) ;
116+ Console . WriteLine ( "Function read successfully" ) ;
117+ Console . WriteLine ( JsonConvert . SerializeObject ( func , Formatting . Indented ) ) ;
118+ }
119+ Console . WriteLine ( "Function list extract complete" ) ;
120+ }
121+
122+ Console . WriteLine ( "File Parsed Successfully." ) ;
123+ var json = JsonConvert . SerializeObject ( fullFile , Formatting . Indented ) ;
124+ var jsonPath = sb2Path . Replace ( ".stb" , ".json" ) ;
125+ File . WriteAllText ( jsonPath , json ) ;
126+ }
127+
128+ private static uint ReadUint ( BinaryReader reader )
129+ {
130+ var bytes = reader . ReadBytes ( 4 ) ;
131+ return BitConverter . ToUInt32 ( bytes , 0 ) ;
132+ }
133+ private static Sb2Instruction ReadInstruction ( BinaryReader reader )
134+ {
135+ var instruction = new Sb2Instruction ( ) ;
136+ var instructionBits = ReadUint ( reader ) ;
137+ instruction . OpCode = ( OpCode ) ( instructionBits & 0xFF ) ;
138+
139+ switch ( instruction . OpCode )
140+ {
141+ case OpCode . _push_stack :
142+ case OpCode . _push_ptr :
143+ instruction . Mode = ( instructionBits >> 24 ) & 0xFF ;
144+ instruction . Address = ( instructionBits >> 8 ) & 0xFFFF ;
145+ break ;
146+ case OpCode . _push :
147+ instruction . Value = ( instructionBits >> 12 ) & 0xFFF ;
148+ instruction . Type = ( DataType ) ( ( instructionBits >> 8 ) & 0xF ) ;
149+ break ;
150+ case OpCode . _cmp :
151+ instruction . Function = ( ComparisonFunction ) ( ( instructionBits >> 8 ) & 0xF ) ;
152+ break ;
153+ case OpCode . _jmp :
154+ instruction . Address = ( instructionBits >> 8 ) & 0xFFFFFF ;
155+ break ;
156+ case OpCode . _bf :
157+ case OpCode . _bt :
158+ instruction . Address = ( instructionBits >> 8 ) & 0xFFFFFF ;
159+ instruction . Restore = ( instructionBits >> 24 ) & 0xFF ;
160+ break ;
161+ case OpCode . _div :
162+ case OpCode . _mod :
163+ case OpCode . _neg :
164+ case OpCode . _itof :
165+ case OpCode . _ftoi :
166+ case OpCode . _deref :
167+ case OpCode . _pop :
168+ case OpCode . _add :
169+ case OpCode . _sub :
170+ case OpCode . _mul :
171+ // These opcodes follow the Empty encoding
172+ // No additional fields to extract
173+ break ;
174+ default :
175+ break ;
176+ }
177+ return instruction ;
178+ }
179+ }
180+
181+ public class SB2
182+ {
183+ public SB2Header Header { get ; set ; }
184+ public List < SB2ExternalFunctionTableEntry > ExternalFunctionTable { get ; set ; }
185+ public List < SB2Function > Functions { get ; set ; }
186+
187+
188+ }
189+ public class SB2Header ( )
190+ {
191+ public string Magic { get ; set ; }
192+ public uint unk_function_data_offset { get ; set ; }
193+ public uint codeStartByteOffset { get ; set ; }
194+ public uint header_byte_count { get ; set ; }
195+ public uint external_function_count { get ; set ; }
196+ public uint unk0 { get ; set ; }
197+ public uint global_variable_count { get ; set ; }
198+ public uint unk1 { get ; set ; }
199+ public uint unk2 { get ; set ; }
200+ public uint unk3 { get ; set ; }
201+ public uint unk4 { get ; set ; }
202+ public uint unk5 { get ; set ; }
203+ public uint unk6 { get ; set ; }
204+ public uint unk7 { get ; set ; }
205+ public uint unk8 { get ; set ; }
206+ public uint unk9 { get ; set ; }
207+ }
208+ public class SB2ExternalFunctionTableEntry
209+ {
210+ public uint Id { get ; set ; }
211+ public uint function_data_byte_offset { get ; set ; }
212+ }
213+
214+ public class SB2Function ( )
215+ {
216+ public uint CodeStartOffset { get ; set ; }
217+ public uint NameByteOffset { get ; set ; }
218+ public uint StackSize { get ; set ; }
219+ public uint ArgumentCount { get ; set ; }
220+ public uint unk0 { get ; set ; }
221+ public uint unk1 { get ; set ; }
222+ public uint unk2 { get ; set ; }
223+ public uint unk3 { get ; set ; }
224+ public uint unk4 { get ; set ; }
225+ public uint unk5 { get ; set ; }
226+ public uint unk6 { get ; set ; }
227+ public uint unk7 { get ; set ; }
228+ public uint unk8 { get ; set ; }
229+ public uint unk9 { get ; set ; }
230+ public List < Sb2Instruction > Instructions { get ; set ; }
231+ public byte [ ] LocalData { get ; set ; }
232+ }
233+ public class Sb2Instruction
234+ {
235+ [ JsonConverter ( typeof ( StringEnumConverter ) ) ]
236+ public OpCode OpCode { get ; set ; }
237+ public uint Mode { get ; set ; }
238+ public uint Address { get ; set ; }
239+ public uint Value { get ; set ; }
240+ [ JsonConverter ( typeof ( StringEnumConverter ) ) ]
241+ public DataType Type { get ; set ; }
242+ public uint Restore { get ; set ; }
243+ [ JsonConverter ( typeof ( StringEnumConverter ) ) ]
244+ public ComparisonFunction Function { get ; set ; }
245+ }
246+ public enum ComparisonFunction
247+ {
248+ _eq = 0 ,
249+ _ne = 1 ,
250+ _lt = 2 ,
251+ _le = 3 ,
252+ _gt = 4 ,
253+ _ge = 5 ,
254+ count
255+ }
256+ public enum DataType
257+ {
258+ invalid ,
259+ _int = 1 ,
260+ _flt = 2 ,
261+ _str = 3 ,
262+ _ptr = 4 ,
263+ count
264+ }
265+ public enum OpCode
266+ {
267+ _end = 0 ,
268+ _push_stack = 1 ,
269+ _push_ptr = 2 ,
270+ _push = 3 ,
271+ _pop = 4 ,
272+ _deref = 5 ,
273+ _add = 6 ,
274+ _sub = 7 ,
275+ _mul = 8 ,
276+ _div = 9 ,
277+ _mod = 10 ,
278+ _neg = 11 ,
279+ _itof = 12 ,
280+ _ftoi = 13 ,
281+ _cmp = 14 ,
282+ _ret = 15 ,
283+ _jmp = 16 ,
284+ _bf = 17 ,
285+ _bt = 18 ,
286+ _call = 19 ,
287+ _print = 20 ,
288+ _ext = 21 ,
289+ _nop = 22 ,
290+ _yld = 23 ,
291+ _and = 24 ,
292+ _or = 25 ,
293+ _not = 26 ,
294+ _exit = 27 ,
295+ _unk1 = 28 ,
296+ _sin = 29 ,
297+ _cos = 30 ,
298+ count
299+ }
300+ }
0 commit comments