Skip to content

Commit 2e82a7a

Browse files
committed
Added Fmod5Sharp as a submodule with improvements
Check: SamboyCoding/Fmod5Sharp#13 SamboyCoding/Fmod5Sharp#14
1 parent 596462a commit 2e82a7a

File tree

9 files changed

+76
-68
lines changed

9 files changed

+76
-68
lines changed

.gitmodules

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[submodule "Fmod5Sharp"]
2+
path = Fmod5Sharp
3+
url = https://github.com/Masusder/Fmod5Sharp.git
4+
branch = improved

FModBankParser.Demo/Main.cs

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.CommandLine;
2+
using System.Diagnostics;
23
using System.Text;
34

45
namespace FModBankParser.Demo;
@@ -35,15 +36,7 @@ public static int Main(string[] args)
3536
parseResult.GetValue(outDirOption)
3637
));
3738

38-
int result = rootCommand.Parse(args).Invoke();
39-
40-
if (Environment.UserInteractive)
41-
{
42-
Console.WriteLine("\nPress any key to exit...");
43-
Console.ReadKey();
44-
}
45-
46-
return result;
39+
return rootCommand.Parse(args).Invoke();
4740
}
4841

4942
private static void RunParseAndProcess(FileSystemInfo? fsInfo, string? keyString, bool exportAudio, DirectoryInfo? outDir)
@@ -53,33 +46,29 @@ private static void RunParseAndProcess(FileSystemInfo? fsInfo, string? keyString
5346

5447
try
5548
{
56-
if (fsInfo is FileInfo file)
49+
switch (fsInfo)
5750
{
58-
if (!file.Extension.Equals(".bank", StringComparison.OrdinalIgnoreCase))
59-
{
60-
Console.Error.WriteLine($"The file must be a .bank file: {file.Name}");
51+
case FileInfo file:
52+
if (!file.Extension.Equals(".bank", StringComparison.OrdinalIgnoreCase))
53+
{
54+
Console.Error.WriteLine($"The file must be a .bank file: {file.Name}");
55+
return;
56+
}
57+
58+
ProcessBankFile(file, encryptionKey, exportAudio, outputDirectory);
59+
return;
60+
case DirectoryInfo dir:
61+
ProcessBankDirectory(dir, encryptionKey, exportAudio, outputDirectory);
62+
break;
63+
case not { Exists: true }:
64+
Console.Error.WriteLine("Unsupported path type.");
6165
return;
62-
}
63-
64-
ProcessBankFile(file, encryptionKey, exportAudio, outputDirectory);
65-
}
66-
else if (fsInfo is DirectoryInfo dir)
67-
{
68-
ProcessBankDirectory(dir, encryptionKey, exportAudio, outputDirectory);
69-
}
70-
else
71-
{
72-
Console.Error.WriteLine("Unsupported path type.");
7366
}
7467
}
7568
catch (Exception ex)
7669
{
70+
if (Debugger.IsAttached) throw; // To preserve stack trace during debugging
7771
Console.Error.WriteLine($"Unhandled exception: {ex.GetType().Name}: {ex.Message}");
78-
79-
if (System.Diagnostics.Debugger.IsAttached)
80-
{
81-
System.Diagnostics.Debugger.Break();
82-
}
8372
}
8473
}
8574

FModBankParser.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<Solution>
2+
<Project Path="Fmod5Sharp/Fmod5Sharp/Fmod5Sharp.csproj" />
23
<Project Path="FModBankParser.Demo/FModBankParser.Demo.csproj" />
34
<Project Path="FModBankParser/FModBankParser.csproj" />
45
</Solution>

FModBankParser/FModBankParser.csproj

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
<Project Sdk="Microsoft.NET.Sdk">
2-
32
<PropertyGroup>
43
<OutputType>Library</OutputType>
54
<TargetFramework>net10.0</TargetFramework>
@@ -18,16 +17,18 @@
1817
</PropertyGroup>
1918

2019
<ItemGroup>
21-
<PackageReference Include="Fmod5Sharp" Version="3.0.1" />
20+
<None Include="..\README.md" Pack="true" PackagePath="" Link="README.md" />
2221
</ItemGroup>
2322

