/// <summary> /// Gets the file info of the provided path. /// </summary> /// <returns>The file info, or null if the file doesn't exist in the archive.</returns> /// <param name="filePath">File path.</param> public MPQFileInfo GetFileInfo(string filePath) { if (this.IsDisposed) { throw new ObjectDisposedException(ToString(), "Cannot use a disposed archive."); } if (ContainsFile(filePath)) { HashTableEntry hashEntry = this.ArchiveHashTable.FindEntry(filePath); BlockTableEntry blockEntry = this.ArchiveBlockTable.GetEntry((int)hashEntry.GetBlockEntryIndex()); if (HasFileAttributes()) { return(new MPQFileInfo(filePath, hashEntry, blockEntry)); } else { return(new MPQFileInfo(filePath, hashEntry, blockEntry, this.FileAttributes.FileAttributes[(int)hashEntry.GetBlockEntryIndex()])); } } else { return(null); } }
/// <inheritdoc /> /// <exception cref="ObjectDisposedException">Thrown if the archive has been disposed.</exception> /// <exception cref="FileNotFoundException">Thrown if the archive does not contain a file at the given path.</exception> public MPQFileInfo GetFileInfo(string filePath) { ThrowIfDisposed(); if (!ContainsFile(filePath)) { throw new FileNotFoundException("The given file was not present in the archive.", filePath); } HashTableEntry hashEntry = ArchiveHashTable.FindEntry(filePath); BlockTableEntry blockEntry = ArchiveBlockTable.GetEntry((int)hashEntry.GetBlockEntryIndex()); if (HasFileAttributes()) { return(new MPQFileInfo(filePath, hashEntry, blockEntry)); } return(new MPQFileInfo(filePath, hashEntry, blockEntry, FileAttributes.FileAttributes[(int)hashEntry.GetBlockEntryIndex()])); }
// TODO: Filter files based on language and platform /// <summary> /// Extract the file at <paramref name="filePath"/> from the archive. /// </summary> /// <returns>The file as a byte array, or null if the file could not be found.</returns> /// <param name="filePath">Path to the file in the archive.</param> public byte[] ExtractFile(string filePath) { if (this.IsDisposed) { throw new ObjectDisposedException(ToString(), "Cannot use a disposed archive."); } // Reset all positions to be safe this.ArchiveReader.BaseStream.Position = 0; HashTableEntry fileHashEntry = this.ArchiveHashTable.FindEntry(filePath); if (fileHashEntry == null) { return(null); } BlockTableEntry fileBlockEntry = this.ArchiveBlockTable.GetEntry((int)fileHashEntry.GetBlockEntryIndex()); // Drop out if the file is not actually a file if (!fileBlockEntry.HasData()) { return(null); } // Seek to the beginning of the file's sectors long adjustedBlockOffset; if (this.Header.GetFormat() >= MPQFormat.ExtendedV1 && RequiresExtendedFormat()) { ushort upperOffsetBits = this.ExtendedBlockTable[(int)fileHashEntry.GetBlockEntryIndex()]; adjustedBlockOffset = (long)fileBlockEntry.GetExtendedBlockOffset(upperOffsetBits); } else { adjustedBlockOffset = fileBlockEntry.GetBlockOffset(); } this.ArchiveReader.BaseStream.Position = adjustedBlockOffset; // Calculate the decryption key if neccesary uint fileKey = MPQCrypt.CreateFileEncryptionKey ( filePath, fileBlockEntry.ShouldEncryptionKeyBeAdjusted(), adjustedBlockOffset, fileBlockEntry.GetFileSize() ); // Examine the file storage types and extract as neccesary if (fileBlockEntry.IsSingleUnit()) { return(ExtractSingleUnitFile(fileBlockEntry, fileKey)); } if (fileBlockEntry.IsCompressed()) { return(ExtractCompressedSectoredFile(fileBlockEntry, fileKey, adjustedBlockOffset)); } return(ExtractUncompressedSectoredFile(fileBlockEntry, fileKey)); }