// Compressed files start with an array of offsets to make seeking possible
        private void LoadBlockPositions()
        {
            int blockposcount = (int)((mBlock.FileSize + mBlockSize - 1) / mBlockSize) + 1;

            mBlockPositions = new uint[blockposcount];

            lock (mStream)
            {
                mStream.Seek(mBlock.FilePos, SeekOrigin.Begin);
                BinaryReader br = new BinaryReader(mStream);
                for (int i = 0; i < blockposcount; i++)
                    mBlockPositions[i] = br.ReadUInt32();
            }

            uint blockpossize = (uint)blockposcount * 4;
#if true
            // OW:

            // If the archive if protected some way, perform additional check
            // Sometimes, the file appears not to be encrypted, but it is.
            // Edit: In WoW 1.10+, there's a new flag. With this flag present,
            // there's one additional entry in the block table. If this flag
            // is present, we skip this test to keep the file readable.

            if ((mBlock.Flags & MpqFileFlags.FileHasMetadata) == 0)
            {
                if (mBlockPositions[0] != blockpossize)
                    mBlock.Flags |= MpqFileFlags.Encrypted;
            }

            if (mBlock.IsEncrypted)
            {
                if (mSeed1 == 0)
                {
                    mSeed1 = MpqArchive.DetectFileSeed(mBlockPositions, blockpossize);
                    if (mSeed1 == 0)
                        throw new MpqParserException("Unable to determine encyption seed");
                }

                MpqArchive.DecryptBlock(mBlockPositions, mSeed1);
                mSeed1++; // Add 1 because the first block is the offset list
            }
#else
            // StormLib takes this to mean the data is encrypted
            if (mBlockPositions[0] != blockpossize)
            {
                if (mSeed1 == 0)
                {
                    mSeed1 = MpqArchiveReader.DetectFileSeed(mBlockPositions, blockpossize);
                    if (mSeed1 == 0)
                        throw new Exception("Unable to determine encyption seed");
                }
                MpqArchiveReader.DecryptBlock(mBlockPositions, mSeed1);
                mSeed1++; // Add 1 because the first block is the offset list
            }
#endif
        }
        private byte[] LoadBlock(int BlockIndex, int ExpectedLength)
        {
            uint offset;
            int toread;

            if (mBlock.IsCompressed)
            {
                offset = mBlockPositions[BlockIndex];
                toread = (int)(mBlockPositions[BlockIndex + 1] - offset);
            }
            else
            {
                offset = (uint)(BlockIndex * mBlockSize);
                toread = ExpectedLength;
            }
            offset += mBlock.FilePos;

            byte[] data = new byte[toread];
            lock (mStream)
            {
                mStream.Seek(offset, SeekOrigin.Begin);
                mStream.Read(data, 0, toread);
            }

            if (mBlock.IsEncrypted && mBlock.FileSize > 3)
            {
                if (mSeed1 == 0)
                {
                    uint value0 = BitConverter.ToUInt32(data, 0);
                    uint value1 = BitConverter.ToUInt32(data, 4);
                    mSeed1 = MpqArchive.DetectFileSeed(value0, value1, 0x2fbfbbef, 0x3d3d3d2f); // .J unicode magic
                    if (mSeed1 == 0)
                    {
                        mSeed1 = MpqArchive.DetectFileSeed(value0, value1, 0x3d3d2f2f, 0x3d3d3d3d); // .J ascii
                        if (mSeed1 == 0)
                        {
                            mSeed1 = MpqArchive.DetectFileSeed(value0, value1, 0x46464952, mBlock.FileSize - 8); // RIFF
                            if (mSeed1 == 0) throw new MpqParserException("Unable to determine encryption key");
                        }
                    }
                }
                MpqArchive.DecryptBlock(data, (uint)(mSeed1 + BlockIndex));
            }

            if (mBlock.IsCompressed && data.Length != ExpectedLength)
            {
                if ((mBlock.Flags & MpqFileFlags.CompressedMulti) != 0)
                    data = DecompressMulti(data, ExpectedLength);
                else
                    data = PKDecompress(new MemoryStream(data), ExpectedLength);
            }

            return data;
        }
Example #3
0
        // Compressed files start with an array of offsets to make seeking possible
        private void LoadBlockPositions()
        {
            int blockposcount = (int)((_entry.FileSize + _blockSize - 1) / _blockSize) + 1;

            // Files with metadata have an extra block containing block checksums
            if ((_entry.Flags & MpqFileFlags.FileHasMetadata) != 0)
            {
                blockposcount++;
            }

            _blockPositions = new uint[blockposcount];

            lock (_stream)
            {
                _stream.Seek(_entry.FilePos, SeekOrigin.Begin);
                BinaryReader br = new BinaryReader(_stream);
                for (int i = 0; i < blockposcount; i++)
                {
                    _blockPositions[i] = br.ReadUInt32();
                }
            }

            uint blockpossize = (uint)blockposcount * 4;

            /*
             * if(_blockPositions[0] != blockpossize)
             *  _entry.Flags |= MpqFileFlags.Encrypted;
             */

            if (_entry.IsEncrypted)
            {
                if (_entry.EncryptionSeed == 0)  // This should only happen when the file name is not known
                {
                    _entry.EncryptionSeed = MpqArchive.DetectFileSeed(_blockPositions[0], _blockPositions[1], blockpossize) + 1;
                    if (_entry.EncryptionSeed == 1)
                    {
                        throw new MpqParserException("Unable to determine encyption seed");
                    }
                }

                MpqArchive.DecryptBlock(_blockPositions, _entry.EncryptionSeed - 1);

                if (_blockPositions[0] != blockpossize)
                {
                    throw new MpqParserException("Decryption failed");
                }
                if (_blockPositions[1] > _blockSize + blockpossize)
                {
                    throw new MpqParserException("Decryption failed");
                }
            }
        }