Пример #1
0
        public void TestRecreatePKCompressed()
        {
            const string inputArchivePath = @"TestArchives\PKCompressed.w3x";

            using var inputArchive     = MpqArchive.Open(inputArchivePath);
            using var recreatedArchive = MpqArchive.Create(
                      (Stream?)null,
                      inputArchive.GetMpqFiles().ToArray(),
                      (ushort)inputArchive.Header.HashTableSize,
                      inputArchive.Header.BlockSize);

            for (var i = 0; i < inputArchive.Header.BlockTableSize; i++)
            {
                inputArchive.BaseStream.Position     = inputArchive[i].FilePosition;
                recreatedArchive.BaseStream.Position = recreatedArchive[i].FilePosition;

                var size1 = inputArchive[i].CompressedSize;
                var size2 = recreatedArchive[i].CompressedSize;
                StreamAssert.AreEqual(inputArchive.BaseStream, recreatedArchive.BaseStream, size1 > size2 ? size1 : size2);
            }

            inputArchive.BaseStream.Position     = 0;
            recreatedArchive.BaseStream.Position = 0;
            StreamAssert.AreEqual(inputArchive.BaseStream, recreatedArchive.BaseStream, MpqHeader.Size);
        }
Пример #2
0
        public void TestWithPreArchiveData()
        {
            var memoryStream = new MemoryStream();
            var randomData   = new byte[999];

            randomData[100] = 99;
            memoryStream.Write(randomData, 0, randomData.Length);

            var randomFiles = new List <MpqFile>();

            for (var i = 0; i < 35; i++)
            {
                var fileStream = new MemoryStream();
                fileStream.Write(randomData, 0, randomData.Length);
                fileStream.Position = 0;
                randomFiles.Add(MpqFile.New(fileStream, $"file{i}"));
            }

            using var a = MpqArchive.Create(memoryStream, randomFiles, new MpqArchiveCreateOptions()
            {
                ListFileCreateMode = MpqFileCreateMode.None, AttributesCreateMode = MpqFileCreateMode.None
            });

            memoryStream.Position = 0;
            var archive = MpqArchive.Open(memoryStream);

            foreach (var file in archive.GetMpqFiles())
            {
                file.MpqStream.Seek(100, SeekOrigin.Begin);
                Assert.AreEqual(99, file.MpqStream.ReadByte());
            }

            archive.Dispose();
        }
Пример #3
0
        public void TestStoreCompressedThenRetrieveFile(string filename)
        {
            var fileStream = File.OpenRead(filename);
            var mpqFile    = new MpqFile(fileStream, filename, MpqFileFlags.Exists | MpqFileFlags.Compressed, BlockSize);
            var archive    = MpqArchive.Create(new MemoryStream(), new List <MpqFile>()
            {
                mpqFile
            });

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

            // Reload file, since the filestream gets disposed when the mpqfile is added to an mpqarchive.
            fileStream = File.OpenRead(filename);

            Assert.AreEqual(fileStream.Length, openedStream.Length);

            using (var fileStreamReader = new StreamReader(fileStream))
            {
                using (var openedStreamReader = new StreamReader(openedStream))
                {
                    StringAssert.Equals(fileStreamReader.ReadToEnd(), openedStreamReader.ReadToEnd());
                }
            }
        }
Пример #4
0
        public void TestWithPreArchiveDataAndNoFiles()
        {
            var memoryStream = new MemoryStream();
            var randomData   = new byte[999];

            memoryStream.Write(randomData, 0, randomData.Length);

            using var a = MpqArchive.Create(memoryStream, Array.Empty <MpqFile>(), new MpqArchiveCreateOptions());

            memoryStream.Position = 0;
            MpqArchive.Open(memoryStream).Dispose();
        }
Пример #5
0
        public void TestStoreThenRetrieveFile(string filename)
        {
            var fileStream = File.OpenRead(filename);
            var mpqFile    = MpqFile.New(fileStream, filename, true);
            var archive    = MpqArchive.Create(new MemoryStream(), new List <MpqFile>()
            {
                mpqFile
            });

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

            StreamAssert.AreEqual(fileStream, openedStream, true);
        }
