mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-24 03:44:13 +08:00
(Csystem): archive index reading moved to specialized classes.
This commit is contained in:
parent
77cb9a853f
commit
2ee030aa84
@ -174,7 +174,9 @@ namespace GameRes.Formats.Cyberworks
|
|||||||
Extensions = new string[] { "dat", "04", "05", "06", "app" };
|
Extensions = new string[] { "dat", "04", "05", "06", "app" };
|
||||||
}
|
}
|
||||||
|
|
||||||
static readonly ArchiveNameParser[] s_name_parsers = { new ArcNameParser(), new DatNameParser(), new InKyouParser() };
|
static readonly ArchiveNameParser[] s_name_parsers = {
|
||||||
|
new ArcNameParser(), new DatNameParser(), new InKyouParser()
|
||||||
|
};
|
||||||
|
|
||||||
public override ArcFile TryOpen (ArcView file)
|
public override ArcFile TryOpen (ArcView file)
|
||||||
{
|
{
|
||||||
@ -195,62 +197,12 @@ namespace GameRes.Formats.Cyberworks
|
|||||||
var toc = ReadToc (toc_name, 8);
|
var toc = ReadToc (toc_name, 8);
|
||||||
if (null == toc)
|
if (null == toc)
|
||||||
return null;
|
return null;
|
||||||
|
using (var index = new ArcIndexReader (toc, file, arc_idx))
|
||||||
int entry_size = LittleEndian.ToInt32 (toc, 0) + 4;
|
|
||||||
if (entry_size < 0x16)
|
|
||||||
return null;
|
|
||||||
int count = toc.Length / entry_size;
|
|
||||||
if (!IsSaneCount (count))
|
|
||||||
return null;
|
|
||||||
var type = new char[2];
|
|
||||||
var dir = new List<Entry> (count);
|
|
||||||
bool has_images = false;
|
|
||||||
using (var index = new BinMemoryStream (toc, file.Name))
|
|
||||||
{
|
{
|
||||||
while (index.Position < index.Length)
|
if (!index.Read())
|
||||||
{
|
return null;
|
||||||
entry_size = index.ReadInt32();
|
return ArchiveFromDir (file, index.Dir, index.HasImages);
|
||||||
if (entry_size <= 0)
|
|
||||||
return null;
|
|
||||||
var next_pos = index.Position + entry_size;
|
|
||||||
uint id = index.ReadUInt32();
|
|
||||||
var entry = new PackedEntry { Name = id.ToString ("D6") };
|
|
||||||
entry.UnpackedSize = index.ReadUInt32();
|
|
||||||
entry.Size = index.ReadUInt32();
|
|
||||||
entry.IsPacked = entry.UnpackedSize != entry.Size;
|
|
||||||
entry.Offset = index.ReadUInt32();
|
|
||||||
type[0] = (char)index.ReadByte();
|
|
||||||
type[1] = (char)index.ReadByte();
|
|
||||||
int entry_idx = 0;
|
|
||||||
if (entry_size >= 0x17)
|
|
||||||
{
|
|
||||||
index.ReadInt32();
|
|
||||||
entry_idx = index.ReadByte();
|
|
||||||
}
|
|
||||||
if (entry_idx == arc_idx)
|
|
||||||
{
|
|
||||||
if (type[0] > 0x20 && type[0] < 0x7F)
|
|
||||||
{
|
|
||||||
string ext;
|
|
||||||
if (type[1] > 0x20 && type[1] < 0x7F)
|
|
||||||
ext = new string (type);
|
|
||||||
else
|
|
||||||
ext = new string (type[0], 1);
|
|
||||||
if ("b0" == ext || "n0" == ext || "o0" == ext || "0b" == ext)
|
|
||||||
{
|
|
||||||
entry.Type = "image";
|
|
||||||
has_images = true;
|
|
||||||
}
|
|
||||||
else if ("j0" == ext || "k0" == ext || "u0" == ext)
|
|
||||||
entry.Type = "audio";
|
|
||||||
entry.Name = Path.ChangeExtension (entry.Name, ext);
|
|
||||||
}
|
|
||||||
dir.Add (entry);
|
|
||||||
}
|
|
||||||
index.Position = next_pos;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ArchiveFromDir (file, dir, has_images);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ArcFile ArchiveFromDir (ArcView file, List<Entry> dir, bool has_images)
|
internal ArcFile ArchiveFromDir (ArcView file, List<Entry> dir, bool has_images)
|
||||||
@ -509,87 +461,66 @@ namespace GameRes.Formats.Cyberworks
|
|||||||
var toc = ReadToc (toc_name, 4);
|
var toc = ReadToc (toc_name, 4);
|
||||||
if (null == toc)
|
if (null == toc)
|
||||||
return null;
|
return null;
|
||||||
|
using (var index = new DatIndexReader (toc, file))
|
||||||
bool has_images = false;
|
|
||||||
var dir = new List<Entry>();
|
|
||||||
int entry_size = toc.ToInt32 (0);
|
|
||||||
if (entry_size <= 0 || entry_size > 0x11)
|
|
||||||
return null;
|
|
||||||
using (var index = new BinMemoryStream (toc))
|
|
||||||
{
|
{
|
||||||
while (index.Position < index.Length)
|
if (!index.Read())
|
||||||
{
|
return null;
|
||||||
entry_size = index.ReadInt32();
|
return ArchiveFromDir (file, index.Dir, index.HasImages);
|
||||||
if (entry_size <= 0)
|
|
||||||
return null;
|
|
||||||
var next_pos = index.Position + entry_size;
|
|
||||||
uint id = index.ReadUInt32();
|
|
||||||
var entry = new PackedEntry { Name = id.ToString ("D6") };
|
|
||||||
entry.UnpackedSize = index.ReadUInt32();
|
|
||||||
entry.Size = index.ReadUInt32();
|
|
||||||
entry.IsPacked = entry.UnpackedSize != entry.Size;
|
|
||||||
entry.Offset = index.ReadUInt32();
|
|
||||||
if (!entry.CheckPlacement (file.MaxOffset))
|
|
||||||
return null;
|
|
||||||
char type = (char)index.ReadByte();
|
|
||||||
if (type > 0x20 && type < 0x7F)
|
|
||||||
{
|
|
||||||
string ext = new string (type, 1);
|
|
||||||
if ('b' == type)
|
|
||||||
{
|
|
||||||
entry.Type = "image";
|
|
||||||
has_images = true;
|
|
||||||
}
|
|
||||||
else if ('k' == type || 'j' == type)
|
|
||||||
entry.Type = "audio";
|
|
||||||
entry.Name = Path.ChangeExtension (entry.Name, ext);
|
|
||||||
}
|
|
||||||
dir.Add (entry);
|
|
||||||
index.Position = next_pos;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ArchiveFromDir (file, dir, has_images);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class TocUnpacker : IDisposable
|
internal sealed class TocUnpacker : IDisposable
|
||||||
{
|
{
|
||||||
ArcView m_file;
|
ArcView m_file;
|
||||||
|
bool m_should_dispose;
|
||||||
|
|
||||||
public long Length { get { return m_file.MaxOffset; } }
|
public long Length { get { return m_file.MaxOffset; } }
|
||||||
|
public uint PackedSize { get; private set; }
|
||||||
|
public uint UnpackedSize { get; private set; }
|
||||||
|
|
||||||
public TocUnpacker (string toc_name)
|
public TocUnpacker (string toc_name) : this (VFS.OpenView (toc_name), true)
|
||||||
{
|
{
|
||||||
m_file = VFS.OpenView (toc_name);
|
}
|
||||||
|
|
||||||
|
public TocUnpacker (ArcView file, bool should_dispose = false)
|
||||||
|
{
|
||||||
|
m_file = file;
|
||||||
|
m_should_dispose = should_dispose;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] Unpack (int num_length)
|
public byte[] Unpack (int num_length)
|
||||||
{
|
{
|
||||||
int data_offset = num_length*2;
|
return Unpack (0, num_length);
|
||||||
if (m_file.MaxOffset <= data_offset)
|
|
||||||
return null;
|
|
||||||
uint unpacked_size = DecodeDecimal (0, num_length);
|
|
||||||
if (unpacked_size <= 4 || unpacked_size > 0x1000000)
|
|
||||||
return null;
|
|
||||||
uint packed_size = DecodeDecimal (num_length, num_length);
|
|
||||||
if (packed_size > m_file.MaxOffset - data_offset)
|
|
||||||
return null;
|
|
||||||
return Unpack (data_offset, packed_size, unpacked_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] Unpack (int offset, uint packed_size, uint unpacked_size)
|
public byte[] Unpack (long offset, int num_length)
|
||||||
{
|
{
|
||||||
using (var toc_s = m_file.CreateStream (offset, packed_size))
|
long data_offset = offset + num_length*2;
|
||||||
|
if (m_file.MaxOffset <= data_offset)
|
||||||
|
return null;
|
||||||
|
UnpackedSize = DecodeDecimal (offset, num_length);
|
||||||
|
if (UnpackedSize <= 4 || UnpackedSize > 0x1000000)
|
||||||
|
return null;
|
||||||
|
PackedSize = DecodeDecimal (offset+num_length, num_length);
|
||||||
|
if (PackedSize > m_file.MaxOffset - data_offset || 0 == PackedSize)
|
||||||
|
return null;
|
||||||
|
return UnpackAt (data_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] UnpackAt (long offset)
|
||||||
|
{
|
||||||
|
using (var toc_s = m_file.CreateStream (offset, PackedSize))
|
||||||
using (var lzss = new LzssStream (toc_s))
|
using (var lzss = new LzssStream (toc_s))
|
||||||
{
|
{
|
||||||
var toc = new byte[unpacked_size];
|
var toc = new byte[UnpackedSize];
|
||||||
if (toc.Length != lzss.Read (toc, 0, toc.Length))
|
if (toc.Length != lzss.Read (toc, 0, toc.Length))
|
||||||
return null;
|
return null;
|
||||||
return toc;
|
return toc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint DecodeDecimal (long offset, int num_length)
|
internal uint DecodeDecimal (long offset, int num_length)
|
||||||
{
|
{
|
||||||
uint v = 0;
|
uint v = 0;
|
||||||
uint rank = 1;
|
uint rank = 1;
|
||||||
@ -605,11 +536,152 @@ namespace GameRes.Formats.Cyberworks
|
|||||||
bool _disposed = false;
|
bool _disposed = false;
|
||||||
public void Dispose ()
|
public void Dispose ()
|
||||||
{
|
{
|
||||||
if (!_disposed)
|
if (m_should_dispose && !_disposed)
|
||||||
{
|
{
|
||||||
m_file.Dispose();
|
m_file.Dispose();
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal abstract class IndexReader : IDisposable
|
||||||
|
{
|
||||||
|
protected IBinaryStream m_index;
|
||||||
|
readonly long m_max_offset;
|
||||||
|
private List<Entry> m_dir;
|
||||||
|
|
||||||
|
public List<Entry> Dir { get { return m_dir; } }
|
||||||
|
public long MaxOffset { get { return m_max_offset; } }
|
||||||
|
public bool HasImages { get; protected set; }
|
||||||
|
|
||||||
|
public IndexReader (byte[] toc, ArcView file)
|
||||||
|
{
|
||||||
|
m_index = new BinMemoryStream (toc);
|
||||||
|
m_max_offset = file.MaxOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Read ()
|
||||||
|
{
|
||||||
|
int entry_size = m_index.ReadInt32();
|
||||||
|
if (entry_size < 0x11)
|
||||||
|
return false;
|
||||||
|
int count = (int)m_index.Length / (entry_size + 4);
|
||||||
|
if (!ArchiveFormat.IsSaneCount (count))
|
||||||
|
return false;
|
||||||
|
m_index.Position = 0;
|
||||||
|
m_dir = new List<Entry> (count);
|
||||||
|
while (m_index.Position < m_index.Length)
|
||||||
|
{
|
||||||
|
entry_size = m_index.ReadInt32();
|
||||||
|
if (entry_size <= 0)
|
||||||
|
return false;
|
||||||
|
var next_pos = m_index.Position + entry_size;
|
||||||
|
var entry = ReadEntryInfo();
|
||||||
|
if (ReadEntryType (entry, entry_size))
|
||||||
|
{
|
||||||
|
if (!entry.CheckPlacement (MaxOffset))
|
||||||
|
return false;
|
||||||
|
m_dir.Add (entry);
|
||||||
|
}
|
||||||
|
m_index.Position = next_pos;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal PackedEntry ReadEntryInfo ()
|
||||||
|
{
|
||||||
|
uint id = m_index.ReadUInt32();
|
||||||
|
var entry = new PackedEntry { Name = id.ToString ("D6") };
|
||||||
|
entry.UnpackedSize = m_index.ReadUInt32();
|
||||||
|
entry.Size = m_index.ReadUInt32();
|
||||||
|
entry.IsPacked = entry.UnpackedSize != entry.Size;
|
||||||
|
entry.Offset = m_index.ReadUInt32();
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract bool ReadEntryType (Entry entry, int entry_size);
|
||||||
|
|
||||||
|
public void Dispose ()
|
||||||
|
{
|
||||||
|
Dispose (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _disposed = false;
|
||||||
|
protected virtual void Dispose (bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && !_disposed)
|
||||||
|
{
|
||||||
|
m_index.Dispose();
|
||||||
|
_disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ArcIndexReader : IndexReader
|
||||||
|
{
|
||||||
|
int m_arc_number;
|
||||||
|
|
||||||
|
public ArcIndexReader (byte[] toc, ArcView file, int arc_number) : base (toc, file)
|
||||||
|
{
|
||||||
|
m_arc_number = arc_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
char[] m_type = new char[2];
|
||||||
|
|
||||||
|
protected override bool ReadEntryType (Entry entry, int entry_size)
|
||||||
|
{
|
||||||
|
m_type[0] = (char)m_index.ReadByte();
|
||||||
|
m_type[1] = (char)m_index.ReadByte();
|
||||||
|
int entry_idx = 0;
|
||||||
|
if (entry_size >= 0x17)
|
||||||
|
{
|
||||||
|
m_index.ReadInt32();
|
||||||
|
entry_idx = m_index.ReadByte();
|
||||||
|
}
|
||||||
|
if (entry_idx != m_arc_number)
|
||||||
|
return false;
|
||||||
|
if (m_type[0] > 0x20 && m_type[0] < 0x7F)
|
||||||
|
{
|
||||||
|
string ext;
|
||||||
|
if (m_type[1] > 0x20 && m_type[1] < 0x7F)
|
||||||
|
ext = new string (m_type);
|
||||||
|
else
|
||||||
|
ext = new string (m_type[0], 1);
|
||||||
|
if ("b0" == ext || "n0" == ext || "o0" == ext || "0b" == ext)
|
||||||
|
{
|
||||||
|
entry.Type = "image";
|
||||||
|
HasImages = true;
|
||||||
|
}
|
||||||
|
else if ("j0" == ext || "k0" == ext || "u0" == ext)
|
||||||
|
entry.Type = "audio";
|
||||||
|
entry.Name = Path.ChangeExtension (entry.Name, ext);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DatIndexReader : IndexReader
|
||||||
|
{
|
||||||
|
public DatIndexReader (byte[] toc, ArcView file) : base (toc, file)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool ReadEntryType (Entry entry, int entry_size)
|
||||||
|
{
|
||||||
|
char type = (char)m_index.ReadByte();
|
||||||
|
if (type > 0x20 && type < 0x7F)
|
||||||
|
{
|
||||||
|
string ext = new string (type, 1);
|
||||||
|
if ('b' == type)
|
||||||
|
{
|
||||||
|
entry.Type = "image";
|
||||||
|
HasImages = true;
|
||||||
|
}
|
||||||
|
else if ('k' == type || 'j' == type)
|
||||||
|
entry.Type = "audio";
|
||||||
|
entry.Name = Path.ChangeExtension (entry.Name, ext);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user