diff --git a/.gitignore b/.gitignore index d9a98a5..2c7d742 100644 --- a/.gitignore +++ b/.gitignore @@ -224,3 +224,4 @@ AppPackages/ ##### # End of core ignore list, below put you custom 'per project' settings (patterns or path) ##### +/GalanthusCli/Properties/launchSettings.json diff --git a/Galanthus/GameManager.cs b/Galanthus/GameManager.cs index 9f64ed0..9304971 100644 --- a/Galanthus/GameManager.cs +++ b/Galanthus/GameManager.cs @@ -130,4 +130,21 @@ public static bool LoadGame(string inDirectory, Platform inPlatform, Compression return true; } + public static Block GetFileBytesFromPath(string filePath, string inDirectory) + { + string dataDir = Path.Combine(inDirectory, CodeName, "sdf", Platform.ToString().ToLower(), "data"); + Block data = null; + if (filePath != null) + { + foreach (Structs.File file in m_toc.Files) + { + if (file.Name == filePath) + { + data = m_toc.GetFileBytes(file, dataDir); + break; + } + } + } + return data; + } } \ No newline at end of file diff --git a/Galanthus/SdfToc.cs b/Galanthus/SdfToc.cs index c70b172..e1a8323 100644 --- a/Galanthus/SdfToc.cs +++ b/Galanthus/SdfToc.cs @@ -2,9 +2,11 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.IO; using Galanthus.Structs; using Galanthus.Utils; using StreamUtils; +using File = Galanthus.Structs.File; namespace Galanthus; @@ -516,4 +518,117 @@ public void Dispose() header.Dispose(); } } + + public unsafe Block GetFileBytes(File fileEntry, string dataDir) + { + int outBufferSize = 0; + string sdfPath = null; + + //get final file size + foreach (DataSlice dataSlice in fileEntry.DataSlices) + { + if (fileEntry.DdsIndex != -1) + { + outBufferSize += m_ddsHeaders[fileEntry.DdsIndex].Size; + } + + if (!TryGetDataFile(dataSlice, out string? sdfName)) + { + Console.WriteLine($"Wrong index {dataSlice.Index}"); + continue; + } + + sdfPath = Path.Combine(dataDir, sdfName); + if (System.IO.File.Exists(sdfPath)) + { + outBufferSize += (int)dataSlice.DecompressedSize; + } + + } + Block outBuffer = new(outBufferSize); + + + //add dds header + if (fileEntry.DdsIndex != -1) + { + m_ddsHeaders[fileEntry.DdsIndex].CopyTo(outBuffer); + outBuffer.Shift(m_ddsHeaders[fileEntry.DdsIndex].Size); + } + + //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); + if (System.IO.File.Exists(sdfPath)) + { + using (DataStream stream = BlockStream.FromFile(sdfPath, dataSlice.Offset, (int)dataSlice.CompressedSize)) + { + //read slice + Block compressedBuffer = new((int)dataSlice.CompressedSize); + stream.ReadExactly(compressedBuffer); + + //decrypt slice + if (dataSlice.IsEncrypted) + { + if (m_header.Version >= 0x29 && compressedBuffer.Size >= 8) + { + // first they use XTEA encryption, then they use des encryption + XTEA((uint*)compressedBuffer.Ptr, 32); + + // DES-PCBC + // Problem is c# doesnt have native support for it + if (Crypto.DecryptDes((nuint)compressedBuffer.Ptr, (compressedBuffer.Size >> 3) << 3, (nuint)compressedBuffer.Ptr, (nuint)KeyManager.Key.Ptr, + (nuint)KeyManager.Iv.Ptr) != 0) + { + return null; + } + } + else if (compressedBuffer.Size >= 0x100) + { + // AES-192-OFB + // Problem is c# doesnt have native support for it + if (Crypto.DecryptAes((nuint)compressedBuffer.Ptr, 0x100, (nuint)compressedBuffer.Ptr, (nuint)KeyManager.Key.Ptr, + (nuint)KeyManager.Iv.Ptr) != 0) + { + return null; + } + } + } + + //decompress slice + if (dataSlice.IsCompressed) + { + if (!dataSlice.IsOodle) + { + ZStd.Decompress(compressedBuffer, ref outBuffer); + } + else + { + Console.WriteLine("Oodle slice!"); + } + } + else + { + compressedBuffer.CopyTo(outBuffer); + } + + outBuffer.Shift((int)dataSlice.DecompressedSize); + compressedBuffer.Dispose(); + } + } + else + { + Console.WriteLine($"{sdfName} does not exist, skipping slice."); + } + } + + outBuffer.ResetShift(); + return outBuffer; + } } \ No newline at end of file diff --git a/GalanthusCli/Program.cs b/GalanthusCli/Program.cs index e63c54c..63dca5f 100644 --- a/GalanthusCli/Program.cs +++ b/GalanthusCli/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.CommandLine; using System.IO; using Galanthus;