Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add methods for getting file data from the vfs #1

Merged
merged 7 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,4 @@ AppPackages/
#####
# End of core ignore list, below put you custom 'per project' settings (patterns or path)
#####
/GalanthusCli/Properties/launchSettings.json
17 changes: 17 additions & 0 deletions Galanthus/GameManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,21 @@ public static bool LoadGame(string inDirectory, Platform inPlatform, Compression

return true;
}
public static Byte[] TryGetFileBytes(string filePath, string inDirectory)
CosmicDreamsOfCode marked this conversation as resolved.
Show resolved Hide resolved
{
string dataDir = Path.Combine(inDirectory, CodeName, "sdf", Platform.ToString().ToLower(), "data");
Byte[] data = null;
if (filePath != null)
{
foreach (Structs.File file in m_toc.Files)
{
if (file.Name == filePath)
{
data = m_toc.GetFileBytes(m_toc, file, dataDir);
break;
}
}
}
return data;
}
}
106 changes: 104 additions & 2 deletions Galanthus/SdfToc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using Galanthus.Structs;
using Galanthus.Utils;
using StreamUtils;
using File = Galanthus.Structs.File;

namespace Galanthus;

Expand All @@ -17,14 +20,16 @@ public class SdfToc : IDisposable
private List<Block<byte>> m_ddsHeaders;
private List<File> m_files;
private DataSliceIndexSettings m_settings;
private string m_encryptionMethod;

public SdfToc(TocHeader inHeader, List<Locale> inLocales, List<Block<byte>> inDdsHeaders, List<File> inFiles, DataSliceIndexSettings inSettings)
public SdfToc(TocHeader inHeader, List<Locale> inLocales, List<Block<byte>> inDdsHeaders, List<File> inFiles, DataSliceIndexSettings inSettings, string inEncryptionMethod)
{
m_header = inHeader;
m_locales = inLocales;
m_ddsHeaders = inDdsHeaders;
m_files = inFiles;
m_settings = inSettings;
m_encryptionMethod = inEncryptionMethod;
}

public static unsafe SdfToc? Read(DataStream inStream)
Expand Down Expand Up @@ -204,15 +209,18 @@ public SdfToc(TocHeader inHeader, List<Locale> inLocales, List<Block<byte>> inDd
return null;
}

string encryptionMethod = "None";
if (isEncrypted)
{

if (KeyManager.Key is null || KeyManager.Iv is null)
{
return null;
}

if (header.Version >= 0x29 && compressedFileTable.Size >= 8)
{
encryptionMethod = "XTEA+DES";
// first they use XTEA encryption, then they use des encryption
XTEA((uint*)compressedFileTable.Ptr, 32);

Expand All @@ -226,6 +234,7 @@ public SdfToc(TocHeader inHeader, List<Locale> inLocales, List<Block<byte>> inDd
}
else if (compressedFileTable.Size >= 0x100)
{
encryptionMethod = "AES";
// AES-192-OFB
// Problem is c# doesnt have native support for it
if (Crypto.DecryptAes((nuint)compressedFileTable.Ptr, 0x100, (nuint)compressedFileTable.Ptr, (nuint)KeyManager.Key.Ptr,
Expand Down Expand Up @@ -258,7 +267,7 @@ public SdfToc(TocHeader inHeader, List<Locale> inLocales, List<Block<byte>> inDd

Console.WriteLine($"Got {files.Count} files.");

return new SdfToc(header, locales, ddsHeaders, files, settings);
return new SdfToc(header, locales, ddsHeaders, files, settings, encryptionMethod);
}

public bool TryGetDataFile(DataSlice inSlice, [NotNullWhen(true)] out string? path)
Expand Down Expand Up @@ -516,4 +525,97 @@ public void Dispose()
header.Dispose();
}
}

public unsafe Byte[] GetFileBytes(SdfToc toc, Structs.File fileEntry, string dataDir)
{
List<Byte[]> fileData = new List<Byte[]>();
string sdfPath = null;

//add dds header
fileData.Add(toc.m_ddsHeaders[fileEntry.DdsIndex].ToArray());

//read slices
foreach (DataSlice dataSlice in fileEntry.DataSlices)
{
if (!TryGetDataFile(dataSlice, out string? sdfName))
{
Console.WriteLine($"Wrong index {dataSlice.Index}");
continue;
}

sdfPath = Path.Combine(dataDir, sdfName);
CosmicDreamsOfCode marked this conversation as resolved.
Show resolved Hide resolved

using (DataStream stream = BlockStream.FromFile(sdfPath))
{
//read slice
stream.Position = dataSlice.Offset;
Block<Byte> data = new((int)dataSlice.CompressedSize);
stream.ReadExactly(data);

//decrypt slice
if (dataSlice.IsEncrypted)
{
if (toc.m_encryptionMethod == "XTEA+DES")
CosmicDreamsOfCode marked this conversation as resolved.
Show resolved Hide resolved
{
// first they use XTEA encryption, then they use des encryption
XTEA((uint*)data.Ptr, 32);

// DES-PCBC
// Problem is c# doesnt have native support for it
if (Crypto.DecryptDes((nuint)data.Ptr, (data.Size >> 3) << 3, (nuint)data.Ptr, (nuint)KeyManager.Key.Ptr,
(nuint)KeyManager.Iv.Ptr) != 0)
{
return null;
}
}
else if (toc.m_encryptionMethod == "AES")
{
// AES-192-OFB
// Problem is c# doesnt have native support for it
if (Crypto.DecryptAes((nuint)data.Ptr, 0x100, (nuint)data.Ptr, (nuint)KeyManager.Key.Ptr,
(nuint)KeyManager.Iv.Ptr) != 0)
{
return null;
}
}
}

//decompress slice
if (dataSlice.IsCompressed)
{
if (!dataSlice.IsOodle)
{
Block<byte> decompressedData = new((int)dataSlice.DecompressedSize);
ZStd.Decompress(data, ref decompressedData);

data = decompressedData;
}
else
{
Console.WriteLine("Oodle slice!");
}
}

//add slice to list
fileData.Add(data.ToArray());
}
}

return CombineByteArray(fileData.ToArray());
CosmicDreamsOfCode marked this conversation as resolved.
Show resolved Hide resolved
}

public static byte[] CombineByteArray(params byte[][] arrays)
{
//
//from https://github.com/KillzXGaming/Switch-Toolbox/blob/master/Switch_Toolbox_Library/Util/Util.cs#L155
//
byte[] rv = new byte[arrays.Sum(a => a.Length)];
int offset = 0;
foreach (byte[] array in arrays)
{
Buffer.BlockCopy(array, 0, rv, offset, array.Length);
offset += array.Length;
}
return rv;
}
}
7 changes: 6 additions & 1 deletion GalanthusCli/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.CommandLine;
using System.IO;
using Galanthus;
Expand Down Expand Up @@ -71,6 +71,11 @@ private static void LoadGame(DirectoryInfo inGameDirectory, string? inPlatform,
{
Console.WriteLine("Failed to load game.");
}
else
CosmicDreamsOfCode marked this conversation as resolved.
Show resolved Hide resolved
{
byte[] bytes = GameManager.TryGetFileBytes(@"moria/baked/art/ui/boot/rkb.dds", inGameDirectory.FullName);
File.WriteAllBytes(@"E:\Game-Dumps\MRKB-DumpTest\BASE\moria\baked\art\ui\boot\Galanthus--rkb.dds", bytes);
}

KeyManager.Key?.Dispose();
KeyManager.Iv?.Dispose();
Expand Down