mirror of
https://github.com/lifegpc/GARbro.git
synced 2026-07-08 01:31:41 +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:
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user