Beispiel #1
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>
        /// <exception cref="FileDeletedException">Thrown if the file is deleted in the archive.</exception>
        public byte[] ExtractFile(string filePath)
        {
            ThrowIfDisposed();

            // Reset all positions to be safe
            ArchiveReader.BaseStream.Position = 0;

            HashTableEntry fileHashEntry;

            try
            {
                fileHashEntry = ArchiveHashTable.FindEntry(filePath);
            }
            catch (FileNotFoundException fex)
            {
                throw new FileNotFoundException("No file found at the given path.", filePath, fex);
            }

            BlockTableEntry fileBlockEntry = ArchiveBlockTable.GetEntry((int)fileHashEntry.GetBlockEntryIndex());

            // Drop out if the file has been deleted
            if (fileBlockEntry.IsDeleted())
            {
                throw new FileDeletedException("The given file is deleted.", filePath);
            }

            // Seek to the beginning of the file's sectors
            long adjustedBlockOffset;

            if (Header.GetFormat() >= MPQFormat.ExtendedV1 && RequiresExtendedFormat())
            {
                ushort upperOffsetBits = ExtendedBlockTable[(int)fileHashEntry.GetBlockEntryIndex()];
                adjustedBlockOffset = (long)fileBlockEntry.GetExtendedBlockOffset(upperOffsetBits);
            }
            else
            {
                adjustedBlockOffset = fileBlockEntry.GetBlockOffset();
            }
            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));
        }
Beispiel #2
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));
        }
Beispiel #3
0
        public bool TryExtractFile(string filePath, out byte[] data)
        {
            ThrowIfDisposed();

            data = null;

            // Reset all positions to be safe
            _archiveReader.BaseStream.Position = 0;

            if (!ArchiveHashTable.TryFindEntry(filePath, out var fileHashEntry))
            {
                return(false);
            }

            var fileBlockEntry = ArchiveBlockTable.GetEntry((int)fileHashEntry.GetBlockEntryIndex());

            // Drop out if the file has been deleted
            if (fileBlockEntry.IsDeleted())
            {
                return(false);
            }

            // Seek to the beginning of the file's sectors
            long adjustedBlockOffset;

            if (Header.GetFormat() == MPQFormat.ExtendedV1 && RequiresExtendedFormat())
            {
                var upperOffsetBits = ExtendedBlockTable[(int)fileHashEntry.GetBlockEntryIndex()];
                adjustedBlockOffset = (long)fileBlockEntry.GetExtendedBlockOffset(upperOffsetBits);
            }
            else
            {
                adjustedBlockOffset = fileBlockEntry.GetBlockOffset();
            }

            _archiveReader.BaseStream.Position = adjustedBlockOffset;

            // Calculate the decryption key if necessary
            var fileKey = MPQCrypt.CreateFileEncryptionKey
                          (
                filePath,
                fileBlockEntry.ShouldEncryptionKeyBeAdjusted(),
                adjustedBlockOffset,
                fileBlockEntry.GetFileSize()
                          );

            // Examine the file storage types and extract as necessary
            if (fileBlockEntry.IsSingleUnit())
            {
                data = ExtractSingleUnitFile(fileBlockEntry, fileKey);
                return(true);
            }

            if (fileBlockEntry.IsCompressed())
            {
                data = ExtractCompressedSectoredFile(fileBlockEntry, fileKey, adjustedBlockOffset);
                return(true);
            }

            data = ExtractUncompressedSectoredFile(fileBlockEntry, fileKey);
            return(true);
        }