(QLIE): better handling of version 1 archives.

This commit is contained in:
morkt 2018-06-19 13:05:31 +04:00
parent 48451ea482
commit 28aed8df37
2 changed files with 59 additions and 5 deletions

View File

@ -91,12 +91,14 @@ namespace GameRes.Formats.Qlie
/// </summary> /// </summary>
static readonly string[] KeyLocations = { ".", "..", @"..\DLL", "DLL" }; static readonly string[] KeyLocations = { ".", "..", @"..\DLL", "DLL" };
public static Dictionary<string, byte[]> KnownKeys = new Dictionary<string, byte[]>(); static QlieScheme DefaultScheme = new QlieScheme { KnownKeys = new Dictionary<string, byte[]>() };
public static Dictionary<string, byte[]> KnownKeys { get { return DefaultScheme.KnownKeys; } }
public override ResourceScheme Scheme public override ResourceScheme Scheme
{ {
get { return new QlieScheme { KnownKeys = KnownKeys }; } get { return DefaultScheme; }
set { KnownKeys = ((QlieScheme)value).KnownKeys; } set { DefaultScheme = (QlieScheme)value; }
} }
public override ArcFile TryOpen (ArcView file) public override ArcFile TryOpen (ArcView file)
@ -156,7 +158,8 @@ namespace GameRes.Formats.Qlie
entry.UnpackedSize = index.ReadUInt32(); // [+0C] entry.UnpackedSize = index.ReadUInt32(); // [+0C]
entry.IsPacked = 0 != index.ReadInt32(); // [+10] entry.IsPacked = 0 != index.ReadInt32(); // [+10]
entry.EncryptionMethod = index.ReadInt32(); // [+14] entry.EncryptionMethod = index.ReadInt32(); // [+14]
entry.Hash = index.ReadUInt32(); // [+18] if (pack_version.Major > 1)
entry.Hash = index.ReadUInt32(); // [+18]
entry.KeyFile = key_file; entry.KeyFile = key_file;
if (read_pack_keyfile && entry.Name.Contains ("pack_keyfile")) if (read_pack_keyfile && entry.Name.Contains ("pack_keyfile"))
{ {

View File

@ -56,7 +56,9 @@ namespace GameRes.Formats.Qlie
public static IEncryption Create (ArcView file, Version version, byte[] arc_key) public static IEncryption Create (ArcView file, Version version, byte[] arc_key)
{ {
if (2 == version.Major || 1 == version.Major) if (1 == version.Major)
return new EncryptionV1();
else if (2 == version.Major)
return new EncryptionV2(); return new EncryptionV2();
else if (3 == version.Major && 1 == version.Minor) else if (3 == version.Major && 1 == version.Minor)
return new EncryptionV3_1 (file); return new EncryptionV3_1 (file);
@ -73,6 +75,55 @@ namespace GameRes.Formats.Qlie
public abstract void DecryptEntry (byte[] data, int offset, int length, QlieEntry entry); public abstract void DecryptEntry (byte[] data, int offset, int length, QlieEntry entry);
} }
internal class EncryptionV1 : QlieEncryption
{
public EncryptionV1 ()
{
NameKey = 0xC4;
ArcKey = 0;
}
public override uint CalculateHash (byte[] data, int length)
{
return 0; // not implemented
}
public override string DecryptName (byte[] name, int name_length)
{
int key = NameKey ^ 0x3E;
for (int k = 0; k < name_length; ++k)
name[k] ^= (byte)(((k + 1) ^ key) + k + 1);
return Encodings.cp932.GetString (name, 0, name_length);
}
public override void DecryptEntry (byte[] data, int offset, int length, QlieEntry entry)
{
if (offset < 0)
throw new ArgumentOutOfRangeException ("offset");
if (length > data.Length || offset > data.Length - length)
throw new ArgumentOutOfRangeException ("length");
uint arc_key = ArcKey;
ulong hash = 0xA73C5F9DA73C5F9Dul;
ulong xor = arc_key ^ 0xFEC9753Eu;
xor |= xor << 32;
unsafe
{
fixed (byte* raw = data)
{
ulong* encoded = (ulong*)(raw + offset);
for (int i = 0; i < length / 8; ++i)
{
hash = MMX.PAddD (hash, 0xCE24F523CE24F523ul) ^ xor;
xor = *encoded ^ hash;
*encoded++ = xor;
}
}
}
}
}
internal class EncryptionV2 : QlieEncryption internal class EncryptionV2 : QlieEncryption
{ {
public EncryptionV2 () public EncryptionV2 ()