示例#1
0
        /// <summary>
        /// Don't forget to wrap semaphore.
        /// </summary>
        /// <param name="entry"></param>
        /// <param name="destStream"></param>
        private void ExtractToStreamInternal(BA2GeneralFileEntry entry, Stream destStream)
        {
            // DeflateStream throws exception when
            // reads zlib compressed file header
            const int zlibHeaderLength = 2;

            // offset to file data
            UInt64 dataOffset = entry.IsCompressed() ? entry.Offset + zlibHeaderLength : entry.Offset;

            m_archiveStream.Seek((long)dataOffset, SeekOrigin.Begin);

            byte[] rawData = new byte[entry.UnpackedLength];

            if (entry.IsCompressed())
            {
                using (var uncompressStream = new DeflateStream(m_archiveStream, CompressionMode.Decompress, leaveOpen: true))
                {
                    var bytesReaden = uncompressStream.Read(rawData, 0, (int)entry.UnpackedLength);
                }
            }
            else
            {
                // TODO
                // entry.UnpackedLength => dataLength;
                m_archiveStream.Read(rawData, 0, (int)entry.UnpackedLength);
            }

            destStream.Write(rawData, 0, rawData.Length);
            destStream.Flush();

            destStream.Seek(0, SeekOrigin.Begin);
        }
示例#2
0
        /// <summary>
        /// Extract single file to specified directory by index.
        /// </summary>
        /// <param name="index">The index.</param>
        /// <param name="destination">Absolute or relative directory path where extracted file will be placed.</param>
        /// <param name="overwriteFile">Overwrite existing file in directory with extracted one?</param>
        /// <exception cref="IndexOutOfRangeException">
        /// <c>index</c> is less than 0 or more than total files in archive.
        /// </exception>
        /// <exception cref="ArgumentNullException" />
        /// <exception cref="BA2ExtractionException"></exception>
        public override void Extract(int index, string destination, bool overwriteFile)
        {
            CheckDisposed();
            if (index < 0 || index > this.TotalFiles)
            {
                throw new IndexOutOfRangeException(nameof(index));
            }
            if (destination == null)
            {
                throw new ArgumentNullException(nameof(destination));
            }

            BA2GeneralFileEntry entry = fileEntries[index];
            string extractPath        = CreateDirectoryAndGetPath(entry, destination, overwriteFile);

            using (var stream = File.Create(extractPath, 4096, FileOptions.SequentialScan))
            {
                try
                {
                    accessSemaphore.Wait();
                    ExtractToStreamInternal(entry, stream);
                }
                finally
                {
                    accessSemaphore.Release();
                }
            }
        }
示例#3
0
        private void ExtractFilesInternal(BA2GeneralFileEntry[] entries, string destination, CancellationToken cancellationToken,
                                          IProgress <int> progress, bool overwriteFiles)
        {
            try
            {
                accessSemaphore.Wait(cancellationToken);

                if (string.IsNullOrWhiteSpace(destination))
                {
                    throw new ArgumentException(nameof(destination));
                }

                int totalEntries = entries.Count();

                bool shouldUpdate = cancellationToken != null || progress != null;

                int counter         = 0;
                int updateFrequency = Math.Max(1, totalEntries / 100);
                int nextUpdate      = updateFrequency;

                BlockingCollection <string> readyFilenames = new BlockingCollection <string>(totalEntries);

                Action createDirs = () =>
                                    CreateDirectoriesForFiles(entries, readyFilenames, cancellationToken, destination, overwriteFiles);

                if (IsMultithreaded)
                {
                    Task.Run(createDirs, cancellationToken);
                }
                else
                {
                    createDirs();
                }

                for (int i = 0; i < totalEntries; i++)
                {
                    BA2GeneralFileEntry entry = entries[i];
                    using (var stream = File.Create(readyFilenames.Take(), 4096, FileOptions.SequentialScan))
                    {
                        ExtractToStreamInternal(entry, stream);
                    }

                    counter++;
                    if (shouldUpdate && counter >= nextUpdate)
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                        progress?.Report(counter);
                        nextUpdate += updateFrequency;
                    }
                }
            }
            finally
            {
                accessSemaphore.Release();
            }
        }
示例#4
0
        private BA2GeneralFileEntry[] ConstructEntriesFromIndexes(IEnumerable <int> indexes)
        {
            BA2GeneralFileEntry[] entries = new BA2GeneralFileEntry[indexes.Count()];
            int i = 0;

            foreach (int index in indexes)
            {
                // TODO throw new IndexOutOfRange
                entries[i] = fileEntries[index];
                i++;
            }

            return(entries);
        }
示例#5
0
        /// <summary>
        /// Preloads the data.
        /// </summary>
        /// <remarks>
        /// Do not call base.PreloadData().
        /// </remarks>
        /// <param name="reader">The reader.</param>
        internal override void PreloadData(BinaryReader reader)
        {
            CheckDisposed();

            try
            {
                accessSemaphore.Wait();

                this.BuildFileList();

                m_archiveStream.Seek(BA2Loader.HeaderSize, SeekOrigin.Begin);
                fileEntries = new BA2GeneralFileEntry[TotalFiles];

                for (int i = 0; i < TotalFiles; i++)
                {
                    BA2GeneralFileEntry entry = new BA2GeneralFileEntry()
                    {
                        Unknown0       = reader.ReadUInt32(),
                        Extension      = Encoding.ASCII.GetChars(reader.ReadBytes(4)),
                        Unknown1       = reader.ReadUInt32(),
                        Unknown2       = reader.ReadUInt32(),
                        Offset         = reader.ReadUInt64(),
                        PackedLength   = reader.ReadUInt32(),
                        UnpackedLength = reader.ReadUInt32(),
                        Unknown3       = reader.ReadUInt32(),
                        Index          = i
                    };

                    // 3131961357 = 0xBAADF00D as uint little-endian (0x0DF0ADBA)
                    // System.Diagnostics.Debug.Assert(entry.Unknown3 == 3131961357);

                    fileEntries[i] = entry;
                }
            }
            finally
            {
                accessSemaphore.Release();
            }
        }