private void Init() { if (LocateMpqHeader() == false) { throw new MpqParserException("Unable to find MPQ header"); } if (_mpqHeader.HashTableOffsetHigh != 0 || _mpqHeader.ExtendedBlockTableOffset != 0 || _mpqHeader.BlockTableOffsetHigh != 0) { throw new MpqParserException("MPQ format version 1 features are not supported"); } var reader = new BinaryReader(BaseStream); _blockSize = 0x200 << _mpqHeader.BlockSize; // Load hash table BaseStream.Seek(_mpqHeader.HashTablePos, SeekOrigin.Begin); _hashTable = new HashTable(reader, _mpqHeader.HashTableSize); // Load entry table BaseStream.Seek(_mpqHeader.BlockTablePos, SeekOrigin.Begin); _blockTable = new BlockTable(reader, _mpqHeader.BlockTableSize, (uint)_headerOffset); }
private void Build(ICollection <MpqFile> mpqFiles, ushort?hashTableSize, ushort blockSize) { _blockSize = 0x200 << blockSize; var fileCount = (uint)mpqFiles.Count; _hashTable = new HashTable(Math.Max(hashTableSize ?? fileCount * 8, fileCount)); _blockTable = new BlockTable(fileCount); using (var writer = new BinaryWriter(BaseStream, new UTF8Encoding(false, true), true)) { // Skip the MPQ header, since its contents will be calculated afterwards. writer.Seek((int)MpqHeader.Size, SeekOrigin.Current); const bool archiveBeforeTables = true; uint hashTableEntries = 0; // Write Archive var fileIndex = (uint)0; var fileOffset = archiveBeforeTables ? MpqHeader.Size : throw new NotImplementedException(); var filePos = fileOffset; // TODO: add support for encryption of the archive files foreach (var mpqFile in mpqFiles) { uint locale = 0; mpqFile.AddToArchive((uint)_headerOffset, fileIndex, filePos, locale, _hashTable.Mask); if (archiveBeforeTables) { mpqFile.WriteToStream(writer); } hashTableEntries += _hashTable.Add(mpqFile.MpqHash, mpqFile.HashIndex, mpqFile.HashCollisions); _blockTable.Add(mpqFile.MpqEntry); filePos += mpqFile.MpqEntry.CompressedSize; fileIndex++; } // Match size of blocktable with amount of occupied entries in hashtable /* * for ( var i = blockTable.Size; i < hashTableEntries; i++ ) * { * var entry = MpqEntry.Dummy; * entry.SetPos( filePos ); * blockTable.Add( entry ); * } * blockTable.UpdateSize(); */ _hashTable.WriteToStream(writer); _blockTable.WriteToStream(writer); if (!archiveBeforeTables) { foreach (var mpqFile in mpqFiles) { mpqFile.WriteToStream(writer); } } writer.Seek((int)_headerOffset, SeekOrigin.Begin); _mpqHeader = new MpqHeader(filePos - fileOffset, _hashTable.Size, _blockTable.Size, blockSize, archiveBeforeTables); _mpqHeader.WriteToStream(writer); } }