// 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 }
internal MpqStream(MpqArchive File, MpqBlock Block) { mBlock = Block; mStream = File.BaseStream; mBlockSize = File.BlockSize; if (mBlock.IsCompressed) LoadBlockPositions(); }
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; }
private byte[] LoadBlock(int blockIndex, int expectedLength) { uint offset; int toread; uint encryptionseed; if (_entry.IsCompressed) { offset = _blockPositions[blockIndex]; toread = (int)(_blockPositions[blockIndex + 1] - offset); } else { offset = (uint)(blockIndex * _blockSize); toread = expectedLength; } offset += _entry.FilePos; byte[] data = new byte[toread]; lock (_stream) { _stream.Seek(offset, SeekOrigin.Begin); int read = _stream.Read(data, 0, toread); if (read != toread) { throw new MpqParserException("Insufficient data or invalid data length"); } } if (_entry.IsEncrypted && _entry.FileSize > 3) { if (_entry.EncryptionSeed == 0) { throw new MpqParserException("Unable to determine encryption key"); } encryptionseed = (uint)(blockIndex + _entry.EncryptionSeed); MpqArchive.DecryptBlock(data, encryptionseed); } if (_entry.IsCompressed && (toread != expectedLength)) { if ((_entry.Flags & MpqFileFlags.CompressedMulti) != 0) { data = DecompressMulti(data, expectedLength); } else { data = PKDecompress(new MemoryStream(data), expectedLength); } } return(data); }
internal MpqStream(MpqArchive archive, MpqEntry entry) { _entry = entry; _stream = archive.BaseStream; _blockSize = archive.BlockSize; if (_entry.IsCompressed && !_entry.IsSingleUnit) { LoadBlockPositions(); } }
// 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"); } } }
private uint CalculateEncryptionSeed() { if (Filename == null) { return(0); } uint seed = MpqArchive.HashString(Path.GetFileName(Filename), 0x300); if ((Flags & MpqFileFlags.BlockOffsetAdjustedKey) == MpqFileFlags.BlockOffsetAdjustedKey) { seed = (seed + _fileOffset) ^ FileSize; } return(seed); }
public MpqArchiveReader(string path) { mpq = new MpqArchive(path); }