mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-23 05:35:34 +08:00
Merge pull request #46 from MkfsSion/ageengine
ArcFormats: Support S5IC archieve
This commit is contained in:
commit
5915546fdf
@ -27,8 +27,10 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.IO;
|
||||
using GameRes.Utility;
|
||||
using GameRes.Compression;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace GameRes.Formats.Eushully
|
||||
{
|
||||
@ -63,15 +65,64 @@ namespace GameRes.Formats.Eushully
|
||||
return null;
|
||||
}
|
||||
|
||||
static internal string GetAAIName(string alf_name)
|
||||
{
|
||||
const string pattern = @"^(APPEND(?:[0-9]+)?)(?:_[0-9]+)?\.ALF$";
|
||||
var match = Regex.Match(alf_name, pattern);
|
||||
if (match.Success)
|
||||
return match.Groups[1].Value;
|
||||
return alf_name;
|
||||
}
|
||||
|
||||
internal IEnumerable<string> GetIndexNames (string alf_name)
|
||||
{
|
||||
yield return "sys5ini.bin";
|
||||
yield return "sys4ini.bin";
|
||||
yield return "sys3ini.bin";
|
||||
yield return Path.ChangeExtension (alf_name, "AAI");
|
||||
yield return Path.ChangeExtension (GetAAIName(alf_name), "AAI");
|
||||
}
|
||||
|
||||
Tuple<string, Dictionary<string, List<Entry>>> LastAccessedIndex;
|
||||
|
||||
|
||||
internal class AGEArchiveInfo
|
||||
{
|
||||
public readonly byte[] signature;
|
||||
public readonly int offset;
|
||||
public readonly bool isNameUnicode;
|
||||
public readonly bool isLZSSCompressed;
|
||||
|
||||
public AGEArchiveInfo(byte[] Signature, int Offset, bool IsNameUnicode, bool IsLZSSCompressed)
|
||||
{
|
||||
signature = Signature;
|
||||
offset = Offset;
|
||||
isNameUnicode = IsNameUnicode;
|
||||
isLZSSCompressed = IsLZSSCompressed;
|
||||
}
|
||||
}
|
||||
|
||||
static AGEArchiveInfo[] infos =
|
||||
{
|
||||
new AGEArchiveInfo(Encoding.ASCII.GetBytes("S3IN"), 0x12C, false, false),
|
||||
new AGEArchiveInfo(Encoding.ASCII.GetBytes("S3IC"), 0x134, false, true),
|
||||
new AGEArchiveInfo(Encoding.ASCII.GetBytes("S3AC"), 0x114, false, true),
|
||||
new AGEArchiveInfo(Encoding.ASCII.GetBytes("S4IC"), 0x134, false, true),
|
||||
new AGEArchiveInfo(Encoding.ASCII.GetBytes("S4AC"), 0x114, false, true),
|
||||
new AGEArchiveInfo(Encoding.Unicode.GetBytes("S5IC"), 0x224, true, true),
|
||||
new AGEArchiveInfo(Encoding.Unicode.GetBytes("S5AC"), 0x21C, true, true)
|
||||
};
|
||||
|
||||
static internal AGEArchiveInfo GetAGEArcInfo(ArcView view)
|
||||
{
|
||||
byte[] sig = view.View.ReadBytes(0, 8);
|
||||
var siglow = sig.Take(4);
|
||||
var res = infos.Where(i => Enumerable.SequenceEqual(i.signature, siglow));
|
||||
if (res.Any()) return res.First();
|
||||
res = infos.Where(i => Enumerable.SequenceEqual(i.signature, sig));
|
||||
if (res.Any()) return res.First();
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Entry> ReadIndex (string ini_file, string arc_name)
|
||||
{
|
||||
if (null == LastAccessedIndex
|
||||
@ -81,24 +132,21 @@ namespace GameRes.Formats.Eushully
|
||||
using (var ini = VFS.OpenView (ini_file))
|
||||
{
|
||||
IBinaryStream index;
|
||||
bool is_append = ini.View.AsciiEqual (0, "S4AC");
|
||||
if (is_append || ini.View.AsciiEqual (0, "S4IC") || ini.View.AsciiEqual (0, "S3IC"))
|
||||
|
||||
AGEArchiveInfo info = GetAGEArcInfo (ini);
|
||||
if (info == null) return null;
|
||||
|
||||
if (info.isLZSSCompressed)
|
||||
{
|
||||
uint offset = is_append ? 0x114u : 0x134u;
|
||||
uint packed_size = ini.View.ReadUInt32 (offset);
|
||||
var packed = ini.CreateStream (offset+4, packed_size);
|
||||
var unpacked = new LzssStream (packed);
|
||||
index = new BinaryStream (unpacked, ini_file);
|
||||
}
|
||||
else if (ini.View.AsciiEqual (0, "S3IN"))
|
||||
{
|
||||
index = ini.CreateStream (0x12C);
|
||||
index = new BinaryStream(new LzssStream(ini.CreateStream(info.offset + 4, (uint)ini.View.ReadInt32(info.offset))), ini_file);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
{
|
||||
index = ini.CreateStream(info.offset);
|
||||
}
|
||||
using (index)
|
||||
{
|
||||
var file_table = ReadSysIni (index);
|
||||
var file_table = ReadSysIni (index, info);
|
||||
if (null == file_table)
|
||||
return null;
|
||||
LastAccessedIndex = Tuple.Create (ini_file, file_table);
|
||||
@ -110,7 +158,7 @@ namespace GameRes.Formats.Eushully
|
||||
return dir;
|
||||
}
|
||||
|
||||
internal Dictionary<string, List<Entry>> ReadSysIni (IBinaryStream index)
|
||||
internal Dictionary<string, List<Entry>> ReadSysIni (IBinaryStream index, AGEArchiveInfo info)
|
||||
{
|
||||
int arc_count = index.ReadInt32();
|
||||
if (!IsSaneCount (arc_count))
|
||||
@ -119,7 +167,8 @@ namespace GameRes.Formats.Eushully
|
||||
var arc_list = new List<Entry>[arc_count];
|
||||
for (int i = 0; i < arc_count; ++i)
|
||||
{
|
||||
var name = index.ReadCString (0x100);
|
||||
string name = info.isNameUnicode ? index.ReadCString(0x200, Encoding.Unicode) : index.ReadCString(0x100);
|
||||
|
||||
var file_list = new List<Entry>();
|
||||
file_table.Add (name, file_list);
|
||||
arc_list[i] = file_list;
|
||||
@ -127,9 +176,10 @@ namespace GameRes.Formats.Eushully
|
||||
int file_count = index.ReadInt32();
|
||||
if (!IsSaneCount (file_count))
|
||||
return null;
|
||||
|
||||
for (int i = 0; i < file_count; ++i)
|
||||
{
|
||||
var name = index.ReadCString (0x40);
|
||||
string name = info.isNameUnicode ? index.ReadCString(0x80, Encoding.Unicode) : index.ReadCString(0x40);
|
||||
int arc_id = index.ReadInt32();
|
||||
if (arc_id < 0 || arc_id >= arc_list.Length)
|
||||
return null;
|
||||
|
@ -170,6 +170,27 @@ namespace GameRes
|
||||
return bin;
|
||||
}
|
||||
|
||||
internal int FindEoS(int start, int length, Encoding enc)
|
||||
{
|
||||
int eos_pos = -1;
|
||||
if (enc.IsUtf16())
|
||||
{
|
||||
for (int i = start + 1; i < start + length; i += 2)
|
||||
{
|
||||
if (m_buffer[i - 1] == 0 && m_buffer[i] == 0)
|
||||
{
|
||||
eos_pos = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eos_pos = Array.IndexOf<byte>(m_buffer, 0, start, length);
|
||||
}
|
||||
return eos_pos;
|
||||
}
|
||||
|
||||
uint ReadSignature ()
|
||||
{
|
||||
if (m_header_size >= 4)
|
||||
@ -307,10 +328,7 @@ namespace GameRes
|
||||
public string ReadCString (int length, Encoding enc)
|
||||
{
|
||||
length = FillBuffer (length);
|
||||
int i;
|
||||
for (i = 0; i < length; ++i)
|
||||
if (0 == m_buffer[m_buffer_pos+i])
|
||||
break;
|
||||
int i = FindEoS(m_buffer_pos, length, enc) - m_buffer_pos;
|
||||
string s = enc.GetString (m_buffer, m_buffer_pos, i);
|
||||
m_buffer_pos += length;
|
||||
return s;
|
||||
|
Loading…
Reference in New Issue
Block a user