diff --git a/Legacy/ADVGSys/ImageBMP.cs b/Legacy/ADVGSys/ImageBMP.cs new file mode 100644 index 00000000..e63e23a9 --- /dev/null +++ b/Legacy/ADVGSys/ImageBMP.cs @@ -0,0 +1,68 @@ +//! \file ImageBMP.cs +//! \date 2019 May 29 +//! \brief Compressed bitmap format. +// +// Copyright (C) 2019 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 GameRes.Compression; + +namespace GameRes.Formats.AdvgSys +{ + [Export(typeof(ImageFormat))] + public class AdvgFormat : ImageFormat + { + public override string Tag { get { return "BMP/ADVG"; } } + public override string Description { get { return "Compressed bitmap format"; } } + public override uint Signature { get { return 0; } } + + public override ImageMetaData ReadMetaData (IBinaryStream file) + { + var header = file.ReadHeader (0xA); + if (!((header[4] & 0xF) == 0xF && header.AsciiEqual (5, "BM"))) + return null; + using (var input = OpenBitmapStream (file)) + return Bmp.ReadMetaData (input); + } + + public override ImageData Read (IBinaryStream file, ImageMetaData info) + { + using (var input = OpenBitmapStream (file, true)) + return Bmp.Read (input, info); + } + + internal IBinaryStream OpenBitmapStream (IBinaryStream input, bool seekable = false) + { + input.Position = 4; + Stream bmp = new LzssStream (input.AsStream, LzssMode.Decompress, true); + if (seekable) + bmp = new SeekableStream (bmp); + return new BinaryStream (bmp, input.Name); + } + + public override void Write (Stream file, ImageData image) + { + throw new System.NotImplementedException ("AdvgFormat.Write not implemented"); + } + } +} diff --git a/Legacy/Aos/ArcDAT.cs b/Legacy/Aos/ArcDAT.cs new file mode 100644 index 00000000..fdd0f628 --- /dev/null +++ b/Legacy/Aos/ArcDAT.cs @@ -0,0 +1,72 @@ +//! \file ArcDAT.cs +//! \date 2019 Jun 06 +//! \brief AOS engine resource archive. +// +// Copyright (C) 2019 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; + +// [001124][emu] Luna Season ~150 Bun no 1 no Koibito~ + +namespace GameRes.Formats.Aos +{ + [Export(typeof(ArchiveFormat))] + public class DatOpener : ArchiveFormat + { + public override string Tag { get { return "DAT/PACK"; } } + public override string Description { get { return "AOS 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) + { + if (!file.Name.HasExtension (".dat")) + return null; + var idx_name = VFS.ChangeFileName (file.Name, "index.idx"); + if (!VFS.FileExists (idx_name)) + return null; + using (var index = VFS.OpenBinaryStream (idx_name)) + { + var dir = new List(); + while (index.PeekByte() != -1) + { + var name = index.ReadCString (0x34); + if (string.IsNullOrEmpty (name)) + break; + var entry = Create (name); + entry.Offset = index.ReadUInt32(); + entry.Size = index.ReadUInt32(); + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + } + if (0 == dir.Count) + return null; + return new ArcFile (file, this, dir); + } + } + } +} diff --git a/Legacy/Artel/ArcPFD.cs b/Legacy/Artel/ArcPFD.cs new file mode 100644 index 00000000..4cee172d --- /dev/null +++ b/Legacy/Artel/ArcPFD.cs @@ -0,0 +1,70 @@ +//! \file ArcPFD.cs +//! \date 2019 May 22 +//! \brief ADVG Script Interpreter System resource archive. +// +// Copyright (C) 2019 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; + +// [060127][Artel] Horizont + +namespace GameRes.Formats.Artel +{ + [Export(typeof(ArchiveFormat))] + public class PfdOpener : ArchiveFormat + { + public override string Tag { get { return "PFD"; } } + public override string Description { get { return "Artel ADVG 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) + { + int count = file.View.ReadInt32 (0); + if (!IsSaneCount (count)) + return null; + int index_offset = 4; + int data_offset = index_offset + count * 0x20; + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + var name = file.View.ReadString (index_offset, 0x15); + if (string.IsNullOrEmpty (name)) + return null; + var ext = file.View.ReadString (index_offset+0x15, 3); + if (!string.IsNullOrEmpty (ext)) + name = Path.ChangeExtension (name, ext); + var entry = Create (name); + entry.Offset = file.View.ReadUInt32 (index_offset+0x18); + entry.Size = file.View.ReadUInt32 (index_offset+0x1C); + if (entry.Offset < data_offset || !entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + index_offset += 0x20; + } + return new ArcFile (file, this, dir); + } + } +} diff --git a/Legacy/Artel/AudioMUW.cs b/Legacy/Artel/AudioMUW.cs new file mode 100644 index 00000000..d66785eb --- /dev/null +++ b/Legacy/Artel/AudioMUW.cs @@ -0,0 +1,60 @@ +//! \file AudioMUW.cs +//! \date 2019 May 22 +//! \brief ADVG Script Interpreter System audio file. +// +// Copyright (C) 2019 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; + +namespace GameRes.Formats.Artel +{ + [Export(typeof(AudioFormat))] + public class MuwAudio : AudioFormat + { + public override string Tag { get { return "MUW"; } } + public override string Description { get { return "Artel ADVG engine audio file"; } } + public override uint Signature { get { return 0x46464952; } } // 'RIFF' + public override bool CanWrite { get { return false; } } + + public override SoundInput TryOpen (IBinaryStream file) + { + var header = file.ReadHeader (0x24); + if (!header.AsciiEqual (0, "RIFF") || !header.AsciiEqual (8, "PCMWFMT ")) + return null; + uint data_pos = header.ToUInt32 (0x10) + 0x14; + file.Position = data_pos; + if (file.ReadUInt32() != 0x61746164) // 'data' + return null; + uint data_size = file.ReadUInt32(); + var format = new WaveFormat { + FormatTag = header.ToUInt16 (0x14), + Channels = header.ToUInt16 (0x16), + SamplesPerSecond = header.ToUInt32 (0x18), + AverageBytesPerSecond = header.ToUInt32 (0x1C), + BlockAlign = header.ToUInt16 (0x20), + BitsPerSample = header.ToUInt16 (0x22), + }; + var pcm = new StreamRegion (file.AsStream, data_pos+8, data_size); + return new RawPcmInput (pcm, format); + } + } +} diff --git a/Legacy/Artel/ImageMRL.cs b/Legacy/Artel/ImageMRL.cs new file mode 100644 index 00000000..6bb9deb2 --- /dev/null +++ b/Legacy/Artel/ImageMRL.cs @@ -0,0 +1,165 @@ +//! \file ImageMRL.cs +//! \date 2019 May 22 +//! \brief ADVG Script Interpreter System image format. +// +// Copyright (C) 2019 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; + +namespace GameRes.Formats.Artel +{ + internal class MrlMetaData : ImageMetaData + { + public bool HasAlpha; + } + + [Export(typeof(ImageFormat))] + public class MrlFormat : ImageFormat + { + public override string Tag { get { return "MRL"; } } + public override string Description { get { return "Artel ADVG engine image format"; } } + public override uint Signature { get { return 0x524D754D; } } // 'MuMRL' + + public override ImageMetaData ReadMetaData (IBinaryStream file) + { + var header = file.ReadHeader (0x18); + if (header[4] != 'L') + return null; + int bpp = header.ToUInt16 (0xC) * 8; + bool has_alpha = (header[8] & 8) != 0; + if (24 == bpp && has_alpha) + bpp = 32; + return new MrlMetaData { + Width = header.ToUInt32 (0x10), + Height = header.ToUInt32 (0x14), + BPP = bpp, + HasAlpha = has_alpha, + }; + } + + public override ImageData Read (IBinaryStream file, ImageMetaData info) + { + var meta = (MrlMetaData)info; + BitmapPalette palette = null; + file.Position = 0x18; + if (8 == info.BPP) + palette = ReadPalette (file.AsStream); + int stride = info.iWidth * (info.BPP / 8); + int channel_size = info.iWidth * info.iHeight; + var pixels = new byte[stride * info.iHeight]; + var input_length = (int)(file.Length - file.Position); + var input = file.ReadBytes (input_length); + + DecryptInput (input, 8); + MrlDecompress (input, pixels); + RestoreOutput (pixels); + + byte[] image; + if (8 == info.BPP) + { + if (!meta.HasAlpha) + return ImageData.CreateFlipped (info, PixelFormats.Indexed8, palette, pixels, stride); + stride = info.iWidth * 4; + image = new byte[stride * info.iHeight]; + int src = 0; + int asrc = channel_size; + var colors = palette.Colors; + for (int dst = 0; dst < image.Length; dst += 4) + { + byte c = pixels[src++]; + image[dst ] = colors[c].B; + image[dst+1] = colors[c].G; + image[dst+2] = colors[c].R; + image[dst+3] = pixels[asrc++]; + } + } + else + { + image = new byte[pixels.Length]; + int channels = info.BPP / 8; + int src = 0; + for (int c = 0; c < channels; ++c) + { + int dst = c; + for (int i = 0; i < channel_size; ++i) + { + image[dst] = pixels[src++]; + dst += channels; + } + } + } + PixelFormat format = meta.HasAlpha ? PixelFormats.Bgra32 : PixelFormats.Bgr24; + return ImageData.CreateFlipped (info, format, palette, image, stride); + } + + public override void Write (Stream file, ImageData image) + { + throw new System.NotImplementedException ("MrlFormat.Write not implemented"); + } + + internal static void DecryptInput (byte[] data, byte key) + { + for (int i = 0; i < data.Length; ++i) + { + data[i] ^= key++; + } + } + + internal static void MrlDecompress (byte[] input, byte[] output) + { + int src = 0; + int dst = 0; + while (src < input.Length && dst < output.Length) + { + byte p = input[src++]; + if (p != 0) + { + output[dst++] = p; + } + else + { + int count = 1; + do + { + p = input[src++]; + count += p; + } + while (0xFF == p); + dst += count; + } + } + } + + internal static void RestoreOutput (byte[] data) + { + byte key = data[0]; + for (int i = 1; i < data.Length; ++i) + { + data[i] ^= key; + key = data[i]; + } + } + } +} diff --git a/Legacy/Bom/ImageGRP.cs b/Legacy/Bom/ImageGRP.cs index 3d5e5ef3..e490e06e 100644 --- a/Legacy/Bom/ImageGRP.cs +++ b/Legacy/Bom/ImageGRP.cs @@ -160,7 +160,7 @@ namespace GameRes.Formats.Bom for (int i = 0; i <= 316; ++i) { v4 = dword_6FF464[v1] + dword_6FF468[v1]; - dword_709870[v1] = v2; + dword_70986C[v1 + 1] = v2; dword_6FF95C[i] = v4; dword_704360[i] = v1; dword_70986C[v1] = v2; @@ -175,9 +175,13 @@ namespace GameRes.Formats.Bom dword_6FFE50 = 0xFFFF; } + int[] dword_704360 = new int[317]; + int[] dword_6FF95C = new int[317]; + int[] dword_70986C = new int[634]; + int sub_408BE0 () { - for (int i = dword_704850; i < 635; i = dword_703E68[GetNextBit() + i]) + for (int i = dword_704360[316]; i < 635; i = dword_703E68[GetNextBit() + i]) ; int ctl = i - 635; sub_408C80 (ctl); @@ -210,7 +214,7 @@ namespace GameRes.Formats.Bom int v8; // eax@7 int v9; // esi@9 - if (dword_6FFE4C == 0x8000) + if (dword_6FF95C[316] == 0x8000) sub_408D50(); int v1 = dword_70A258[a1]; do @@ -251,6 +255,98 @@ namespace GameRes.Formats.Bom while (v1 != 0); } + void sub_408D50 () + { + int v3; // ecx@2 + int v4; // edi@3 + int v5; // ecx@5 + int *v6; // ebx@5 + unsigned int v7; // eax@6 + int *v8; // edx@6 + int v9; // ecx@6 + int *v10; // edi@6 + unsigned int v11; // ebp@7 + int v12; // ecx@8 + int *i; // edi@8 + int *v14; // eax@10 + int *v15; // ecx@10 + int v16; // edx@13 + int *v17; // ecx@13 + int v18; // eax@14 + int v19; // [sp+10h] [bp-8h]@5 + signed int v20; // [sp+14h] [bp-4h]@5 + + int v1 = 0; + int v2 = 0; + for (int i = 0; i < 635; ++i) + { + int v3 = dword_703E68[i]; + if (v3 >= 635) + { + v4 = dword_6FF464[i]; + dword_703E68[v2] = v3; + dword_6FF464[v2] = (int)((uint)(v4 + 1) >> 1); + ++v2; + } + } + int v5 = 318; + v19 = 0; + v20 = 318; + v6 = dword_6FF464; + do + { + v7 = *v6 + v6[1]; + v8 = &dword_6FF95C[v1]; + v9 = v5 - 1; + v10 = &dword_6FF95C[v1 - 1]; + dword_6FF95C[v1] = v7; + if ( v7 < *v10 ) + { + do + { + v11 = *(v10 - 1); + --v10; + --v9; + } + while ( v7 < v11 ); + } + v12 = v9 + 1; + for ( i = &dword_6FF464[v12]; v8 > i; --v8 ) + *v8 = *(v8 - 1); + *i = v7; + v14 = &dword_704360[v1]; + v15 = &dword_703E68[v12]; + if ( &dword_704360[v1] > v15 ) + { + do + { + *v14 = *(v14 - 1); + --v14; + } + while ( v14 > v15 ); + } + v6 += 2; + *v15 = v19; + ++v1; + v5 = v20 + 1; + v19 += 2; + ++v20; + } + while ( v1 < 317 ); + v16 = 0; + v17 = dword_703E68; + do + { + v18 = *v17; + if ( *v17 < 635 ) + dword_70986C[v18 + 1] = v16; + dword_70986C[v18] = v16; + ++v17; + ++v16; + } + while ( (signed int)v17 < (signed int)&unk_704854 ); + } + void PutByte (int a1) { if (dword_6FF460 != 0) diff --git a/Legacy/Dall/ArcPEL.cs b/Legacy/Dall/ArcPEL.cs new file mode 100644 index 00000000..d7081b2d --- /dev/null +++ b/Legacy/Dall/ArcPEL.cs @@ -0,0 +1,69 @@ +//! \file ArcPEL.cs +//! \date 2019 May 28 +//! \brief Dall resource archive. +// +// Copyright (C) 2019 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.Dall +{ + [Export(typeof(ArchiveFormat))] + public class PelOpener : ArchiveFormat + { + public override string Tag { get { return "PEL"; } } + public override string Description { get { return "Dall 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 ("PEL")) + return null; + int count = file.View.ReadInt16 (0); + if (!IsSaneCount (count)) + return null; + using (var input = file.CreateStream()) + { + input.Position = 2; + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + var name = input.ReadCString (0x14); + uint size = input.ReadUInt32(); + var entry = Create (name); + entry.Offset = input.Position; + entry.Size = size; + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + input.Seek (size, SeekOrigin.Current); + } + return new ArcFile (file, this, dir); + } + } + } +} diff --git a/Legacy/Discovery/ArcDAT.cs b/Legacy/Discovery/ArcDAT.cs index a2331742..acfb6fe3 100644 --- a/Legacy/Discovery/ArcDAT.cs +++ b/Legacy/Discovery/ArcDAT.cs @@ -32,6 +32,7 @@ using System.Windows.Media.Imaging; using GameRes.Compression; // [000225][Discovery] Tsukiyo no Hitomi wa Kurenai ni +// [001102][Discovery] Twins Rhapsody namespace GameRes.Formats.Discovery { @@ -135,8 +136,8 @@ namespace GameRes.Formats.Discovery entry.BodySize = index.ToUInt32 (index_offset+4); entry.BodyUnpacked = index.ToUInt32 (index_offset+8); entry.BodyOffset = index.ToUInt32 (index_offset+0xC); - entry.HeaderUnpacked = index.ToUInt32 (index_offset+0x10); - entry.HeaderSize = index.ToUInt32 (index_offset+0x14); + entry.HeaderSize = index.ToUInt32 (index_offset+0x10); + entry.HeaderUnpacked = index.ToUInt32 (index_offset+0x14); entry.Offset = index.ToUInt32 (index_offset+0x18); entry.Size = entry.HeaderSize + entry.BodySize; entry.UnpackedSize = entry.HeaderUnpacked + entry.BodyUnpacked; @@ -270,16 +271,7 @@ namespace GameRes.Formats.Discovery public int Stride { get; private set; } public BitmapPalette Palette { get; private set; } - public ImageData Image { - get { - if (null == m_image) - { - Unpack(); - m_image = ImageData.CreateFlipped (Info, Format, Palette, m_output, Stride); - } - return m_image; - } - } + public ImageData Image { get { return m_image ?? (m_image = Unpack()); } } public BDataDecoder (ArcFile arc, BDataEntry entry) { @@ -289,14 +281,17 @@ namespace GameRes.Formats.Discovery if (entry.Extra > 0) total_size += 10 * (uint)entry.Extra + 2; Stride = ((int)entry.Width * entry.BPP / 8 + 3) & ~3; - Format = PixelFormats.Bgr24; + if (8 == entry.BPP) + Format = PixelFormats.Indexed8; + else + Format = PixelFormats.Bgr24; m_output = new byte[Stride * (int)entry.Height]; m_colors = entry.Colors; m_extra = entry.Extra; m_input = arc.File.CreateStream (entry.Offset, total_size); } - private void Unpack () + private ImageData Unpack () { m_input.Position = 0; if (m_colors > 0) @@ -305,6 +300,7 @@ namespace GameRes.Formats.Discovery m_input.Seek (10 * m_extra + 2, SeekOrigin.Current); using (var lzss = new LzssStream (m_input.AsStream, LzssMode.Decompress, true)) lzss.Read (m_output, 0, m_output.Length); + return ImageData.CreateFlipped (Info, Format, Palette, m_output, Stride); } bool m_disposed = false; diff --git a/Legacy/Eye/ImageCSF.cs b/Legacy/Eye/ImageCSF.cs new file mode 100644 index 00000000..fb9b2512 --- /dev/null +++ b/Legacy/Eye/ImageCSF.cs @@ -0,0 +1,67 @@ +//! \file ImageCSF.cs +//! \date 2019 May 28 +//! \brief Compressed bitmap format. +// +// Copyright (C) 2019 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 GameRes.Compression; + +namespace GameRes.Formats.Eye +{ + [Export(typeof(ImageFormat))] + public class CsfFormat : ImageFormat + { + public override string Tag { get { return "CSF"; } } + public override string Description { get { return "Compressed bitmap format"; } } + public override uint Signature { get { return 0; } } + + public override ImageMetaData ReadMetaData (IBinaryStream file) + { + var header = file.ReadHeader (0xB); + if (!header.AsciiEqual ("CSF")) + return null; + using (var input = UnpackedStream (file)) + return Bmp.ReadMetaData (input); + } + + public override ImageData Read (IBinaryStream file, ImageMetaData info) + { + using (var input = UnpackedStream (file)) + return Bmp.Read (input, info); + } + + IBinaryStream UnpackedStream (IBinaryStream input) + { + input.Position = 0xB; + var unpacked = new LzssStream (input.AsStream, LzssMode.Decompress, true); + return new BinaryStream (unpacked, input.Name); + } + + public override void Write (Stream file, ImageData image) + { + throw new System.NotImplementedException ("CsfFormat.Write not implemented"); + } + } +} diff --git a/Legacy/Legacy.csproj b/Legacy/Legacy.csproj index 511b4244..20ffc4ce 100644 --- a/Legacy/Legacy.csproj +++ b/Legacy/Legacy.csproj @@ -70,6 +70,7 @@ + @@ -78,10 +79,14 @@ + + + + @@ -90,9 +95,11 @@ + + @@ -124,6 +131,9 @@ + + + @@ -217,6 +227,8 @@ + + @@ -260,6 +272,7 @@ + diff --git a/Legacy/Libido/ArcARC.cs b/Legacy/Libido/ArcARC.cs index 9eb66d02..1b83f1ae 100644 --- a/Legacy/Libido/ArcARC.cs +++ b/Legacy/Libido/ArcARC.cs @@ -29,6 +29,7 @@ using System.ComponentModel.Composition; using System.IO; using GameRes.Compression; +// [991203][Libido] Ren'Ai Kumikyoku // [030228][Libido] Libido 7 DVD namespace GameRes.Formats.Libido @@ -48,27 +49,34 @@ namespace GameRes.Formats.Libido if (!IsSaneCount (count)) return null; + const int name_buf_size = 0x14; + var name_buf = new byte[name_buf_size]; + var is_name_encrypted = new Lazy (() => -1 != Array.IndexOf (name_buf, 0xFF, 0, name_buf_size)); uint index_offset = 4; - var name_buf = new byte[0x14]; var dir = new List (count); for (int i = 0; i < count; ++i) { - file.View.Read (index_offset, name_buf, 0, 0x14); + file.View.Read (index_offset, name_buf, 0, name_buf_size); int j; - for (j = 0; j < 0x14; ++j) + if (is_name_encrypted.Value) { - name_buf[j] ^= 0xFF; - if (0 == name_buf[j]) - break; + for (j = 0; j < name_buf_size; ++j) + { + name_buf[j] ^= 0xFF; + if (0 == name_buf[j]) + break; + } } - if (0 == j || -1 != Array.IndexOf (name_buf, 0xFF, 0, j)) + else + j = Array.IndexOf (name_buf, 0, 0, name_buf_size); + if (j <= 0 || -1 != Array.IndexOf (name_buf, 0xFF, 0, j)) return null; var name = Encodings.cp932.GetString (name_buf, 0, j); var entry = Create (name); entry.UnpackedSize = file.View.ReadUInt32 (index_offset+0x14); entry.Size = file.View.ReadUInt32 (index_offset+0x18); entry.Offset = file.View.ReadUInt32 (index_offset+0x1C); - if (!entry.CheckPlacement (file.MaxOffset)) + if (entry.Offset <= index_offset || !entry.CheckPlacement (file.MaxOffset)) return null; entry.IsPacked = entry.Size != entry.UnpackedSize; dir.Add (entry); diff --git a/Legacy/Ransel/ArcBCD.cs b/Legacy/Ransel/ArcBCD.cs new file mode 100644 index 00000000..3412404a --- /dev/null +++ b/Legacy/Ransel/ArcBCD.cs @@ -0,0 +1,76 @@ +//! \file ArcBCD.cs +//! \date 2019 Jun 02 +//! \brief ransel engine resource archive. +// +// Copyright (C) 2019 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.Ransel +{ + [Export(typeof(ArchiveFormat))] + public class BcdOpener : ArchiveFormat + { + public override string Tag { get { return "BCD"; } } + public override string Description { get { return "ransel engine resource archive"; } } + public override uint Signature { get { return 0x616E6942; } } // 'BinaryCombineData' + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public override ArcFile TryOpen (ArcView file) + { + if (!file.View.AsciiEqual (0, "BinaryCombineData")) + return null; + var bcl_name = Path.ChangeExtension (file.Name, "bcl"); + using (var bcl = VFS.OpenStream (bcl_name)) + using (var index = new StreamReader (bcl, Encodings.cp932)) + { + if (index.ReadLine() != "[BinaryCombineData]") + return null; + var filename = index.ReadLine(); + if (!VFS.IsPathEqualsToFileName (file.Name, filename)) + return null; + index.ReadLine(); + var dir = new List(); + while ((filename = index.ReadLine()) != null) + { + if (!filename.StartsWith ("[") || !filename.EndsWith ("]")) + return null; + filename = filename.Substring (1, filename.Length-2); + var offset = index.ReadLine(); + var size = index.ReadLine(); + index.ReadLine(); + var entry = Create (filename); + entry.Offset = UInt32.Parse (offset); + entry.Size = UInt32.Parse (size); + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + } + return new ArcFile (file, this, dir); + } + } + } +} diff --git a/Legacy/Regrips/AudioWRG.cs b/Legacy/Regrips/AudioWRG.cs new file mode 100644 index 00000000..bf83b232 --- /dev/null +++ b/Legacy/Regrips/AudioWRG.cs @@ -0,0 +1,65 @@ +//! \file AudioWRG.cs +//! \date 2019 May 05 +//! \brief Regrips obfuscated audio. +// +// Copyright (C) 2019 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; + +namespace GameRes.Formats.Regrips +{ + [Export(typeof(AudioFormat))] + public class WrgAudio : AudioFormat + { + public override string Tag { get { return "WRG"; } } + public override string Description { get { return "Regrips encrypted WAVE file"; } } + public override uint Signature { get { return 0xB9B9B6AD; } } + public override bool CanWrite { get { return false; } } + + public override SoundInput TryOpen (IBinaryStream file) + { + var input = new XoredStream (file.AsStream, 0xFF); + return Wav.TryOpen (new BinaryStream (input, file.Name)); + } + } + + [Export(typeof(AudioFormat))] + public class MrgAudio : AudioFormat + { + public override string Tag { get { return "MRG"; } } + public override string Description { get { return "Regrips encrypted MP3 file"; } } + public override uint Signature { get { return 0; } } + public override bool CanWrite { get { return false; } } + + static readonly ResourceInstance Mp3Format = new ResourceInstance ("MP3"); + + public override SoundInput TryOpen (IBinaryStream file) + { + var header = file.ReadHeader (2); + if (header[0] != 0) + return null; + file.Position = 0; + var input = new XoredStream (file.AsStream, 0xFF); + return Mp3Format.Value.TryOpen (new BinaryStream (input, file.Name)); + } + } +} diff --git a/Legacy/Regrips/ImagePRG.cs b/Legacy/Regrips/ImagePRG.cs new file mode 100644 index 00000000..490ee502 --- /dev/null +++ b/Legacy/Regrips/ImagePRG.cs @@ -0,0 +1,93 @@ +//! \file ImagePRG.cs +//! \date 2019 May 05 +//! \brief Regrips obfuscated image. +// +// Copyright (C) 2019 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; + +namespace GameRes.Formats.Regrips +{ + [Export(typeof(ImageFormat))] + public class PrgFormat : ImageFormat + { + public override string Tag { get { return "PRG"; } } + public override string Description { get { return "Regrips encrypted image format"; } } + public override uint Signature { get { return 0xB8B1AF76; } } + public override bool CanWrite { get { return false; } } + + public override ImageMetaData ReadMetaData (IBinaryStream file) + { + using (var input = DecryptStream (file)) + return Png.ReadMetaData (input); + } + + public override ImageData Read (IBinaryStream file, ImageMetaData info) + { + using (var input = DecryptStream (file)) + return Png.Read (input, info); + } + + internal IBinaryStream DecryptStream (IBinaryStream input) + { + var stream = new XoredStream (input.AsStream, 0xFF, true); + return new BinaryStream (stream, input.Name); + } + + public override void Write (Stream file, ImageData image) + { + throw new System.NotImplementedException ("PrgFormat.Write not implemented"); + } + } + + [Export(typeof(ImageFormat))] + public class BrgFormat : PrgFormat + { + public override string Tag { get { return "BRG"; } } + public override string Description { get { return "Regrips encrypted bitmap"; } } + public override uint Signature { get { return 0; } } + public override bool CanWrite { get { return false; } } + + public override ImageMetaData ReadMetaData (IBinaryStream file) + { + var header = file.ReadHeader (2); + if (header[0] != 0xBD || header[1] != 0xB2) + return null; + file.Position = 0; + using (var input = DecryptStream (file)) + return Bmp.ReadMetaData (input); + } + + public override ImageData Read (IBinaryStream file, ImageMetaData info) + { + using (var input = DecryptStream (file)) + return Bmp.Read (input, info); + } + + public override void Write (Stream file, ImageData image) + { + throw new System.NotImplementedException ("BrgFormat.Write not implemented"); + } + } +} diff --git a/Legacy/Zone/ArcPKD.cs b/Legacy/Zone/ArcPKD.cs new file mode 100644 index 00000000..3843f7ca --- /dev/null +++ b/Legacy/Zone/ArcPKD.cs @@ -0,0 +1,70 @@ +//! \file ArcPKD.cs +//! \date 2019 Jun 25 +//! \brief Zone resource archive. +// +// Copyright (C) 2019 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.Zone +{ + // [991118][Zone] Guren + + [Export(typeof(ArchiveFormat))] + public class PkdOpener : ArchiveFormat + { + public override string Tag { get { return "PKD/ZONE"; } } + public override string Description { get { return "Zone resource archive"; } } + public override uint Signature { get { return 1; } } + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public override ArcFile TryOpen (ArcView file) + { + if (!file.Name.HasExtension (".pkd")) + return null; + int count = file.View.ReadInt32 (4); + if (!IsSaneCount (count)) + return null; + uint data_offset = file.View.ReadUInt32 (0xC); + uint index_offset = 0x10; + 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 = Create (name); + entry.Offset = file.View.ReadUInt32 (index_offset+0x20) + data_offset; + entry.Size = file.View.ReadUInt32 (index_offset+0x24); + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + index_offset += 0x2C; + } + return new ArcFile (file, this, dir); + } + } +} diff --git a/Legacy/Zone/ImageBM_.cs b/Legacy/Zone/ImageBM_.cs new file mode 100644 index 00000000..c9b2d8b3 --- /dev/null +++ b/Legacy/Zone/ImageBM_.cs @@ -0,0 +1,117 @@ +//! \file ImageBM_.cs +//! \date 2019 Jun 25 +//! \brief Zone compressed image. +// +// Copyright (C) 2019 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; + +namespace GameRes.Formats.Zone +{ + internal class Bm_MetaData : ImageMetaData + { + public bool IsCompressed; + public byte RleFlag; + } + + [Export(typeof(ImageFormat))] + public class Bm_Format : ImageFormat + { + public override string Tag { get { return "BM_/ZONE"; } } + public override string Description { get { return "Zone compressed image"; } } + public override uint Signature { get { return 0; } } + + public override ImageMetaData ReadMetaData (IBinaryStream file) + { + if (!file.Name.HasExtension (".bm_")) + return null; + var header = file.ReadHeader (0x18); + int signature = header.ToInt32 (0); + if (signature != 0 && signature != 1) + return null; + file.Position = 0x418; + return new Bm_MetaData { + Width = header.ToUInt32 (4), + Height = header.ToUInt32 (8), + BPP = 8, + IsCompressed = signature != 0, + RleFlag = file.ReadUInt8(), + }; + } + + public override ImageData Read (IBinaryStream file, ImageMetaData info) + { + var meta = (Bm_MetaData)info; + file.Position = 0x18; + var palette = ReadPalette (file.AsStream); + var pixels = new byte[info.Width * info.Height]; + file.Position = 0x424; + if (meta.IsCompressed) + ReadRle (file, pixels, meta.RleFlag); + else + file.Read (pixels, 0, pixels.Length); + if (meta.IsCompressed) + return ImageData.Create (info, PixelFormats.Indexed8, palette, pixels); + else + return ImageData.CreateFlipped (info, PixelFormats.Indexed8, palette, pixels, info.iWidth); + } + + void ReadRle (IBinaryStream input, byte[] output, byte rle_flag) + { + int dst = 0; + while (dst < output.Length) + { + byte b = input.ReadUInt8(); + if (b != rle_flag) + { + output[dst++] = b; + continue; + } + b = input.ReadUInt8(); + if (0 == b) + { + output[dst++] = rle_flag; + continue; + } + int count = 0; + while (1 == b) + { + count += 0x100; + b = input.ReadUInt8(); + } + count += b; + if (b != 0) + input.ReadByte(); + b = input.ReadUInt8(); + while (count --> 0) + output[dst++] = b; + } + } + + public override void Write (Stream file, ImageData image) + { + throw new System.NotImplementedException ("Bm_Format.Write not implemented"); + } + } +}