diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index f3fc4d32..e558dade 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -63,6 +63,7 @@ + diff --git a/ArcFormats/GSD/ArcADS.cs b/ArcFormats/GSD/ArcADS.cs new file mode 100644 index 00000000..654e7e95 --- /dev/null +++ b/ArcFormats/GSD/ArcADS.cs @@ -0,0 +1,140 @@ +//! \file ArcADS.cs +//! \date Sun Feb 07 14:40:32 2016 +//! \brief ADVDX engine resource archive. +// +// Copyright (C) 2016 by morkt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using GameRes.Utility; + +namespace GameRes.Formats.BlackRainbow +{ + using EncryptedViewStream = NScripter.EncryptedViewStream; + + [Serializable] + public class AdsScheme : ResourceScheme + { + public Dictionary KnownKeys; + } + + [Export(typeof(ArchiveFormat))] + public class AdsOpener : ArchiveFormat + { + public override string Tag { get { return "ADS"; } } + public override string Description { get { return "ADVDX engine resource archive"; } } + public override uint Signature { get { return 0; } } + public override bool IsHierarchic { get { return false; } } + public override bool CanCreate { get { return false; } } + + public static Dictionary KnownKeys = new Dictionary(); + + public override ResourceScheme Scheme + { + get { return new AdsScheme { KnownKeys = KnownKeys }; } + set { KnownKeys = ((AdsScheme)value).KnownKeys; } + } + + public override ArcFile TryOpen (ArcView file) + { + if (!file.Name.EndsWith (".ads", StringComparison.InvariantCultureIgnoreCase)) + return null; + foreach (var key in KnownKeys.Values) + { + using (var arc = new EncryptedViewStream (file, key, true)) + { + uint signature = FormatCatalog.ReadSignature (arc); + if (2 == signature || 4 == signature || 5 == signature) + { + var dir = ReadIndex (arc, key); + if (dir != null) + return new AdsArchive (file, this, dir, key); + } + } + } + return null; + } + + List ReadIndex (Stream arc, byte[] key) + { + arc.Position = 8; + using (var reader = new ArcView.Reader (arc)) + { + int count = reader.ReadInt32(); + if (!IsSaneCount (count)) + return null; + uint base_offset = reader.ReadUInt32(); + uint index_size = 4u * (uint)count; + var max_offset = arc.Length; + if (base_offset >= max_offset || base_offset < (0x10+index_size)) + return null; + var index = new List (count); + for (int i = 0; i < count; ++i) + { + uint offset = reader.ReadUInt32(); + if (offset != 0xffffffff) + { + if (offset >= max_offset-base_offset) + return null; + index.Add (base_offset + offset); + } + } + var name_buffer = new byte[0x20]; + var dir = new List (index.Count); + for (int i = 0; i < index.Count; ++i) + { + long offset = index[i]; + reader.BaseStream.Position = offset; + reader.Read (name_buffer, 0, 0x20); + string name = Binary.GetCString (name_buffer, 0, 0x20); + var entry = FormatCatalog.Instance.Create (name); + entry.Offset = offset + 0x24; + entry.Size = reader.ReadUInt32(); + dir.Add (entry); + } + return dir; + } + } + + public override Stream OpenEntry (ArcFile arc, Entry entry) + { + var ads_arc = arc as AdsArchive; + if (null == ads_arc) + return base.OpenEntry (arc, entry); + var input = new EncryptedViewStream (ads_arc.File, ads_arc.Key, true); + return new StreamRegion (input, entry.Offset, entry.Size); + } + } + + internal class AdsArchive : ArcFile + { + public readonly byte[] Key; + + public AdsArchive (ArcView arc, ArchiveFormat impl, ICollection dir, byte[] key) + : base (arc, impl, dir) + { + Key = key; + } + } +} diff --git a/supported.html b/supported.html index 553d0a75..99ff6d30 100644 --- a/supported.html +++ b/supported.html @@ -204,12 +204,15 @@ Unionism Quartet
*.ycgYCGNo *.isaISM ARCHIVEDNoISMGreen ~Akizora no Screen~ *.isgISM IMAGEFILENo -*.dat
*.pak-NoBlack Rainbow +*.dat
*.pak-NoBlack Rainbow Gadget
+Gitai Saimin
Fukou na Kami
Saiminjutsu
+Soukan Yuugi 2
*.bmd_BMDYes +*.asd-No *.dat-YesStudio e.go!Men at Work 2 *.mbl-NoMarble Chikatetsu Fuusa Jiken