From 4a42acbb691686cd47233b95459f84de3ae78693 Mon Sep 17 00:00:00 2001 From: morkt Date: Sun, 29 Jan 2017 06:56:48 +0400 Subject: [PATCH] implemented BMX, MBF, VPK1, WVX0 and WSM2 archives. --- ArcFormats/ArcFormats.csproj | 7 ++ ArcFormats/Tanaka/ArcARC0.cs | 72 +++++++++++++ ArcFormats/Tanaka/ArcBMX.cs | 82 ++++++++++++++ ArcFormats/Tanaka/ArcMBF.cs | 79 ++++++++++++++ ArcFormats/Tanaka/ArcVPK.cs | 82 ++++++++++++++ ArcFormats/Tanaka/ArcWRC.cs | 71 ++++++++++++ ArcFormats/Tanaka/ArcWSM.cs | 80 ++++++++++++++ ArcFormats/Tanaka/ImageBC.cs | 204 +++++++++++++++++++++++++++++++++++ supported.html | 20 +++- 9 files changed, 696 insertions(+), 1 deletion(-) create mode 100644 ArcFormats/Tanaka/ArcARC0.cs create mode 100644 ArcFormats/Tanaka/ArcBMX.cs create mode 100644 ArcFormats/Tanaka/ArcMBF.cs create mode 100644 ArcFormats/Tanaka/ArcVPK.cs create mode 100644 ArcFormats/Tanaka/ArcWRC.cs create mode 100644 ArcFormats/Tanaka/ArcWSM.cs create mode 100644 ArcFormats/Tanaka/ImageBC.cs diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index a5ba3ef4..cd3ff1e0 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -347,6 +347,13 @@ + + + + + + + diff --git a/ArcFormats/Tanaka/ArcARC0.cs b/ArcFormats/Tanaka/ArcARC0.cs new file mode 100644 index 00000000..82805506 --- /dev/null +++ b/ArcFormats/Tanaka/ArcARC0.cs @@ -0,0 +1,72 @@ +//! \file ArcARC0.cs +//! \date Sat Jan 28 17:58:01 2017 +//! \brief Archive format by Tanaka Tatsuhiro. +// +// Copyright (C) 2017 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; + +namespace GameRes.Formats.Will +{ + [Export(typeof(ArchiveFormat))] + public class Arc0Opener : ArchiveFormat + { + public override string Tag { get { return "ARC0/WILL"; } } + public override string Description { get { return "Tanaka Tatsuhiro's engine resource archive"; } } + public override uint Signature { get { return 0x30435241; } } // 'ARC0' + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public Arc0Opener () + { + Extensions = new string[] { "arc" }; + } + + public override ArcFile TryOpen (ArcView file) + { + uint total_size = file.View.ReadUInt32 (4); + if (total_size != file.MaxOffset) + return null; + int count = file.View.ReadInt32 (8); + if (!IsSaneCount (count)) + return null; + + var dir = new List (count); + uint index_offset = 0x10; + for (int i = 0; i < count; ++i) + { + uint offset = file.View.ReadUInt32 (index_offset); + uint size = file.View.ReadUInt32 (index_offset+4); + var name = file.View.ReadString (index_offset+0xC, 0x14); + var entry = FormatCatalog.Instance.Create (name); + entry.Offset = offset; + entry.Size = size; + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + index_offset += 0x20; + } + return new ArcFile (file, this, dir); + } + } +} diff --git a/ArcFormats/Tanaka/ArcBMX.cs b/ArcFormats/Tanaka/ArcBMX.cs new file mode 100644 index 00000000..87546767 --- /dev/null +++ b/ArcFormats/Tanaka/ArcBMX.cs @@ -0,0 +1,82 @@ +//! \file ArcBMX.cs +//! \date Sat Jan 28 17:16:32 2017 +//! \brief Archive format by Tanaka Tatsuhiro. +// +// Copyright (C) 2017 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; + +namespace GameRes.Formats.Will +{ + [Export(typeof(ArchiveFormat))] + public class BmxOpener : ArchiveFormat + { + public override string Tag { get { return "BMX"; } } + public override string Description { get { return "Tanaka Tatsuhiro's engine 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) + { + uint total_size = file.View.ReadUInt32 (0); + if (total_size != file.MaxOffset) + return null; + int count = file.View.ReadInt32 (4); + if (!IsSaneCount (count)) + return null; + + var dir = new List (count); + uint index_offset = 0x10; + uint next_offset = file.View.ReadUInt32 (index_offset+0x1C); + for (int i = 0; i < count; ++i) + { + var name = file.View.ReadString (index_offset, 0x1C); + if (0 == name.Length) + break; + index_offset += 0x20; + var entry = FormatCatalog.Instance.Create (name); + entry.Offset = next_offset; + if (i+1 < count) + { + next_offset = file.View.ReadUInt32 (index_offset+0x1C); + if (0 == next_offset) + next_offset = (uint)file.MaxOffset; + } + else + { + next_offset = (uint)file.MaxOffset; + } + entry.Size = (uint)(next_offset - entry.Offset); + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + if (string.IsNullOrEmpty (entry.Type)) + entry.Type = "image"; + dir.Add (entry); + } + if (0 == dir.Count) + return null; + return new ArcFile (file, this, dir); + } + } +} diff --git a/ArcFormats/Tanaka/ArcMBF.cs b/ArcFormats/Tanaka/ArcMBF.cs new file mode 100644 index 00000000..e4bd3214 --- /dev/null +++ b/ArcFormats/Tanaka/ArcMBF.cs @@ -0,0 +1,79 @@ +//! \file ArcMBF.cs +//! \date Sat Jan 28 18:07:18 2017 +//! \brief Graphic archive format by Tanaka Tatsuhiro. +// +// Copyright (C) 2017 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; + +namespace GameRes.Formats.Will +{ + [Export(typeof(ArchiveFormat))] + public class MbfOpener : ArchiveFormat + { + public override string Tag { get { return "MBF"; } } + public override string Description { get { return "Tanaka Tatsuhiro's engine image archive"; } } + public override uint Signature { get { return 0x3046424D; } } // 'MBF0' + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public override ArcFile TryOpen (ArcView file) + { + int count = file.View.ReadInt32 (4); + if (!IsSaneCount (count)) + return null; + uint data_offset = file.View.ReadUInt32 (8); + uint index_offset = 0x20; + if (0 != (file.View.ReadByte (0xC) & 1)) + { + index_offset += file.View.ReadUInt16 (index_offset); + --count; + } + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + uint name_length = file.View.ReadUInt16 (index_offset); + if (name_length < 3) + return null; + var name = file.View.ReadString (index_offset+2, name_length-2); + if (0 == name.Length) + return null; + var entry = FormatCatalog.Instance.Create (name); + dir.Add (entry); + index_offset += name_length; + } + foreach (var entry in dir) + { + if (!file.View.AsciiEqual (data_offset, "BC")) + return null; + entry.Offset = data_offset; + entry.Size = file.View.ReadUInt32 (data_offset+2); + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + entry.Type = "image"; + data_offset += entry.Size; + } + return new ArcFile (file, this, dir); + } + } +} diff --git a/ArcFormats/Tanaka/ArcVPK.cs b/ArcFormats/Tanaka/ArcVPK.cs new file mode 100644 index 00000000..408815c0 --- /dev/null +++ b/ArcFormats/Tanaka/ArcVPK.cs @@ -0,0 +1,82 @@ +//! \file ArcVPK.cs +//! \date Sun Jan 29 04:57:12 2017 +//! \brief Audio archive format by Tanaka Tatsuhiro. +// +// Copyright (C) 2017 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; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; + +namespace GameRes.Formats.Will +{ + [Export(typeof(ArchiveFormat))] + public class VpkOpener : ArchiveFormat + { + public override string Tag { get { return "VPK1"; } } + public override string Description { get { return "Tanaka Tatsuhiro's engine audio archive"; } } + public override uint Signature { get { return 0x314B5056; } } // 'VPK1' + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public VpkOpener () + { + Extensions = new string[] { "vpk" }; + } + + public override ArcFile TryOpen (ArcView file) + { + uint data_size = file.View.ReadUInt32 (4); + int count = file.View.ReadInt32 (8); + if (!IsSaneCount (count)) + return null; + + uint index_offset = 0x20; + uint index_size = file.View.ReadUInt32 (0xC); + if (data_size + index_size != file.MaxOffset) + return null; + long data_offset = index_offset + index_size; + if (data_offset >= file.MaxOffset || data_offset <= index_offset) + return null; + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + var name = file.View.ReadString (index_offset, 4); + if (0 == name.Length) + return null; + uint n1 = file.View.ReadUInt16 (index_offset+4); + uint n2 = file.View.ReadUInt16 (index_offset+6); + uint n3 = file.View.ReadUInt32 (index_offset+8); + name = string.Format ("{0}_{1:D2}_{2}_{3:D3}.wav", name, n1, n2, n3); + var entry = FormatCatalog.Instance.Create (name); + entry.Offset = file.View.ReadUInt32 (index_offset+0x0C); + entry.Size = file.View.ReadUInt32 (index_offset+0x10); + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + index_offset += 0x14; + } + return new ArcFile (file, this, dir); + } + } +} diff --git a/ArcFormats/Tanaka/ArcWRC.cs b/ArcFormats/Tanaka/ArcWRC.cs new file mode 100644 index 00000000..d3026ba4 --- /dev/null +++ b/ArcFormats/Tanaka/ArcWRC.cs @@ -0,0 +1,71 @@ +//! \file ArcWRC.cs +//! \date Sun Jan 29 05:18:02 2017 +//! \brief Audio archive format by Tanaka Tatsuhiro. +// +// Copyright (C) 2017 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; + +namespace GameRes.Formats.Will +{ + [Export(typeof(ArchiveFormat))] + public class WrcOpener : ArchiveFormat + { + public override string Tag { get { return "WRC"; } } + public override string Description { get { return "Tanaka Tatsuhiro's engine audio archive"; } } + public override uint Signature { get { return 0x30585657; } } // 'WVX0' + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public override ArcFile TryOpen (ArcView file) + { + uint total_size = file.View.ReadUInt32 (4); + if (total_size != file.MaxOffset) + return null; + int count = file.View.ReadInt32 (8); + if (!IsSaneCount (count)) + return null; + + var dir = new List (count); + uint index_offset = 0x10; + uint next_offset = file.View.ReadUInt32 (index_offset+0x1C); + for (int i = 0; i < count; ++i) + { + var name = file.View.ReadString (index_offset, 0x1C); + if (0 == name.Length) + return null; + index_offset += 0x20; + var entry = FormatCatalog.Instance.Create (name); + entry.Offset = next_offset; + next_offset = i+1 < count ? file.View.ReadUInt32 (index_offset+0x1C) : (uint)file.MaxOffset; + entry.Size = (uint)(next_offset - entry.Offset); + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + if (string.IsNullOrEmpty (entry.Type)) + entry.Type = "audio"; + dir.Add (entry); + } + return new ArcFile (file, this, dir); + } + } +} diff --git a/ArcFormats/Tanaka/ArcWSM.cs b/ArcFormats/Tanaka/ArcWSM.cs new file mode 100644 index 00000000..ce0b7742 --- /dev/null +++ b/ArcFormats/Tanaka/ArcWSM.cs @@ -0,0 +1,80 @@ +//! \file ArcWSM.cs +//! \date Sun Jan 29 05:30:28 2017 +//! \brief Music archive format by Tanaka Tatsuhiro. +// +// Copyright (C) 2017 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 GameRes.Utility; + +namespace GameRes.Formats.Will +{ + [Export(typeof(ArchiveFormat))] + public class WsmOpener : ArchiveFormat + { + public override string Tag { get { return "WSM"; } } + public override string Description { get { return "Tanaka Tatsuhiro's engine music archive"; } } + public override uint Signature { get { return 0x324D5357; } } // 'WSM2' + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public override ArcFile TryOpen (ArcView file) + { + uint index_size = file.View.ReadUInt32 (4); + int count = file.View.ReadInt32 (0xC); + if (!IsSaneCount (count) || index_size >= file.MaxOffset - 0x40) + return null; + int table_offset = file.View.ReadInt32 (0x10); + int table_count = file.View.ReadInt32 (0x14); + if (table_offset >= index_size || !IsSaneCount (table_count)) + return null; + var index = file.View.ReadBytes (0x40, index_size); + var dir = new List (count); + for (int i = 0; i < table_count; ++i) + { + var entry = new Entry { Type = "audio" }; + entry.Offset = index.ToUInt32 (table_offset) - 0x14; + entry.Size = index.ToUInt32 (table_offset+8) + 0x14; + table_offset += 0x20; + dir.Add (entry); + } + int index_offset = 0; + for (int i = 0; i < count; ++i) + { + int entry_pos = index.ToInt32 (index_offset); + index_offset += 4; + int name_length = index[entry_pos+1]; + var name = Binary.GetCString (index, entry_pos+2, name_length-2); + if (0 == name.Length) + return null; + entry_pos += name_length; + int entry_idx = index[entry_pos+3]; + if (entry_idx >= dir.Count) + return null; + var entry = dir[entry_idx]; + entry.Name = string.Format ("{0:D2}_{1}.wav", entry_idx, name); + } + return new ArcFile (file, this, dir); + } + } +} diff --git a/ArcFormats/Tanaka/ImageBC.cs b/ArcFormats/Tanaka/ImageBC.cs new file mode 100644 index 00000000..b80d2553 --- /dev/null +++ b/ArcFormats/Tanaka/ImageBC.cs @@ -0,0 +1,204 @@ +//! \file ImageBC.cs +//! \date Sat Jan 28 18:21:09 2017 +//! \brief Image format by Tanaka Tatsuhiro. +// +// Copyright (C) 2017 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; +using System.ComponentModel.Composition; +using System.IO; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using GameRes.Utility; + +namespace GameRes.Formats.Will +{ + internal class TxMetaData : BmpMetaData + { + public int Colors; + public int Stride; + public long DataOffset; + } + + [Export(typeof(ImageFormat))] + public class BcFormat : ImageFormat + { + public override string Tag { get { return "BC"; } } + public override string Description { get { return "Tanaka Tatsuhiro's engine image format"; } } + public override uint Signature { get { return 0; } } + + public override ImageMetaData ReadMetaData (IBinaryStream file) + { + var header = file.ReadHeader (0x12); + if (!header.AsciiEqual ("BC")) + return null; + uint data_offset = header.ToUInt32 (0xA); + uint width = file.ReadUInt32(); + uint height = file.ReadUInt32(); + file.ReadInt16(); + int bpp = file.ReadInt16(); + file.Position = 0x2E; + int colors = file.ReadInt32(); + file.Position = data_offset; + if (file.ReadUInt32() != 0x34305854) // 'TX04' + return null; + int stride = file.ReadUInt16(); + if (height != file.ReadUInt16()) + return null; + return new TxMetaData + { + Width = width, + Height = height, + BPP = bpp, + Stride = stride, + DataOffset = file.Position, + Colors = colors <= 0 ? 0x100 : colors, + }; + } + + public override ImageData Read (IBinaryStream file, ImageMetaData info) + { + var reader = new TxReader (file, (TxMetaData)info); + var pixels = reader.Unpack(); + return ImageData.CreateFlipped (info, reader.Format, reader.Palette, pixels, reader.Stride); + } + + public override void Write (Stream file, ImageData image) + { + throw new System.NotImplementedException ("BcFormat.Write not implemented"); + } + } + + internal class TxReader + { + IBinaryStream m_input; + TxMetaData m_info; + byte[] m_output; + + public PixelFormat Format { get; private set; } + public BitmapPalette Palette { get; private set; } + public byte[] Data { get { return m_output; } } + public int Stride { get { return m_info.Stride; } } + + public TxReader (IBinaryStream input, TxMetaData info) + { + m_input = input; + m_info = info; + m_output = new byte[m_info.Stride * (int)m_info.Height]; + if (24 == m_info.BPP) + Format = PixelFormats.Bgr24; + else if (32 == m_info.BPP) + Format = PixelFormats.Bgra32; + else if (16 == m_info.BPP) + Format = PixelFormats.Bgr555; + else if (8 == m_info.BPP) + { + Format = PixelFormats.Indexed8; + m_input.Position = 0x36; + Palette = ImageFormat.ReadPalette (m_input.AsStream, m_info.Colors); + } + else + throw new InvalidFormatException(); + } + + public byte[] Unpack () + { + m_input.Position = m_info.DataOffset; + Decompress(); + int pixel_size = m_info.BPP / 8; + if (pixel_size > 1) + { + for (int row = 0; row < m_output.Length; row += m_info.Stride) + { + int dst = row; + for (uint x = 1; x < m_info.Width; ++x) + { + for (int i = 0; i < pixel_size; ++i) + m_output[dst+pixel_size+i] += m_output[dst+i]; + dst += pixel_size; + } + } + } + return m_output; + } + + void Decompress () + { + m_input.Read (m_output, 0, 2); + int dst = 2; + while (dst < m_output.Length) + { + int count = m_input.ReadByte(); + if (-1 == count) + break; + if (0xE0 == (count & 0xE0)) + { + count = Math.Min ((count & 0x1F) + 1, m_output.Length - dst); + m_input.Read (m_output, dst, count); + dst += count; + continue; + } + int offset, src; + if (0xC0 == (count & 0xE0)) + { + // this is how it is in the original code + offset = (count + (m_input.ReadUInt8() << 5)) & 0x1F; + count = m_input.ReadUInt8(); + src = dst - 1 - offset; + } + else if (0 == (count & 0xC0)) + { + offset = (count >> 3) & 7; + count &= 7; + if (count != 7) + count += 2; + else + count = m_input.ReadUInt8(); + src = dst - 1 - offset; + } + else if (0x40 == (count & 0xC0)) + { + offset = (count >> 2) & 0xF; + count &= 3; + if (count != 3) + count += 2; + else + count = m_input.ReadUInt8(); + src = dst - Stride + offset - 8; + } + else + { + offset = (count >> 2) & 0xF; + count &= 3; + if (count != 3) + count += 2; + else + count = m_input.ReadUInt8(); + src = dst - Stride * 2 + offset - 8; + } + count = Math.Min (count, m_output.Length - dst); + Binary.CopyOverlapped (m_output, src, dst, count); + dst += count; + } + } + } +} diff --git a/supported.html b/supported.html index 3d35b97c..2347b2bb 100644 --- a/supported.html +++ b/supported.html @@ -435,6 +435,7 @@ Touka Gettan
*\x00\x00\x04\x00No *.warWARC 1.7
WARC 1.5
WARC 1.4
WARC 1.3
WARC 1.2NoShiina Rio +Ao no Juuai ShiinaRio v2.34
Aneiro ShiinaRio v2.49
Can Fes! ~Itazura Majo to Naisho no Gakuensai~ ShiinaRio v2.47
Chikan Circle ShiinaRio v2.46
@@ -443,7 +444,9 @@ Chuuchuu Nurse ShiinaRio v2.45
Classmate no Okaa-san ShiinaRio v2.37
Cleavage ShiinaRio v2.33
Danchi Wife ~Hitozuma Nude Model no Kenshin~ ShiinaRio v2.47
+Dokodemo Sukishite Itsudemo Sukishite ShiinaRio v2.44
Doushite Daite Kurenai no!?ShiinaRio v2.49
+Douryou no Oku-san ~Netori Tsuma, Netorare Tsuma~ ShiinaRio v2.46
Draculius ShiinaRio v2.38
Enkaku Sousa 2.36 or 2.37
Gensou no Idea ~Oratorio Phantasm Historia~ShiinaRio v2.49
@@ -458,6 +461,8 @@ Hitozuma Onna Kyoushi Reika ShiinaRio v2.39
Idol Koukai Chijoku Sex ShiinaRio v2.46
Intruder ShiinaRio v2.49
Itsuka, Dokoka de ~Ano Ameoto no Kioku~2.36 or 2.37
+Iyashinbo The Motion ShiinaRio v2.47
+Jukubo Gui ~Moto Guradoru no Okaa-san~ ShiinaRio v2.37
Kateinai Choukyou ShiinaRio v2.31
Kichiku Nakadashi SuieibuShiinaRio v2.41
Last Waltz ~Hakudaku Mamire no Natsu Gasshuku~ ShiinaRio v2.47
@@ -478,6 +483,7 @@ RinĂ—Sen ShiinaRio v2.47
Ryoumaden ~Houkago no Rakuen~ ShiinaRio v2.47
Sabae no Ou ShiinaRio v2.36
Shinigami no Testament ShiinaRio v2.49
+Shinseki no Oba-san ~Hanare no Netsujo, Honke no Gosai~ ShiinaRio v2.36
Shojo MamaShiinaRio v2.49
Signalist Stars!!ShiinaRio v2.50
Sorcery JokersShiinaRio v2.50
@@ -1081,8 +1087,10 @@ Hitomi no Rakuin ~Inbaku no Mesu Dorei~
Jokujima
Saiin Haramase Keyword
-*.grp
*.bin-
TPWNoTirol
Ankh +*.grp
*.bin-
TPWNoTirol
Talisman
Ankh Aigan Shoujo
+Blaze of Destiny
+Blaze of Destiny II
Mozu
*.gpcGpc7NoSuper NekoX @@ -1287,6 +1295,7 @@ Lost Child
*.esdESDNo *.pakNEKOPACK4ANoNekoSDK In Vitro Shoujo -Aragaishi Junshin Naru Shoujo-
+Kyonyuu Fantasy - Digital Novel
Shirudaku Settai Okawari Ippaime
*.pcfPackCodeNoSymphony @@ -1385,6 +1394,15 @@ Shoukoujo
*.arc\x00ARCNoOne-up Dedenden!
+*.arcARC0NoWill +Bishimai Kutsujoku no Heya
+ +*.bmx-No +*.mbfMBF0No +*.vpkVPK1No +*.wrcWVX0No +*.wsmWSM2No +*BCNo

1 Non-encrypted only