2423
<ItemGroup>
25-
<None Include="..\README.md" Pack="true" PackagePath="" Link="README.md" />
24+
<ProjectReference Include="..\Fmod5Sharp\Fmod5Sharp\Fmod5Sharp.csproj" />
25+
</ItemGroup>
26+
27+
<ItemGroup>
28+
<PackageReference Include="SubstreamSharp" Version="1.0.3" />
2629
</ItemGroup>
2730

2831
<PropertyGroup>
2932
<PackageReadmeFile>README.md</PackageReadmeFile>
3033
</PropertyGroup>
31-
32-
3334
</Project>

FModBankParser/FModReader.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,6 @@ public static T[] ReadVersionedElemListImp<T>(BinaryReader Ar, Func<BinaryReader
684684
for (int i = 0; i < count; i++)
685685
{
686686
_ = Ar.ReadUInt16(); // Payload size
687-
688687
if (readElem != null)
689688
{
690689
result[i] = readElem(Ar);
@@ -698,7 +697,7 @@ public static T[] ReadVersionedElemListImp<T>(BinaryReader Ar, Func<BinaryReader
698697
return result;
699698
}
700699

701-
public static T[] ReadElemListImp<T>(BinaryReader Ar, Func<BinaryReader, T>? readElem = null, int? expectedSize = null)
700+
public static T[] ReadElemListImp<T>(BinaryReader Ar, Func<BinaryReader, T>? readElem = null)
702701
{
703702
uint raw = ReadX16(Ar);
704703
int count = (int)(raw >> 1);
@@ -707,18 +706,10 @@ public static T[] ReadElemListImp<T>(BinaryReader Ar, Func<BinaryReader, T>? rea
707706

708707
var result = new T[count];
709708

710-
ushort payloadSize = Ar.ReadUInt16();
709+
_ = Ar.ReadUInt16(); // Payload size
711710
for (int i = 0; i < count; i++)
712711
{
713-
// Pass size for debugging purposes only
714-
if (expectedSize != null && payloadSize != expectedSize)
715-
{
716-
Ar.BaseStream.Position += payloadSize;
717-
#if DEBUG
718-
Debug.WriteLine($"Warning: '{typeof(T).Name}' element size {payloadSize} does not match expected {expectedSize}, skipping");
719-
#endif
720-
}
721-
else if (readElem != null)
712+
if (readElem != null)
722713
{
723714
result[i] = readElem(Ar);
724715
}

FModBankParser/FSB5Decryption.cs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ namespace FModBankParser;
6464
/// </summary>
6565
public class FSB5Decryption
6666
{
67+
private static readonly string FSB5Header = "FSB5";
6768
private static readonly byte[] ReverseBitsTable =
6869
[
6970
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
@@ -84,22 +85,48 @@ public class FSB5Decryption
8485
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
8586
];
8687

87-
public static bool IsFSB5Header(byte[] bytes) { return bytes.Length >= 4 && Encoding.ASCII.GetString(bytes, 0, 4) == "FSB5"; }
88+
public static bool IsFSB5Header(Stream stream)
89+
{
90+
long pos = stream.Position;
91+
Span<byte> header = stackalloc byte[4];
92+
stream.ReadExactly(header);
93+
stream.Position = pos;
94+
return Encoding.ASCII.GetString(header) == FSB5Header;
95+
}
8896

89-
public static void Decrypt(byte[] fsbBytes, byte[]? key)
97+
public static Stream Decrypt(Stream fsbStream, byte[]? key)
9098
{
9199
if (key == null || key.Length == 0)
92-
throw new Exception("FSB5 is encrypted, but encryption key wasn't provided, cannot decrypt");
93-
if (fsbBytes == null)
94-
throw new ArgumentException("Invalid data to decrypt");
100+
throw new ArgumentException("FSB5 is encrypted, but encryption key wasn't provided, cannot decrypt", nameof(key));
101+
102+
const int bufferSize = 65_536;
103+
byte[] buffer = new byte[bufferSize];
104+
var decrypted = new FileStream(Path.GetTempFileName(), FileMode.Create, FileAccess.ReadWrite, FileShare.None, bufferSize, FileOptions.DeleteOnClose);
105+
long position = 0;
95106

96-
for (int i = 0; i < fsbBytes.Length; i++)
107+
fsbStream.Position = 0;
108+
109+
while (position < fsbStream.Length)
97110
{
98-
fsbBytes[i] = (byte)(ReverseBitsTable[fsbBytes[i]] ^ key[i % key.Length]);
111+
int bytesToRead = (int)Math.Min(bufferSize, fsbStream.Length - position);
112+
int bytesRead = fsbStream.Read(buffer, 0, bytesToRead);
113+
114+
if (bytesRead == 0) break;
115+
116+
for (int i = 0; i < bytesRead; i++)
117+
buffer[i] = (byte)(ReverseBitsTable[buffer[i]] ^ key[(position + i) % key.Length]);
118+
119+
decrypted.Write(buffer, 0, bytesRead);
120+
position += bytesRead;
99121
}
100122

101-
if (!IsFSB5Header(fsbBytes)) throw new Exception("Failed to decrypt FSB5, make sure encryption key is correct");
123+
decrypted.Position = 0;
124+
125+
if (!IsFSB5Header(decrypted))
126+
throw new Exception("Failed to decrypt FSB5, make sure encryption key is correct");
102127

103128
Debug.WriteLine("Decrypted FSB5 successfully");
129+
130+
return decrypted;
104131
}
105132
}

FModBankParser/Nodes/SoundDataNode.cs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Fmod5Sharp;
22
using Fmod5Sharp.FmodTypes;
3+
using SubstreamSharp;
34
using System.Diagnostics;
45

56
namespace FModBankParser.Nodes;
@@ -10,32 +11,24 @@ public class SoundDataNode
1011

1112
public SoundDataNode(BinaryReader Ar, long nodeStart, uint size, int soundDataIndex)
1213
{
13-
byte[] sndChunk = Ar.ReadBytes((int)size);
14-
1514
uint fsbOffset = FModReader.SoundDataInfo!.Header[soundDataIndex].FSBOffset;
16-
17-
var relativeOffset = (int)(fsbOffset - nodeStart) - 8;
18-
19-
byte[] fsbBytes = sndChunk[relativeOffset..];
15+
var relativeOffset = fsbOffset - nodeStart - 8;
16+
Stream fsbStream = Ar.BaseStream.Substream(fsbOffset, size);
2017

2118
// In case FSB5 is encrypted
22-
if (!FSB5Decryption.IsFSB5Header(fsbBytes))
19+
if (!FSB5Decryption.IsFSB5Header(fsbStream))
2320
{
2421
Debug.WriteLine($"Encrypted FSB5 header at {fsbOffset}");
25-
FSB5Decryption.Decrypt(fsbBytes, FModReader.EncryptionKey);
22+
fsbStream = FSB5Decryption.Decrypt(fsbStream, FModReader.EncryptionKey);
2623
}
2724

2825
try
2926
{
30-
if (FsbLoader.TryLoadFsbFromByteArray(fsbBytes, out var bank) && bank != null)
27+
if (FsbLoader.TryLoadFsbFromStream(fsbStream, out var bank) && bank != null)
3128
{
3229
SoundBank = bank;
30+
Ar.BaseStream.Position = fsbOffset - relativeOffset + size;
3331
Debug.WriteLine($"FSB5 parsed successfully, samples: {bank.Samples.Count}");
34-
for (int i = 0; i < bank.Samples.Count; i++)
35-
{
36-
var sample = bank.Samples[i];
37-
//Debug.WriteLine($"Sample: {sample.Name}, Index: {i}");
38-
}
3932
}
4033
else
4134
{

Fmod5Sharp

Submodule Fmod5Sharp added at 17ef412

NOTICE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
This library includes material developed by the following third-party libraries:
22

33
- Fmod5Sharp (https://github.com/SamboyCoding/Fmod5Sharp/blob/master/LICENSE) - Copyright (c) 2021 Sam Byass. Licensed under the MIT License.
4+
- SubstreamSharp (https://github.com/connorhaigh/SubstreamSharp/blob/master/Licence.txt) - Copyright (c) 2021 Connor Haigh. Licensed under the MIT License.
45

56
---------------------------------------------------------------------------
67

0 commit comments

Comments
 (0)