diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj
index 845b2104..18565198 100644
--- a/ArcFormats/ArcFormats.csproj
+++ b/ArcFormats/ArcFormats.csproj
@@ -269,9 +269,6 @@
-
-
-
diff --git a/Experimental/Experimental.csproj b/Experimental/Experimental.csproj
index c50022c6..cfe9d36e 100644
--- a/Experimental/Experimental.csproj
+++ b/Experimental/Experimental.csproj
@@ -67,6 +67,7 @@
..\packages\System.Data.SQLite.Core.1.0.106.0\lib\net46\System.Data.SQLite.dll
+
@@ -79,6 +80,9 @@
+
+
+
diff --git a/ArcFormats/RPGMaker/ArcRGSS.cs b/Experimental/RPGMaker/ArcRGSS.cs
similarity index 100%
rename from ArcFormats/RPGMaker/ArcRGSS.cs
rename to Experimental/RPGMaker/ArcRGSS.cs
diff --git a/ArcFormats/RPGMaker/AudioRPGMV.cs b/Experimental/RPGMaker/AudioRPGMV.cs
similarity index 89%
rename from ArcFormats/RPGMaker/AudioRPGMV.cs
rename to Experimental/RPGMaker/AudioRPGMV.cs
index 597a8cb2..a8820b79 100644
--- a/ArcFormats/RPGMaker/AudioRPGMV.cs
+++ b/Experimental/RPGMaker/AudioRPGMV.cs
@@ -23,12 +23,7 @@
// IN THE SOFTWARE.
//
-using System;
using System.ComponentModel.Composition;
-using System.IO;
-using System.Linq;
-using GameRes.Utility;
-using NVorbis;
namespace GameRes.Formats.RPGMaker
{
@@ -45,11 +40,17 @@ namespace GameRes.Formats.RPGMaker
var header = file.ReadHeader (0x14);
if (header[4] != 'V')
return null;
- var key = RpgmvpFormat.DefaultKey;
+ var key = RpgmvDecryptor.LastKey ?? RpgmvDecryptor.FindKeyFor (file.Name);
+ if (null == key)
+ return null;
for (int i = 0; i < 4; ++i)
header[0x10+i] ^= key[i];
if (!header.AsciiEqual (0x10, "OggS"))
+ {
+ RpgmvDecryptor.LastKey = null;
return null;
+ }
+ RpgmvDecryptor.LastKey = key;
var ogg = RpgmvDecryptor.DecryptStream (file, key);
return OggAudio.Instance.TryOpen (ogg);
}
diff --git a/ArcFormats/RPGMaker/ImageRPGMV.cs b/Experimental/RPGMaker/ImageRPGMV.cs
similarity index 61%
rename from ArcFormats/RPGMaker/ImageRPGMV.cs
rename to Experimental/RPGMaker/ImageRPGMV.cs
index 528ebc4a..5a01ca04 100644
--- a/ArcFormats/RPGMaker/ImageRPGMV.cs
+++ b/Experimental/RPGMaker/ImageRPGMV.cs
@@ -23,9 +23,12 @@
// IN THE SOFTWARE.
//
+using System.Collections;
+using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
-using System.Windows.Media;
+using System.Text;
+using System.Web.Script.Serialization;
namespace GameRes.Formats.RPGMaker
{
@@ -41,20 +44,22 @@ namespace GameRes.Formats.RPGMaker
public override string Description { get { return "RPG Maker engine image format"; } }
public override uint Signature { get { return 0x4D475052; } } // 'RPGMV'
- internal static readonly byte[] DefaultKey = {
- 0x77, 0x4E, 0x46, 0x45, 0xFC, 0x43, 0x2F, 0x71, 0x47, 0x95, 0xA2, 0x43, 0xE5, 0x10, 0x13, 0xD8
- };
-
public override ImageMetaData ReadMetaData (IBinaryStream file)
{
var header = file.ReadHeader (0x14);
if (header[4] != 'V')
return null;
- var key = DefaultKey;
+ var key = RpgmvDecryptor.LastKey ?? RpgmvDecryptor.FindKeyFor (file.Name);
+ if (null == key)
+ return null;
for (int i = 0; i < 4; ++i)
header[0x10+i] ^= key[i];
if (!header.AsciiEqual (0x10, "\x89PNG"))
+ {
+ RpgmvDecryptor.LastKey = null;
return null;
+ }
+ RpgmvDecryptor.LastKey = key;
using (var png = RpgmvDecryptor.DecryptStream (file, key, true))
{
var info = Png.ReadMetaData (png);
@@ -92,8 +97,66 @@ namespace GameRes.Formats.RPGMaker
var header = input.ReadBytes (key.Length);
for (int i = 0; i < key.Length; ++i)
header[i] ^= key[i];
- var result = new PrefixStream (header, new StreamRegion (input.AsStream, 0x20, leave_open));
+ var result = new PrefixStream (header, new StreamRegion (input.AsStream, input.Position, leave_open));
return new BinaryStream (result, input.Name);
}
+
+ static byte[] GetKeyFromString (string hex)
+ {
+ if ((hex.Length & 1) != 0)
+ throw new System.ArgumentException ("invalid key string");
+ var key = new byte[hex.Length/2];
+ for (int i = 0; i < key.Length; ++i)
+ {
+ key[i] = (byte)(HexToInt (hex[i * 2]) << 4 | HexToInt (hex[i * 2 + 1]));
+ }
+ return key;
+ }
+
+ static int HexToInt (char x)
+ {
+ if (char.IsDigit (x))
+ return x - '0';
+ else
+ return char.ToUpper (x) - 'A' + 10;
+ }
+
+ static byte[] ParseSystemJson (string filename)
+ {
+ var json = File.ReadAllText (filename, Encoding.UTF8);
+ var serializer = new JavaScriptSerializer();
+ var sys = serializer.DeserializeObject (json) as IDictionary;
+ if (null == sys)
+ return null;
+ var key = sys["encryptionKey"] as string;
+ if (null == key)
+ return null;
+ return GetKeyFromString (key);
+ }
+
+ public static byte[] FindKeyFor (string filename)
+ {
+ foreach (var system_filename in FindSystemJson (filename))
+ {
+ if (File.Exists (system_filename))
+ return ParseSystemJson (system_filename);
+ }
+ return null;
+ }
+
+ static IEnumerable FindSystemJson (string filename)
+ {
+ var dir_name = Path.GetDirectoryName (filename);
+ yield return Path.Combine (dir_name, @"..\..\data\System.json");
+ yield return Path.Combine (dir_name, @"..\..\..\www\data\System.json");
+ yield return Path.Combine (dir_name, @"..\data\System.json");
+ yield return Path.Combine (dir_name, @"data\System.json");
+ }
+
+ internal static readonly byte[] DefaultKey = {
+ 0x77, 0x4E, 0x46, 0x45, 0xFC, 0x43, 0x2F, 0x71, 0x47, 0x95, 0xA2, 0x43, 0xE5, 0x10, 0x13, 0xD8
+ };
+
+ internal static byte[] LastKey = null;
}
}