/// <summary> /// Initializes a new instance of the <see cref="MpqHeroesArchive"/> class. /// </summary> /// <param name="stream">The stream containing the archive to be read.</param> /// <exception cref="ArgumentNullException" /> internal MpqHeroesArchive(Stream stream) { _archiveStream = stream ?? throw new ArgumentNullException(nameof(stream)); Span <byte> headerBuffer = stackalloc byte[2048]; // guess how much the header will be stream.Read(headerBuffer); BitReader bitReader = new BitReader(headerBuffer, EndianType.LittleEndian); _mpqHeader = new MpqHeader(ref bitReader); if (_mpqHeader.HashTableOffsetHigh != 0 || _mpqHeader.ExtendedBlockTableOffset != 0 || _mpqHeader.BlockTableOffsetHigh != 0) { throw new MpqHeroesToolException("MPQ format version 1 features are not supported"); } _blockSize = 0x200 << _mpqHeader.BlockSize; // LoadHashTable Span <byte> hashBuffer = stackalloc byte[(int)(_mpqHeader.HashTableSize * MpqHash.Size)]; // get the hash table buffer stream.Position = (int)_mpqHeader.HashTablePos; stream.Read(hashBuffer); DecryptTable(hashBuffer, "(hash table)"); _mpqHashes = new MpqHash[_mpqHeader.HashTableSize]; BitReader mpqHashesBitReader = new BitReader(hashBuffer, EndianType.LittleEndian); for (int i = 0; i < _mpqHeader.HashTableSize; i++) { _mpqHashes[i] = new MpqHash(ref mpqHashesBitReader); } // LoadEntryTable; Span <byte> entryBuffer = stackalloc byte[(int)(_mpqHeader.BlockTableSize * MpqHeroesArchiveEntry.Size)]; // get the entry table buffer stream.Position = (int)_mpqHeader.BlockTablePos; stream.Read(entryBuffer); DecryptTable(entryBuffer, "(block table)"); _mpqArchiveEntries = new MpqHeroesArchiveEntry[_mpqHeader.BlockTableSize]; BitReader mpqArchivesEntryBitReader = new BitReader(entryBuffer, EndianType.LittleEndian); for (int i = 0; i < _mpqHeader.BlockTableSize; i++) { _mpqArchiveEntries[i] = new MpqHeroesArchiveEntry(ref mpqArchivesEntryBitReader, (uint)_mpqHeader.HeaderOffset); } }
private void ParseReplayServerBattlelobby(StormReplay stormReplay, ArrayPool <byte> pool) { MpqHeroesArchiveEntry entry = _stormMpqArchive.GetEntry(ReplayServerBattlelobby.FileName); int size = (int)entry.FileSize; byte[] poolBuffer = pool.Rent(size); Span <byte> buffer = new Span <byte>(poolBuffer).Slice(0, size); _stormMpqArchive.DecompressEntry(entry, buffer); ReplayServerBattlelobby.Parse(stormReplay, buffer); pool.Return(poolBuffer); }
public MpqHeroesArchiveEntry GetEntry(string fileName) { if (!TryGetHashEntry(fileName, out MpqHash hash)) { throw new FileNotFoundException("File not found: " + fileName); } MpqHeroesArchiveEntry entry = _mpqArchiveEntries[hash.BlockIndex]; if (entry.FileName == null) { entry.FileName = fileName; } return(entry); }
public bool AddListfileFileNames() { if (!AddFileName("(listfile)")) { return(false); } MpqHeroesArchiveEntry entry = GetEntry("(listfile)"); Span <byte> buffer = stackalloc byte[(int)entry.FileSize]; DecompressEntry(entry, buffer); AddFileNames(buffer); return(true); }
public ReadOnlySpan <byte> OpenFile(string filename) { if (!TryGetHashEntry(filename, out MpqHash hash)) { throw new FileNotFoundException("File not found: " + filename); } MpqHeroesArchiveEntry entry = _mpqArchiveEntries[hash.BlockIndex]; if (entry.FileName == null) { entry.FileName = filename; } Span <byte> buffer = new byte[(int)entry.FileSize]; DecompressEntry(entry, buffer); return(buffer); }