Beispiel #1
0
        public void CreateHeaderFromFile_ItemIsNotCompressed_ItemCreated()
        {
            var nefs   = TestArchiveNotModified.Create(@"C:\archive.nefs");
            var itemId = new NefsItemId(TestArchiveNotModified.File3ItemId);
            var item   = NefsItem.CreateFromHeader(itemId, nefs.Header, nefs.Items);

            // File3 is not compressed
            var expected = nefs.Items.GetItem(itemId);

            Assert.Equal(expected.CompressedSize, item.CompressedSize);
            Assert.Equal(expected.DirectoryId, item.DirectoryId);
            Assert.Equal(expected.ExtractedSize, item.ExtractedSize);
            Assert.Equal(expected.FileName, item.FileName);
            Assert.Equal(expected.Id, item.Id);
            Assert.Equal(expected.State, item.State);
            Assert.Equal(NefsItemType.File, item.Type);
            Assert.Equal(@"C:\archive.nefs", item.DataSource.FilePath);
            Assert.Equal(expected.DataSource.Offset, item.DataSource.Offset);
            Assert.False(item.DataSource.ShouldCompress);
            Assert.Single(item.DataSource.Size.ChunkSizes);
            Assert.Equal(expected.ExtractedSize, item.DataSource.Size.ChunkSizes[0]);
            Assert.Equal(expected.ExtractedSize, item.DataSource.Size.ExtractedSize);
            Assert.False(item.DataSource.Size.IsCompressed);
            Assert.Equal(expected.CompressedSize, item.DataSource.Size.Size);
        }
Beispiel #2
0
        public void NefsHeaderPart7_MultipleItems_EntriesPopulated()
        {
            var items = new NefsItemList(@"C:\archive.nefs");

            var file1Id     = new NefsItemId(31);
            var file1Chunks = NefsDataChunk.CreateChunkList(new List <UInt32> {
                11, 12, 13
            }, TestHelpers.TestTransform);
            var file1DataSource = new NefsItemListDataSource(items, 123, new NefsItemSize(456, file1Chunks));
            var file1           = TestHelpers.CreateFile(file1Id.Value, file1Id.Value, "file1", file1DataSource);

            items.Add(file1);

            var file2Id     = new NefsItemId(41);
            var file2Chunks = NefsDataChunk.CreateChunkList(new List <UInt32> {
                14, 15, 16
            }, TestHelpers.TestTransform);
            var file2DataSource = new NefsItemListDataSource(items, 456, new NefsItemSize(789, file2Chunks));
            var file2           = TestHelpers.CreateFile(file2Id.Value, file2Id.Value, "file2", file2DataSource);

            items.Add(file2);

            var dir2Id = new NefsItemId(51);
            var dir1   = TestHelpers.CreateDirectory(dir2Id.Value, dir2Id.Value, "dir1");

            items.Add(dir1);

            var p7 = new NefsHeaderPart7(items);

            Assert.Equal(3, p7.EntriesByIndex.Count);

            // NOTES : Part 7 items are ordered in the same way that part 2 items are ordered (depth
            // first by name).

            /*
             * dir1
             */

            Assert.Equal(51U, p7.EntriesByIndex[0].Id.Value);
            Assert.Equal(51U, p7.EntriesByIndex[0].SiblingId.Value);

            /*
             * file1
             */

            Assert.Equal(31U, p7.EntriesByIndex[1].Id.Value);
            Assert.Equal(41U, p7.EntriesByIndex[1].SiblingId.Value);

            /*
             * file2
             */

            Assert.Equal(41U, p7.EntriesByIndex[2].Id.Value);
            Assert.Equal(51U, p7.EntriesByIndex[2].SiblingId.Value);
        }
