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 @@
+
+
+