/// <summary> /// Initializes a new instance of the <see cref="Warcraft.MPQ.MPQ"/> class. /// This constructor creates an empty archive. /// </summary> /// <param name="inFormat">In format.</param> public MPQ(MPQFormat inFormat) { if (inFormat > MPQFormat.ExtendedV1) { throw new NotImplementedException(); } this.Header = new MPQHeader(inFormat); this.ArchiveHashTable = new HashTable(); this.ArchiveBlockTable = new BlockTable(); }
/// <summary> /// Initializes a new instance of the <see cref="Warcraft.MPQ.MPQ"/> class. /// </summary> /// <param name="mpqStream">An open stream to data containing an MPQ archive.</param> public MPQ([NotNull] Stream mpqStream) { _archiveReader = new BinaryReader(mpqStream); Header = new MPQHeader(_archiveReader.ReadBytes((int)PeekHeaderSize())); // Seek to the hash table and load it _archiveReader.BaseStream.Position = (long)Header.GetHashTableOffset(); var encryptedHashTable = _archiveReader.ReadBytes((int)Header.GetHashTableSize()); var hashTableData = MPQCrypt.DecryptData(encryptedHashTable, HashTable.TableKey); ArchiveHashTable = new HashTable(hashTableData); // Seek to the block table and load it _archiveReader.BaseStream.Position = (long)Header.GetBlockTableOffset(); var encryptedBlockTable = _archiveReader.ReadBytes((int)Header.GetBlockTableSize()); var blockTableData = MPQCrypt.DecryptData(encryptedBlockTable, BlockTable.TableKey); ArchiveBlockTable = new BlockTable(blockTableData); if (Header.GetFormat() != MPQFormat.ExtendedV1) { return; } // Seek to the extended block table and load it, if necessary if (Header.GetExtendedBlockTableOffset() <= 0) { return; } _archiveReader.BaseStream.Position = (long)Header.GetExtendedBlockTableOffset(); var extendedTable = new List <ushort>(); for (var i = 0; i < Header.GetBlockTableEntryCount(); ++i) { extendedTable.Add(_archiveReader.ReadUInt16()); } ExtendedBlockTable = extendedTable; }
/// <summary> /// Releases all resource used by the <see cref="Warcraft.MPQ.MPQ"/> object. /// </summary> /// <remarks>Call <see cref="Dispose"/> when you are finished using the <see cref="Warcraft.MPQ.MPQ"/>. The <see cref="Dispose"/> /// method leaves the <see cref="Warcraft.MPQ.MPQ"/> in an unusable state. After calling <see cref="Dispose"/>, you must /// release all references to the <see cref="Warcraft.MPQ.MPQ"/> so the garbage collector can reclaim the memory that /// the <see cref="Warcraft.MPQ.MPQ"/> was occupying.</remarks> public void Dispose() { this.Header = null; this.ArchiveHashTable = null; this.ArchiveBlockTable = null; if (this.ExtendedBlockTable.Count > 0) { this.ExtendedBlockTable.Clear(); } if (this.ExternalListfile.Count > 0) { this.ExternalListfile.Clear(); } if (this.ArchiveReader != null) { this.ArchiveReader.Close(); this.ArchiveReader.Dispose(); } this.IsDisposed = true; }
/// <inheritdoc /> public void Dispose() { Header = null; ArchiveHashTable = null; ArchiveBlockTable = null; if (ExtendedBlockTable.Count > 0) { ExtendedBlockTable.Clear(); } if (ExternalListfile.Count > 0) { ExternalListfile.Clear(); } if (ArchiveReader != null) { ArchiveReader.Close(); ArchiveReader.Dispose(); } IsDisposed = true; }
/// <summary> /// Initializes a new instance of the <see cref="Warcraft.MPQ.MPQ"/> class. /// </summary> /// <param name="mpqStream">An open stream to data containing an MPQ archive.</param> public MPQ(Stream mpqStream) { this.ArchiveReader = new BinaryReader(mpqStream); this.Header = new MPQHeader(this.ArchiveReader.ReadBytes((int)PeekHeaderSize())); // Seek to the hash table and load it this.ArchiveReader.BaseStream.Position = (long)this.Header.GetHashTableOffset(); byte[] hashTableData; if (this.Header.IsHashTableCompressed()) { byte[] encryptedData = this.ArchiveReader.ReadBytes((int)this.Header.GetCompressedHashTableSize()); byte[] decryptedData = MPQCrypt.DecryptData(encryptedData, HashTable.TableKey); BlockFlags tableFlags = BlockFlags.IsCompressedMultiple; hashTableData = Compression.DecompressSector(decryptedData, tableFlags); } else { byte[] encryptedData = this.ArchiveReader.ReadBytes((int)this.Header.GetHashTableSize()); hashTableData = MPQCrypt.DecryptData(encryptedData, HashTable.TableKey); } this.ArchiveHashTable = new HashTable(hashTableData); // Seek to the block table and load it this.ArchiveReader.BaseStream.Position = (long)this.Header.GetBlockTableOffset(); byte[] blockTableData; if (this.Header.IsBlockTableCompressed()) { byte[] encryptedData = this.ArchiveReader.ReadBytes((int)this.Header.GetCompressedBlockTableSize()); byte[] decryptedData = MPQCrypt.DecryptData(encryptedData, BlockTable.TableKey); BlockFlags tableFlags = BlockFlags.IsCompressedMultiple; blockTableData = Compression.DecompressSector(decryptedData, tableFlags); } else { byte[] encryptedData = this.ArchiveReader.ReadBytes((int)this.Header.GetBlockTableSize()); blockTableData = MPQCrypt.DecryptData(encryptedData, BlockTable.TableKey); } this.ArchiveBlockTable = new BlockTable(blockTableData); // TODO: Seek to the extended hash table and load it // TODO: Seek to the extended block table and load it if (this.Header.GetFormat() >= MPQFormat.ExtendedV1) { // Seek to the extended block table and load it, if neccesary if (this.Header.GetExtendedBlockTableOffset() > 0) { this.ArchiveReader.BaseStream.Position = (long)this.Header.GetExtendedBlockTableOffset(); for (int i = 0; i < this.Header.GetBlockTableEntryCount(); ++i) { this.ExtendedBlockTable.Add(this.ArchiveReader.ReadUInt16()); } } } }