Beispiel #3
0
        public async Task CloseArchiveAsync_ArchiveModifiedAndUserSavesFail_ArchiveSavedAndClosed()
        {
            var w      = this.CreateWorkspace();
            var closed = false;

            w.ArchiveClosed += (o, e) => closed = true;

            // Open an archive
            var archivePath = @"C:\archive.nefs";
            var archive     = TestHelpers.CreateTestArchive(archivePath);

            this.nefsReaderMock.Setup(r => r.ReadArchiveAsync(It.IsAny <NefsArchiveSource>(), It.IsAny <NefsProgress>()))
            .ReturnsAsync(archive);
            this.fileSystem.AddFile(archivePath, new MockFileData("hi"));
            await w.OpenArchiveAsync(archivePath);

            Assert.Same(archive, w.Archive);
            Assert.False(w.ArchiveIsModified);

            // Modify archvie
            var itemId = new NefsItemId(0);
            var item   = w.Archive.Items.GetItems(itemId).First();
            var cmd    = new RemoveFileCommand(item, item.State);

            w.Execute(cmd);

            // Mock user choosing to save before closing
            this.MockMessageBox(DialogResult.Yes);

            // Mock the save to fail
            this.nefsWriterMock.Setup(n => n.WriteArchiveAsync(
                                          It.IsAny <string>(),
                                          It.IsAny <NefsArchive>(),
                                          It.IsAny <NefsProgress>()))
            .ThrowsAsync(new IOException());

            // Close the archive
            var result = await w.CloseArchiveAsync();

            Assert.False(result);
            Assert.False(closed);
            Assert.Same(archive, w.Archive);
            Assert.True(w.ArchiveIsModified);
            Assert.Equal(archivePath, w.ArchiveSource.DataFilePath);
            Assert.Equal(archivePath, w.ArchiveSource.HeaderFilePath);

            // Verify writer was called
            this.nefsWriterMock.Verify(
                n => n.WriteArchiveAsync(
                    It.IsAny <string>(),
                    It.IsAny <NefsArchive>(),
                    It.IsAny <NefsProgress>()), Times.Once());
        }
Beispiel #4
0
        public async Task CloseArchiveAsync_ArchiveModifiedAndUserDoesNotSave_ArchiveClosedWithoutSaving()
        {
            var w      = this.CreateWorkspace();
            var closed = false;

            w.ArchiveClosed += (o, e) => closed = true;

            // Open an archive
            var archivePath = @"C:\archive.nefs";
            var archive     = TestHelpers.CreateTestArchive(archivePath);

            this.nefsReaderMock.Setup(r => r.ReadArchiveAsync(It.IsAny <NefsArchiveSource>(), It.IsAny <NefsProgress>()))
            .ReturnsAsync(archive);
            this.fileSystem.AddFile(archivePath, new MockFileData("hi"));
            await w.OpenArchiveAsync(archivePath);

            Assert.Same(archive, w.Archive);
            Assert.False(w.ArchiveIsModified);

            // Modify archvie
            var itemId = new NefsItemId(0);
            var item   = w.Archive.Items.GetItems(itemId).First();
            var cmd    = new RemoveFileCommand(item, item.State);

            w.Execute(cmd);

            // Mock user choosing NOT to save before closing
            this.MockMessageBox(DialogResult.No);

            // Close the archive
            var result = await w.CloseArchiveAsync();

            Assert.True(result);
            Assert.True(closed);
            Assert.Null(w.Archive);
            Assert.False(w.ArchiveIsModified);
            Assert.Null(w.ArchiveSource);

            // Verify not saved
            this.nefsWriterMock.Verify(
                n => n.WriteArchiveAsync(
                    It.IsAny <string>(),
                    It.IsAny <NefsArchive>(),
                    It.IsAny <NefsProgress>()), Times.Never());
        }
