From 24262179f3f1b9e735c3656bd5c0543f2428d1ec Mon Sep 17 00:00:00 2001 From: Crsky Date: Mon, 14 Apr 2025 02:38:00 +0800 Subject: [PATCH] (Valkyria): Support V1 resource archive --- ArcFormats/Valkyria/ArcDAT.cs | 78 +++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/ArcFormats/Valkyria/ArcDAT.cs b/ArcFormats/Valkyria/ArcDAT.cs index ede8dacb..ac2c6eec 100644 --- a/ArcFormats/Valkyria/ArcDAT.cs +++ b/ArcFormats/Valkyria/ArcDAT.cs @@ -23,8 +23,11 @@ // IN THE SOFTWARE. // +using System; using System.Collections.Generic; using System.ComponentModel.Composition; +using System.IO; +using System.Linq; namespace GameRes.Formats.Valkyria { @@ -40,6 +43,8 @@ namespace GameRes.Formats.Valkyria public override ArcFile TryOpen (ArcView file) { uint index_size = file.View.ReadUInt32 (0); + if (0 == index_size) + return TryOpenV1 (file); if (0 == index_size || index_size >= file.MaxOffset) return null; int count = (int)index_size / 0x10C; @@ -62,5 +67,78 @@ namespace GameRes.Formats.Valkyria } return new ArcFile (file, this, dir); } + + private ArcFile TryOpenV1(ArcView file) + { + var index_size = file.View.ReadUInt32 (4); + if (0 == index_size || index_size >= file.MaxOffset) + return null; + int count = (int)index_size / 0x10C; + if (index_size != (uint)count * 0x10Cu || !IsSaneCount (count)) + return null; + var dir_path = Path.GetDirectoryName (file.Name); + if (null == dir_path) + return null; + var arc_key = ReadArcKey (dir_path); + if (null == arc_key) + return null; + uint index_offset = 8; + long base_offset = index_offset + index_size; + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + var name = file.View.ReadString (index_offset, 0x104); + var key = GetEntryKey (arc_key, file.View.ReadBytes (index_offset, 0x104)); + index_offset += 0x104; + var entry = FormatCatalog.Instance.Create (name); + entry.Offset = base_offset + (file.View.ReadUInt32 (index_offset) ^ key); + entry.Size = file.View.ReadUInt32 (index_offset + 4) ^ key; + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + index_offset += 8; + dir.Add (entry); + } + return new ArcFile (file, this, dir); + } + + private static byte[] ReadArcKey (string dir_path) + { + var file_path = Path.Combine (dir_path, "system.dat"); + if (!File.Exists (file_path)) + return null; + var info = new byte[260]; + using (var fs = File.OpenRead (file_path)) + { + fs.Position = 0x10E; + fs.Read (info, 0, 260); + fs.Close (); + } + var key = new byte[4]; + var len = info.TakeWhile (x => x != 0).Count (); + for (int i = len, j = 0; i != 0; i--) + { + key[j] += info[i]; + if (++j == 4) + j = 0; + } + return key; + } + + private static uint GetEntryKey (byte[] arc_key, byte[] name) + { + var key = new byte[4]; + var len = name.TakeWhile (x => x != 0).Count (); + for (int i = len, j = 0; i != 0; i--) + { + key[j] += name[i]; + if (++j == 4) + j = 0; + } + key[0] += arc_key[3]; + key[1] += arc_key[2]; + key[2] += arc_key[1]; + key[3] += arc_key[0]; + return BitConverter.ToUInt32 (key, 0); + } } }