From 803dfdfdda55bb4f0ebb6d07a0a713986b1fc432 Mon Sep 17 00:00:00 2001 From: morkt Date: Sun, 7 Oct 2018 08:59:21 +0400 Subject: [PATCH] (Legacy): DM archives and PKT images. --- Legacy/DigitalMonkey/ArcDM.cs | 85 ++++++++++++++ Legacy/DigitalMonkey/ImagePKT.cs | 183 +++++++++++++++++++++++++++++++ 2 files changed, 268 insertions(+) create mode 100644 Legacy/DigitalMonkey/ArcDM.cs create mode 100644 Legacy/DigitalMonkey/ImagePKT.cs diff --git a/Legacy/DigitalMonkey/ArcDM.cs b/Legacy/DigitalMonkey/ArcDM.cs new file mode 100644 index 00000000..c161203a --- /dev/null +++ b/Legacy/DigitalMonkey/ArcDM.cs @@ -0,0 +1,85 @@ +//! \file ArcDM.cs +//! \date 2018 Oct 07 +//! \brief Digital Monkey resource archive. +// +// Copyright (C) 2018 by morkt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using GameRes.Compression; + +namespace GameRes.Formats.DigitalMonkey +{ + [Export(typeof(ArchiveFormat))] + public class DmOpener : ArchiveFormat + { + public override string Tag { get { return "DM"; } } + public override string Description { get { return "Digital Monkey resource archive"; } } + public override uint Signature { get { return 0; } } + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public override ArcFile TryOpen (ArcView file) + { + if (!file.Name.HasExtension (".dm")) + return null; + int count = file.View.ReadInt32 (0); + if (!IsSaneCount (count)) + return null; + var arc_name = Path.GetFileNameWithoutExtension (file.Name).ToLowerInvariant(); + string type = arc_name == "image" ? "image" + : arc_name == "sound" ? "audio" : ""; + uint index_offset = 4; + uint data_offset = 4 + (uint)count * 0x2C; + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + var name = file.View.ReadString (index_offset, 0x20); + if (string.IsNullOrWhiteSpace (name)) + return null; + var entry = new PackedEntry { + Name = name, + Type = type, + UnpackedSize = file.View.ReadUInt32 (index_offset+0x20), + Size = file.View.ReadUInt32 (index_offset+0x24), + Offset = file.View.ReadUInt32 (index_offset+0x28), + IsPacked = true, + }; + if (entry.Offset < data_offset || !entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + index_offset += 0x2C; + } + return new ArcFile (file, this, dir); + } + + public override Stream OpenEntry (ArcFile arc, Entry entry) + { + var pent = (PackedEntry)entry; + if (null == pent || !pent.IsPacked) + return base.OpenEntry (arc, entry); + var input = arc.File.CreateStream (entry.Offset, entry.Size); + return new ZLibStream (input, CompressionMode.Decompress); + } + } +} diff --git a/Legacy/DigitalMonkey/ImagePKT.cs b/Legacy/DigitalMonkey/ImagePKT.cs new file mode 100644 index 00000000..718c01d2 --- /dev/null +++ b/Legacy/DigitalMonkey/ImagePKT.cs @@ -0,0 +1,183 @@ +//! \file ImagePKT.cs +//! \date 2018 Oct 07 +//! \brief Digital Monkey image format. +// +// Copyright (C) 2018 by morkt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +using System.ComponentModel.Composition; +using System.IO; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +// [030725][Digital Monkey] Kono Sora ga Tsuieru Toki ni + +namespace GameRes.Formats.DigitalMonkey +{ + internal class PktMetaData : ImageMetaData + { + public int Version; + public uint DataOffset; + public uint AlphaOffset; + public bool HasAlpha; + public int AlphaRleCount; + } + + [Export(typeof(ImageFormat))] + public class PktFormat : ImageFormat + { + public override string Tag { get { return "PKT/DM"; } } + public override string Description { get { return "Digital Monkey image format"; } } + public override uint Signature { get { return 0x31544B50; } } // 'PKT10' + + public PktFormat () + { + Extensions = new [] { "pkt", "msk", /*"dm"*/ }; + Signatures = new uint[] { 0x31544B50, 0x32544B50, 0x39544B50 }; // 'PKT10', 'PKT20', 'PKT99' + } + + public override ImageMetaData ReadMetaData (IBinaryStream file) + { + var header = file.ReadHeader (0x30); + if (header[5] != 0) + return null; + int version = header[3] * 10 + header[4] - 528; + if (version != 10 && version != 20 && version != 99) + return null; + return new PktMetaData { + Width = header.ToUInt32 (0x14), + Height = header.ToUInt32 (0x18), + BPP = 20 == version ? 24 : 8, + Version = version, + DataOffset = header.ToUInt32 (0x20), + AlphaOffset = header.ToUInt32 (0x24), + HasAlpha = header.ToInt32 (0x28) != 0, + AlphaRleCount = header.ToInt32 (0x2C), + }; + } + + public override ImageData Read (IBinaryStream file, ImageMetaData info) + { + var reader = new PktReader (file, (PktMetaData)info); + var pixels = reader.Unpack(); + return ImageData.Create (info, reader.Format, reader.Palette, pixels); + } + + public override void Write (Stream file, ImageData image) + { + throw new System.NotImplementedException ("PktFormat.Write not implemented"); + } + } + + internal class PktReader + { + IBinaryStream m_input; + PktMetaData m_info; + byte[] m_output; + + public PixelFormat Format { get; private set; } + public BitmapPalette Palette { get; private set; } + + public PktReader (IBinaryStream input, PktMetaData info) + { + m_input = input; + m_info = info; + if (99 == m_info.Version) + Format = PixelFormats.Gray8; + else if (m_info.HasAlpha) + Format = PixelFormats.Bgra32; + else if (10 == m_info.Version) + Format = PixelFormats.Indexed8; + else if (20 == m_info.Version) + Format = PixelFormats.Bgr24; + else + throw new InvalidFormatException(); + m_output = new byte[(int)m_info.Width * (int)m_info.Height * (m_info.BPP / 8)]; + } + + public byte[] Unpack () + { + if (99 == m_info.Version) + return ReadGrayScale(); + m_input.Position = m_info.DataOffset; + if (10 == m_info.Version) + Palette = ImageFormat.ReadPalette (m_input.AsStream, 0x100, PaletteFormat.Bgr); + m_input.Read (m_output, 0, m_output.Length); + if (!m_info.HasAlpha) + return m_output; + m_input.Position = m_info.AlphaOffset; + int plane_size = (int)m_info.Width * (int)m_info.Height; + var alpha = new byte[plane_size]; + RleUnpack (m_input, m_info.AlphaRleCount, alpha); + var pixels = new byte[4 * plane_size]; + if (8 == m_info.BPP) + ApplyAlpha8bpp (alpha, pixels); + else + ApplyAlpha24bpp (alpha, pixels); + return pixels; + } + + byte[] ReadGrayScale () + { + m_input.Position = m_info.AlphaOffset + 8; + RleUnpack (m_input, m_info.AlphaRleCount, m_output); + return m_output; + } + + void ApplyAlpha8bpp (byte[] alpha, byte[] output) + { + var colors = Palette.Colors; + int dst = 0; + for (int src = 0; src < m_output.Length; ++src) + { + var color = colors[m_output[src]]; + output[dst++] = color.B; + output[dst++] = color.G; + output[dst++] = color.R; + output[dst++] = alpha[src]; + } + } + + void ApplyAlpha24bpp (byte[] alpha, byte[] output) + { + int src = 0, dst = 0; + for (int asrc = 0; asrc < alpha.Length; ++asrc) + { + output[dst++] = m_output[src++]; + output[dst++] = m_output[src++]; + output[dst++] = m_output[src++]; + output[dst++] = alpha[asrc]; + } + } + + internal static void RleUnpack (IBinaryStream input, int chunk_count, byte[] output) + { + int dst = 0; + for (int i = 0; i < chunk_count; ++i) + { + int count = input.ReadUInt8(); + byte val = input.ReadUInt8(); + for (int j = 0; j < count; ++j) + output[dst++] = val; + } + } + } +}