mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-27 07:34:00 +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="AZSys\ArcAZSys.cs" />
|
||||||
<Compile Include="Ethornell\ArcBGI.cs" />
|
<Compile Include="Ethornell\ArcBGI.cs" />
|
||||||
<Compile Include="Ffa\ArcBlackPackage.cs" />
|
<Compile Include="Ffa\ArcBlackPackage.cs" />
|
||||||
<None Include="Macromedia\ArcCCT.cs" />
|
|
||||||
<Compile Include="Cherry\ArcCherry.cs" />
|
<Compile Include="Cherry\ArcCherry.cs" />
|
||||||
<Compile Include="Circus\ArcCircus.cs" />
|
<Compile Include="Circus\ArcCircus.cs" />
|
||||||
<Compile Include="ArcCommon.cs" />
|
<Compile Include="ArcCommon.cs" />
|
||||||
|
@ -55,7 +55,7 @@ namespace GameRes.Formats.TinkerBell
|
|||||||
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
var entry = FormatCatalog.Instance.Create<Entry> (name);
|
||||||
entry.Offset = file.View.ReadUInt32 (index_offset+0x18);
|
entry.Offset = file.View.ReadUInt32 (index_offset+0x18);
|
||||||
entry.Size = file.View.ReadUInt32 (index_offset+0x10);
|
entry.Size = file.View.ReadUInt32 (index_offset+0x10);
|
||||||
if (!entry.CheckPlacement (file.MaxOffset))
|
if (entry.Offset <= index_offset || !entry.CheckPlacement (file.MaxOffset))
|
||||||
return null;
|
return null;
|
||||||
dir.Add (entry);
|
dir.Add (entry);
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ namespace GameRes.Formats
|
|||||||
Section m_overlay;
|
Section m_overlay;
|
||||||
uint m_image_base = 0;
|
uint m_image_base = 0;
|
||||||
List<ImageSection> m_section_list;
|
List<ImageSection> m_section_list;
|
||||||
|
bool? m_is_NE;
|
||||||
|
|
||||||
public ExeFile (ArcView file)
|
public ExeFile (ArcView file)
|
||||||
{
|
{
|
||||||
@ -56,9 +57,18 @@ namespace GameRes.Formats
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Section Whole { get; private set; }
|
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>
|
/// <summary>
|
||||||
/// Dictionary of executable file sections.
|
/// Dictionary of executable file sections.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
///
|
||||||
public IReadOnlyDictionary<string, Section> Sections
|
public IReadOnlyDictionary<string, Section> Sections
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -255,6 +265,11 @@ namespace GameRes.Formats
|
|||||||
|
|
||||||
private void InitSectionTable ()
|
private void InitSectionTable ()
|
||||||
{
|
{
|
||||||
|
if (IsWin16)
|
||||||
|
{
|
||||||
|
InitNe();
|
||||||
|
return;
|
||||||
|
}
|
||||||
long pe_offset = GetHeaderOffset();
|
long pe_offset = GetHeaderOffset();
|
||||||
int opt_header = View.ReadUInt16 (pe_offset+0x14); // SizeOfOptionalHeader
|
int opt_header = View.ReadUInt16 (pe_offset+0x14); // SizeOfOptionalHeader
|
||||||
long section_table = pe_offset+opt_header+0x18;
|
long section_table = pe_offset+opt_header+0x18;
|
||||||
@ -294,6 +309,26 @@ namespace GameRes.Formats
|
|||||||
m_section_list = list;
|
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>
|
/// <summary>
|
||||||
/// Helper class for executable file resources access.
|
/// Helper class for executable file resources access.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -38,17 +38,18 @@ namespace GameRes.Formats
|
|||||||
|
|
||||||
public MbImageFormat ()
|
public MbImageFormat ()
|
||||||
{
|
{
|
||||||
Extensions = new[] { "bmp", "gra" };
|
Extensions = new[] { "bmp", "gra", "xxx" };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ImageMetaData ReadMetaData (IBinaryStream stream)
|
public override ImageMetaData ReadMetaData (IBinaryStream stream)
|
||||||
{
|
{
|
||||||
int c1 = stream.ReadByte();
|
int c1 = stream.ReadByte();
|
||||||
int c2 = stream.ReadByte();
|
int c2 = stream.ReadByte();
|
||||||
|
// MB/MC/MK/CL
|
||||||
switch (c1)
|
switch (c1)
|
||||||
{
|
{
|
||||||
case 'M':
|
case 'M':
|
||||||
if ('B' != c2 && 'C' != c2)
|
if ('B' != c2 && 'C' != c2 && 'K' != c2)
|
||||||
return null;
|
return null;
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
|
@ -88,7 +88,7 @@ namespace GameRes.Formats.KiriKiri
|
|||||||
|
|
||||||
public Xp3Opener ()
|
public Xp3Opener ()
|
||||||
{
|
{
|
||||||
Signatures = new uint[] { 0x0d335058, 0 };
|
Signatures = new uint[] { 0x0d335058, 0x00905A4D, 0 };
|
||||||
Extensions = new[] { "XP3", "EXE" };
|
Extensions = new[] { "XP3", "EXE" };
|
||||||
ContainedFormats = new[] { "TLG", "BMP", "PNG", "JPEG", "OGG", "WAV", "TXT" };
|
ContainedFormats = new[] { "TLG", "BMP", "PNG", "JPEG", "OGG", "WAV", "TXT" };
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ namespace GameRes.Formats.LiveMaker
|
|||||||
public VffOpener ()
|
public VffOpener ()
|
||||||
{
|
{
|
||||||
Extensions = new string[] { "dat", "exe" };
|
Extensions = new string[] { "dat", "exe" };
|
||||||
Signatures = new uint[] { 0x666676, 0 };
|
Signatures = new uint[] { 0x666676, 0x00905A4D, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ArcFile TryOpen (ArcView file)
|
public override ArcFile TryOpen (ArcView file)
|
||||||
|
@ -50,7 +50,7 @@ namespace GameRes.Formats.MAI
|
|||||||
|
|
||||||
public CmFormat ()
|
public CmFormat ()
|
||||||
{
|
{
|
||||||
Extensions = new string[] { "cm" };
|
Extensions = new string[] { "cmp" };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write (Stream file, ImageData image)
|
public override void Write (Stream file, ImageData image)
|
||||||
@ -60,24 +60,22 @@ namespace GameRes.Formats.MAI
|
|||||||
|
|
||||||
public override ImageMetaData ReadMetaData (IBinaryStream stream)
|
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;
|
return null;
|
||||||
var header = stream.ReadBytes (0x1e);
|
if (1 != header[0x0E])
|
||||||
if (header.Length != 0x1e)
|
|
||||||
return null;
|
return null;
|
||||||
if (1 != header[0x0c])
|
uint size = LittleEndian.ToUInt32 (header, 2);
|
||||||
return null;
|
|
||||||
uint size = LittleEndian.ToUInt32 (header, 0);
|
|
||||||
if (size != stream.Length)
|
if (size != stream.Length)
|
||||||
return null;
|
return null;
|
||||||
var info = new CmMetaData();
|
var info = new CmMetaData();
|
||||||
info.Width = LittleEndian.ToUInt16 (header, 4);
|
info.Width = LittleEndian.ToUInt16 (header, 6);
|
||||||
info.Height = LittleEndian.ToUInt16 (header, 6);
|
info.Height = LittleEndian.ToUInt16 (header, 8);
|
||||||
info.Colors = LittleEndian.ToUInt16 (header, 8);
|
info.Colors = LittleEndian.ToUInt16 (header, 0x0A);
|
||||||
info.BPP = header[0x0a];
|
info.BPP = header[0x0C];
|
||||||
info.IsCompressed = 0 != header[0x0b];
|
info.IsCompressed = 0 != header[0x0D];
|
||||||
info.DataOffset = LittleEndian.ToUInt32 (header, 0x0e);
|
info.DataOffset = LittleEndian.ToUInt32 (header, 0x10);
|
||||||
info.DataLength = LittleEndian.ToUInt32 (header, 0x12);
|
info.DataLength = LittleEndian.ToUInt32 (header, 0x14);
|
||||||
if (info.DataLength > size)
|
if (info.DataLength > size)
|
||||||
return null;
|
return null;
|
||||||
return info;
|
return info;
|
||||||
@ -158,7 +156,7 @@ namespace GameRes.Formats.MAI
|
|||||||
|
|
||||||
public AmFormat ()
|
public AmFormat ()
|
||||||
{
|
{
|
||||||
Extensions = new string[] { "am", "ami" };
|
Extensions = new string[] { "amp", "ami" };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Write (Stream file, ImageData image)
|
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];
|
m_pixels = new byte[m_width*m_height*4];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static readonly Color Default8bppTransparencyColor = Color.FromRgb (0, 0xFE, 0);
|
||||||
|
|
||||||
public void Unpack ()
|
public void Unpack ()
|
||||||
{
|
{
|
||||||
if (m_info.Colors > 0)
|
if (m_info.Colors > 0)
|
||||||
@ -262,13 +262,23 @@ namespace GameRes.Formats.MAI
|
|||||||
m_pixels[dst+3] = alpha;
|
m_pixels[dst+3] = alpha;
|
||||||
};
|
};
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
const int alphaScale = 0x11;
|
||||||
|
var alphaColor = Color.FromRgb (0, 0xFE, 0);
|
||||||
copy_pixel = (src, dst, alpha) => {
|
copy_pixel = (src, dst, alpha) => {
|
||||||
var color = Palette.Colors[m_output[src]];
|
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] = color.B;
|
||||||
m_pixels[dst+1] = color.G;
|
m_pixels[dst+1] = color.G;
|
||||||
m_pixels[dst+2] = color.R;
|
m_pixels[dst+2] = color.R;
|
||||||
m_pixels[dst+3] = alpha;
|
m_pixels[dst+3] = alpha;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
int src_stride = m_width * m_pixel_size;
|
int src_stride = m_width * m_pixel_size;
|
||||||
for (int y = 0; y < m_height; ++y)
|
for (int y = 0; y < m_height; ++y)
|
||||||
{
|
{
|
||||||
|
@ -190,6 +190,9 @@ namespace GameRes.Formats.Apple
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 0x001E: // DefHilite
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x0090:
|
case 0x0090:
|
||||||
case 0x0091:
|
case 0x0091:
|
||||||
case 0x0098:
|
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))]
|
[Export(typeof(ArchiveFormat))]
|
||||||
public class DxrOpener : ArchiveFormat
|
public class DxrOpener : ArchiveFormat
|
||||||
{
|
{
|
||||||
public override string Tag { get => "DXR"; }
|
public override string Tag => "DXR";
|
||||||
public override string Description { get => "Macromedia Director resource archive"; }
|
public override string Description => "Macromedia Director resource archive";
|
||||||
public override uint Signature { get => 0x52494658; } // 'XFIR'
|
public override uint Signature => SignatureXFIR; // 'XFIR'
|
||||||
public override bool IsHierarchic { get => false; }
|
public override bool IsHierarchic => false;
|
||||||
public override bool CanWrite { get => false; }
|
public override bool CanWrite => false;
|
||||||
|
|
||||||
|
public const uint SignatureXFIR = 0x52494658u;
|
||||||
|
public const uint SignatureRIFX = 0x58464952u;
|
||||||
|
|
||||||
public DxrOpener ()
|
public DxrOpener ()
|
||||||
{
|
{
|
||||||
Extensions = new[] { "dxr", "cxt", "cct", "dcr" };
|
Extensions = new[] { "dxr", "cxt", "cct", "dcr", "exe" };
|
||||||
Signatures = new[] { 0x52494658u, 0x58464952u };
|
Signatures = new[] { SignatureXFIR, SignatureRIFX, 0x00905A4Du, 0u };
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static readonly HashSet<string> RawChunks = new HashSet<string> {
|
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;
|
internal bool ConvertText = true;
|
||||||
|
|
||||||
public override ArcFile TryOpen (ArcView file)
|
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())
|
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);
|
var reader = new Reader (input, ord);
|
||||||
reader.Position = 4;
|
reader.Position = base_offset;
|
||||||
uint length = reader.ReadU32();
|
|
||||||
var context = new SerializationContext();
|
var context = new SerializationContext();
|
||||||
var dir_file = new DirectorFile();
|
var dir_file = new DirectorFile();
|
||||||
if (!dir_file.Deserialize (context, reader))
|
if (!dir_file.Deserialize (context, reader))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var dir = new List<Entry> ();
|
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)
|
foreach (DirectorEntry entry in dir_file.Directory)
|
||||||
{
|
{
|
||||||
if (entry.Size != 0 && entry.Offset != -1 && RawChunks.Contains (entry.FourCC))
|
if (entry.Size != 0 && entry.Offset != -1 && RawChunks.Contains (entry.FourCC))
|
||||||
{
|
{
|
||||||
entry.Name = string.Format ("{0:D6}.{1}", entry.Id, entry.FourCC.Trim());
|
entry.Name = string.Format ("{0:D6}.{1}", entry.Id, entry.FourCC.Trim());
|
||||||
if ("snd " == entry.FourCC)
|
if ("File" == entry.FourCC)
|
||||||
entry.Type = "audio";
|
{
|
||||||
|
entry.Offset -= 8;
|
||||||
|
entry.Size += 8;
|
||||||
|
}
|
||||||
dir.Add (entry);
|
dir.Add (entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,7 +167,7 @@ namespace GameRes.Formats.Macromedia
|
|||||||
entry = ImportBitmap (piece, dir_file, cast);
|
entry = ImportBitmap (piece, dir_file, cast);
|
||||||
else if (piece.Type == DataType.Sound)
|
else if (piece.Type == DataType.Sound)
|
||||||
entry = ImportSound (piece, dir_file);
|
entry = ImportSound (piece, dir_file);
|
||||||
if (entry != null)
|
if (entry != null && entry.Size > 0)
|
||||||
dir.Add (entry);
|
dir.Add (entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -381,6 +393,56 @@ namespace GameRes.Formats.Macromedia
|
|||||||
zstream.Read (data, 0, data.Length);
|
zstream.Read (data, 0, data.Length);
|
||||||
return new BinMemoryStream (data, entry.Name);
|
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
|
internal class BitmapEntry : PackedEntry
|
||||||
@ -409,8 +471,11 @@ namespace GameRes.Formats.Macromedia
|
|||||||
Right = reader.ReadI16();
|
Right = reader.ReadI16();
|
||||||
reader.Skip (0x0C);
|
reader.Skip (0x0C);
|
||||||
BitDepth = reader.ReadU16() & 0xFF; // ???
|
BitDepth = reader.ReadU16() & 0xFF; // ???
|
||||||
reader.Skip (2);
|
if (data.Length >= 0x1C)
|
||||||
Palette = reader.ReadI16();
|
{
|
||||||
|
reader.Skip (2);
|
||||||
|
Palette = reader.ReadI16();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! \file AudioEDIM.cs
|
//! \file AudioEDIM.cs
|
||||||
//! \date Fri Jun 26 06:52:33 2015
|
//! \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
|
// Copyright (C) 2015 by morkt
|
||||||
//
|
//
|
||||||
@ -33,7 +33,7 @@ namespace GameRes.Formats.Selen
|
|||||||
public class EdimAudio : Mp3Audio
|
public class EdimAudio : Mp3Audio
|
||||||
{
|
{
|
||||||
public override string Tag { get { return "EDIM"; } }
|
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 uint Signature { get { return 0x40010000; } }
|
||||||
public override bool CanWrite { get { return false; } }
|
public override bool CanWrite { get { return false; } }
|
||||||
|
|
||||||
|
@ -75,6 +75,9 @@ namespace GameRes.Formats.Macromedia
|
|||||||
DirectorConfig m_config = new DirectorConfig();
|
DirectorConfig m_config = new DirectorConfig();
|
||||||
List<Cast> m_casts = new List<Cast>();
|
List<Cast> m_casts = new List<Cast>();
|
||||||
Dictionary<int, byte[]> m_ilsMap = new Dictionary<int, byte[]>();
|
Dictionary<int, byte[]> m_ilsMap = new Dictionary<int, byte[]>();
|
||||||
|
string m_codec;
|
||||||
|
|
||||||
|
public string Codec => m_codec;
|
||||||
|
|
||||||
public bool IsAfterBurned { get; private set; }
|
public bool IsAfterBurned { get; private set; }
|
||||||
|
|
||||||
@ -96,14 +99,14 @@ namespace GameRes.Formats.Macromedia
|
|||||||
|
|
||||||
public bool Deserialize (SerializationContext context, Reader reader)
|
public bool Deserialize (SerializationContext context, Reader reader)
|
||||||
{
|
{
|
||||||
reader.Position = 8;
|
reader.Skip (8);
|
||||||
string codec = reader.ReadFourCC();
|
m_codec = reader.ReadFourCC();
|
||||||
if (codec == "MV93" || codec == "MC95")
|
if (m_codec == "MV93" || m_codec == "MC95")
|
||||||
{
|
{
|
||||||
if (!ReadMMap (context, reader))
|
if (!ReadMMap (context, reader))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (codec == "FGDC" || codec == "FGDM")
|
else if (m_codec == "FGDC" || m_codec == "FGDM")
|
||||||
{
|
{
|
||||||
IsAfterBurned = true;
|
IsAfterBurned = true;
|
||||||
if (!ReadAfterBurner (context, reader))
|
if (!ReadAfterBurner (context, reader))
|
||||||
@ -111,7 +114,7 @@ namespace GameRes.Formats.Macromedia
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Trace.WriteLine (string.Format ("Unknown codec '{0}'", codec), "DXR");
|
Trace.WriteLine (string.Format ("Unknown m_codec '{0}'", m_codec), "DXR");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return ReadKeyTable (context, reader)
|
return ReadKeyTable (context, reader)
|
||||||
@ -119,7 +122,7 @@ namespace GameRes.Formats.Macromedia
|
|||||||
&& ReadCasts (context, reader);
|
&& ReadCasts (context, reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadMMap (SerializationContext context, Reader reader)
|
internal bool ReadMMap (SerializationContext context, Reader reader)
|
||||||
{
|
{
|
||||||
if (reader.ReadFourCC() != "imap")
|
if (reader.ReadFourCC() != "imap")
|
||||||
return false;
|
return false;
|
||||||
|
@ -71,7 +71,7 @@ namespace GameRes.Formats.Macromedia
|
|||||||
: info.BPP == 8 ? PixelFormats.Indexed8
|
: info.BPP == 8 ? PixelFormats.Indexed8
|
||||||
: info.BPP == 16 ? PixelFormats.Bgr555
|
: info.BPP == 16 ? PixelFormats.Bgr555
|
||||||
: info.DepthType == 0x87 // i have no clue what this is
|
: 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
|
: PixelFormats.Bgra32; // depth type 0x82/84/85/86/8C
|
||||||
m_palette = palette;
|
m_palette = palette;
|
||||||
}
|
}
|
||||||
@ -151,32 +151,7 @@ namespace GameRes.Formats.Macromedia
|
|||||||
{
|
{
|
||||||
for (int line = 0; line < m_output.Length; line += m_stride)
|
for (int line = 0; line < m_output.Length; line += m_stride)
|
||||||
{
|
{
|
||||||
int x = 0;
|
UnpackScanLine (m_output, line);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return m_output;
|
return m_output;
|
||||||
}
|
}
|
||||||
@ -186,33 +161,7 @@ namespace GameRes.Formats.Macromedia
|
|||||||
var scan_line = new byte[m_stride];
|
var scan_line = new byte[m_stride];
|
||||||
for (int line = 0; line < m_output.Length; line += m_stride)
|
for (int line = 0; line < m_output.Length; line += m_stride)
|
||||||
{
|
{
|
||||||
int x = 0;
|
UnpackScanLine (scan_line, 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int dst = line;
|
int dst = line;
|
||||||
for (int i = 0; i < m_width; ++i)
|
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
|
#region IDisposable Members
|
||||||
bool m_disposed = false;
|
bool m_disposed = false;
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ namespace GameRes.Formats.RealLive
|
|||||||
int offset = input.ReadUInt16();
|
int offset = input.ReadUInt16();
|
||||||
int count = (offset & 0xF) + 2;
|
int count = (offset & 0xF) + 2;
|
||||||
offset >>= 4;
|
offset >>= 4;
|
||||||
Binary.CopyOverlapped (output, dst-offset, dst, count);
|
Binary.CopyOverlapped (output, dst-offset-1, dst, count);
|
||||||
dst += count;
|
dst += count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ namespace GameRes.Formats.YuRis
|
|||||||
|
|
||||||
public YpfOpener ()
|
public YpfOpener ()
|
||||||
{
|
{
|
||||||
Signatures = new uint[] { 0x00465059, 0 };
|
Signatures = new uint[] { 0x00465059, 0x00905A4D, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
static public Dictionary<string, YpfScheme> KnownSchemes { get { return DefaultScheme.KnownSchemes; } }
|
static public Dictionary<string, YpfScheme> KnownSchemes { get { return DefaultScheme.KnownSchemes; } }
|
||||||
|
@ -52,30 +52,37 @@ namespace GameRes.Formats.Zyx
|
|||||||
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
public override ImageMetaData ReadMetaData (IBinaryStream file)
|
||||||
{
|
{
|
||||||
int count = file.ReadInt16();
|
int count = file.ReadInt16();
|
||||||
if (count <= 0)
|
if (count < 0 || count > 0x100)
|
||||||
return null;
|
return null;
|
||||||
var tiles = new Tile[count];
|
Tile[] tiles = null;
|
||||||
for (int i = 0; i < count; ++i)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
var tile = new Tile();
|
tiles = new Tile[count];
|
||||||
tile.Left = file.ReadInt16();
|
for (int i = 0; i < count; ++i)
|
||||||
tile.Top = file.ReadInt16();
|
{
|
||||||
if (tile.Left < 0 || tile.Top < 0)
|
var tile = new Tile();
|
||||||
return null;
|
tile.Left = file.ReadInt16();
|
||||||
tile.Right = file.ReadInt16();
|
tile.Top = file.ReadInt16();
|
||||||
tile.Bottom = file.ReadInt16();
|
if (tile.Left < 0 || tile.Top < 0)
|
||||||
if (tile.Right <= tile.Left || tile.Bottom <= tile.Top)
|
return null;
|
||||||
return null;
|
tile.Right = file.ReadInt16();
|
||||||
tiles[i] = tile;
|
tile.Bottom = file.ReadInt16();
|
||||||
|
if (tile.Right <= tile.Left || tile.Bottom <= tile.Top)
|
||||||
|
return null;
|
||||||
|
tiles[i] = tile;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int width = file.ReadInt16();
|
int width = file.ReadInt16();
|
||||||
int height = file.ReadInt16();
|
int height = file.ReadInt16();
|
||||||
if (width <= 0 || height <= 0)
|
if (width <= 0 || height <= 0)
|
||||||
return null;
|
return null;
|
||||||
foreach (var tile in tiles)
|
if (tiles != null)
|
||||||
{
|
{
|
||||||
if (tile.Right > width || tile.Bottom > height)
|
foreach (var tile in tiles)
|
||||||
return null;
|
{
|
||||||
|
if (tile.Right > width || tile.Bottom > height)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new SplMetaData
|
return new SplMetaData
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user