コード例 #1
0
ファイル: MpqStructs.cs プロジェクト: KroneckerX/WCell
 public MpqBlock(BinaryReader br, uint HeaderOffset)
 {
     FilePos = br.ReadUInt32() + HeaderOffset;
     CompressedSize = br.ReadUInt32();
     FileSize = br.ReadUInt32();
     Flags = (MpqFileFlags)br.ReadUInt32();
 }
コード例 #2
0
 public MpqBlock(BinaryReader br, uint HeaderOffset)
 {
     FilePos        = br.ReadUInt32() + HeaderOffset;
     CompressedSize = br.ReadUInt32();
     FileSize       = br.ReadUInt32();
     Flags          = (MpqFileFlags)br.ReadUInt32();
 }
コード例 #3
0
ファイル: MpqEntry.cs プロジェクト: Drake53/MpqTool
        internal MpqEntry(string filename, uint compressedSize, uint fileSize, MpqFileFlags flags)
        {
            CompressedSize = compressedSize;
            FileSize       = fileSize;
            Flags          = flags;

            _filename = filename;
        }
コード例 #4
0
ファイル: MpqEntry.cs プロジェクト: Drake53/MpqTool
        internal MpqEntry(uint filePos, uint compressedSize, uint fileSize, MpqFileFlags flags)
        {
            FilePos        = filePos;
            CompressedSize = compressedSize;
            FileSize       = fileSize;
            Flags          = flags;

            IsAdded = true;
        }
コード例 #5
0
        internal MpqFile(ulong?hashedName, MpqStream mpqStream, MpqFileFlags flags, MpqLocale locale, bool leaveOpen)
        {
            _name          = hashedName;
            _mpqStream     = mpqStream ?? throw new ArgumentNullException(nameof(mpqStream));
            _isStreamOwner = !leaveOpen;

            _flags           = flags;
            _locale          = locale;
            _compressionType = MpqCompressionType.ZLib;
        }
