/// <summary>
        /// Initializes a new instance of the <see cref="Nefs16HeaderPart4"/> class from a list of items.
        /// </summary>
        /// <param name="items">The items to initialize from.</param>
        internal Nefs16HeaderPart4(NefsItemList items)
        {
            this.entriesByIndex = new List <Nefs16HeaderPart4Entry>();
            this.indexLookup    = new Dictionary <Guid, uint>();

            var nextStartIdx = 0U;

            foreach (var item in items.EnumerateById())
            {
                if (item.Type == NefsItemType.Directory || item.DataSource.Size.Chunks.Count == 0)
                {
                    // Item does not have a part 4 entry
                    continue;
                }

                // Log this start index to item's Guid to allow lookup later
                this.indexLookup.Add(item.Guid, nextStartIdx);

                // Create entry for each data chunk
                foreach (var chunk in item.DataSource.Size.Chunks)
                {
                    // Create entry
                    var entry = new Nefs16HeaderPart4Entry();
                    entry.Data0x00_CumulativeBlockSize.Value = chunk.CumulativeSize;
                    entry.Data0x04_TransformType.Value       = (ushort)this.GetTransformType(chunk.Transform);
                    entry.Data0x06_Checksum.Value            = 0; // TODO
                    this.entriesByIndex.Add(entry);

                    nextStartIdx++;
                }
            }
        }
示例#2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NefsHeaderPart4"/> class from a list of items.
        /// </summary>
        /// <param name="items">The items to initialize from.</param>
        internal NefsHeaderPart4(NefsItemList items)
        {
            this.entriesByIndex = new SortedDictionary <UInt32, NefsHeaderPart4Entry>();
            this.indexById      = new Dictionary <NefsItemId, UInt32>();

            var nextIdx = 0;

            foreach (var item in items.EnumerateById())
            {
                if (!item.DataSource.Size.IsCompressed)
                {
                    // Item does not have a part 4 entry since it has no compressed data
                    continue;
                }

                // Create entry
                var entry = new NefsHeaderPart4Entry(item.Id);
                entry.ChunkSizes.AddRange(item.DataSource.Size.ChunkSizes);

                // Add to entries list and advance index
                this.entriesByIndex.Add((uint)nextIdx, entry);
                this.indexById.Add(item.Id, (uint)nextIdx);
                nextIdx += entry.ChunkSizes.Count;
            }

            // Compute size
            this.ComputeSize();
        }
示例#3
0
        public void NefsHeaderPart7_NoItems_EntriesEmpty()
        {
            var items = new NefsItemList(@"C:\archive.nefs");
            var p7    = new NefsHeaderPart7(items);

            Assert.Empty(p7.EntriesByIndex);
        }
        public void EnumerateDepthFirstById_ItemsOrderedCorrectly()
        {
            // Purposely skip id numbers
            var fileA = TestHelpers.CreateItem(0, 0, "fileA", 100, 200, new List <UInt32> {
                200
            }, NefsItemType.File);
            var fileB = TestHelpers.CreateItem(3, 3, "fileB", 100, 200, new List <UInt32> {
                200
            }, NefsItemType.File);
            var dir0      = TestHelpers.CreateItem(5, 5, "dir0", 0, 0, new List <UInt32>(), NefsItemType.Directory);
            var dir0File0 = TestHelpers.CreateItem(7, 5, "dir0File0", 100, 200, new List <UInt32> {
                200
            }, NefsItemType.File);

            var list = new NefsItemList(@"C:\data.nefs");

            list.Add(fileB);
            list.Add(fileA);
            list.Add(dir0);
            list.Add(dir0File0);

            var result = list.EnumerateDepthFirstById();

            Assert.Equal(4, result.Count());
            Assert.Same(fileA, result.ElementAt(0));
            Assert.Same(fileB, result.ElementAt(1));
            Assert.Same(dir0, result.ElementAt(2));
            Assert.Same(dir0File0, result.ElementAt(3));
        }
