Skip to content

Commit 6953d62

Browse files
committed
添加YukimiScript.Runtime.Bytecode.Parser
1 parent f4170d8 commit 6953d62

File tree

3 files changed

+351
-93
lines changed

3 files changed

+351
-93
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>net462;netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
5+
<ImplicitUsings>disable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
<LangVersion>9.0</LangVersion>
8+
<Version>0.8.6</Version>
9+
<Authors>Seng Jik</Authors>
10+
<Company>Strrationalism</Company>
11+
<PackageProjectUrl>https://github.com/Strrationalism/YukimiScript</PackageProjectUrl>
12+
<RepositoryUrl>https://github.com/Strrationalism/YukimiScript</RepositoryUrl>
13+
<RepositoryType>git</RepositoryType>
14+
<PackageLicenseExpression>MIT</PackageLicenseExpression>
15+
<Title>YukimiScript.Runtime.Bytecode.Parser</Title>
16+
17+
</PropertyGroup>
18+
19+
</Project>
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
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

Comments
 (0)