Beispiel #5
0
        /// <summary>
        /// Reads header part 6 from an input stream.
        /// </summary>
        /// <param name="stream">The stream to read from.</param>
        /// <param name="offset">The offset to the header part from the beginning of the stream.</param>
        /// <param name="size">The size of the header part.</param>
        /// <param name="part2">
        /// Header part 2. This is used to lookup item ids since part 6 metadata does not store item ids.
        /// </param>
        /// <param name="p">Progress info.</param>
        /// <returns>The loaded header part.</returns>
        internal async Task <NefsHeaderPart6> ReadHeaderPart6Async(Stream stream, uint offset, uint size, NefsHeaderPart2 part2, NefsProgress p)
        {
            var entries = new List <NefsHeaderPart6Entry>();
            var ids     = new HashSet <NefsItemId>();

            // Validate inputs
            if (!this.ValidateHeaderPartStream(stream, offset, size, "6"))
            {
                return(new NefsHeaderPart6(entries));
            }

            // Get entries in part 6
            var numEntries  = size / NefsHeaderPart6Entry.Size;
            var entryOffset = offset;

            for (var i = 0; i < numEntries; ++i)
            {
                using (p.BeginTask(1.0f / numEntries))
                {
                    // Make sure there is a corresponding index in part 2
                    if (i >= part2.EntriesByIndex.Count)
                    {
                        Log.LogError($"Could not find matching item entry for part 6 index {i} in part 2.");
                        continue;
                    }

                    // Check for duplicate item ids
                    var id = new NefsItemId(part2.EntriesByIndex[i].Id.Value);
                    if (ids.Contains(id))
                    {
                        Log.LogError($"Found duplicate item id in part 6: {id.Value}");
                        continue;
                    }

                    var entry = new NefsHeaderPart6Entry(id);
                    await FileData.ReadDataAsync(stream, entryOffset, entry, p);

                    ids.Add(id);
                    entries.Add(entry);
                    entryOffset += NefsHeaderPart6Entry.Size;
                }
            }

            return(new NefsHeaderPart6(entries));
        }
Beispiel #6
0
        public async Task SaveArchiveAsync_SaveFailed_NotSaved()
        {
            var w     = this.CreateWorkspace();
            var saved = false;

            w.ArchiveSaved += (o, e) => saved = true;

            // Open an archive
            var archivePath = @"C:\archive.nefs";
            var archive     = TestHelpers.CreateTestArchive(archivePath);

            this.nefsReaderMock.Setup(r => r.ReadArchiveAsync(It.IsAny <NefsArchiveSource>(), It.IsAny <NefsProgress>()))
            .ReturnsAsync(archive);
            this.fileSystem.AddFile(archivePath, new MockFileData("hi"));
            await w.OpenArchiveAsync(archivePath);

            Assert.Same(archive, w.Archive);
            Assert.False(w.ArchiveIsModified);

            // Modify archvie
            var itemId = new NefsItemId(0);
            var item   = w.Archive.Items.GetItems(itemId).First();
            var cmd    = new RemoveFileCommand(item, item.State);

            w.Execute(cmd);

            // Mock save falied
            this.nefsWriterMock.Setup(n =>
                                      n.WriteArchiveAsync(
                                          It.IsAny <string>(),
                                          It.IsAny <NefsArchive>(),
                                          It.IsAny <NefsProgress>()))
            .ThrowsAsync(new IOException());

            // Save archive
            var result = await w.SaveArchiveAsync(archivePath);

            Assert.False(result);
            Assert.False(saved);
            Assert.Same(archive, w.Archive);
            Assert.True(w.ArchiveIsModified);
            Assert.Equal(archivePath, w.ArchiveSource.DataFilePath);
            Assert.Equal(archivePath, w.ArchiveSource.HeaderFilePath);
        }