示例#5
0
        /// <summary>
        /// Prepares a new list of items to be written out. The source list is cloned and then
        /// updated. Deleted items are removed. Item data is compressed if needed. Other item
        /// metadata is updated. The original item list is not modified; instead a new, updated list
        /// is returned.
        /// </summary>
        /// <param name="sourceItems">
        /// The source items list to prepare. This list nor its items are modified.
        /// </param>
        /// <param name="workDir">The temporary working directory.</param>
        /// <param name="p">Progress info.</param>
        /// <returns>A prepared item list ready for writing.</returns>
        private async Task <NefsItemList> PrepareItemsAsync(
            NefsItemList sourceItems,
            string workDir,
            NefsProgress p)
        {
            // Create a new items list - original source list is not modified. The new list is
            // returned that removes deleted items and has updated metadata for the other items.
            var items         = sourceItems.Clone() as NefsItemList;
            var itemsToRemove = new List <NefsItem>();

            foreach (var item in items.EnumerateById())
            {
                if (item.State == NefsItemState.Removed)
                {
                    // Item was deleted; remove item from list
                    itemsToRemove.Add(item);
                }
                else
                {
                    // Compress any new or replaced files and update chunk sizes
                    await this.PrepareItemAsync(item, workDir, sourceItems, p);
                }
            }

            // Remove deleted items
            foreach (var item in itemsToRemove)
            {
                items.Remove(item.Id);
            }

            // Return the new list
            return(items);
        }
        public void GetItemFirstChildId_GotIt()
        {
            var file0 = TestHelpers.CreateItem(0, 0, "file0", 100, 200, new List <UInt32> {
                200
            }, NefsItemType.File);
            var dir0      = TestHelpers.CreateItem(5, 5, "dir0", 0, 0, new List <UInt32>(), NefsItemType.Directory);
            var dir0FileB = TestHelpers.CreateItem(7, 5, "dir0FileB", 100, 200, new List <UInt32> {
                200
            }, NefsItemType.File);
            var dir0FileA = TestHelpers.CreateItem(9, 5, "dir0FileA", 100, 200, new List <UInt32> {
                200
            }, NefsItemType.File);

            var list = new NefsItemList(@"C:\data.nefs");

            list.Add(file0);
            list.Add(dir0);
            list.Add(dir0FileB);
            list.Add(dir0FileA);

            Assert.Equal(0U, list.GetItemFirstChildId(file0.Id).Value);
            Assert.Equal(7U, list.GetItemFirstChildId(dir0.Id).Value);
            Assert.Equal(7U, list.GetItemFirstChildId(dir0FileB.Id).Value);
            Assert.Equal(9U, list.GetItemFirstChildId(dir0FileA.Id).Value);
        }
