diff --git a/Legacy/UMeSoft/ArcBIN.cs b/Legacy/UMeSoft/ArcBIN.cs new file mode 100644 index 00000000..0380da15 --- /dev/null +++ b/Legacy/UMeSoft/ArcBIN.cs @@ -0,0 +1,236 @@ +//! \file ArcBIN.cs +//! \date 2018 Mar 05 +//! \brief UmeSoft 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.Utility; + +namespace GameRes.Formats.UMeSoft +{ + [Export(typeof(ArchiveFormat))] + public class BinOpener : ArchiveFormat + { + public override string Tag { get { return "BIN/UME"; } } + public override string Description { get { return "U-Me Soft resources 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 ((count & 0xFFFF) != 0) + return null; + count = (count >> 16) - 1; + if (!IsSaneCount (count)) + return null; + + uint index_offset = 0xC; + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + var name = file.View.ReadUInt32 (index_offset).ToString ("D5"); + var entry = new PackedEntry { + Name = name, + Offset = file.View.ReadUInt32 (index_offset+4) << 11, + Size = file.View.ReadUInt32 (index_offset+8), + }; + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + index_offset += 12; + } + foreach (PackedEntry entry in dir) + { + uint signature; + if (entry.Size > 13 && file.View.AsciiEqual (entry.Offset+2, "ike")) + { + int unpacked_size = file.View.ReadByte (entry.Offset+11) + + ((file.View.ReadByte (entry.Offset+12) + + (file.View.ReadByte (entry.Offset+10) >> 2 << 8)) << 8); + entry.IsPacked = true; + entry.UnpackedSize = (uint)unpacked_size; + signature = file.View.ReadUInt32 (entry.Offset+0xF); + entry.Offset += 13; + entry.Size -= 13; + } + else + signature = file.View.ReadUInt32 (entry.Offset); + entry.ChangeType (AutoEntry.DetectFileType (signature)); + } + return new ArcFile (file, this, dir); + } + + public override Stream OpenEntry (ArcFile arc, Entry entry) + { + var pent = entry as PackedEntry; + if (null == pent || !pent.IsPacked) + return base.OpenEntry (arc, entry); + using (var input = arc.File.CreateStream (entry.Offset, entry.Size)) + { + var reader = new IkeReader (input, (int)pent.UnpackedSize); + var data = reader.Unpack(); + return new BinMemoryStream (data, entry.Name); + } + } + } + + internal class IkeReader + { + IBinaryStream m_input; + byte[] m_output; + + public IkeReader (IBinaryStream input, int unpacked_size) + { + m_input = input; + m_output = new byte[unpacked_size]; + } + + public byte[] Unpack () + { + m_bits = 2; + GetBit(); + int dst = 0; + while (dst < m_output.Length) + { + int offset, shift, count; + if (GetBit() != 0) + { + m_output[dst++] = m_input.ReadUInt8(); + continue; + } + if (GetBit() != 0) + { + offset = m_input.ReadUInt8() | -0x100; + shift = 0; + if (GetBit() == 0) + shift += 0x100; + if (GetBit() == 0) + { + offset -= 0x200; + if (GetBit() == 0) + { + shift <<= 1; + if (GetBit() == 0) + shift += 0x100; + offset -= 0x200; + if (GetBit() == 0) + { + shift <<= 1; + if (GetBit() == 0) + shift += 0x100; + offset -= 0x400; + if (GetBit() == 0) + { + offset -= 0x800; + shift <<= 1; + if (GetBit() == 0) + shift += 0x100; + } + } + } + } + offset -= shift; + if (GetBit() != 0) + { + count = 3; + } + else if (GetBit() != 0) + { + count = 4; + } + else if (GetBit() != 0) + { + count = 5; + } + else if (GetBit() != 0) + { + count = 6; + } + else if (GetBit() != 0) + { + if (GetBit() != 0) + count = 8; + else + count = 7; + } + else if (GetBit() != 0) + { + count = m_input.ReadUInt8() + 17; + } + else + { + count = 9; + if (GetBit() != 0) + count = 13; + if (GetBit() != 0) + count += 2; + if (GetBit() != 0) + count++; + } + } + else + { + offset = m_input.ReadUInt8() | -0x100; + if (GetBit() != 0) + { + offset -= 0x100; + if (GetBit() == 0) + offset -= 0x400; + if (GetBit() == 0) + offset -= 0x200; + if (GetBit() == 0) + offset -= 0x100; + } + else if (offset == -1) + { + if (GetBit() == 0) + break; + else + continue; + } + count = 2; + } + Binary.CopyOverlapped (m_output, dst+offset, dst, count); + dst += count; + } + return m_output; + } + + int m_bits; + + int GetBit () + { + int bit = m_bits & 1; + m_bits >>= 1; + if (1 == m_bits) + { + m_bits = m_input.ReadUInt16() | 0x10000; + } + return bit; + } + } +} diff --git a/Legacy/UMeSoft/AudioSTR.cs b/Legacy/UMeSoft/AudioSTR.cs new file mode 100644 index 00000000..502f5db5 --- /dev/null +++ b/Legacy/UMeSoft/AudioSTR.cs @@ -0,0 +1,53 @@ +//! \file AudioSTR.cs +//! \date 2018 Mar 18 +//! \brief UmeSoft audio file. +// +// 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; + +namespace GameRes.Formats.UMeSoft +{ + [Export(typeof(AudioFormat))] + public sealed class WstrAudio : AudioFormat + { + public override string Tag { get { return "STR"; } } + public override string Description { get { return "U-Me Soft audio file"; } } + public override uint Signature { get { return 0x52545357; } } // 'WSTR' + public override bool CanWrite { get { return false; } } + + public override SoundInput TryOpen (IBinaryStream file) + { + var header = file.ReadHeader (0x20); + var format = new WaveFormat { + FormatTag = 1, + Channels = header.ToUInt16 (4), + SamplesPerSecond = header.ToUInt32 (8), + BitsPerSample = header.ToUInt16 (6), + }; + format.BlockAlign = (ushort)(format.Channels * format.BitsPerSample / 8); + format.SetBPS(); + var input = new StreamRegion (file.AsStream, 0x20); + return new RawPcmInput (input, format); + } + } +}