Example #1
0
        /// <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);
            }
        }
Example #2
0
        /// <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()]));
        }
Example #3
0
        // 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));
        }