/// <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++; } } }
/// <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(); }
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)); }
/// <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); }
/// <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); }
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); }
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); }
/// <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; }
/// <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); }
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")} "); }
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); }
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]); }
/// <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); } }
/// <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)); }
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]); }
/// <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); } }
/// <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); }
/// <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)); }
/// <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); } }