diff --git a/ArcFormats/Actgs/ArcCG.cs b/ArcFormats/Actgs/ArcCG.cs index 3b5834c7..a146c8e8 100644 --- a/ArcFormats/Actgs/ArcCG.cs +++ b/ArcFormats/Actgs/ArcCG.cs @@ -26,7 +26,10 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; +using System.IO; using System.Linq; +using GameRes.Compression; +using GameRes.Utility; namespace GameRes.Formats.Actgs { @@ -41,7 +44,8 @@ namespace GameRes.Formats.Actgs public override ArcFile TryOpen (ArcView file) { - var key = FindKey (file); + var pattern = file.View.ReadBytes (4, 8); + var key = FindKey (4, pattern); if (null == key) return null; uint signature_key = key.ToUInt32 (0); @@ -61,10 +65,9 @@ namespace GameRes.Formats.Actgs } } - byte[] FindKey (ArcView file) + internal byte[] FindKey (int offset, byte[] pattern) { - var pattern = file.View.ReadBytes (4, 8); - return Array.Find (KnownKeys, k => KeySequence (k).Skip (4).Take (8).SequenceEqual (pattern)); + return Array.Find (KnownKeys, k => KeySequence (k).Skip (offset).Take (pattern.Length).SequenceEqual (pattern)); } internal static IEnumerable KeySequence (byte[] key) @@ -76,4 +79,64 @@ namespace GameRes.Formats.Actgs } } } + + [Export(typeof(ArchiveFormat))] + public class ArcCgOpener : CgOpener + { + public override string Tag { get { return "CG/ACTGS/2"; } } + public override string Description { get { return "ACTGS engine resource archive"; } } + public override uint Signature { get { return 0; } } + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public override ArcFile TryOpen (ArcView file) + { + if (file.MaxOffset <= 0x1020) + return null; + int count = file.View.ReadInt32 (0); + if (!IsSaneCount (count)) + return null; + var pattern = file.View.ReadBytes (0x1018, 8); + var key = FindKey (0x18, pattern); + if (null == key) + return null; + var dir = new List (count); + var buffer = new byte[0x20]; + long offset = 0x1000; + while (file.View.Read (offset, buffer, 0, 0x20) == 0x20) + { + offset += 0x20; + Decrypt (buffer, 0, 0x20, key); + uint size = buffer.ToUInt32 (0); + var name = Binary.GetCString (buffer, 4); + var entry = FormatCatalog.Instance.Create (name); + entry.Offset = offset; + entry.Size = size; + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + offset += (size + 0xFu) & ~0xFu; + dir.Add (entry); + } + if (0 == dir.Count) + return null; + return new ActressArchive (file, this, dir, key); + } + + public override Stream OpenEntry (ArcFile arc, Entry entry) + { + var actarc = arc as ActressArchive; + if (null == actarc || null == actarc.Key) + return base.OpenEntry (arc, entry); + var header = ReadEntryHeader (actarc, entry); + Stream input; + if (entry.Size <= 0x20) + input = new BinMemoryStream (header, entry.Name); + else + input = new PrefixStream (header, arc.File.CreateStream (entry.Offset+0x20, entry.Size-0x20)); + if (header.AsciiEqual ("BM")) + return input; + input.Position = 4; + return new LzssStream (input); + } + } } diff --git a/ArcFormats/Actgs/ArcDAT.cs b/ArcFormats/Actgs/ArcDAT.cs index 80ea7c03..9c19283b 100644 --- a/ArcFormats/Actgs/ArcDAT.cs +++ b/ArcFormats/Actgs/ArcDAT.cs @@ -125,10 +125,7 @@ namespace GameRes.Formats.Actgs var input = arc.File.CreateStream (entry.Offset+12, packed_size); return new LzssStream (input); } - uint length = Math.Min (entry.Size, 0x20u); - var header = new byte[length]; - arc.File.View.Read (entry.Offset, header, 0, length); - Decrypt (header, 0, (int)length, actarc.Key); + var header = ReadEntryHeader (actarc, entry); if (entry.Size <= 0x20) return new BinMemoryStream (header, entry.Name); var rest = arc.File.CreateStream (entry.Offset+0x20, entry.Size-0x20); @@ -150,6 +147,14 @@ namespace GameRes.Formats.Actgs } } + internal byte[] ReadEntryHeader (ActressArchive arc, Entry entry) + { + uint length = Math.Min (entry.Size, 0x20u); + var header = arc.File.View.ReadBytes (entry.Offset, length); + Decrypt (header, 0, header.Length, arc.Key); + return header; + } + public override ResourceScheme Scheme { get { return new ActressScheme { KnownKeys = KnownKeys }; }