Beispiel #7
0
        public async Task CloseArchiveAsync_ArchiveModifiedAndUserCancels_ArchiveNotClosed()
        {
            var w      = this.CreateWorkspace();
            var closed = false;

            w.ArchiveClosed += (o, e) => closed = true;

            // Open an archive
            var archivePath = @"C:\archive.nefs";
            var archive     = TestHelpers.CreateTestArchive(archivePath);

            this.nefsReaderMock.Setup(r => r.ReadArchiveAsync(It.IsAny <NefsArchiveSource>(), It.IsAny <NefsProgress>()))
            .ReturnsAsync(archive);
            this.fileSystem.AddFile(archivePath, new MockFileData("hi"));
            await w.OpenArchiveAsync(archivePath);

            Assert.Same(archive, w.Archive);
            Assert.False(w.ArchiveIsModified);

            // Modify archvie
            var itemId = new NefsItemId(0);
            var item   = w.Archive.Items.GetItems(itemId).First();
            var cmd    = new RemoveFileCommand(item, item.State);

            w.Execute(cmd);

            // Mock user cancelling the request to save before closing
            this.MockMessageBox(DialogResult.Cancel);

            // Close the archive
            var result = await w.CloseArchiveAsync();

            Assert.False(result);
            Assert.False(closed);
            Assert.Same(archive, w.Archive);
            Assert.True(w.ArchiveIsModified);
            Assert.Equal(archivePath, w.ArchiveSource.DataFilePath);
            Assert.Equal(archivePath, w.ArchiveSource.HeaderFilePath);
        }
Beispiel #8
0
        /// <summary>
        /// Reads header part 2 from an input stream.
        /// </summary>
        /// <param name="stream">The stream to read from.</param>
        /// <param name="offset">The offset to the header part from the beginning of the stream.</param>
        /// <param name="size">The size of the header part.</param>
        /// <param name="p">Progress info.</param>
        /// <returns>The loaded header part.</returns>
        internal async Task <NefsHeaderPart2> ReadHeaderPart2Async(Stream stream, uint offset, uint size, NefsProgress p)
        {
            var entries = new List <NefsHeaderPart2Entry>();
            var ids     = new HashSet <NefsItemId>();

            // Validate inputs
            if (!this.ValidateHeaderPartStream(stream, offset, size, "2"))
            {
                return(new NefsHeaderPart2(entries));
            }

            // Get entries in part 2
            var numEntries  = size / NefsHeaderPart2Entry.Size;
            var entryOffset = offset;

            for (var i = 0; i < numEntries; ++i)
            {
                using (p.BeginTask(1.0f / numEntries))
                {
                    var entry = new NefsHeaderPart2Entry();
                    await FileData.ReadDataAsync(stream, entryOffset, entry, p);

                    // Check for duplicate item ids
                    var id = new NefsItemId(entry.Id.Value);
                    if (ids.Contains(id))
                    {
                        Log.LogError($"Found duplicate item id in part 2: {id.Value}");
                        continue;
                    }

                    ids.Add(id);
                    entries.Add(entry);
                    entryOffset += NefsHeaderPart2Entry.Size;
                }
            }

            return(new NefsHeaderPart2(entries));
        }
Beispiel #9
0
        public void Clone_ItemCloned()
        {
            var nefs   = TestArchiveNotModified.Create(@"C:\archive.nefs");
            var itemId = new NefsItemId(TestArchiveNotModified.File3ItemId);
            var item   = NefsItem.CreateFromHeader(itemId, nefs.Header, nefs.Items);

            item.UpdateState(NefsItemState.Replaced);

            var clone = item.Clone() as NefsItem;

            Assert.Equal(item.CompressedSize, clone.CompressedSize);
            Assert.Same(item.DataSource, clone.DataSource);
            Assert.Equal(item.DirectoryId, clone.DirectoryId);
            Assert.Equal(item.ExtractedSize, clone.ExtractedSize);
            Assert.Equal(item.FileName, clone.FileName);
            Assert.Equal(item.Id, clone.Id);
            Assert.Equal(item.Part6Unknown0x00, clone.Part6Unknown0x00);
            Assert.Equal(item.Part6Unknown0x01, clone.Part6Unknown0x01);
            Assert.Equal(item.Part6Unknown0x02, clone.Part6Unknown0x02);
            Assert.Equal(item.Part6Unknown0x03, clone.Part6Unknown0x03);
            Assert.Equal(item.State, clone.State);
            Assert.Equal(item.Type, clone.Type);
        }
