diff --git a/ArcFormats/Softpal/ImagePGD.cs b/ArcFormats/Softpal/ImagePGD.cs index 412761b9..6c3cd836 100644 --- a/ArcFormats/Softpal/ImagePGD.cs +++ b/ArcFormats/Softpal/ImagePGD.cs @@ -23,6 +23,7 @@ // IN THE SOFTWARE. // +using System; using System.ComponentModel.Composition; using System.IO; using System.Windows.Media; @@ -61,12 +62,9 @@ namespace GameRes.Formats.Softpal public override ImageData Read (Stream stream, ImageMetaData info) { - stream.Position = 0x20; - using (var reader = new ArcView.Reader (stream)) + using (var reader = new PgdReader (stream, 0x20)) { - int unpacked_size = reader.ReadInt32(); - reader.ReadInt32(); // packed_size - var planes = Unpack (reader, unpacked_size); + var planes = reader.Unpack11(); var pixels = new byte[planes.Length]; int plane_size = (int)info.Width*(int)info.Height; int b_src = 0; @@ -85,40 +83,177 @@ namespace GameRes.Formats.Softpal } } - byte[] Unpack (BinaryReader input, int unpacked_size) + public override void Write (Stream file, ImageData image) { - var output = new byte[unpacked_size]; - int dst = 0; - int ctl = 2; - while (dst < output.Length) + throw new NotImplementedException ("Pgd11Format.Write not implemented"); + } + } + + [Export(typeof(ImageFormat))] + public class Pgd00Format : ImageFormat + { + public override string Tag { get { return "PGD/00_C"; } } + public override string Description { get { return "Image format used by Softpal subsidiaries"; } } + public override uint Signature { get { return 0; } } + + public Pgd00Format () + { + Extensions = new string[] { "pgd" }; + } + + public override ImageMetaData ReadMetaData (Stream stream) + { + var header = new byte[0x24]; + if (header.Length != stream.Read (header, 0, header.Length)) + return null; + if (!Binary.AsciiEqual (header, 0x18, "00_C")) + return null; + return new ImageMetaData { - ctl >>= 1; - if (1 == ctl) + Width = LittleEndian.ToUInt32 (header, 8), + Height = LittleEndian.ToUInt32 (header, 12), + OffsetX = LittleEndian.ToInt32 (header, 0), + OffsetY = LittleEndian.ToInt32 (header, 4), + BPP = 32, + }; + } + + public override ImageData Read (Stream stream, ImageMetaData info) + { + using (var reader = new PgdReader (stream, 0x1C)) + { + var data = reader.Unpack00(); + using (var tga = new MemoryStream (data)) { - ctl = input.ReadByte() | 0x100; + var tga_info = Tga.ReadMetaData (tga); + if (null == tga_info) + throw new InvalidFormatException(); + tga.Position = 0; + return Tga.Read (tga, tga_info); } - int count; - if (0 != (ctl & 1)) - { - int src = input.ReadUInt16(); - count = input.ReadByte(); - if (dst >= 0xFFC) - src += dst - 0xFFC; - Binary.CopyOverlapped (output, src, dst, count); - } - else - { - count = input.ReadByte(); - input.Read (output, dst, count); - } - dst += count; } - return output; } public override void Write (Stream file, ImageData image) { - throw new System.NotImplementedException ("Pgd11Format.Write not implemented"); + throw new NotImplementedException ("Pgd00Format.Write not implemented"); } } + + [Export(typeof(ImageFormat))] + public class PgdTgaFormat : TgaFormat + { + public override string Tag { get { return "PGD/TGA"; } } + public override string Description { get { return "Image format used by Softpal subsidiaries"; } } + public override uint Signature { get { return 0; } } + + public PgdTgaFormat () + { + Extensions = new string[] { "pgd" }; + } + + public override ImageMetaData ReadMetaData (Stream stream) + { + var header = new byte[0x2A]; + if (header.Length != stream.Read (header, 0, header.Length)) + return null; + int x = LittleEndian.ToInt32 (header, 0); + int y = LittleEndian.ToInt32 (header, 4); + if (Math.Abs (x) > 0x2000 || Math.Abs (y) > 0x2000) + return null; + uint width = LittleEndian.ToUInt32 (header, 8); + uint height = LittleEndian.ToUInt32 (header, 12); + if (0 == width || 0 == height + || width != LittleEndian.ToUInt16 (header, 0x24) + || height != LittleEndian.ToUInt16 (header, 0x26)) + return null; + stream.Position = 0x18; + var tga_info = base.ReadMetaData (stream); + if (null == tga_info) + return null; + tga_info.OffsetX = x; + tga_info.OffsetY = y; + return tga_info; + } + + public override ImageData Read (Stream stream, ImageMetaData info) + { + using (var tga = new StreamRegion (stream, 0x18)) + return base.Read (tga, info); + } + + public override void Write (Stream file, ImageData image) + { + throw new NotImplementedException ("PgdTgaFormat.Write not implemented"); + } + } + + internal sealed class PgdReader : IDisposable + { + BinaryReader m_input; + byte[] m_output; + + public byte[] Data { get { return m_output; } } + + public PgdReader (Stream input, int position) + { + input.Position = position; + m_input = new ArcView.Reader (input); + int unpacked_size = m_input.ReadInt32(); + m_input.ReadInt32(); // packed_size + m_output = new byte[unpacked_size]; + } + + public byte[] Unpack00 () + { + return Unpack (3000); + } + + public byte[] Unpack11 () + { + return Unpack (0xFFC); + } + + byte[] Unpack (int look_behind) + { + int dst = 0; + int ctl = 2; + while (dst < m_output.Length) + { + ctl >>= 1; + if (1 == ctl) + { + ctl = m_input.ReadByte() | 0x100; + } + int count; + if (0 != (ctl & 1)) + { + int src = m_input.ReadUInt16(); + count = m_input.ReadByte(); + if (dst > look_behind) + src += dst - look_behind; + Binary.CopyOverlapped (m_output, src, dst, count); + } + else + { + count = m_input.ReadByte(); + m_input.Read (m_output, dst, count); + } + dst += count; + } + return m_output; + } + + #region IDisposable Members + bool _disposed = false; + public void Dispose () + { + if (!_disposed) + { + m_input.Dispose(); + _disposed = true; + } + } + #endregion + } } diff --git a/supported.html b/supported.html index f6eff8d9..020848e8 100644 --- a/supported.html +++ b/supported.html @@ -690,6 +690,7 @@ Komokyun!! ~Heart ni Yureru Tamashi no Fandisc~
Houmon Hanbai ~Otona no Omocha Irimasen ka?~
*.pac-
PACNoUnison Shift +Maruhi Jinjibu Ryoujokuka
Unity Marriage ~Futari no Hanayome~
*.pgdGENo