示例#7
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Nefs20HeaderPart6"/> class from a list of items.
        /// </summary>
        /// <param name="items">The list of items in the archive.</param>
        internal Nefs20HeaderPart6(NefsItemList items)
        {
            this.entriesByIndex = new List <Nefs20HeaderPart6Entry>();
            this.entriesByGuid  = new Dictionary <Guid, Nefs20HeaderPart6Entry>();

            // Sort part 6 by item id. Part 1 and part 6 order must match.
            foreach (var item in items.EnumerateById())
            {
                var flags = Nefs20HeaderPart6Flags.None;
                flags |= item.Attributes.V20IsZlib ? Nefs20HeaderPart6Flags.IsZlib : 0;
                flags |= item.Attributes.V20IsAes ? Nefs20HeaderPart6Flags.IsAes : 0;
                flags |= item.Attributes.IsDirectory ? Nefs20HeaderPart6Flags.IsDirectory : 0;
                flags |= item.Attributes.IsDuplicated ? Nefs20HeaderPart6Flags.IsDuplicated : 0;
                flags |= item.Attributes.V20Unknown0x10 ? Nefs20HeaderPart6Flags.Unknown0x10 : 0;
                flags |= item.Attributes.V20Unknown0x20 ? Nefs20HeaderPart6Flags.Unknown0x20 : 0;
                flags |= item.Attributes.V20Unknown0x40 ? Nefs20HeaderPart6Flags.Unknown0x40 : 0;
                flags |= item.Attributes.V20Unknown0x80 ? Nefs20HeaderPart6Flags.Unknown0x80 : 0;

                var entry = new Nefs20HeaderPart6Entry(item.Guid);
                entry.Data0x00_Volume.Value  = item.Attributes.Part6Volume;
                entry.Data0x02_Flags.Value   = (byte)flags;
                entry.Data0x03_Unknown.Value = item.Attributes.Part6Unknown0x3;

                this.entriesByGuid.Add(item.Guid, entry);
                this.entriesByIndex.Add(entry);
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="Nefs20HeaderPart4"/> class from a list of items.
        /// </summary>
        /// <param name="items">The items to initialize from.</param>
        internal Nefs20HeaderPart4(NefsItemList items)
        {
            this.entriesByIndex = new List <Nefs20HeaderPart4Entry>();
            this.indexLookup    = new Dictionary <Guid, uint>();

            var nextStartIdx = 0U;

            foreach (var item in items.EnumerateById())
            {
                if (item.DataSource.Size.ExtractedSize == item.DataSource.Size.TransformedSize)
                {
                    // Item does not have a part 4 entry since it has no compressed data
                    continue;
                }

                // Log this start index to item's Guid to allow lookup later
                this.indexLookup.Add(item.Guid, nextStartIdx);

                // Create entry for each data chunk
                foreach (var chunk in item.DataSource.Size.Chunks)
                {
                    // Create entry
                    var entry = new Nefs20HeaderPart4Entry();
                    entry.Data0x00_CumulativeChunkSize.Value = chunk.CumulativeSize;
                    this.entriesByIndex.Add(entry);

                    nextStartIdx++;
                }
            }
        }
        public void NefsHeaderPart1_MultipleItems_EntriesPopulated()
        {
            var items = new NefsItemList(@"C:\archive.nefs");

            var file1DataSource = new NefsItemListDataSource(items, 123, new NefsItemSize(456, new List <UInt32> {
                11, 12, 13
            }));
            var file1 = new NefsItem(new NefsItemId(0), "file1", new NefsItemId(0), NefsItemType.File, file1DataSource, TestHelpers.CreateUnknownData());

            items.Add(file1);

            var file2DataSource = new NefsItemListDataSource(items, 456, new NefsItemSize(789, new List <UInt32> {
                14, 15, 16
            }));
            var file2 = new NefsItem(new NefsItemId(1), "file2", new NefsItemId(1), NefsItemType.File, file2DataSource, TestHelpers.CreateUnknownData());

            items.Add(file2);

            var dir1DataSource = new NefsEmptyDataSource();
            var dir1           = new NefsItem(new NefsItemId(2), "dir1", new NefsItemId(2), NefsItemType.Directory, dir1DataSource, TestHelpers.CreateUnknownData());

            items.Add(dir1);

            var p4 = new NefsHeaderPart4(items);
            var p1 = new NefsHeaderPart1(items, p4);

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

            /*
             * dir1
             */

            // Offset to data and index to p4 are both 0 since this is a directory
            Assert.Equal(2, (int)p1.EntriesById[dir1.Id].Id.Value);
            Assert.Equal(0, (int)p1.EntriesById[dir1.Id].OffsetToData);
            Assert.Equal(0, (int)p1.EntriesById[dir1.Id].MetadataIndex);
            Assert.Equal(0, (int)p1.EntriesById[dir1.Id].IndexIntoPart4);

            /*
             * file1
             */

            Assert.Equal(0, (int)p1.EntriesById[file1.Id].Id.Value);
            Assert.Equal(123, (int)p1.EntriesById[file1.Id].OffsetToData);
            Assert.Equal(1, (int)p1.EntriesById[file1.Id].MetadataIndex);
            Assert.Equal(0, (int)p1.EntriesById[file1.Id].IndexIntoPart4);

            /*
             * file2
             */

            Assert.Equal(1, (int)p1.EntriesById[file2.Id].Id.Value);
            Assert.Equal(456, (int)p1.EntriesById[file2.Id].OffsetToData);
            Assert.Equal(2, (int)p1.EntriesById[file2.Id].MetadataIndex);

            // There are 3 chunks for file1, so file2's chunks start right after that (hence p4
            // index == 3)
            Assert.Equal(3, (int)p1.EntriesById[file2.Id].IndexIntoPart4);
        }
示例#10
0
        public void NefsHeaderPart2_NoItems_EntriesEmpty()
        {
            var items = new NefsItemList(@"C:\archive.nefs");
            var p3    = new NefsHeaderPart3(items);
            var p2    = new NefsHeaderPart2(items, p3);

            Assert.Empty(p2.EntriesByIndex);
        }
示例#11
0
        public void NefsHeaderPart6_NoItems_EntriesEmpty()
        {
            var items = new NefsItemList(@"C:\archive.nefs");
            var p6    = new Nefs20HeaderPart6(items);

            Assert.Empty(p6.EntriesByIndex);
            Assert.Empty(p6.EntriesByGuid);
        }
        public void NefsHeaderPart1_NoItems_EntriesEmpty()
        {
            var items = new NefsItemList(@"C:\archive.nefs");
            var p4    = new NefsHeaderPart4(items);
            var p1    = new NefsHeaderPart1(items, p4);

            Assert.Empty(p1.EntriesById);
        }
        public void NefsHeaderPart4_NoItems_EntriesEmpty()
        {
            var items = new NefsItemList(@"C:\archive.nefs");
            var p4    = new Nefs20HeaderPart4(items);

            Assert.Empty(p4.EntriesByIndex);
            Assert.Equal(0U, p4.Size);
        }
        public void NefsHeaderPart3_NoItems_EntriesEmpty()
        {
            var items = new NefsItemList(@"C:\archive.nefs");
            var p3    = new NefsHeaderPart3(items);

            Assert.Single(p3.OffsetsByFileName);
            Assert.Single(p3.FileNamesByOffset);
            Assert.Equal(13, (int)p3.Size);
        }
示例#15
0
 /// <summary>
 /// Initializes a new instance of the <see cref="NefsItemListDataSource"/> class.
 /// </summary>
 /// <param name="items">
 /// The items list that specifies the file the item's data is stored in.
 /// </param>
 /// <param name="offset">The offset in the source file where the data begins.</param>
 /// <param name="size">The size of the item's data in bytes.</param>
 public NefsItemListDataSource(
     NefsItemList items,
     UInt64 offset,
     NefsItemSize size)
 {
     this.Items  = items ?? throw new ArgumentNullException(nameof(items));
     this.Offset = offset;
     this.Size   = size;
 }
示例#16
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NefsHeaderPart3"/> class.
        /// </summary>
        /// <param name="items">The list of items in the archive.</param>
        internal NefsHeaderPart3(NefsItemList items)
        {
            // Add the archive file name to the list and sort strings alphabetically
            var strings = items.EnumerateById().Select(i => i.FileName)
                          .Append(items.DataFileName)
                          .Distinct()
                          .OrderBy(i => i);

            this.Init(strings);
        }
        public void Add_ParentNotInList_ArgumentExceptionThrown()
        {
            var list = new NefsItemList(@"C:\data.nefs");
            var item = TestHelpers.CreateItem(0, 1, "file1.txt", 100, 200, new List <UInt32> {
                200
            }, NefsItemType.File);

            Assert.Throws <ArgumentException>(() => list.Add(item));
            Assert.Equal(0, list.Count);
        }
示例#18
0
        private string GetDebugInfoVersion16(NefsItem item, Nefs16Header h, NefsItemList items)
        {
            var p1         = h.Part1.EntriesByGuid[item.Guid];
            var p2         = h.Part2.EntriesByIndex[(int)p1.IndexPart2];
            var p6         = h.Part6.EntriesByGuid[item.Guid];
            var p7         = h.Part7.EntriesByIndex[(int)p1.IndexPart2];
            var numChunks  = h.TableOfContents.ComputeNumChunks(p2.ExtractedSize);
            var chunkSize  = h.TableOfContents.BlockSize;
            var attributes = p6.CreateAttributes();

            return($@"Item Info
-----------------------------------------------------------
Item name:                  {item.FileName}
Item path:                  {items.GetItemFilePath(item.Id)}

Part 1
-----------------------------------------------------------
Offset to data:             {p1.OffsetToData.ToString("X")}
Index in part 2:            {p1.IndexPart2.ToString("X")}
Index in part 4:            {p1.IndexPart4.ToString("X")}
Id:                         {p1.Id.Value.ToString("X")}

Part 2
-----------------------------------------------------------
Directory id:               {p2.DirectoryId.Value.ToString("X")}
First child id:             {p2.FirstChildId.Value.ToString("X")}
Offset in part 3:           {p2.OffsetIntoPart3.ToString("X")}
Extracted size:             {p2.ExtractedSize.ToString("X")}
Id:                         {p2.Id.Value.ToString("X")}

Part 4
-----------------------------------------------------------
Chunks                      {this.PrintChunkSizesToString(h.Part4.CreateChunksList(p1.IndexPart4, numChunks, chunkSize, h.Intro.GetAesKey()))}

Part 6
-----------------------------------------------------------
0x00:                       {p6.Volume.ToString("X")}
0x02:                       {((byte)p6.Flags).ToString("X")}
0x03:                       {p6.Unknown0x3.ToString("X")}

IsTransformed:              {attributes.V16IsTransformed}
IsDirectory:                {attributes.IsDirectory}
IsDuplicated:               {attributes.IsDuplicated}
IsCacheable:                {attributes.IsCacheable}
Unknown 0x10:               {attributes.V16Unknown0x10}
IsPatched:                  {attributes.IsPatched}
Unknown 0x40:               {attributes.V16Unknown0x40}
Unknown 0x80:               {attributes.V16Unknown0x80}

Part 7
-----------------------------------------------------------
Sibling id:                 {p7.SiblingId.Value.ToString("X")}
Item id:                    {p7.Id.Value.ToString("X")}
");
        }
示例#19
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);
        }
        public void Add_ItemIsInRoot_ItemAdded()
        {
            var list = new NefsItemList(@"C:\data.nefs");
            var item = TestHelpers.CreateItem(0, 0, "file1.txt", 100, 200, new List <UInt32> {
                200
            }, NefsItemType.File);

            list.Add(item);

            Assert.Equal(1, list.Count);
            Assert.Equal("file1.txt", list.EnumerateDepthFirstByName().First().FileName);
        }
示例#21
0
        public async Task WriteHeaderPart3Async_ValidData_Written()
        {
            var items = new NefsItemList(@"C:\hi.txt");
            var file1 = TestHelpers.CreateItem(0, 0, "file1", 10, 11, new List <UInt32> {
                12, 13
            }, NefsItemType.File);
            var file2 = TestHelpers.CreateItem(1, 1, "file2", 20, 21, new List <UInt32> {
                22, 23
            }, NefsItemType.File);
            var dir1 = TestHelpers.CreateItem(2, 2, "dir1", 0, 0, new List <UInt32> {
                0
            }, NefsItemType.Directory);
            var file3 = TestHelpers.CreateItem(3, 2, "file3", 30, 31, new List <UInt32> {
                32, 33
            }, NefsItemType.File);

            items.Add(file1);
            items.Add(file2);
            items.Add(dir1);
            items.Add(file3);

            var part3 = new NefsHeaderPart3(items);

            /*
             * Write
             */

            var writer = this.CreateWriter();

            byte[] buffer;
            var    offset = 5;

            using (var ms = new MemoryStream())
            {
                await writer.WriteHeaderPart3Async(ms, (uint)offset, part3, new NefsProgress());

                buffer = ms.ToArray();
            }

            /*
             * Verify
             */

            // Null terminated strings
            Assert.Equal("dir1", Encoding.ASCII.GetString(buffer, offset + 0, 4));
            Assert.Equal(0, buffer[offset + 4]);
            Assert.Equal("file1", Encoding.ASCII.GetString(buffer, offset + 5, 5));
            Assert.Equal(0, buffer[offset + 10]);
            Assert.Equal("file2", Encoding.ASCII.GetString(buffer, offset + 11, 5));
            Assert.Equal(0, buffer[offset + 16]);
            Assert.Equal("file3", Encoding.ASCII.GetString(buffer, offset + 17, 5));
            Assert.Equal(0, buffer[offset + 22]);
        }
        public void NefsHeaderPart3_MultipleItems_EntriesPopulated()
        {
            var items = new NefsItemList(@"C:\archive.nefs");

            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(0, 0, "file1", file1DataSource);

            items.Add(file1);

            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(1, 1, "file2", file2DataSource);

            items.Add(file2);

            var dir1 = TestHelpers.CreateDirectory(2, 2, "dir1");

            items.Add(dir1);

            var file3Chunks = NefsDataChunk.CreateChunkList(new List <UInt32> {
                22, 23, 24
            }, TestHelpers.TestTransform);
            var file3DataSource = new NefsItemListDataSource(items, 222, new NefsItemSize(333, file3Chunks));
            var file3           = TestHelpers.CreateFile(3, dir1.Id.Value, "file3", file3DataSource);

            items.Add(file3);

            var p3 = new NefsHeaderPart3(items);

            Assert.Equal(5, p3.OffsetsByFileName.Count);
            Assert.Equal(5, p3.FileNamesByOffset.Count);

            // Four file names plus a null terminal for each.
            Assert.Equal(36, (int)p3.Size);

            // Strings table is sorted alphabetically - and also contains data file name
            Assert.Equal("archive.nefs", p3.FileNamesByOffset[0]);
            Assert.Equal("dir1", p3.FileNamesByOffset[13]);
            Assert.Equal("file1", p3.FileNamesByOffset[18]);
            Assert.Equal("file2", p3.FileNamesByOffset[24]);
            Assert.Equal("file3", p3.FileNamesByOffset[30]);

            Assert.Equal(18, (int)p3.OffsetsByFileName[file1.FileName]);
            Assert.Equal(24, (int)p3.OffsetsByFileName[file2.FileName]);
            Assert.Equal(13, (int)p3.OffsetsByFileName[dir1.FileName]);
            Assert.Equal(30, (int)p3.OffsetsByFileName[file3.FileName]);
        }
示例#23
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NefsHeaderPart7"/> class from a list of items.
        /// </summary>
        /// <param name="items">The list of items in the archive.</param>
        internal NefsHeaderPart7(NefsItemList items)
        {
            this.entriesByIndex = new List <NefsHeaderPart7Entry>();

            foreach (var item in items.EnumerateDepthFirstByName())
            {
                var entry = new NefsHeaderPart7Entry();
                entry.Data0x00_SiblingId.Value = items.GetItemSiblingId(item.Id).Value;
                entry.Data0x04_Id.Value        = item.Id.Value;

                this.entriesByIndex.Add(entry);
            }
        }
示例#24
0
        /// <inheritdoc/>
        public NefsItem CreateItemInfo(Guid guid, NefsItemList dataSourceList)
        {
            var p1 = this.Part1.EntriesByGuid[guid];
            var p2 = this.Part2.EntriesByIndex[(int)p1.IndexPart2];
            var p6 = this.Part6.EntriesByGuid[guid];
            var id = p1.Id;

            // Gather attributes
            var attributes = p6.CreateAttributes();

            // Find parent
            var parentId = this.GetItemDirectoryId(p1.IndexPart2);

            // Offset and size
            var dataOffset    = p1.Data0x00_OffsetToData.Value;
            var extractedSize = p2.Data0x0c_ExtractedSize.Value;

            // Transform
            var transform = new NefsDataTransform(this.TableOfContents.BlockSize, true, this.Intro.IsEncrypted ? this.Intro.GetAesKey() : null);

            // Data source
            INefsDataSource dataSource;

            if (attributes.IsDirectory)
            {
                // Item is a directory
                dataSource = new NefsEmptyDataSource();
                transform  = null;
            }
            else if (p1.IndexPart4 == 0xFFFFFFFFU)
            {
                // Item is not compressed
                var size = new NefsItemSize(extractedSize);
                dataSource = new NefsItemListDataSource(dataSourceList, dataOffset, size);
            }
            else
            {
                // Item is compressed
                var numChunks = this.TableOfContents.ComputeNumChunks(p2.ExtractedSize);
                var chunkSize = this.TableOfContents.BlockSize;
                var chunks    = this.Part4.CreateChunksList(p1.IndexPart4, numChunks, chunkSize, this.Intro.GetAesKey());
                var size      = new NefsItemSize(extractedSize, chunks);
                dataSource = new NefsItemListDataSource(dataSourceList, dataOffset, size);
            }

            // File name and path
            var fileName = this.GetItemFileName(p1.IndexPart2);

            // Create item
            return(new NefsItem(p1.Guid, id, fileName, parentId, dataSource, transform, attributes));
        }
示例#25
0
        public async Task WriteHeaderPart4Async_ValidData_Written()
        {
            var items = new NefsItemList(@"C:\hi.txt");
            var file1 = TestHelpers.CreateItem(0, 0, "file1", 10, 11, new List <UInt32> {
                12, 13
            }, NefsItemType.File);
            var file2 = TestHelpers.CreateItem(1, 1, "file2", 20, 21, new List <UInt32> {
                22, 23
            }, NefsItemType.File);
            var dir1 = TestHelpers.CreateItem(2, 2, "dir1", 0, 0, new List <UInt32> {
                0
            }, NefsItemType.Directory);
            var file3 = TestHelpers.CreateItem(3, 2, "file3", 30, 31, new List <UInt32> {
                32, 33
            }, NefsItemType.File);

            items.Add(file1);
            items.Add(file2);
            items.Add(dir1);
            items.Add(file3);

            var part4 = new Nefs20HeaderPart4(items);

            /*
             * Write
             */

            var writer = this.CreateWriter();

            byte[] buffer;
            var    offset = 5;

            using (var ms = new MemoryStream())
            {
                await writer.WriteHeaderPart4Async(ms, (uint)offset, part4, new NefsProgress());

                buffer = ms.ToArray();
            }

            /*
             * Verify
             */

            Assert.Equal(24 + offset, buffer.Length);
            Assert.Equal(12, BitConverter.ToInt32(buffer, offset + 0));
            Assert.Equal(13, BitConverter.ToInt32(buffer, offset + 4));
            Assert.Equal(22, BitConverter.ToInt32(buffer, offset + 8));
            Assert.Equal(23, BitConverter.ToInt32(buffer, offset + 12));
            Assert.Equal(32, BitConverter.ToInt32(buffer, offset + 16));
            Assert.Equal(33, BitConverter.ToInt32(buffer, offset + 20));
        }
        public void NefsHeaderPart3_MultipleItems_EntriesPopulated()
        {
            var items = new NefsItemList(@"C:\archive.nefs");

            var file1DataSource = new NefsItemListDataSource(items, 123, new NefsItemSize(456, new List <UInt32> {
                11, 12, 13
            }));
            var file1 = new NefsItem(new NefsItemId(0), "file1", new NefsItemId(0), NefsItemType.File, file1DataSource, TestHelpers.CreateUnknownData());

            items.Add(file1);

            var file2DataSource = new NefsItemListDataSource(items, 456, new NefsItemSize(789, new List <UInt32> {
                14, 15, 16
            }));
            var file2 = new NefsItem(new NefsItemId(1), "file2", new NefsItemId(1), NefsItemType.File, file2DataSource, TestHelpers.CreateUnknownData());

            items.Add(file2);

            var dir1DataSource = new NefsEmptyDataSource();
            var dir1           = new NefsItem(new NefsItemId(2), "dir1", new NefsItemId(2), NefsItemType.Directory, dir1DataSource, TestHelpers.CreateUnknownData());

            items.Add(dir1);

            var file3DataSource = new NefsItemListDataSource(items, 222, new NefsItemSize(333, new List <UInt32> {
                22, 23, 24
            }));
            var file3 = new NefsItem(new NefsItemId(3), "file3", dir1.Id, NefsItemType.File, file3DataSource, TestHelpers.CreateUnknownData());

            items.Add(file3);

            var p3 = new NefsHeaderPart3(items);

            Assert.Equal(5, p3.OffsetsByFileName.Count);
            Assert.Equal(5, p3.FileNamesByOffset.Count);

            // Four file names plus a null terminal for each.
            Assert.Equal(36, (int)p3.Size);

            // Strings table is sorted alphabetically - and also contains data file name
            Assert.Equal("archive.nefs", p3.FileNamesByOffset[0]);
            Assert.Equal("dir1", p3.FileNamesByOffset[13]);
            Assert.Equal("file1", p3.FileNamesByOffset[18]);
            Assert.Equal("file2", p3.FileNamesByOffset[24]);
            Assert.Equal("file3", p3.FileNamesByOffset[30]);

            Assert.Equal(18, (int)p3.OffsetsByFileName[file1.FileName]);
            Assert.Equal(24, (int)p3.OffsetsByFileName[file2.FileName]);
            Assert.Equal(13, (int)p3.OffsetsByFileName[dir1.FileName]);
            Assert.Equal(30, (int)p3.OffsetsByFileName[file3.FileName]);
        }
示例#27
0
        /// <summary>
        /// Prepares an item's data to be written to the archive.
        /// </summary>
        /// <param name="item">The item to prepare.</param>
        /// <param name="workDir">The temporary working directory.</param>
        /// <param name="items">The source items list.</param>
        /// <param name="p">Progress info.</param>
        private async Task PrepareItemAsync(NefsItem item, string workDir, NefsItemList items, NefsProgress p)
        {
            // Deleted items should not be prepared
            if (item.State == NefsItemState.Removed)
            {
                throw new ArgumentException("Trying to prepare a removed item.", nameof(item));
            }

            // Nothing to do for directories
            if (item.Type == NefsItemType.Directory)
            {
                return;
            }

            // Only added or replaced files need prepared
            if (item.State != NefsItemState.Added && item.State != NefsItemState.Replaced)
            {
                return;
            }

            // Item should have a data source
            if (item.DataSource == null)
            {
                throw new ArgumentException("Item does not have a data source.", nameof(item));
            }

            // Make sure the new file still exists
            if (!this.FileSystem.File.Exists(item.DataSource.FilePath))
            {
                throw new IOException($"Cannot find source file {item.DataSource.FilePath}.");
            }

            // Compress to temp location if needed
            if (!item.DataSource.IsTransformed)
            {
                // Prepare the working directory
                var filePathInArchive     = items.GetItemFilePath(item.Id);
                var filePathInArchiveHash = HashHelper.HashStringMD5(filePathInArchive);
                var fileWorkDir           = Path.Combine(workDir, filePathInArchiveHash);
                this.FileSystem.ResetOrCreateDirectory(fileWorkDir);

                // Transform the file
                var destFilePath = Path.Combine(workDir, "inject.dat");
                var newSize      = await this.Transformer.TransformFileAsync(item.DataSource, destFilePath, item.Transform, p);

                // Update data source to point to the transformed temp file
                var dataSource = new NefsFileDataSource(destFilePath, 0, newSize, isTransformed: true);
                item.UpdateDataSource(dataSource, NefsItemState.Replaced);
            }
        }
示例#28
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NefsHeader"/> class.
        /// </summary>
        /// <param name="intro">Header intro.</param>
        /// <param name="toc">Header intro table of contents.</param>
        /// <param name="items">List of items.</param>
        public NefsHeader(NefsHeaderIntro intro, NefsHeaderIntroToc toc, NefsItemList items)
        {
            this.Intro           = intro ?? throw new ArgumentNullException(nameof(intro));
            this.TableOfContents = toc ?? throw new ArgumentNullException(nameof(toc));

            this.Part3 = new NefsHeaderPart3(items);
            this.Part4 = new NefsHeaderPart4(items);

            this.Part1 = new NefsHeaderPart1(items, this.Part4);
            this.Part2 = new NefsHeaderPart2(items, this.Part3);
            this.Part5 = new NefsHeaderPart5();
            this.Part6 = new NefsHeaderPart6(items);
            this.Part7 = new NefsHeaderPart7(items);
            this.Part8 = new NefsHeaderPart8(intro.HeaderSize - toc.OffsetToPart8);
        }
示例#29
0
        /// <summary>
        /// Creates a test archive. Does not write an archive to disk. Just creates a <see
        /// cref="NefsArchive"/> object.
        /// </summary>
        /// <param name="filePath">The file path to use for the archive.</param>
        /// <returns>A <see cref="NefsArchive"/>.</returns>
        public static NefsArchive Create(string filePath)
        {
            var items = new NefsItemList(filePath);

            Assert.Empty(items.EnumerateById());
            Assert.Empty(items.EnumerateDepthFirstByName());

            var intro = new NefsHeaderIntro();

            intro.Data0x6c_NumberOfItems.Value = (uint)items.Count;
            var toc = new Nefs20HeaderIntroToc();

            var header = new Nefs20Header(intro, toc, items);

            return(new NefsArchive(header, items));
        }
示例#30
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NefsHeaderPart2"/> class.
        /// </summary>
        /// <param name="items">The list of items in the archive.</param>
        /// <param name="part3">Header part 3.</param>
        internal NefsHeaderPart2(NefsItemList items, NefsHeaderPart3 part3)
        {
            this.entriesByIndex = new List <NefsHeaderPart2Entry>();

            foreach (var item in items.EnumerateDepthFirstByName())
            {
                var entry = new NefsHeaderPart2Entry();
                entry.Data0x00_DirectoryId.Value     = item.DirectoryId.Value;
                entry.Data0x04_FirstChildId.Value    = items.GetItemFirstChildId(item.Id).Value;
                entry.Data0x08_OffsetIntoPart3.Value = part3.OffsetsByFileName[item.FileName];
                entry.Data0x0c_ExtractedSize.Value   = item.DataSource.Size.ExtractedSize;
                entry.Data0x10_Id.Value = item.Id.Value;

                this.entriesByIndex.Add(entry);
            }
        }