Beispiel #10
0
        private NefsItemList CreateItems(string dataFilePath, NefsHeader h)
        {
            var items    = new NefsItemList(dataFilePath);
            var numItems = h.TableOfContents.Part1Size / NefsHeaderPart1Entry.Size;

            for (var i = 0; i < numItems; ++i)
            {
                // Create the item
                var id = new NefsItemId((uint)i);

                try
                {
                    var item = NefsItem.CreateFromHeader(id, h, items);
                    items.Add(item);
                }
                catch (Exception)
                {
                    Log.LogError($"Failed to create item {id}, skipping.");
                }
            }

            return(items);
        }
Beispiel #11
0
        /// <summary>
        /// Gets the file name of an item.
        /// </summary>
        /// <param name="id">The item id.</param>
        /// <returns>The item's file name.</returns>
        public string GetItemFileName(NefsItemId id)
        {
            var offsetIntoPart3 = this.Part2.EntriesById[id].Data0x08_OffsetIntoPart3.Value;

            return(this.Part3.FileNamesByOffset[offsetIntoPart3]);
        }
Beispiel #12
0
 /// <summary>
 /// Gets the directory id for an item. If the item is in the root directory, the directory
 /// id will equal the item's id.
 /// </summary>
 /// <param name="id">The item id.</param>
 /// <returns>The directory id.</returns>
 public NefsItemId GetItemDirectoryId(NefsItemId id)
 {
     return(new NefsItemId(this.Part2.EntriesById[id].Data0x00_DirectoryId.Value));
 }
Beispiel #13
0
        public void NefsHeaderPart7_MultipleItems_EntriesPopulated()
        {
            var items = new NefsItemList(@"C:\archive.nefs");

            var file1Id         = new NefsItemId(31);
            var file1DataSource = new NefsItemListDataSource(items, 123, new NefsItemSize(456, new List <UInt32> {
                11, 12, 13
            }));
            var file1UnknownData = new NefsItemUnknownData
            {
                Part6Unknown0x00 = 1,
                Part6Unknown0x01 = 2,
                Part6Unknown0x02 = 3,
                Part6Unknown0x03 = 4,
            };

            var file1 = new NefsItem(file1Id, "file1", file1Id, NefsItemType.File, file1DataSource, file1UnknownData);

            items.Add(file1);

            var file2Id         = new NefsItemId(41);
            var file2DataSource = new NefsItemListDataSource(items, 456, new NefsItemSize(789, new List <UInt32> {
                14, 15, 16
            }));
            var file2UnknownData = new NefsItemUnknownData
            {
                Part6Unknown0x00 = 7,
                Part6Unknown0x01 = 8,
                Part6Unknown0x02 = 9,
                Part6Unknown0x03 = 10,
            };
            var file2 = new NefsItem(file2Id, "file2", file2Id, NefsItemType.File, file2DataSource, file2UnknownData);

            items.Add(file2);

            var dir2Id          = new NefsItemId(51);
            var dir1DataSource  = new NefsEmptyDataSource();
            var dir1UnknownData = new NefsItemUnknownData
            {
                Part6Unknown0x00 = 13,
                Part6Unknown0x01 = 14,
                Part6Unknown0x02 = 15,
                Part6Unknown0x03 = 16,
            };
            var dir1 = new NefsItem(dir2Id, "dir1", dir2Id, NefsItemType.Directory, dir1DataSource, dir1UnknownData);

            items.Add(dir1);

            var p7 = new NefsHeaderPart7(items);

            Assert.Equal(3, p7.EntriesById.Count);

            /*
             * file1
             */

            Assert.Equal(31U, p7.EntriesById[file1.Id].Id.Value);
            Assert.Equal(41U, p7.EntriesById[file1.Id].SiblingId.Value);

            /*
             * file2
             */

            Assert.Equal(41U, p7.EntriesById[file2.Id].Id.Value);
            Assert.Equal(51U, p7.EntriesById[file2.Id].SiblingId.Value);

            /*
             * dir1
             */

            Assert.Equal(51U, p7.EntriesById[dir1.Id].Id.Value);
            Assert.Equal(51U, p7.EntriesById[dir1.Id].SiblingId.Value);
        }
