From b18ede8684407333abbe95963c75bef9f5f6420e Mon Sep 17 00:00:00 2001 From: morkt Date: Tue, 31 May 2016 02:41:33 +0400 Subject: [PATCH] implemented '*_scr.med' archives decryption. --- ArcFormats/ArcFormats.csproj | 7 ++ ArcFormats/DxLib/ArcMED.cs | 110 +++++++++++++++++++++ ArcFormats/DxLib/WidgetSCR.xaml | 9 ++ ArcFormats/DxLib/WidgetSCR.xaml.cs | 22 +++++ ArcFormats/Properties/Settings.Designer.cs | 12 +++ ArcFormats/Properties/Settings.settings | 3 + ArcFormats/app.config | 3 + 7 files changed, 166 insertions(+) create mode 100644 ArcFormats/DxLib/WidgetSCR.xaml create mode 100644 ArcFormats/DxLib/WidgetSCR.xaml.cs diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index c646a782..36fdb1f2 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -87,6 +87,9 @@ + + WidgetSCR.xaml + @@ -532,6 +535,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/ArcFormats/DxLib/ArcMED.cs b/ArcFormats/DxLib/ArcMED.cs index 94812997..eb8d06b1 100644 --- a/ArcFormats/DxLib/ArcMED.cs +++ b/ArcFormats/DxLib/ArcMED.cs @@ -27,9 +27,69 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; +using GameRes.Formats.Properties; +using GameRes.Formats.Strings; +using GameRes.Utility; namespace GameRes.Formats.DxLib { + public interface IScriptEncryption + { + int StartOffset { get; } + + bool IsEncrypted (byte[] data); + void Decrypt (byte[] data, int offset, int length); + } + + [Serializable] + public class FudegakiEncryption : IScriptEncryption + { + readonly byte[] Key; + + public FudegakiEncryption (string keyword) + { + Key = Encodings.cp932.GetBytes (keyword); + } + + public int StartOffset { get { return 0x10; } } + + public bool IsEncrypted (byte[] data) + { + return LittleEndian.ToInt32 (data, 0) + 0x10 == data.Length && Key.Length > 0; + } + + public void Decrypt (byte[] data, int offset, int length) + { + for (int i = 0; i < length; ++i) + { + data[offset+i] += Key[(offset+i) % Key.Length]; + } + } + } + + [Serializable] + public class MedOptions : ResourceOptions + { + public IScriptEncryption Encryption; + } + + [Serializable] + public class ScrMedScheme : ResourceScheme + { + public Dictionary KnownSchemes; + } + + internal class ScrMedArchive : ArcFile + { + public readonly IScriptEncryption Encryption; + + public ScrMedArchive (ArcView arc, ArchiveFormat impl, ICollection dir, IScriptEncryption enc) + : base (arc, impl, dir) + { + Encryption = enc; + } + } + [Export(typeof(ArchiveFormat))] public class MedOpener : ArchiveFormat { @@ -41,6 +101,14 @@ namespace GameRes.Formats.DxLib static readonly Lazy PrsFormat = new Lazy (() => ImageFormat.FindByTag ("PRS")); + public static Dictionary KnownSchemes = new Dictionary(); + + public override ResourceScheme Scheme + { + get { return new ScrMedScheme { KnownSchemes = KnownSchemes }; } + set { KnownSchemes = ((ScrMedScheme)value).KnownSchemes; } + } + public override ArcFile TryOpen (ArcView file) { if (!file.View.AsciiEqual (0, "MD")) @@ -72,7 +140,49 @@ namespace GameRes.Formats.DxLib dir.Add (entry); index_offset += 8; } + var base_name = Path.GetFileNameWithoutExtension (file.Name); + if (base_name.EndsWith ("_scr", StringComparison.InvariantCultureIgnoreCase) + && KnownSchemes.Count > 0) + { + var options = Query (arcStrings.ArcEncryptedNotice); + if (options.Encryption != null) + return new ScrMedArchive (file, this, dir, options.Encryption); + } return new ArcFile (file, this, dir); } + + public override Stream OpenEntry (ArcFile arc, Entry entry) + { + var scr_arc = arc as ScrMedArchive; + if (null == scr_arc || entry.Size <= scr_arc.Encryption.StartOffset) + return base.OpenEntry (arc, entry); + var data = arc.File.View.ReadBytes (entry.Offset, entry.Size); + if (scr_arc.Encryption.IsEncrypted (data)) + { + var offset = scr_arc.Encryption.StartOffset; + scr_arc.Encryption.Decrypt (data, offset, data.Length-offset); + } + return new MemoryStream (data); + } + + public override ResourceOptions GetDefaultOptions () + { + return new MedOptions { + Encryption = GetEncryption (Settings.Default.MEDScriptScheme), + }; + } + + public override object GetAccessWidget () + { + return new GUI.WidgetSCR(); + } + + public static IScriptEncryption GetEncryption (string scheme) + { + IScriptEncryption enc; + if (string.IsNullOrEmpty (scheme) || !KnownSchemes.TryGetValue (scheme, out enc)) + return null; + return enc; + } } } diff --git a/ArcFormats/DxLib/WidgetSCR.xaml b/ArcFormats/DxLib/WidgetSCR.xaml new file mode 100644 index 00000000..1ce0e615 --- /dev/null +++ b/ArcFormats/DxLib/WidgetSCR.xaml @@ -0,0 +1,9 @@ + + + diff --git a/ArcFormats/DxLib/WidgetSCR.xaml.cs b/ArcFormats/DxLib/WidgetSCR.xaml.cs new file mode 100644 index 00000000..11318576 --- /dev/null +++ b/ArcFormats/DxLib/WidgetSCR.xaml.cs @@ -0,0 +1,22 @@ +using System.Windows.Controls; +using System.Linq; +using GameRes.Formats.DxLib; +using GameRes.Formats.Strings; + +namespace GameRes.Formats.GUI +{ + /// + /// Interaction logic for WidgetSCR.xaml + /// + public partial class WidgetSCR : StackPanel + { + public WidgetSCR() + { + InitializeComponent(); + var keys = new string[] { arcStrings.ArcIgnoreEncryption }; + ScriptScheme.ItemsSource = keys.Concat (MedOpener.KnownSchemes.Keys.OrderBy (x => x)); + if (-1 == ScriptScheme.SelectedIndex) + ScriptScheme.SelectedIndex = 0; + } + } +} diff --git a/ArcFormats/Properties/Settings.Designer.cs b/ArcFormats/Properties/Settings.Designer.cs index f1312dd4..de96d561 100644 --- a/ArcFormats/Properties/Settings.Designer.cs +++ b/ArcFormats/Properties/Settings.Designer.cs @@ -537,5 +537,17 @@ namespace GameRes.Formats.Properties { this["NCARCScheme"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string MEDScriptScheme { + get { + return ((string)(this["MEDScriptScheme"])); + } + set { + this["MEDScriptScheme"] = value; + } + } } } diff --git a/ArcFormats/Properties/Settings.settings b/ArcFormats/Properties/Settings.settings index 07de4ed3..1abee176 100644 --- a/ArcFormats/Properties/Settings.settings +++ b/ArcFormats/Properties/Settings.settings @@ -131,5 +131,8 @@ + + + \ No newline at end of file diff --git a/ArcFormats/app.config b/ArcFormats/app.config index c4096b3a..ce5836a9 100644 --- a/ArcFormats/app.config +++ b/ArcFormats/app.config @@ -133,6 +133,9 @@ + + +