Example #1
0
        public override ArcFile TryOpen(ArcView file)
        {
            if (file.MaxOffset <= 0x1c)
            {
                return(null);
            }
            long index_offset = file.MaxOffset - 0x1c;

            if (!file.View.AsciiEqual(index_offset, "FilePackVer") ||
                '.' != file.View.ReadByte(index_offset + 0xC))
            {
                return(null);
            }
            using (var index = new PackIndexReader(this, file, index_offset))
            {
                byte[] arc_key          = null;
                byte[] key_file         = null;
                bool   use_pack_keyfile = false;
                if (index.PackVersion.Major >= 3)
                {
                    key_file         = FindKeyFile(file);
                    use_pack_keyfile = key_file != null;
                    // currently, user is prompted to choose encryption scheme only if there's 'key.fkey' file found.
                    if (use_pack_keyfile && index.PackVersion.Minor == 0)
                    {
                        arc_key = QueryEncryption(file);
                    }
//                    use_pack_keyfile = null != arc_key;
                }
                var          enc = QlieEncryption.Create(file, index.PackVersion, arc_key);
                List <Entry> dir = null;
                try
                {
                    dir = index.Read(enc, key_file, use_pack_keyfile);
                }
                catch
                {
                    if (index.PackVersion.Major == 1)
                    {
                        enc = new EncryptionV2();
                        dir = index.Read(enc, key_file, use_pack_keyfile);
                    }
                }
                if (null == dir)
                {
                    return(null);
                }
                return(new QlieArchive(file, this, dir, enc));
            }
        }
Example #2
0
        public override ArcFile TryOpen(ArcView file)
        {
            if (file.MaxOffset <= 0x1c)
            {
                return(null);
            }
            long index_offset = file.MaxOffset - 0x1c;

            if (!file.View.AsciiEqual(index_offset, "FilePackVer") ||
                '.' != file.View.ReadByte(index_offset + 0xC))
            {
                return(null);
            }
            var pack_version = new Version(file.View.ReadByte(index_offset + 0xB) - '0',
                                           file.View.ReadByte(index_offset + 0xD) - '0');
            int count = file.View.ReadInt32(index_offset + 0x10);

            if (!IsSaneCount(count))
            {
                return(null);
            }
            index_offset = file.View.ReadInt64(index_offset + 0x14);
            if (index_offset < 0 || index_offset >= file.MaxOffset)
            {
                return(null);
            }

            byte[] arc_key          = null;
            byte[] key_file         = null;
            bool   use_pack_keyfile = false;

            if (pack_version.Major >= 3)
            {
                key_file         = FindKeyFile(file);
                use_pack_keyfile = key_file != null;
                // currently, user is prompted to choose encryption scheme only if there's 'key.fkey' file found.
                if (use_pack_keyfile && pack_version.Minor == 0)
                {
                    arc_key = QueryEncryption(file);
                }
//                use_pack_keyfile = null != arc_key;
            }
            var enc = QlieEncryption.Create(file, pack_version, arc_key);

            bool read_pack_keyfile = 3 == pack_version.Major && use_pack_keyfile;
            var  name_buffer       = new byte[0x100];
            var  dir = new List <Entry> (count);

            using (var index = file.CreateStream(index_offset))
            {
                for (int i = 0; i < count; ++i)
                {
                    int name_length = index.ReadUInt16();
                    if (enc.IsUnicode)
                    {
                        name_length *= 2;
                    }
                    if (name_length > name_buffer.Length)
                    {
                        name_buffer = new byte[name_length];
                    }
                    if (name_length != index.Read(name_buffer, 0, name_length))
                    {
                        return(null);
                    }
                    var name  = enc.DecryptName(name_buffer, name_length);
                    var entry = Create <QlieEntry> (name);
                    if (use_pack_keyfile)
                    {
                        entry.RawName = name_buffer.Take(name_length).ToArray();
                    }

                    entry.Offset = index.ReadInt64();           // [+00]
                    entry.Size   = index.ReadUInt32();          // [+08]
                    if (!entry.CheckPlacement(file.MaxOffset))
                    {
                        return(null);
                    }
                    entry.UnpackedSize     = index.ReadUInt32();     // [+0C]
                    entry.IsPacked         = 0 != index.ReadInt32(); // [+10]
                    entry.EncryptionMethod = index.ReadInt32();      // [+14]
                    if (pack_version.Major > 1)
                    {
                        entry.Hash = index.ReadUInt32();            // [+18]
                    }
                    entry.KeyFile = key_file;
                    if (read_pack_keyfile && entry.Name.Contains("pack_keyfile"))
                    {
                        // note that 'pack_keyfile' itself is encrypted using 'key.fkey' file contents.
                        key_file          = ReadEntryBytes(file, entry, enc);
                        read_pack_keyfile = false;
                    }
                    dir.Add(entry);
                }
            }
            return(new QlieArchive(file, this, dir, enc));
        }