Beispiel #14
0
 /// <summary>
 /// Initializes a new instance of the <see cref="NefsHeaderPart4Entry"/> class.
 /// </summary>
 /// <param name="id">The id of the item this entry is for.</param>
 internal NefsHeaderPart4Entry(NefsItemId id)
 {
     this.Id = id;
 }
Beispiel #15
0
        /// <summary>
        /// Reads header part 4 from an input stream.
        /// </summary>
        /// <param name="stream">The stream to read from.</param>
        /// <param name="offset">The offset to the header part from the beginning of the stream.</param>
        /// <param name="size">The size of the header part.</param>
        /// <param name="part1">Header part 1.</param>
        /// <param name="part2">Header part 2.</param>
        /// <param name="p">Progress info.</param>
        /// <returns>The loaded header part.</returns>
        internal async Task <NefsHeaderPart4> ReadHeaderPart4Async(
            Stream stream,
            uint offset,
            uint size,
            NefsHeaderPart1 part1,
            NefsHeaderPart2 part2,
            NefsProgress p)
        {
            var entries = new Dictionary <uint, NefsHeaderPart4Entry>();

            // Validate inputs
            if (!this.ValidateHeaderPartStream(stream, offset, size, "4"))
            {
                return(new NefsHeaderPart4(entries));
            }

            // Get the chunk sizes for each item in the archive
            var numItems = part1.EntriesById.Count;

            for (var i = 0; i < numItems; ++i)
            {
                using (p.BeginTask(1.0f / numItems))
                {
                    var id = new NefsItemId((uint)i);

                    // Part 1 entry
                    if (!part1.EntriesById.ContainsKey(id))
                    {
                        Log.LogError($"Failed to find part 1 entry for item {id} when reading part 4.");
                        continue;
                    }

                    var p1 = part1.EntriesById[id];

                    // Part 2 entry
                    if (!part2.EntriesById.ContainsKey(id))
                    {
                        Log.LogError($"Failed to find part 2 entry for item {id} when reading part 4.");
                        continue;
                    }

                    var p2 = part2.EntriesById[id];

                    // Create part 4 entry
                    var entry = new NefsHeaderPart4Entry(id);

                    // Check if item has part 4 entry
                    if (p1.IndexIntoPart4 == 0xFFFFFFFF)
                    {
                        // Item is most likely not compressed or has no data
                        continue;
                    }

                    if (p2.Data0x0c_ExtractedSize.Value == 0)
                    {
                        // Item is probably a directory
                        continue;
                    }

                    // Get number of chunks
                    var numChunks = (int)Math.Ceiling(p2.Data0x0c_ExtractedSize.Value / (double)NefsHeader.ChunkSize);
                    if (numChunks == 0)
                    {
                        Log.LogError($"Item {p1.Id} contains no compressed chunks but was expected to.");
                        continue;
                    }

                    // Seek stream to start of chunk sizes for this item
                    var itemOffset = offset + p1.OffsetIntoPart4;
                    if ((long)itemOffset + NefsHeaderPart4.DataSize > stream.Length)
                    {
                        Log.LogError($"Item {p1.Id} has part 4 entry that is outside the bounds of header part 4.");
                        continue;
                    }

                    // Seek stream
                    stream.Seek((long)itemOffset, SeekOrigin.Begin);

                    // Process the chunk sizes
                    for (var chunkIdx = 0; chunkIdx < numChunks; ++chunkIdx)
                    {
                        var bytes = new byte[NefsHeaderPart4.DataSize];
                        await stream.ReadAsync(bytes, 0, NefsHeaderPart4.DataSize);

                        entry.ChunkSizes.Add(BitConverter.ToUInt32(bytes, 0));
                    }

                    // Record entry
                    entries.Add(p1.IndexIntoPart4, entry);
                }
            }

            // Return part 4
            return(new NefsHeaderPart4(entries));
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="NefsHeaderPart6Entry"/> class.
 /// </summary>
 /// <param name="id">The item id this entry is for.</param>
 public NefsHeaderPart6Entry(NefsItemId id)
 {
     this.Id = id;
 }