mirror of
https://github.com/crskycode/GARbro.git
synced 2026-07-08 01:30:18 +08:00
(RctFormat): added support for "incremental" images.
doesn't work inside archives, requires filesystem abstraction layer.
This commit is contained in:
@@ -29,7 +29,6 @@ using System.Text;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.Composition;
|
using System.ComponentModel.Composition;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
@@ -56,11 +55,13 @@ namespace GameRes.Formats.Majiro
|
|||||||
[Export(typeof(ImageFormat))]
|
[Export(typeof(ImageFormat))]
|
||||||
public class RctFormat : ImageFormat
|
public class RctFormat : ImageFormat
|
||||||
{
|
{
|
||||||
public override string Tag { get { return "RCT"; } }
|
public override string Tag { get { return "RCT"; } }
|
||||||
public override string Description { get { return "Majiro game engine RGB image format"; } }
|
public override string Description { get { return "Majiro game engine RGB image format"; } }
|
||||||
public override uint Signature { get { return 0x9a925a98; } }
|
public override uint Signature { get { return 0x9a925a98; } }
|
||||||
|
|
||||||
public static Dictionary<string, string> KnownKeys = new Dictionary<string, string> {
|
public bool OverlayFrames = true;
|
||||||
|
|
||||||
|
public static readonly Dictionary<string, string> KnownKeys = new Dictionary<string, string> {
|
||||||
{ "Akatsuki no Goei", "おぬぐり食べる?" },
|
{ "Akatsuki no Goei", "おぬぐり食べる?" },
|
||||||
{ "Nagisa no", "青い空に向かって、溜息を一つこぼす。" },
|
{ "Nagisa no", "青い空に向かって、溜息を一つこぼす。" },
|
||||||
{ "White ~blanche comme la lune~", "たった3枚の紙" },
|
{ "White ~blanche comme la lune~", "たった3枚の紙" },
|
||||||
@@ -119,40 +120,22 @@ namespace GameRes.Formats.Majiro
|
|||||||
var meta = info as RctMetaData;
|
var meta = info as RctMetaData;
|
||||||
if (null == meta)
|
if (null == meta)
|
||||||
throw new ArgumentException ("RctFormat.Read should be supplied with RctMetaData", "info");
|
throw new ArgumentException ("RctFormat.Read should be supplied with RctMetaData", "info");
|
||||||
if (meta.AddSize > 0)
|
byte[] base_image = null;
|
||||||
{
|
if (meta.AddSize > 0 && OverlayFrames)
|
||||||
Trace.WriteLine (string.Format ("{0} bytes of additional data", meta.AddSize), "RctFormat.Read");
|
base_image = ReadBaseImage (file, meta);
|
||||||
file.Position = meta.DataOffset;
|
|
||||||
byte[] data = new byte[meta.AddSize];
|
|
||||||
if (data.Length != file.Read (data, 0, data.Length))
|
|
||||||
throw new EndOfStreamException();
|
|
||||||
}
|
|
||||||
file.Position = meta.DataOffset + meta.AddSize;
|
file.Position = meta.DataOffset + meta.AddSize;
|
||||||
if (meta.IsEncrypted)
|
if (meta.IsEncrypted)
|
||||||
{
|
file = OpenEncryptedStream (file, meta.DataSize);
|
||||||
if (null == Key)
|
|
||||||
{
|
|
||||||
var password = QueryPassword();
|
|
||||||
if (string.IsNullOrEmpty (password))
|
|
||||||
throw new UnknownEncryptionScheme();
|
|
||||||
Key = InitDecryptionKey (password);
|
|
||||||
}
|
|
||||||
byte[] data = new byte[meta.DataSize];
|
|
||||||
if (data.Length != file.Read (data, 0, data.Length))
|
|
||||||
throw new EndOfStreamException();
|
|
||||||
|
|
||||||
for (int i = 0; i < data.Length; ++i)
|
|
||||||
{
|
|
||||||
data[i] ^= Key[i & 0x3FF];
|
|
||||||
}
|
|
||||||
file = new MemoryStream (data);
|
|
||||||
}
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var reader = new Reader (file, meta))
|
using (var reader = new Reader (file, meta))
|
||||||
{
|
{
|
||||||
reader.Unpack();
|
reader.Unpack();
|
||||||
return ImageData.Create (meta, PixelFormats.Bgr24, null, reader.Data, (int)meta.Width*3);
|
var pixels = reader.Data;
|
||||||
|
if (base_image != null)
|
||||||
|
pixels = CombineImage (base_image, pixels);
|
||||||
|
return ImageData.Create (meta, PixelFormats.Bgr24, null, pixels, (int)meta.Width*3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -163,6 +146,74 @@ namespace GameRes.Formats.Majiro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte[] CombineImage (byte[] base_image, byte[] overlay)
|
||||||
|
{
|
||||||
|
for (int i = 2; i < base_image.Length; i += 3)
|
||||||
|
{
|
||||||
|
if (0 == overlay[i-2] && 0 == overlay[i-1] && 0xff == overlay[i])
|
||||||
|
{
|
||||||
|
overlay[i-2] = base_image[i-2];
|
||||||
|
overlay[i-1] = base_image[i-1];
|
||||||
|
overlay[i] = base_image[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] ReadBaseImage (Stream file, RctMetaData meta)
|
||||||
|
{
|
||||||
|
file.Position = meta.DataOffset;
|
||||||
|
byte[] name_bin = new byte[meta.AddSize];
|
||||||
|
if (name_bin.Length != file.Read (name_bin, 0, name_bin.Length))
|
||||||
|
throw new EndOfStreamException();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string name = Encodings.cp932.GetString (name_bin, 0, name_bin.Length-1);
|
||||||
|
if (File.Exists (name))
|
||||||
|
{
|
||||||
|
using (var base_file = File.OpenRead (name))
|
||||||
|
{
|
||||||
|
var base_info = ReadMetaData (base_file) as RctMetaData;
|
||||||
|
if (null != base_info && 0 == base_info.AddSize
|
||||||
|
&& meta.Width == base_info.Width && meta.Height == base_info.Height)
|
||||||
|
{
|
||||||
|
base_file.Position = base_info.DataOffset;
|
||||||
|
Stream input = base_file;
|
||||||
|
if (base_info.IsEncrypted)
|
||||||
|
input = OpenEncryptedStream (base_file, base_info.DataSize);
|
||||||
|
using (var reader = new Reader (input, base_info))
|
||||||
|
{
|
||||||
|
reader.Unpack();
|
||||||
|
return reader.Data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { /* ignore baseline image read errors */ }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream OpenEncryptedStream (Stream file, uint data_size)
|
||||||
|
{
|
||||||
|
if (null == Key)
|
||||||
|
{
|
||||||
|
var password = QueryPassword();
|
||||||
|
if (string.IsNullOrEmpty (password))
|
||||||
|
throw new UnknownEncryptionScheme();
|
||||||
|
Key = InitDecryptionKey (password);
|
||||||
|
}
|
||||||
|
byte[] data = new byte[data_size];
|
||||||
|
if (data.Length != file.Read (data, 0, data.Length))
|
||||||
|
throw new EndOfStreamException();
|
||||||
|
|
||||||
|
for (int i = 0; i < data.Length; ++i)
|
||||||
|
{
|
||||||
|
data[i] ^= Key[i & 0x3FF];
|
||||||
|
}
|
||||||
|
return new MemoryStream (data);
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] InitDecryptionKey (string password)
|
private byte[] InitDecryptionKey (string password)
|
||||||
{
|
{
|
||||||
byte[] bin_pass = Encodings.cp932.GetBytes (password);
|
byte[] bin_pass = Encodings.cp932.GetBytes (password);
|
||||||
|
|||||||
Reference in New Issue
Block a user