mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-23 19:34:15 +08:00
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.
This commit is contained in:
parent
bfd81f9ec4
commit
3c3f2013ef
@ -729,7 +729,6 @@
|
||||
<Compile Include="AZSys\ArcAZSys.cs" />
|
||||
<Compile Include="Ethornell\ArcBGI.cs" />
|
||||
<Compile Include="Ffa\ArcBlackPackage.cs" />
|
||||
<None Include="Macromedia\ArcCCT.cs" />
|
||||
<Compile Include="Cherry\ArcCherry.cs" />
|
||||
<Compile Include="Circus\ArcCircus.cs" />
|
||||
<Compile Include="ArcCommon.cs" />
|
||||
|
@ -55,7 +55,7 @@ namespace GameRes.Formats.TinkerBell
|
||||
var entry = FormatCatalog.Instance.Create<Entry> (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);
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ namespace GameRes.Formats
|
||||
Section m_overlay;
|
||||
uint m_image_base = 0;
|
||||
List<ImageSection> m_section_list;
|
||||
bool? m_is_NE;
|
||||
|
||||
public ExeFile (ArcView file)
|
||||
{
|
||||
@ -56,9 +57,18 @@ namespace GameRes.Formats
|
||||
/// </summary>
|
||||
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");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary of executable file sections.
|
||||
/// </summary>
|
||||
///
|
||||
public IReadOnlyDictionary<string, Section> 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<string, Section>(); // these are empty for 16-bit executables
|
||||
m_section_list = new List<ImageSection>(); //
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for executable file resources access.
|
||||
/// </summary>
|
||||
|
@ -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':
|
||||
|
@ -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" };
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -190,6 +190,9 @@ namespace GameRes.Formats.Apple
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x001E: // DefHilite
|
||||
break;
|
||||
|
||||
case 0x0090:
|
||||
case 0x0091:
|
||||
case 0x0098:
|
||||
|
@ -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<Entry> 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> (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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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<string> RawChunks = new HashSet<string> {
|
||||
"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<Entry> ();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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; } }
|
||||
|
||||
|
@ -75,6 +75,9 @@ namespace GameRes.Formats.Macromedia
|
||||
DirectorConfig m_config = new DirectorConfig();
|
||||
List<Cast> m_casts = new List<Cast>();
|
||||
Dictionary<int, byte[]> m_ilsMap = new Dictionary<int, byte[]>();
|
||||
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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ namespace GameRes.Formats.YuRis
|
||||
|
||||
public YpfOpener ()
|
||||
{
|
||||
Signatures = new uint[] { 0x00465059, 0 };
|
||||
Signatures = new uint[] { 0x00465059, 0x00905A4D, 0 };
|
||||
}
|
||||
|
||||
static public Dictionary<string, YpfScheme> KnownSchemes { get { return DefaultScheme.KnownSchemes; } }
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user