Пример #6
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);
        }
Пример #7
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);
        }
Пример #8
0
        public void TestStoreThenRetrieveFile(string filename)
        {
            var fileStream = File.OpenRead(filename);
            // var mpqFile = new MpqKnownFile(filename, fileStream, MpqFileFlags.Exists, MpqLocale.Neutral, true);
            var mpqFile = MpqFile.New(fileStream, filename);
            var archive = MpqArchive.Create(new MemoryStream(), new List <MpqFile>()
            {
                mpqFile
            });

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

            fileStream.Position = 0;
            StreamAssert.AreEqual(fileStream, openedStream);
        }
Пример #9
0
        public void TestDeleteFile()
        {
            const string inputArchivePath = @".\TestArchives\NewLuaMap.w3m";
            const string fileName         = "war3map.lua";

            using var inputArchive = MpqArchive.Open(inputArchivePath);
            var newFile = MpqFile.New(null, fileName);

            var mpqFiles = inputArchive.GetMpqFiles();
            var oldFile  = mpqFiles.FirstOrDefault(file => file.IsSameAs(newFile)) ?? throw new FileNotFoundException($"File not found: {fileName}");
            var newFiles = mpqFiles.Select(file => ReferenceEquals(file, oldFile) ? newFile : file).ToArray();

            using var outputArchive = MpqArchive.Create((Stream?)null, newFiles, (ushort)inputArchive.Header.HashTableSize, inputArchive.Header.BlockSize);

            Assert.IsTrue(outputArchive.FileExists(fileName, out var entryIndex));
            Assert.AreEqual(0U, outputArchive[entryIndex].FileSize);
        }
Пример #10
0
        public void TestDeleteFile()
        {
            var          inputArchivePath = TestDataProvider.GetFile(@"Maps\NewLuaMap.w3m");
            const string fileName         = "war3map.lua";

            using var inputArchive = MpqArchive.Open(inputArchivePath);
            var newFile = MpqFile.New(null, fileName);

            var mpqFiles = inputArchive.GetMpqFiles();
            var oldFile  = mpqFiles.FirstOrDefault(file => file.Equals(newFile)) ?? throw new FileNotFoundException($"File not found: {fileName}");
            var newFiles = mpqFiles.Select(file => ReferenceEquals(file, oldFile) ? newFile : file).ToArray();

            using var outputArchive = MpqArchive.Create((Stream?)null, newFiles, new MpqArchiveCreateOptions { BlockSize = inputArchive.Header.BlockSize, HashTableSize = (ushort)inputArchive.Header.HashTableSize, AttributesFlags = AttributesFlags.DateTime | AttributesFlags.Crc32 });

            Assert.IsTrue(outputArchive.FileExists(fileName, out var entryIndex));
            Assert.AreEqual(0U, outputArchive[entryIndex].FileSize);
        }
Пример #11
0
        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);
        }
Пример #12
0
        public void TestRecreatePKCompressed()
        {
            var inputArchivePath = TestDataProvider.GetPath(@"Maps\PKCompressed.w3x");

            using var inputArchive     = MpqArchive.Open(inputArchivePath);
            using var recreatedArchive = MpqArchive.Create((Stream?)null, inputArchive.GetMpqFiles().ToArray(), new MpqArchiveCreateOptions { BlockSize = inputArchive.Header.BlockSize, HashTableSize = (ushort)inputArchive.Header.HashTableSize, ListFileCreateMode = MpqFileCreateMode.None, AttributesCreateMode = MpqFileCreateMode.None });

            for (var i = 0; i < inputArchive.Header.BlockTableSize; i++)
            {
                inputArchive.BaseStream.Position     = inputArchive[i].FilePosition;
                recreatedArchive.BaseStream.Position = recreatedArchive[i].FilePosition;

                // var size1 = inputArchive[i].CompressedSize;
                // var size2 = recreatedArchive[i].CompressedSize;
                // StreamAssert.AreEqual(inputArchive.BaseStream, recreatedArchive.BaseStream, size1 > size2 ? size1 : size2);
                StreamAssert.AreEqual(inputArchive.BaseStream, recreatedArchive.BaseStream);
            }

            inputArchive.BaseStream.Position     = 0;
            recreatedArchive.BaseStream.Position = 0;
            StreamAssert.AreEqual(inputArchive.BaseStream, recreatedArchive.BaseStream, MpqHeader.Size);
        }
