diff --git a/ArcFormats/elf/ArcAi5Win.cs b/ArcFormats/elf/ArcAi5Win.cs index 73ea0f05..a2ad1ed0 100644 --- a/ArcFormats/elf/ArcAi5Win.cs +++ b/ArcFormats/elf/ArcAi5Win.cs @@ -77,147 +77,95 @@ namespace GameRes.Formats.Elf int count = file.View.ReadInt32 (0); if (!IsSaneCount (count)) return null; - var reader = new IndexReader (file, count); - foreach (var scheme in KnownSchemes.Values) - { - try - { - var dir = reader.Read (scheme); - if (dir != null) - return new ArcFile (file, this, dir); - } - catch { /* ignore parse errors */ } - } + var reader = new Ai5ArcIndexReader (file, count); + var dir = reader.TrySchemes (KnownSchemes.Values); + if (dir != null) + return new ArcFile (file, this, dir); return null; } public override Stream OpenEntry (ArcFile arc, Entry entry) { var input = arc.File.CreateStream (entry.Offset, entry.Size); - if (entry.Name.HasAnyOfExtensions ("mes", "lib")) + if (entry.Name.HasAnyOfExtensions ("mes", "lib", "a", "a6", "msk")) return new LzssStream (input); return input; } + } - internal class IndexReader + internal class Ai5ArcIndexReader + { + protected ArcView m_file; + protected int m_count; + protected List m_dir; + protected byte[] m_name_buf = new byte[0x100]; + + public Ai5ArcIndexReader (ArcView file, int count) { - ArcView m_file; - int m_count; - List m_dir; - byte[] m_name_buf = new byte[0x100]; - - public IndexReader (ArcView file, int count) - { - m_file = file; - m_count = count; - m_dir = new List (m_count); - } - - public List Read (ArcIndexScheme scheme) - { - if (scheme.NameLength > m_name_buf.Length) - m_name_buf = new byte[scheme.NameLength]; - m_dir.Clear(); - int index_offset = 4; - uint index_size = (uint)(m_count * (scheme.NameLength + 8)); - if (index_size > m_file.View.Reserve (index_offset, index_size)) - return null; - for (int i = 0; i < m_count; ++i) - { - m_file.View.Read (index_offset, m_name_buf, 0, (uint)scheme.NameLength); - int n; - for (n = 0; n < m_name_buf.Length; ++n) - { - m_name_buf[n] ^= scheme.NameKey; - if (0 == m_name_buf[n]) - break; - if (m_name_buf[n] < 0x20) - return null; - } - if (0 == n) - return null; - string name = Encodings.cp932.GetString (m_name_buf, 0, n); - index_offset += scheme.NameLength; - var entry = FormatCatalog.Instance.Create (name); - entry.Size = m_file.View.ReadUInt32 (index_offset) ^ scheme.SizeKey; - entry.Offset = m_file.View.ReadUInt32 (index_offset+4) ^ scheme.OffsetKey; - if (entry.Offset < index_size+4 || !entry.CheckPlacement (m_file.MaxOffset)) - return null; - m_dir.Add (entry); - index_offset += 8; - } - return m_dir; - } + m_file = file; + m_count = count; + m_dir = new List (m_count); } - /* - internal class IndexReader + public List TrySchemes (IEnumerable schemes) { - ArcView m_file; - int m_count; - byte[] m_first = new byte[0x108]; - - public const int MinNameLength = 0x10; - public const int MaxNameLength = 0x100; - - public IndexReader (ArcView file) + foreach (var scheme in schemes) { - m_file = file; - m_count = m_file.View.ReadInt32 (0); - m_file.View.Read (4, m_first, 0, m_first.Length); - } - - ArcIndexScheme m_scheme = new ArcIndexScheme(); - - public ArcIndexScheme Parse () - { - if (m_count <= 0 || m_count > 0xfffff) - return null; - - uint supposed_first_offset = (uint)(m_count * (name_length + 8)); - - uint first_size = LittleEndian.ToUInt32 (first_entry, name_length); - uint first_offset = LittleEndian.ToUInt32 (first_entry, name_length+4); - - uint supposed_offset_key = first_offset ^ supposed_first_offset; - int last_index_offset = 4 + (m_count - 1) * (name_length + 8); - uint last_size = m_file.View.ReadUInt32 (last_index_offset + name_length); - uint last_offset = m_file.View.ReadUInt32 (last_index_offset + name_length + 4); - last_offset ^= supposed_offset_key; - } - - bool ParseFirstEntry (int name_length) - { - int index_offset = 4; - } - - public byte NameKey { get; private set; } - - int GuessNameLength (int initial) - { - int name_pos = initial; - byte sym; - do + try { - do - { - sym = first_entry[name_pos++]; - } - while (name_pos < MaxNameLength && sym != first_entry[name_pos]); - if (MaxNameLength == name_pos) - return 0; - while (name_pos < MaxNameLength && sym == first_entry[name_pos]) - { - ++name_pos; - } - if (MaxNameLength == name_pos && sym == first_entry[name_pos] && sym == first_entry[name_pos+1]) - return 0; + var dir = Read (scheme); + if (dir != null) + return dir; } - while (name_pos < MinNameLength || 0 != (name_pos & 1)); - NameKey = sym; - return name_pos; + catch { /* ignore parse errors */ } } + return null; + } + + public List Read (ArcIndexScheme scheme) + { + if (scheme.NameLength > m_name_buf.Length) + m_name_buf = new byte[scheme.NameLength]; + m_dir.Clear(); + int index_offset = 4; + uint index_size = (uint)(m_count * (scheme.NameLength + 8)); + if (index_size > m_file.View.Reserve (index_offset, index_size)) + return null; + for (int i = 0; i < m_count; ++i) + { + m_file.View.Read (index_offset, m_name_buf, 0, (uint)scheme.NameLength); + string name = DecryptName (scheme); + if (null == name) + return null; + index_offset += scheme.NameLength; + var entry = FormatCatalog.Instance.Create (name); + entry.Size = m_file.View.ReadUInt32 (index_offset) ^ scheme.SizeKey; + entry.Offset = m_file.View.ReadUInt32 (index_offset+4) ^ scheme.OffsetKey; + if (entry.Offset < index_size+4 || !entry.CheckPlacement (m_file.MaxOffset)) + return null; + m_dir.Add (entry); + index_offset += 8; + } + return m_dir; + } + + internal string DecryptName (ArcIndexScheme scheme) + { + int n; + for (n = 0; n < m_name_buf.Length; ++n) + { + if (n > scheme.NameLength) + return null; + m_name_buf[n] ^= scheme.NameKey; + if (0 == m_name_buf[n]) + break; + if (m_name_buf[n] < 0x20) + return null; + } + if (n != 0) + return Encodings.cp932.GetString (m_name_buf, 0, n); + else + return null; } - */ } }