コード例 #6
0
ファイル: MpqArchiveBuilder.cs プロジェクト: ihaiucom/War3Net
        public void AddFile(MpqFile file, MpqFileFlags targetFlags)
        {
            if (file is null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            file.TargetFlags = targetFlags;
            _modifiedFiles.Add(file);
        }
コード例 #7
0
ファイル: MpqEntry.cs プロジェクト: Drake53/MpqTool
        internal MpqEntry(uint filePos, uint headerOffset, uint compressedSize, uint fileSize, MpqFileFlags flags)
        {
            _fileOffset    = filePos - headerOffset;
            FilePos        = filePos;
            CompressedSize = compressedSize;
            FileSize       = fileSize;
            Flags          = flags;
            EncryptionSeed = 0;

            IsAdded = true;
        }
コード例 #8
0
ファイル: MpqBlockEntry.cs プロジェクト: sgraf812/crystalmpq
 internal MpqBlockEntry(long offset, uint compressedSize, uint uncompressedSize, uint flags, ref uint fileIndex)
 {
     this.Offset = offset;
     this.CompressedSize = compressedSize;
     this.UncompressedSize = uncompressedSize;
     this.Flags = unchecked((MpqFileFlags)flags);
     this.Name = "";
     this.FileIndex = (this.Flags & MpqFileFlags.Exists) != 0 ? fileIndex++ : 0;
     this.Seed = 0;
     this.Listed = false;
 }
コード例 #9
0
 internal MpqBlockEntry(long offset, uint compressedSize, uint uncompressedSize, uint flags, ref uint fileIndex)
 {
     this.Offset           = offset;
     this.CompressedSize   = compressedSize;
     this.UncompressedSize = uncompressedSize;
     this.Flags            = unchecked ((MpqFileFlags)flags);
     this.Name             = "";
     this.FileIndex        = (this.Flags & MpqFileFlags.Exists) != 0 ? fileIndex++ : 0;
     this.Seed             = 0;
     this.Listed           = false;
 }
コード例 #10
0
 private string CompressionTypeString(MpqFileFlags Flags)
 {
     if ((Flags & MpqFileFlags.CompressedMulti) != ((MpqFileFlags)0))
     {
         return("Multi");
     }
     if ((Flags & MpqFileFlags.CompressedPK) != ((MpqFileFlags)0))
     {
         return("PKZip");
     }
     return("");
 }
コード例 #11
0
ファイル: MpqFile.cs プロジェクト: TriggerEdge/War3Net
        private uint _hashIndex; // position in hashtable

        /// <summary>
        /// Initializes a new instance of the <see cref="MpqFile"/> class.
        /// </summary>
        /// <param name="sourceStream"></param>
        /// <param name="fileName"></param>
        /// <param name="flags"></param>
        /// <param name="blockSize"></param>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="sourceStream"/> argument is null.</exception>
        public MpqFile(Stream sourceStream, string fileName, MpqFileFlags flags, ushort blockSize)
        {
            _baseStream = sourceStream ?? throw new ArgumentNullException(nameof(sourceStream));
            _fileName   = fileName;

            _blockSize = 0x200 << blockSize;

            var fileSize       = (uint)_baseStream.Length;
            var compressedSize = ((flags & MpqFileFlags.Compressed) != 0) ? Compress() : fileSize;

            _entry = new MpqEntry(fileName, compressedSize, fileSize, flags);
        }
コード例 #12
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MpqEntry"/> class.
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="headerOffset">The containing <see cref="MpqArchive"/>'s header offset.</param>
        /// <param name="fileOffset">The file's position in the archive, relative to the header offset.</param>
        /// <param name="compressedSize">The compressed size of the file.</param>
        /// <param name="fileSize">The uncompressed size of the file.</param>
        /// <param name="flags">The file's <see cref="MpqFileFlags"/>.</param>
        internal MpqEntry(string?filename, uint headerOffset, uint fileOffset, uint compressedSize, uint fileSize, MpqFileFlags flags)
        {
            _headerOffset   = headerOffset;
            _fileOffset     = fileOffset;
            _filename       = filename;
            _compressedSize = compressedSize;
            _fileSize       = fileSize;
            _flags          = flags;

            if (filename != null)
            {
                UpdateEncryptionSeed();
            }
        }
コード例 #13
0
        public void TestStoreThenRetrieveEmptyFileWithFlags(MpqFileFlags flags)
        {
            const string FileName = "someRandomFile.empty";

            using var mpqFile   = MpqFile.New(null, FileName);
            mpqFile.TargetFlags = flags;
            using var archive   = MpqArchive.Create(new MemoryStream(), new List <MpqFile>()
            {
                mpqFile
            }, new MpqArchiveCreateOptions { BlockSize = BlockSize });

            using var openedArchive = MpqArchive.Open(archive.BaseStream);
            var openedStream = openedArchive.OpenFile(FileName);

            Assert.IsTrue(openedStream.Length == 0);
        }
コード例 #14
0
        public void TestStoreThenRetrieveFileWithFlags(string fileName, MpqFileFlags flags)
        {
            using var fileStream = File.OpenRead(fileName);
            var mpqFile = MpqFile.New(fileStream, fileName, true);

            mpqFile.TargetFlags = flags;
            using var archive   = MpqArchive.Create(new MemoryStream(), new List <MpqFile>()
            {
                mpqFile
            }, new MpqArchiveCreateOptions { BlockSize = BlockSize });

            using var openedArchive = MpqArchive.Open(archive.BaseStream);
            var openedStream = openedArchive.OpenFile(fileName);

            StreamAssert.AreEqual(fileStream, openedStream, true);
        }
コード例 #15
0
ファイル: MpqUnknownFile.cs プロジェクト: yungshing/War3Net
        /// <summary>
        /// Initializes a new instance of the <see cref="MpqUnknownFile"/> class.
        /// </summary>
        internal MpqUnknownFile(MpqStream mpqStream, MpqFileFlags flags, MpqHash mpqHash, uint hashIndex, uint hashCollisions, uint?encryptionSeed = null)
            : base(mpqHash.Name, mpqStream, flags, mpqHash.Locale, false)
        {
            if (mpqHash.Mask == 0)
            {
                throw new ArgumentException("Expected the Mask value of mpqHash argument to be set to a non-zero value.", nameof(mpqHash));
            }

            if (flags.HasFlag(MpqFileFlags.Encrypted) && encryptionSeed is null)
            {
                throw new ArgumentException($"Cannot encrypt an {nameof(MpqUnknownFile)} without an encryption seed.", nameof(flags));
            }

            _hashMask       = mpqHash.Mask;
            _hashIndex      = hashIndex;
            _hashCollisions = hashCollisions;
            _encryptionSeed = encryptionSeed;
        }
コード例 #16
0
ファイル: MpqArchiveTest.cs プロジェクト: pilgarlicx/War3Net
        public void TestStoreThenRetrieveEmptyFileWithFlags(MpqFileFlags flags)
        {
            const string FileName = "someRandomFile.empty";

            // var mpqFile = new MpqKnownFile(FileName, null, flags, MpqLocale.Neutral);
            var mpqFile = MpqFile.New(null, FileName);

            mpqFile.TargetFlags = flags;
            var archive = MpqArchive.Create(new MemoryStream(), new List <MpqFile>()
            {
                mpqFile
            }, blockSize: BlockSize);

            var openedArchive = MpqArchive.Open(archive.BaseStream);
            var openedStream  = openedArchive.OpenFile(FileName);

            Assert.IsTrue(openedStream.Length == 0);
        }
コード例 #17
0
ファイル: MpqArchiveTest.cs プロジェクト: pilgarlicx/War3Net
        public void TestStoreThenRetrieveFileWithFlags(string filename, MpqFileFlags flags)
        {
            var fileStream = File.OpenRead(filename);
            // var mpqFile = new MpqKnownFile(filename, fileStream, flags, MpqLocale.Neutral, true);
            var mpqFile = MpqFile.New(fileStream, filename);

            mpqFile.TargetFlags = flags;
            var archive = MpqArchive.Create(new MemoryStream(), new List <MpqFile>()
            {
                mpqFile
            }, blockSize: BlockSize);

            var openedArchive = MpqArchive.Open(archive.BaseStream);
            var openedStream  = openedArchive.OpenFile(filename);

            fileStream.Position = 0;
            StreamAssert.AreEqual(fileStream, openedStream);
        }
コード例 #18
0
ファイル: MpqFile.cs プロジェクト: TriggerEdge/War3Net
        /// <summary>
        /// Initializes a new instance of the <see cref="MpqFile"/> class, for which the filename is unknown.
        /// </summary>
        /// <param name="sourceStream"></param>
        /// <param name="mpqHash"></param>
        /// <param name="hashIndex"></param>
        /// <param name="hashCollisions"></param>
        /// <param name="flags"></param>
        /// <param name="blockSize"></param>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ArgumentNullException">Thrown when the <paramref name="sourceStream"/> argument is null.</exception>
        public MpqFile(Stream sourceStream, MpqHash mpqHash, uint hashIndex, uint hashCollisions, MpqFileFlags flags, ushort blockSize)
            : this(sourceStream, null, flags, blockSize)
        {
            if (mpqHash.Mask == 0)
            {
                throw new ArgumentException("Expected the Mask value of mpqHash argument to be set to a non-zero value.", nameof(mpqHash));
            }

            _hash           = mpqHash;
            _hashIndex      = hashIndex;
            _hashCollisions = hashCollisions;
        }
コード例 #19
0
ファイル: MpqStream.cs プロジェクト: yungshing/War3Net
        internal Stream Transform(MpqFileFlags targetFlags, MpqCompressionType compressionType, uint targetFilePosition, int targetBlockSize)
        {
            using var memoryStream = new MemoryStream();
            CopyTo(memoryStream);
            memoryStream.Position = 0;
            var fileSize = memoryStream.Length;

            using var compressedStream = GetCompressedStream(memoryStream, targetFlags, compressionType, targetBlockSize);
            var compressedSize = (uint)compressedStream.Length;

            var resultStream = new MemoryStream();

            var blockPosCount = (uint)(((int)fileSize + targetBlockSize - 1) / targetBlockSize) + 1;

            if (targetFlags.HasFlag(MpqFileFlags.Encrypted) && blockPosCount > 1)
            {
                var blockPositions = new int[blockPosCount];
                var singleUnit     = targetFlags.HasFlag(MpqFileFlags.SingleUnit);

                var hasBlockPositions = !singleUnit && ((targetFlags & MpqFileFlags.Compressed) != 0);
                if (hasBlockPositions)
                {
                    for (var blockIndex = 0; blockIndex < blockPosCount; blockIndex++)
                    {
                        using (var br = new BinaryReader(compressedStream, new UTF8Encoding(), true))
                        {
                            for (var i = 0; i < blockPosCount; i++)
                            {
                                blockPositions[i] = (int)br.ReadUInt32();
                            }
                        }

                        compressedStream.Seek(0, SeekOrigin.Begin);
                    }
                }
                else
                {
                    if (singleUnit)
                    {
                        blockPosCount = 2;
                    }

                    blockPositions[0] = 0;
                    for (var blockIndex = 2; blockIndex < blockPosCount; blockIndex++)
                    {
                        blockPositions[blockIndex - 1] = targetBlockSize * (blockIndex - 1);
                    }

                    blockPositions[blockPosCount - 1] = (int)compressedSize;
                }

                var encryptionSeed = _baseEncryptionSeed;
                if (targetFlags.HasFlag(MpqFileFlags.BlockOffsetAdjustedKey))
                {
                    encryptionSeed = MpqEntry.AdjustEncryptionSeed(encryptionSeed, targetFilePosition, (uint)fileSize);
                }

                var currentOffset = 0;
                using (var writer = new BinaryWriter(resultStream, new UTF8Encoding(false, true), true))
                {
                    for (var blockIndex = hasBlockPositions ? 0 : 1; blockIndex < blockPosCount; blockIndex++)
                    {
                        var toWrite = blockPositions[blockIndex] - currentOffset;

                        var data = StormBuffer.EncryptStream(compressedStream, (uint)(encryptionSeed + blockIndex - 1), currentOffset, toWrite);
                        writer.Write(data);

                        currentOffset += toWrite;
                    }
                }
            }
            else
            {
                compressedStream.CopyTo(resultStream);
            }

            resultStream.Position = 0;
            return(resultStream);
        }
コード例 #20
0
ファイル: MpqKnownFile.cs プロジェクト: yungshing/War3Net
 /// <summary>
 /// Initializes a new instance of the <see cref="MpqKnownFile"/> class.
 /// </summary>
 internal MpqKnownFile(string fileName, MpqStream mpqStream, MpqFileFlags flags, MpqLocale locale, bool leaveOpen = false)
     : base(MpqHash.GetHashedFileName(fileName), mpqStream, flags, locale, leaveOpen)
 {
     _fileName = fileName;
 }
コード例 #21
0
ファイル: MpqStream.cs プロジェクト: yungshing/War3Net
        private Stream GetCompressedStream(Stream baseStream, MpqFileFlags targetFlags, MpqCompressionType compressionType, int targetBlockSize)
        {
            var resultStream = new MemoryStream();
            var singleUnit   = targetFlags.HasFlag(MpqFileFlags.SingleUnit);

            void TryCompress(uint bytes)
            {
                var offset           = baseStream.Position;
                var compressedStream = compressionType switch
                {
                    MpqCompressionType.ZLib => ZLibCompression.Compress(baseStream, (int)bytes, true),

                    _ => throw new NotSupportedException(),
                };

                // Add one because CompressionType byte not written yet.
                var length = compressedStream.Length + 1;

                if (!singleUnit && length >= bytes)
                {
                    baseStream.CopyTo(resultStream, offset, (int)bytes, StreamExtensions.DefaultBufferSize);
                }
                else
                {
                    resultStream.WriteByte((byte)compressionType);
                    compressedStream.Position = 0;
                    compressedStream.CopyTo(resultStream);
                }

                compressedStream.Dispose();

                if (singleUnit)
                {
                    baseStream.Dispose();
                }
            }

            var length = (uint)baseStream.Length;

            if ((targetFlags & MpqFileFlags.Compressed) == 0)
            {
                baseStream.CopyTo(resultStream);
            }
            else if (singleUnit)
            {
                TryCompress(length);
            }
            else
            {
                var blockCount   = (uint)((length + targetBlockSize - 1) / targetBlockSize) + 1;
                var blockOffsets = new uint[blockCount];

                blockOffsets[0]       = 4 * blockCount;
                resultStream.Position = blockOffsets[0];

                for (var blockIndex = 1; blockIndex < blockCount; blockIndex++)
                {
                    var bytesToCompress = blockIndex + 1 == blockCount ? (uint)(baseStream.Length - baseStream.Position) : (uint)targetBlockSize;

                    TryCompress(bytesToCompress);
                    blockOffsets[blockIndex] = (uint)resultStream.Position;
                }

                resultStream.Position = 0;
                using (var writer = new BinaryWriter(resultStream, new System.Text.UTF8Encoding(false, true), true))
                {
                    for (var blockIndex = 0; blockIndex < blockCount; blockIndex++)
                    {
                        writer.Write(blockOffsets[blockIndex]);
                    }
                }
            }

            resultStream.Position = 0;
            return(resultStream);
        }
コード例 #22
0
ファイル: MpqOrphanedFile.cs プロジェクト: yungshing/War3Net
 public MpqOrphanedFile(MpqStream mpqStream, MpqFileFlags flags)
     : base(null, mpqStream, flags, MpqLocale.Neutral, false)
 {
 }
コード例 #23
0
        /// <summary>
        /// Initializes a new instance of the <see cref="MpqStream"/> class.
        /// </summary>
        /// <param name="entry">The file's entry in the <see cref="BlockTable"/>.</param>
        /// <param name="baseStream">The <see cref="MpqArchive"/>'s stream.</param>
        /// <param name="blockSize">The <see cref="MpqArchive.BlockSize"/>.</param>
        internal MpqStream(MpqEntry entry, Stream baseStream, int blockSize)
        {
            _mode          = MpqStreamMode.Read;
            _isStreamOwner = false;

            _filePosition   = entry.FilePosition;
            _fileSize       = entry.FileSize;
            _compressedSize = entry.CompressedSize;
            _flags          = entry.Flags;
            _isCompressed   = (_flags & MpqFileFlags.Compressed) != 0;
            _isEncrypted    = _flags.HasFlag(MpqFileFlags.Encrypted);
            _isSingleUnit   = _flags.HasFlag(MpqFileFlags.SingleUnit);

            _encryptionSeed     = entry.EncryptionSeed;
            _baseEncryptionSeed = entry.BaseEncryptionSeed;

            _stream    = baseStream;
            _blockSize = blockSize;

            if (_isSingleUnit)
            {
                // Read the entire file into memory
                var filedata = new byte[_compressedSize];
                lock (_stream)
                {
                    _stream.Seek(_filePosition, SeekOrigin.Begin);
                    var read = _stream.Read(filedata, 0, filedata.Length);
                    if (read != filedata.Length)
                    {
                        throw new MpqParserException("Insufficient data or invalid data length");
                    }
                }

                if (_isEncrypted && _fileSize > 3)
                {
                    if (_encryptionSeed == 0)
                    {
                        throw new MpqParserException("Unable to determine encryption key");
                    }

                    StormBuffer.DecryptBlock(filedata, _encryptionSeed);
                }

                _currentData = _flags.HasFlag(MpqFileFlags.CompressedMulti) && _compressedSize > 0
                    ? DecompressMulti(filedata, _fileSize)
                    : filedata;
            }
            else
            {
                _currentBlockIndex = -1;

                // Compressed files start with an array of offsets to make seeking possible
                if (_isCompressed)
                {
                    var blockposcount = (int)((_fileSize + _blockSize - 1) / _blockSize) + 1;

                    // Files with metadata have an extra block containing block checksums
                    if ((_flags & MpqFileFlags.FileHasMetadata) != 0)
                    {
                        blockposcount++;
                    }

                    _blockPositions = new uint[blockposcount];

                    lock (_stream)
                    {
                        _stream.Seek(_filePosition, SeekOrigin.Begin);
                        using (var br = new BinaryReader(_stream, new UTF8Encoding(), true))
                        {
                            for (var i = 0; i < blockposcount; i++)
                            {
                                _blockPositions[i] = br.ReadUInt32();
                            }
                        }
                    }

                    var blockpossize = (uint)blockposcount * 4;

                    /*
                     * if (_blockPositions[0] != blockpossize)
                     * {
                     *  // _entry.Flags |= MpqFileFlags.Encrypted;
                     *  throw new MpqParserException();
                     * }
                     */

                    if (_isEncrypted && blockposcount > 1)
                    {
                        var maxOffset1 = (uint)_blockSize + blockpossize;
                        if (_encryptionSeed == 0)
                        {
                            // This should only happen when the file name is not known.
                            if (!entry.TryUpdateEncryptionSeed(_blockPositions[0], _blockPositions[1], blockpossize, maxOffset1))
                            {
                                throw new MpqParserException("Unable to determine encyption seed");
                            }
                        }

                        _encryptionSeed     = entry.EncryptionSeed;
                        _baseEncryptionSeed = entry.BaseEncryptionSeed;
                        StormBuffer.DecryptBlock(_blockPositions, _encryptionSeed - 1);

                        if (_blockPositions[0] != blockpossize)
                        {
                            throw new MpqParserException($"Decryption failed{(string.IsNullOrEmpty(entry.FileName) ? string.Empty : $" for '{entry.FileName}'")} (block position 0).");
                        }

                        if (_blockPositions[1] > maxOffset1)
                        {
                            throw new MpqParserException($"Decryption failed{(string.IsNullOrEmpty(entry.FileName) ? string.Empty : $" for '{entry.FileName}'")} (block position 1).");
                        }
                    }
                }
コード例 #24
0
ファイル: App.cs プロジェクト: merfed/wow2collada
        /// <summary>
        /// Builds a compressions type string
        /// </summary>
        /// <param name="Flags">The flags.</param>
        /// <returns></returns>
        string CompressionTypeString(MpqFileFlags Flags)
        {
            if((Flags & MpqFileFlags.CompressedMulti) != 0)
                return "Multi";

            if((Flags & MpqFileFlags.CompressedPK) != 0)
                return "PKZip";

            return "";
        }