Пример #13
0
        public void TestRecreateArchive(string inputArchivePath, bool loadListFile)
        {
            using var inputArchive = MpqArchive.Open(inputArchivePath, loadListFile);
            if (loadListFile && !inputArchive.FileExists(ListFile.FileName))
            {
                return;
            }

            var mpqFiles = inputArchive.GetMpqFiles().ToArray();

            using var recreatedArchive = MpqArchive.Create((Stream?)null, mpqFiles, new MpqArchiveCreateOptions { BlockSize = inputArchive.Header.BlockSize, ListFileCreateMode = MpqFileCreateMode.None, AttributesCreateMode = MpqFileCreateMode.None });

            // TODO: fix assumption that recreated archive's hashtable cannot be smaller than original
            // TODO: fix assumption of how recreated blocktable's entries are laid out relative to input mpqFiles array? (aka: replace the 'offset' variable)
            var offsetPerUnknownFile  = (recreatedArchive.HashTable.Size / inputArchive.HashTable.Size) - 1;
            var mpqEncryptedFileCount = mpqFiles.Where(mpqFile => mpqFile.IsFilePositionFixed).Count();
            var offset = mpqEncryptedFileCount * (offsetPerUnknownFile + 1);

            mpqEncryptedFileCount = 0;
            for (var index = 0; index < mpqFiles.Length; index++)
            {
                var      mpqFile = mpqFiles[index];
                MpqEntry?inputEntry;
                if (mpqFile is MpqKnownFile knownFile)
                {
                    inputEntry = inputArchive.GetMpqEntries(knownFile.FileName).FirstOrDefault();
                }
                else if (mpqFile is MpqUnknownFile unknownFile)
                {
                    inputArchive.TryGetEntryFromHashTable(mpqFile.HashIndex & inputArchive.HashTable.Mask, out inputEntry);
                }
                else if (mpqFile is MpqOrphanedFile orphanedFile)
                {
                    // TODO
                    throw new NotSupportedException("found orphaned mpqfile");
                }
                else
                {
                    throw new NotImplementedException();
                }

                var blockIndex = index + (int)offset;
                if (mpqFile.IsFilePositionFixed)
                {
                    blockIndex = mpqEncryptedFileCount * ((int)offsetPerUnknownFile + 1);
                    mpqEncryptedFileCount++;
                }

                var recreatedEntry = recreatedArchive[blockIndex];

                if (inputEntry is not null)
                {
                    if (!mpqFile.MpqStream.CanBeDecrypted)
                    {
                        // Check if both files have the same encryption seed.
                        Assert.IsTrue(!mpqFile.TargetFlags.HasFlag(MpqFileFlags.BlockOffsetAdjustedKey) || inputEntry.FileOffset == recreatedEntry.FileOffset);

                        inputArchive.BaseStream.Position     = inputEntry.FilePosition;
                        recreatedArchive.BaseStream.Position = recreatedEntry.FilePosition;

                        var size1 = inputEntry.CompressedSize;
                        var size2 = recreatedEntry.CompressedSize;
                        StreamAssert.AreEqual(inputArchive.BaseStream, recreatedArchive.BaseStream, size1 > size2 ? size1 : size2);
                    }
                    else
                    {
                        using var inputStream     = inputArchive.OpenFile(inputEntry);
                        using var recreatedStream = recreatedArchive.OpenFile(recreatedEntry);

                        StreamAssert.AreEqual(inputStream, recreatedStream, mpqFile is MpqKnownFile known ? known.FileName : "<unknown file>");
                    }
                }
                else
                {
                    Assert.IsFalse(recreatedEntry.Flags.HasFlag(MpqFileFlags.Exists));
                }

                if (mpqFile is MpqUnknownFile && !mpqFile.IsFilePositionFixed)
                {
                    offset += offsetPerUnknownFile;
                }
            }
        }