From 3c3f2013ef6febe43a4aa3b87f08e34560a1ee1c Mon Sep 17 00:00:00 2001 From: morkt Date: Mon, 25 Sep 2023 21:01:22 +0400 Subject: [PATCH] updated formats. (ExeFile): limited support for 16-bit Windows executables. (MbImageFormat): recognize 'MK' signature. (XP3, VF, YPF): added common executable signature. (PICT): improved parser. (Macromedia): improved support, recognize archives within windows executables. (SEEN): fixed decompression. --- ArcFormats/ArcFormats.csproj | 1 - ArcFormats/Cyberworks/ArcP8.cs | 2 +- ArcFormats/ExeFile.cs | 35 ++++ ArcFormats/ImageMB.cs | 5 +- ArcFormats/KiriKiri/ArcXP3.cs | 2 +- ArcFormats/LiveMaker/ArcVF.cs | 2 +- ArcFormats/MAI/ImageMAI.cs | 40 ++-- ArcFormats/Macintosh/ImagePICT.cs | 3 + ArcFormats/Macromedia/ArcCCT.cs | 256 -------------------------- ArcFormats/Macromedia/ArcDXR.cs | 99 ++++++++-- ArcFormats/Macromedia/AudioEDIM.cs | 4 +- ArcFormats/Macromedia/DirectorFile.cs | 15 +- ArcFormats/Macromedia/ImageBITD.cs | 87 ++++----- ArcFormats/RealLive/ArcSEEN.cs | 2 +- ArcFormats/YuRis/ArcYPF.cs | 2 +- ArcFormats/Zyx/ImageSPL.cs | 39 ++-- 16 files changed, 220 insertions(+), 374 deletions(-) delete mode 100644 ArcFormats/Macromedia/ArcCCT.cs diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index 1fac11fa..db64baa0 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -729,7 +729,6 @@ - diff --git a/ArcFormats/Cyberworks/ArcP8.cs b/ArcFormats/Cyberworks/ArcP8.cs index f968e81f..83342d86 100644 --- a/ArcFormats/Cyberworks/ArcP8.cs +++ b/ArcFormats/Cyberworks/ArcP8.cs @@ -55,7 +55,7 @@ namespace GameRes.Formats.TinkerBell var entry = FormatCatalog.Instance.Create (name); entry.Offset = file.View.ReadUInt32 (index_offset+0x18); entry.Size = file.View.ReadUInt32 (index_offset+0x10); - if (!entry.CheckPlacement (file.MaxOffset)) + if (entry.Offset <= index_offset || !entry.CheckPlacement (file.MaxOffset)) return null; dir.Add (entry); } diff --git a/ArcFormats/ExeFile.cs b/ArcFormats/ExeFile.cs index 8c73f48f..b57f9b63 100644 --- a/ArcFormats/ExeFile.cs +++ b/ArcFormats/ExeFile.cs @@ -40,6 +40,7 @@ namespace GameRes.Formats Section m_overlay; uint m_image_base = 0; List m_section_list; + bool? m_is_NE; public ExeFile (ArcView file) { @@ -56,9 +57,18 @@ namespace GameRes.Formats /// public Section Whole { get; private set; } + public bool IsWin16 => m_is_NE ?? (m_is_NE = IsNe()).Value; + + private bool IsNe () + { + uint ne_offset = View.ReadUInt32 (0x3C); + return ne_offset < m_file.MaxOffset-2 && View.AsciiEqual (ne_offset, "NE"); + } + /// /// Dictionary of executable file sections. /// + /// public IReadOnlyDictionary Sections { get @@ -255,6 +265,11 @@ namespace GameRes.Formats private void InitSectionTable () { + if (IsWin16) + { + InitNe(); + return; + } long pe_offset = GetHeaderOffset(); int opt_header = View.ReadUInt16 (pe_offset+0x14); // SizeOfOptionalHeader long section_table = pe_offset+opt_header+0x18; @@ -294,6 +309,26 @@ namespace GameRes.Formats m_section_list = list; } + void InitNe () + { + uint ne_offset = m_file.View.ReadUInt32 (0x3C); + int segment_count = m_file.View.ReadUInt16 (ne_offset + 0x1C); + uint seg_table = m_file.View.ReadUInt16 (ne_offset + 0x22) + ne_offset; + int shift = m_file.View.ReadUInt16 (ne_offset + 0x32); + uint last_seg_end = 0; + for (int i = 0; i < segment_count; ++i) + { + uint offset = (uint)m_file.View.ReadUInt16 (seg_table) << shift; + uint size = m_file.View.ReadUInt16 (seg_table+2); + if (offset + size > last_seg_end) + last_seg_end = offset + size; + } + m_overlay.Offset = last_seg_end; + m_overlay.Size = (uint)(m_file.MaxOffset - last_seg_end); + m_section_table = new Dictionary(); // these are empty for 16-bit executables + m_section_list = new List(); // + } + /// /// Helper class for executable file resources access. /// diff --git a/ArcFormats/ImageMB.cs b/ArcFormats/ImageMB.cs index 39925bdc..0dd5da9f 100644 --- a/ArcFormats/ImageMB.cs +++ b/ArcFormats/ImageMB.cs @@ -38,17 +38,18 @@ namespace GameRes.Formats public MbImageFormat () { - Extensions = new[] { "bmp", "gra" }; + Extensions = new[] { "bmp", "gra", "xxx" }; } public override ImageMetaData ReadMetaData (IBinaryStream stream) { int c1 = stream.ReadByte(); int c2 = stream.ReadByte(); + // MB/MC/MK/CL switch (c1) { case 'M': - if ('B' != c2 && 'C' != c2) + if ('B' != c2 && 'C' != c2 && 'K' != c2) return null; break; case 'C': diff --git a/ArcFormats/KiriKiri/ArcXP3.cs b/ArcFormats/KiriKiri/ArcXP3.cs index 29d05082..02114bc3 100644 --- a/ArcFormats/KiriKiri/ArcXP3.cs +++ b/ArcFormats/KiriKiri/ArcXP3.cs @@ -88,7 +88,7 @@ namespace GameRes.Formats.KiriKiri public Xp3Opener () { - Signatures = new uint[] { 0x0d335058, 0 }; + Signatures = new uint[] { 0x0d335058, 0x00905A4D, 0 }; Extensions = new[] { "XP3", "EXE" }; ContainedFormats = new[] { "TLG", "BMP", "PNG", "JPEG", "OGG", "WAV", "TXT" }; } diff --git a/ArcFormats/LiveMaker/ArcVF.cs b/ArcFormats/LiveMaker/ArcVF.cs index ee40f60f..8bb78d2c 100644 --- a/ArcFormats/LiveMaker/ArcVF.cs +++ b/ArcFormats/LiveMaker/ArcVF.cs @@ -45,7 +45,7 @@ namespace GameRes.Formats.LiveMaker public VffOpener () { Extensions = new string[] { "dat", "exe" }; - Signatures = new uint[] { 0x666676, 0 }; + Signatures = new uint[] { 0x666676, 0x00905A4D, 0 }; } public override ArcFile TryOpen (ArcView file) diff --git a/ArcFormats/MAI/ImageMAI.cs b/ArcFormats/MAI/ImageMAI.cs index 2263d9fb..c636667a 100644 --- a/ArcFormats/MAI/ImageMAI.cs +++ b/ArcFormats/MAI/ImageMAI.cs @@ -50,7 +50,7 @@ namespace GameRes.Formats.MAI public CmFormat () { - Extensions = new string[] { "cm" }; + Extensions = new string[] { "cmp" }; } public override void Write (Stream file, ImageData image) @@ -60,24 +60,22 @@ namespace GameRes.Formats.MAI public override ImageMetaData ReadMetaData (IBinaryStream stream) { - if ('C' != stream.ReadByte() || 'M' != stream.ReadByte()) + var header = stream.ReadHeader (0x20); + if ('C' != header[0] || 'M' != header[1]) return null; - var header = stream.ReadBytes (0x1e); - if (header.Length != 0x1e) + if (1 != header[0x0E]) return null; - if (1 != header[0x0c]) - return null; - uint size = LittleEndian.ToUInt32 (header, 0); + uint size = LittleEndian.ToUInt32 (header, 2); if (size != stream.Length) return null; var info = new CmMetaData(); - info.Width = LittleEndian.ToUInt16 (header, 4); - info.Height = LittleEndian.ToUInt16 (header, 6); - info.Colors = LittleEndian.ToUInt16 (header, 8); - info.BPP = header[0x0a]; - info.IsCompressed = 0 != header[0x0b]; - info.DataOffset = LittleEndian.ToUInt32 (header, 0x0e); - info.DataLength = LittleEndian.ToUInt32 (header, 0x12); + info.Width = LittleEndian.ToUInt16 (header, 6); + info.Height = LittleEndian.ToUInt16 (header, 8); + info.Colors = LittleEndian.ToUInt16 (header, 0x0A); + info.BPP = header[0x0C]; + info.IsCompressed = 0 != header[0x0D]; + info.DataOffset = LittleEndian.ToUInt32 (header, 0x10); + info.DataLength = LittleEndian.ToUInt32 (header, 0x14); if (info.DataLength > size) return null; return info; @@ -158,7 +156,7 @@ namespace GameRes.Formats.MAI public AmFormat () { - Extensions = new string[] { "am", "ami" }; + Extensions = new string[] { "amp", "ami" }; } public override void Write (Stream file, ImageData image) @@ -235,6 +233,8 @@ namespace GameRes.Formats.MAI m_pixels = new byte[m_width*m_height*4]; } + static readonly Color Default8bppTransparencyColor = Color.FromRgb (0, 0xFE, 0); + public void Unpack () { if (m_info.Colors > 0) @@ -262,13 +262,23 @@ namespace GameRes.Formats.MAI m_pixels[dst+3] = alpha; }; else + { + const int alphaScale = 0x11; + var alphaColor = Color.FromRgb (0, 0xFE, 0); copy_pixel = (src, dst, alpha) => { var color = Palette.Colors[m_output[src]]; + if (Default8bppTransparencyColor == color) + alpha = 0; + else if (0 == alpha) + alpha = 0xFF; + else + alpha *= alphaScale; m_pixels[dst] = color.B; m_pixels[dst+1] = color.G; m_pixels[dst+2] = color.R; m_pixels[dst+3] = alpha; }; + } int src_stride = m_width * m_pixel_size; for (int y = 0; y < m_height; ++y) { diff --git a/ArcFormats/Macintosh/ImagePICT.cs b/ArcFormats/Macintosh/ImagePICT.cs index d332afa1..98d999d9 100644 --- a/ArcFormats/Macintosh/ImagePICT.cs +++ b/ArcFormats/Macintosh/ImagePICT.cs @@ -190,6 +190,9 @@ namespace GameRes.Formats.Apple break; } + case 0x001E: // DefHilite + break; + case 0x0090: case 0x0091: case 0x0098: diff --git a/ArcFormats/Macromedia/ArcCCT.cs b/ArcFormats/Macromedia/ArcCCT.cs deleted file mode 100644 index 0f31f25c..00000000 --- a/ArcFormats/Macromedia/ArcCCT.cs +++ /dev/null @@ -1,256 +0,0 @@ -//! \file ArcCCT.cs -//! \date Fri Jun 26 01:15:26 2015 -//! \brief Macromedia Director archive access implementation. -// -// Copyright (C) 2015 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; -using System.Linq; -using System.Text; -using GameRes.Compression; -using GameRes.Utility; - -namespace GameRes.Formats.Macromedia -{ - [Export(typeof(ArchiveFormat))] - public class CctOpener : ArchiveFormat - { - public override string Tag { get { return "CCT"; } } - public override string Description { get { return "Macromedia Shockwave resource archive"; } } - public override uint Signature { get { return 0x52494658; } } // 'XFIR' - public override bool IsHierarchic { get { return false; } } - public override bool CanWrite { get { return false; } } - - public CctOpener () - { - Extensions = new string[] { "cct", "dcr" }; - } - - public override ArcFile TryOpen (ArcView file) - { - uint id = file.View.ReadUInt32 (8); - if (id != 0x46474443 && id != 0x4647444D) // 'CDGF' || 'MDGF' - return null; - - var reader = new CctReader (file); - var dir = reader.ReadIndex(); - if (null != dir) - { - var arc = new ArcFile (file, this, dir); - SetEntryTypes (arc); - return arc; - } - return null; - } - - public override Stream OpenEntry (ArcFile arc, Entry entry) - { - var input = arc.File.CreateStream (entry.Offset, entry.Size); - var packed_entry = entry as PackedEntry; - if (null == packed_entry || !packed_entry.IsPacked) - return input; - else - return new ZLibStream (input, CompressionMode.Decompress); - } - - private void SetEntryTypes (ArcFile arc) - { - foreach (var entry in arc.Dir.OrderBy (x => x.Offset)) - { - if (entry.Name.EndsWith (".edim")) - entry.Type = DetectEdimType (arc, entry); - else if (entry.Name.EndsWith (".bitd")) - entry.Type = "image"; - } - } - - private string DetectEdimType (ArcFile arc, Entry entry) - { - using (var input = OpenEntry (arc, entry)) - { - uint signature = (uint)input.ReadByte() << 24; - signature |= (uint)input.ReadByte() << 16; - signature |= (uint)input.ReadByte() << 8; - signature |= (byte)input.ReadByte(); - if (0xffd8ffe0 == signature) - return "image"; - uint real_size = (entry as PackedEntry).UnpackedSize; - if (signature > 0xffff || signature+4 > real_size) - return ""; - var header = new byte[signature+0x10]; - if (header.Length != input.Read (header, 0, header.Length)) - return ""; - if (0xff == header[signature]) - return "audio"; - return ""; - } - } - } - - internal class CctReader - { - ArcView m_file; - long m_offset; - - public CctReader (ArcView file) - { - m_file = file; - m_offset = 0x0C; - } - - byte[] m_size_buffer = new byte[10]; - - public List ReadIndex () - { - uint section_size = ReadSectionSize ("Fver"); - m_offset += section_size; - section_size = ReadSectionSize ("Fcdr"); - /* - int Mcdr_size; - var Mcdr = ZlibUnpack (m_offset, section_size, out Mcdr_size); - */ - m_offset += section_size; - uint abmp_size = ReadSectionSize ("ABMP"); - int max_count = m_file.View.Read (m_offset, m_size_buffer, 0, Math.Min (10, abmp_size)); - int size_offset = 0; - ReadValue (m_size_buffer, ref size_offset, max_count); - max_count -= size_offset; - - int bmp_unpacked_size = (int)ReadValue (m_size_buffer, ref size_offset, max_count); - m_offset += size_offset; - abmp_size -= (uint)size_offset; - int index_size; - var index = ZlibUnpack (m_offset, abmp_size, out index_size, bmp_unpacked_size); - m_offset += abmp_size; - section_size = ReadSectionSize ("FGEI"); - if (0 != section_size) - throw new NotSupportedException(); - - int index_offset = 0; - ReadValue (index, ref index_offset, index_size-index_offset); - ReadValue (index, ref index_offset, index_size-index_offset); - int entry_count = (int)ReadValue (index, ref index_offset, index_size-index_offset); - if (entry_count <= 0 || entry_count > 0xfffff) - return null; - - var type_buf = new char[4]; - var dir = new List (entry_count); - for (int i = 0; i < entry_count; ++i) - { - uint id = ReadValue (index, ref index_offset, index_size-index_offset); - uint offset = ReadValue (index, ref index_offset, index_size-index_offset); - uint size = ReadValue (index, ref index_offset, index_size-index_offset); - uint unpacked_size = ReadValue (index, ref index_offset, index_size-index_offset); - uint flag = ReadValue (index, ref index_offset, index_size-index_offset); - - if (index_size-index_offset < 4) - return null; - uint type_id = LittleEndian.ToUInt32 (index, index_offset); - index_offset += 4; - if (0 == type_id || uint.MaxValue == offset) - continue; - - Encoding.ASCII.GetChars (index, index_offset-4, 4, type_buf, 0); - var entry = new PackedEntry - { - Name = CreateName (id, type_buf), - Offset = (long)m_offset + offset, - Size = size, - UnpackedSize = unpacked_size, - IsPacked = 0 == flag, - }; - if (entry.CheckPlacement (m_file.MaxOffset)) - { - dir.Add (entry); - } - } - return dir; - } - - string CreateName (uint id, char[] type_buf) - { - Array.Reverse (type_buf); - int t = 3; - while (t >= 0 && ' ' == type_buf[t]) - t--; - if (t >= 0) - { - string ext = new string (type_buf, 0, t+1); - return string.Format ("{0:D8}.{1}", id, ext.ToLowerInvariant()); - } - else - return id.ToString ("D8"); - } - - byte[] ZlibUnpack (long offset, uint size, out int actual_size, int unpacked_size_hint = 0) - { - using (var input = m_file.CreateStream (offset, size)) - using (var zstream = new ZLibStream (input, CompressionMode.Decompress)) - using (var mem = new MemoryStream (unpacked_size_hint)) - { - zstream.CopyTo (mem); - actual_size = (int)mem.Length; - return mem.GetBuffer(); - } - } - - uint ReadSectionSize (string id_str) - { - uint id = ConvertId (id_str); - if (id != m_file.View.ReadUInt32 (m_offset)) - throw new InvalidFormatException(); - m_offset += 4; - if (5 != m_file.View.Read (m_offset, m_size_buffer, 0, 5)) - throw new InvalidFormatException(); - int off_count = 0; - uint size = ReadValue (m_size_buffer, ref off_count, 5); - m_offset += off_count; - return size; - } - - static uint ReadValue (byte[] buffer, ref int offset, int length) - { - uint n = 0; - for (int off_count = 0; off_count < length; ++off_count) - { - uint bits = buffer[offset++]; - n = (n << 7) | (bits & 0x7F); - if (0 == (bits & 0x80)) - return n; - } - throw new InvalidFormatException(); - } - - static uint ConvertId (string id) - { - if (id.Length != 4) - throw new ArgumentException ("Invalid section id"); - uint n = 0; - for (int i = 0; i < 4; ++i) - n = (n << 8) | (byte)id[i]; - return n; - } - } -} diff --git a/ArcFormats/Macromedia/ArcDXR.cs b/ArcFormats/Macromedia/ArcDXR.cs index ed6eabc5..31a19e29 100644 --- a/ArcFormats/Macromedia/ArcDXR.cs +++ b/ArcFormats/Macromedia/ArcDXR.cs @@ -38,46 +38,58 @@ namespace GameRes.Formats.Macromedia [Export(typeof(ArchiveFormat))] public class DxrOpener : ArchiveFormat { - public override string Tag { get => "DXR"; } - public override string Description { get => "Macromedia Director resource archive"; } - public override uint Signature { get => 0x52494658; } // 'XFIR' - public override bool IsHierarchic { get => false; } - public override bool CanWrite { get => false; } + public override string Tag => "DXR"; + public override string Description => "Macromedia Director resource archive"; + public override uint Signature => SignatureXFIR; // 'XFIR' + public override bool IsHierarchic => false; + public override bool CanWrite => false; + + public const uint SignatureXFIR = 0x52494658u; + public const uint SignatureRIFX = 0x58464952u; public DxrOpener () { - Extensions = new[] { "dxr", "cxt", "cct", "dcr" }; - Signatures = new[] { 0x52494658u, 0x58464952u }; + Extensions = new[] { "dxr", "cxt", "cct", "dcr", "exe" }; + Signatures = new[] { SignatureXFIR, SignatureRIFX, 0x00905A4Du, 0u }; } internal static readonly HashSet RawChunks = new HashSet { - "RTE0", "RTE1", "FXmp", "VWFI", "VWSC", "Lscr", "STXT", "XMED", //"snd " + "RTE0", "RTE1", "FXmp", "VWFI", "VWSC", "Lscr", "STXT", "XMED", "File" }; internal bool ConvertText = true; public override ArcFile TryOpen (ArcView file) { + long base_offset = 0; + if (file.View.AsciiEqual (0, "MZ")) + base_offset = LookForXfir (file); + uint signature = file.View.ReadUInt32 (base_offset); + if (signature != SignatureXFIR && signature != SignatureRIFX) + return null; using (var input = file.CreateStream()) { - ByteOrder ord = input.Signature == 0x52494658u ? ByteOrder.LittleEndian : ByteOrder.BigEndian; + ByteOrder ord = signature == SignatureXFIR ? ByteOrder.LittleEndian : ByteOrder.BigEndian; var reader = new Reader (input, ord); - reader.Position = 4; - uint length = reader.ReadU32(); + reader.Position = base_offset; var context = new SerializationContext(); var dir_file = new DirectorFile(); if (!dir_file.Deserialize (context, reader)) return null; var dir = new List (); - ImportMedia (dir_file, dir); + if (dir_file.Codec != "APPL") + ImportMedia (dir_file, dir); foreach (DirectorEntry entry in dir_file.Directory) { if (entry.Size != 0 && entry.Offset != -1 && RawChunks.Contains (entry.FourCC)) { entry.Name = string.Format ("{0:D6}.{1}", entry.Id, entry.FourCC.Trim()); - if ("snd " == entry.FourCC) - entry.Type = "audio"; + if ("File" == entry.FourCC) + { + entry.Offset -= 8; + entry.Size += 8; + } dir.Add (entry); } } @@ -155,7 +167,7 @@ namespace GameRes.Formats.Macromedia entry = ImportBitmap (piece, dir_file, cast); else if (piece.Type == DataType.Sound) entry = ImportSound (piece, dir_file); - if (entry != null) + if (entry != null && entry.Size > 0) dir.Add (entry); } } @@ -381,6 +393,56 @@ namespace GameRes.Formats.Macromedia zstream.Read (data, 0, data.Length); return new BinMemoryStream (data, entry.Name); } + + static readonly byte[] s_xfir = { (byte)'X', (byte)'F', (byte)'I', (byte)'R' }; + + long LookForXfir (ArcView file) + { + var exe = new ExeFile (file); + long pos; + if (exe.IsWin16) + { + pos = exe.FindString (exe.Overlay, s_xfir); + if (pos < 0) + return 0; + } + else + { + pos = exe.Overlay.Offset; + if (pos >= file.MaxOffset) + return 0; + if (file.View.AsciiEqual (pos, "10JP")) + { + pos = file.View.ReadUInt32 (pos+4); + } + } + if (pos >= file.MaxOffset || !file.View.AsciiEqual (pos, "XFIR")) + return 0; + // TODO threat 'LPPA' archives the normal way, like archives that contain entries. + // the problem is, DXR archives contained within 'LPPA' have their offsets relative to executable file, + // so have to figure out way to handle it. + if (!file.View.AsciiEqual (pos+8, "LPPA")) + return pos; + var appl = new DirectorFile(); + var context = new SerializationContext(); + using (var input = file.CreateStream()) + { + var reader = new Reader (input, ByteOrder.LittleEndian); + input.Position = pos + 12; + if (!appl.ReadMMap (context, reader)) + return 0; + foreach (var entry in appl.Directory) + { + // only the first XFIR entry is matched here, but archive may contain multiple sub-archives. + if (entry.FourCC == "File") + { + if (file.View.AsciiEqual (entry.Offset-8, "XFIR")) + return entry.Offset-8; + } + } + return 0; + } + } } internal class BitmapEntry : PackedEntry @@ -409,8 +471,11 @@ namespace GameRes.Formats.Macromedia Right = reader.ReadI16(); reader.Skip (0x0C); BitDepth = reader.ReadU16() & 0xFF; // ??? - reader.Skip (2); - Palette = reader.ReadI16(); + if (data.Length >= 0x1C) + { + reader.Skip (2); + Palette = reader.ReadI16(); + } } } } diff --git a/ArcFormats/Macromedia/AudioEDIM.cs b/ArcFormats/Macromedia/AudioEDIM.cs index 18925d59..aab5eaca 100644 --- a/ArcFormats/Macromedia/AudioEDIM.cs +++ b/ArcFormats/Macromedia/AudioEDIM.cs @@ -1,6 +1,6 @@ //! \file AudioEDIM.cs //! \date Fri Jun 26 06:52:33 2015 -//! \brief Selen wrapper around MP3 stream. +//! \brief Macromedia Director wrapper around MP3 stream. // // Copyright (C) 2015 by morkt // @@ -33,7 +33,7 @@ namespace GameRes.Formats.Selen public class EdimAudio : Mp3Audio { public override string Tag { get { return "EDIM"; } } - public override string Description { get { return "Selen audio format (MP3)"; } } + public override string Description { get { return "Macromedia Director audio format (MP3)"; } } public override uint Signature { get { return 0x40010000; } } public override bool CanWrite { get { return false; } } diff --git a/ArcFormats/Macromedia/DirectorFile.cs b/ArcFormats/Macromedia/DirectorFile.cs index cca399d5..a1b2232f 100644 --- a/ArcFormats/Macromedia/DirectorFile.cs +++ b/ArcFormats/Macromedia/DirectorFile.cs @@ -75,6 +75,9 @@ namespace GameRes.Formats.Macromedia DirectorConfig m_config = new DirectorConfig(); List m_casts = new List(); Dictionary m_ilsMap = new Dictionary(); + string m_codec; + + public string Codec => m_codec; public bool IsAfterBurned { get; private set; } @@ -96,14 +99,14 @@ namespace GameRes.Formats.Macromedia public bool Deserialize (SerializationContext context, Reader reader) { - reader.Position = 8; - string codec = reader.ReadFourCC(); - if (codec == "MV93" || codec == "MC95") + reader.Skip (8); + m_codec = reader.ReadFourCC(); + if (m_codec == "MV93" || m_codec == "MC95") { if (!ReadMMap (context, reader)) return false; } - else if (codec == "FGDC" || codec == "FGDM") + else if (m_codec == "FGDC" || m_codec == "FGDM") { IsAfterBurned = true; if (!ReadAfterBurner (context, reader)) @@ -111,7 +114,7 @@ namespace GameRes.Formats.Macromedia } else { - Trace.WriteLine (string.Format ("Unknown codec '{0}'", codec), "DXR"); + Trace.WriteLine (string.Format ("Unknown m_codec '{0}'", m_codec), "DXR"); return false; } return ReadKeyTable (context, reader) @@ -119,7 +122,7 @@ namespace GameRes.Formats.Macromedia && ReadCasts (context, reader); } - bool ReadMMap (SerializationContext context, Reader reader) + internal bool ReadMMap (SerializationContext context, Reader reader) { if (reader.ReadFourCC() != "imap") return false; diff --git a/ArcFormats/Macromedia/ImageBITD.cs b/ArcFormats/Macromedia/ImageBITD.cs index fb571e6a..0e1795a6 100644 --- a/ArcFormats/Macromedia/ImageBITD.cs +++ b/ArcFormats/Macromedia/ImageBITD.cs @@ -71,7 +71,7 @@ namespace GameRes.Formats.Macromedia : info.BPP == 8 ? PixelFormats.Indexed8 : info.BPP == 16 ? PixelFormats.Bgr555 : info.DepthType == 0x87 // i have no clue what this is - || info.DepthType == 0x8A ? PixelFormats.Bgra32 // depth type 0x87/0x8A + || info.DepthType == 0x8A ? PixelFormats.Bgra32 // depth type 0x87/0x8A : PixelFormats.Bgra32; // depth type 0x82/84/85/86/8C m_palette = palette; } @@ -151,32 +151,7 @@ namespace GameRes.Formats.Macromedia { for (int line = 0; line < m_output.Length; line += m_stride) { - int x = 0; - while (x < m_stride) - { - int b = m_input.ReadByte(); - if (-1 == b) - throw new InvalidFormatException ("Unexpected end of file"); - int count = b; - if (b > 0x7f) - count = (byte)-(sbyte)b; - ++count; - if (x + count > m_stride) - throw new InvalidFormatException(); - if (b > 0x7f) - { - b = m_input.ReadByte(); - if (-1 == b) - throw new InvalidFormatException ("Unexpected end of file"); - for (int i = 0; i < count; ++i) - m_output[line + x++] = (byte)b; - } - else - { - m_input.Read (m_output, line + x, count); - x += count; - } - } + UnpackScanLine (m_output, line); } return m_output; } @@ -186,33 +161,7 @@ namespace GameRes.Formats.Macromedia var scan_line = new byte[m_stride]; for (int line = 0; line < m_output.Length; line += m_stride) { - int x = 0; - while (x < m_stride) - { - int b = m_input.ReadByte(); - if (-1 == b) - break; // one in 5000 images somehow stumbles here -// throw new InvalidFormatException ("Unexpected end of file"); - int count = b; - if (b > 0x7f) - count = (byte)-(sbyte)b; - ++count; - if (x + count > m_stride) - throw new InvalidFormatException(); - if (b > 0x7f) - { - b = m_input.ReadByte(); - if (-1 == b) - throw new InvalidFormatException ("Unexpected end of file"); - for (int i = 0; i < count; ++i) - scan_line[x++] = (byte)b; - } - else - { - m_input.Read (scan_line, x, count); - x += count; - } - } + UnpackScanLine (scan_line, 0); int dst = line; for (int i = 0; i < m_width; ++i) { @@ -222,6 +171,36 @@ namespace GameRes.Formats.Macromedia } } + void UnpackScanLine (byte[] scan_line, int pos) + { + int x = 0; + while (x < m_stride) + { + int b = m_input.ReadByte(); + if (-1 == b) + break; // one in 5000 images somehow stumbles here + int count = b; + if (b > 0x7f) + count = (byte)-(sbyte)b; + ++count; + if (x + count > m_stride) + throw new InvalidFormatException(); + if (b > 0x7f) + { + b = m_input.ReadByte(); + if (-1 == b) + throw new InvalidFormatException ("Unexpected end of file"); + for (int i = 0; i < count; ++i) + scan_line[pos + x++] = (byte)b; + } + else + { + m_input.Read (scan_line, pos+x, count); + x += count; + } + } + } + #region IDisposable Members bool m_disposed = false; diff --git a/ArcFormats/RealLive/ArcSEEN.cs b/ArcFormats/RealLive/ArcSEEN.cs index 772f1ff6..791c0742 100644 --- a/ArcFormats/RealLive/ArcSEEN.cs +++ b/ArcFormats/RealLive/ArcSEEN.cs @@ -111,7 +111,7 @@ namespace GameRes.Formats.RealLive int offset = input.ReadUInt16(); int count = (offset & 0xF) + 2; offset >>= 4; - Binary.CopyOverlapped (output, dst-offset, dst, count); + Binary.CopyOverlapped (output, dst-offset-1, dst, count); dst += count; } } diff --git a/ArcFormats/YuRis/ArcYPF.cs b/ArcFormats/YuRis/ArcYPF.cs index 36336593..08a2f11e 100644 --- a/ArcFormats/YuRis/ArcYPF.cs +++ b/ArcFormats/YuRis/ArcYPF.cs @@ -105,7 +105,7 @@ namespace GameRes.Formats.YuRis public YpfOpener () { - Signatures = new uint[] { 0x00465059, 0 }; + Signatures = new uint[] { 0x00465059, 0x00905A4D, 0 }; } static public Dictionary KnownSchemes { get { return DefaultScheme.KnownSchemes; } } diff --git a/ArcFormats/Zyx/ImageSPL.cs b/ArcFormats/Zyx/ImageSPL.cs index bd26100b..3d28aa0a 100644 --- a/ArcFormats/Zyx/ImageSPL.cs +++ b/ArcFormats/Zyx/ImageSPL.cs @@ -52,30 +52,37 @@ namespace GameRes.Formats.Zyx public override ImageMetaData ReadMetaData (IBinaryStream file) { int count = file.ReadInt16(); - if (count <= 0) + if (count < 0 || count > 0x100) return null; - var tiles = new Tile[count]; - for (int i = 0; i < count; ++i) + Tile[] tiles = null; + if (count > 0) { - var tile = new Tile(); - tile.Left = file.ReadInt16(); - tile.Top = file.ReadInt16(); - if (tile.Left < 0 || tile.Top < 0) - return null; - tile.Right = file.ReadInt16(); - tile.Bottom = file.ReadInt16(); - if (tile.Right <= tile.Left || tile.Bottom <= tile.Top) - return null; - tiles[i] = tile; + tiles = new Tile[count]; + for (int i = 0; i < count; ++i) + { + var tile = new Tile(); + tile.Left = file.ReadInt16(); + tile.Top = file.ReadInt16(); + if (tile.Left < 0 || tile.Top < 0) + return null; + tile.Right = file.ReadInt16(); + tile.Bottom = file.ReadInt16(); + if (tile.Right <= tile.Left || tile.Bottom <= tile.Top) + return null; + tiles[i] = tile; + } } int width = file.ReadInt16(); int height = file.ReadInt16(); if (width <= 0 || height <= 0) return null; - foreach (var tile in tiles) + if (tiles != null) { - if (tile.Right > width || tile.Bottom > height) - return null; + foreach (var tile in tiles) + { + if (tile.Right > width || tile.Bottom > height) + return null; + } } return new SplMetaData {