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; } }