1+ using System ;
2+ using System . Collections . Generic ;
3+
4+ namespace YukimiScript . Runtime . Bytecode . Parser
5+ {
6+ public sealed class YukimiScriptBinary
7+ {
8+ const uint riffBlockID = 0x46464952 ;
9+ const uint yukiMagicCode = 0x494B5559 ;
10+ const uint cstrBlockID = 0x52545343 ;
11+ const uint extrBlockID = 0x52545845 ;
12+ const uint scenBlockID = 0x4E454353 ;
13+ const uint dbgsBlockID = 0x53474244 ;
14+
15+ readonly byte [ ] bytes ;
16+
17+ uint ReadUInt32 ( uint offset )
18+ {
19+ if ( offset + 4 >= bytes . Length )
20+ throw new InvalidYukimiScriptBinary ( ) ;
21+
22+ uint r = 0 ;
23+ r |= bytes [ offset ] ;
24+ r |= ( ( uint ) bytes [ offset + 1 ] ) << 8 ;
25+ r |= ( ( uint ) bytes [ offset + 2 ] ) << 16 ;
26+ r |= ( ( uint ) bytes [ offset + 3 ] ) << 24 ;
27+ return r ;
28+ }
29+
30+ public sealed class InvalidYukimiScriptBinary : Exception { } ;
31+
32+ public readonly struct Block
33+ {
34+ public readonly YukimiScriptBinary Bin ;
35+ public readonly uint Type ;
36+ public readonly uint DataPointer ;
37+ public readonly uint DataEndPointer ;
38+ public readonly uint Size ;
39+
40+ public Block ( YukimiScriptBinary binary , ref uint offset )
41+ {
42+ Bin = binary ;
43+ Type = binary . ReadUInt32 ( offset ) ;
44+ Size = binary . ReadUInt32 ( offset + 4 ) ;
45+ DataPointer = offset + 8 ;
46+ DataEndPointer = offset = DataPointer + Size ;
47+
48+ if ( offset > binary . bytes . Length )
49+ throw new InvalidYukimiScriptBinary ( ) ;
50+ }
51+ }
52+
53+ public readonly IReadOnlyList < Block > SceneBlocks ;
54+ readonly Block cstrBlock ;
55+ readonly Block extrBlock ;
56+
57+ public sealed class SceneParser
58+ {
59+ public readonly Block Block ;
60+ public readonly uint SceneNameCStrPointer ;
61+ public uint Offset => offsetInFile - Block . DataPointer ;
62+ uint offsetInFile ;
63+
64+ public SceneParser ( Block scenBlock )
65+ {
66+ Block = scenBlock ;
67+ SceneNameCStrPointer = scenBlock
68+ . Bin
69+ . ReadUInt32 ( scenBlock . DataPointer ) ;
70+
71+ offsetInFile = scenBlock . DataPointer + 4 ;
72+ }
73+
74+ public bool ReadCommand (
75+ out ushort commandID ,
76+ out ushort argumentsCount )
77+ {
78+ commandID = 0 ;
79+ argumentsCount = 0 ;
80+
81+ if ( offsetInFile + 4 >= Block . DataEndPointer )
82+ return false ;
83+
84+ commandID |= Block . Bin . bytes [ offsetInFile ] ;
85+ commandID |= ( ushort ) ( Block . Bin . bytes [ offsetInFile + 1 ] << 8 ) ;
86+ argumentsCount |= Block . Bin . bytes [ offsetInFile + 2 ] ;
87+ argumentsCount |= ( ushort ) ( Block . Bin . bytes [ offsetInFile + 3 ] << 8 ) ;
88+ offsetInFile += 4 ;
89+ return true ;
90+ }
91+
92+ public enum ArgumentType
93+ {
94+ Int = 0 ,
95+ Float = 1 ,
96+ String = 2 ,
97+ Symbol = 3
98+ }
99+
100+ readonly byte [ ] temp = new byte [ 4 ] ;
101+
102+ public ArgumentType ReadArgument (
103+ out int argInt ,
104+ out float argFloat ,
105+ out uint argCStrPointerString )
106+ {
107+ argInt = 0 ;
108+ argFloat = 0 ;
109+ argCStrPointerString = 0 ;
110+
111+ var first = ( int ) Block . Bin . ReadUInt32 ( offsetInFile ) ;
112+ offsetInFile += 4 ;
113+
114+ if ( first == 0 )
115+ {
116+ argInt = ( int ) Block . Bin . ReadUInt32 ( offsetInFile ) ;
117+ offsetInFile += 4 ;
118+ return ArgumentType . Int ;
119+ }
120+ else if ( first == 1 )
121+ {
122+ if ( BitConverter . IsLittleEndian )
123+ {
124+ temp [ 0 ] = Block . Bin . bytes [ offsetInFile + 0 ] ;
125+ temp [ 1 ] = Block . Bin . bytes [ offsetInFile + 1 ] ;
126+ temp [ 2 ] = Block . Bin . bytes [ offsetInFile + 2 ] ;
127+ temp [ 3 ] = Block . Bin . bytes [ offsetInFile + 3 ] ;
128+ }
129+ else
130+ {
131+ temp [ 0 ] = Block . Bin . bytes [ offsetInFile + 3 ] ;
132+ temp [ 1 ] = Block . Bin . bytes [ offsetInFile + 2 ] ;
133+ temp [ 2 ] = Block . Bin . bytes [ offsetInFile + 1 ] ;
134+ temp [ 3 ] = Block . Bin . bytes [ offsetInFile + 0 ] ;
135+ }
136+
137+ argFloat = BitConverter . ToSingle ( temp , 0 ) ;
138+ offsetInFile += 4 ;
139+ return ArgumentType . Float ;
140+ }
141+ else if ( first >= 2 )
142+ {
143+ argCStrPointerString = ( uint ) first - 2 ;
144+ return ArgumentType . String ;
145+ }
146+ else if ( first <= - 1 )
147+ {
148+ argCStrPointerString = ( uint ) Math . Abs ( first + 1 ) ;
149+ return ArgumentType . Symbol ;
150+ }
151+
152+ throw new InvalidYukimiScriptBinary ( ) ;
153+ }
154+ }
155+
156+ public IEnumerable < uint > ExternDefinitionCStrPointers
157+ {
158+ get
159+ {
160+ for (
161+ uint offset = extrBlock . DataPointer ;
162+ offset < extrBlock . DataEndPointer ;
163+ offset += 4 )
164+ {
165+ yield return ReadUInt32 ( offset ) ;
166+ }
167+ }
168+ }
169+
170+ public YukimiScriptBinary ( byte [ ] bytes )
171+ {
172+ this . bytes = bytes ;
173+
174+ if ( ReadUInt32 ( 0 ) != riffBlockID )
175+ throw new InvalidYukimiScriptBinary ( ) ;
176+
177+ if ( ReadUInt32 ( 4 ) + 8 != bytes . Length )
178+ throw new InvalidYukimiScriptBinary ( ) ;
179+
180+ if ( ReadUInt32 ( 8 ) != yukiMagicCode )
181+ throw new InvalidYukimiScriptBinary ( ) ;
182+
183+ Block ? cstrBlock = null ;
184+ Block ? extrBlock = null ;
185+ List < Block > scenBlocks = new ( ) ;
186+
187+ for ( uint offset = 12 ; offset < bytes . Length ; )
188+ {
189+ Block b = new ( this , ref offset ) ;
190+
191+ if ( b . Type == cstrBlockID && cstrBlock == null )
192+ cstrBlock = b ;
193+ else if ( b . Type == extrBlockID && extrBlock == null )
194+ extrBlock = b ;
195+ else if ( b . Type == scenBlockID )
196+ scenBlocks . Add ( b ) ;
197+ else if ( b . Type != dbgsBlockID ) { }
198+ else
199+ throw new InvalidYukimiScriptBinary ( ) ;
200+ }
201+
202+ if ( cstrBlock == null )
203+ throw new InvalidYukimiScriptBinary ( ) ;
204+
205+ if ( extrBlock == null )
206+ throw new InvalidYukimiScriptBinary ( ) ;
207+
208+ this . cstrBlock = cstrBlock . Value ;
209+ this . extrBlock = extrBlock . Value ;
210+ this . SceneBlocks = scenBlocks . ToArray ( ) ;
211+
212+ Console . WriteLine ( "Scen Blocks:" + scenBlocks . Count ) ;
213+ }
214+
215+ public string GetStringByCStrPointer ( uint cstrPointer )
216+ {
217+ int len = 0 ;
218+ while ( bytes [ cstrBlock . DataPointer + cstrPointer + len ] != '\0 ' )
219+ len ++ ;
220+
221+ return System . Text . Encoding . UTF8 . GetString (
222+ bytes , ( int ) ( cstrBlock . DataPointer + cstrPointer ) , len ) ;
223+ }
224+ }
225+ }
0 commit comments