(XP3): recognize filenames stored in hash table.

This commit is contained in:
morkt 2016-07-01 06:23:03 +04:00
parent 86fb8d4a0e
commit 69e29dc0f9

View File

@ -148,6 +148,7 @@ namespace GameRes.Formats.KiriKiri
var crypt_algorithm = new Lazy<ICrypt> (QueryCryptAlgorithm); var crypt_algorithm = new Lazy<ICrypt> (QueryCryptAlgorithm);
var filename_map = new Dictionary<uint, string>();
var dir = new List<Entry>(); var dir = new List<Entry>();
dir_offset = 0; dir_offset = 0;
using (var header = new BinaryReader (header_stream, Encoding.Unicode)) using (var header = new BinaryReader (header_stream, Encoding.Unicode))
@ -155,26 +156,35 @@ namespace GameRes.Formats.KiriKiri
while (-1 != header.PeekChar()) while (-1 != header.PeekChar())
{ {
uint entry_signature = header.ReadUInt32(); uint entry_signature = header.ReadUInt32();
if (0x656c6946 != entry_signature) // "File"
{
break;
}
long entry_size = header.ReadInt64(); long entry_size = header.ReadInt64();
if (entry_size < 0)
return null;
dir_offset += 12 + entry_size; dir_offset += 12 + entry_size;
var entry = new Xp3Entry(); if (0x6E666E68 == entry_signature) // "hnfn"
while (entry_size > 0)
{ {
uint section = header.ReadUInt32(); uint hash = header.ReadUInt32();
long section_size = header.ReadInt64(); int name_size = header.ReadInt16();
entry_size -= 12; entry_size -= 6;
if (section_size > entry_size) if (name_size * 2 <= entry_size)
break;
entry_size -= section_size;
long next_section_pos = header.BaseStream.Position + section_size;
switch (section)
{ {
case 0x6f666e69: // "info" filename_map[hash] = new string (header.ReadChars (name_size));
}
}
else if (0x656C6946 == entry_signature) // "File"
{
var entry = new Xp3Entry();
while (entry_size > 0)
{
uint section = header.ReadUInt32();
long section_size = header.ReadInt64();
entry_size -= 12;
if (section_size > entry_size)
break;
entry_size -= section_size;
long next_section_pos = header.BaseStream.Position + section_size;
switch (section)
{ {
case 0x6f666e69: // "info"
if (entry.Size != 0 || !string.IsNullOrEmpty (entry.Name)) if (entry.Size != 0 || !string.IsNullOrEmpty (entry.Name))
{ {
goto NextEntry; // ambiguous entry, ignore goto NextEntry; // ambiguous entry, ignore
@ -200,19 +210,21 @@ namespace GameRes.Formats.KiriKiri
else else
entry.Cipher = NoCryptAlgorithm; entry.Cipher = NoCryptAlgorithm;
var name = new string (header.ReadChars (name_size)); string name = null;
if (entry.Cipher.ObfuscatedIndex && ObfuscatedPathRe.IsMatch (name)) if (0 == filename_map.Count || !filename_map.TryGetValue (entry.Hash, out name))
{ {
goto NextEntry; name = new string (header.ReadChars (name_size));
if (entry.Cipher.ObfuscatedIndex && ObfuscatedPathRe.IsMatch (name))
{
goto NextEntry;
}
} }
entry.Name = name; entry.Name = name;
entry.Type = FormatCatalog.Instance.GetTypeFromName (entry.Name); entry.Type = FormatCatalog.Instance.GetTypeFromName (entry.Name);
entry.IsEncrypted = !(entry.Cipher is NoCrypt) entry.IsEncrypted = !(entry.Cipher is NoCrypt)
&& !(entry.Cipher.StratupTjsNotEncrypted && "startup.tjs" == name); && !(entry.Cipher.StratupTjsNotEncrypted && "startup.tjs" == name);
break; break;
} case 0x6d676573: // "segm"
case 0x6d676573: // "segm"
{
int segment_count = (int)(section_size / 0x1c); int segment_count = (int)(section_size / 0x1c);
if (segment_count > 0) if (segment_count > 0)
{ {
@ -237,29 +249,31 @@ namespace GameRes.Formats.KiriKiri
entry.Offset = entry.Segments.First().Offset; entry.Offset = entry.Segments.First().Offset;
} }
break; break;
} case 0x726c6461: // "adlr"
case 0x726c6461: // "adlr" if (4 == section_size)
if (4 == section_size) entry.Hash = header.ReadUInt32();
entry.Hash = header.ReadUInt32(); break;
break;
default: // unknown section default: // unknown section
break; break;
}
header.BaseStream.Position = next_section_pos;
} }
header.BaseStream.Position = next_section_pos; if (!string.IsNullOrEmpty (entry.Name) && entry.Segments.Any())
}
if (!string.IsNullOrEmpty (entry.Name) && entry.Segments.Any())
{
if (entry.Cipher.ObfuscatedIndex)
{ {
DeobfuscateEntry (entry); if (entry.Cipher.ObfuscatedIndex)
{
DeobfuscateEntry (entry);
}
dir.Add (entry);
} }
dir.Add (entry);
} }
NextEntry: NextEntry:
header.BaseStream.Position = dir_offset; header.BaseStream.Position = dir_offset;
} }
} }
if (0 == dir.Count)
return null;
var arc = new ArcFile (file, this, dir); var arc = new ArcFile (file, this, dir);
try try
{ {