/// <summary> /// Creates an item from header data. /// </summary> /// <param name="id">The item id.</param> /// <param name="header">The header data.</param> /// <param name="dataSourceList">The item list to use as the item data source.</param> /// <returns>A new <see cref="NefsItem"/>.</returns> public static NefsItem CreateFromHeader(NefsItemId id, NefsHeader header, NefsItemList dataSourceList) { var p1 = header.Part1.EntriesById[id]; var p2 = header.Part2.EntriesById[id]; // Check if part 6 exists NefsHeaderPart6Entry p6 = null; if (header.Part6.EntriesById.ContainsKey(id)) { p6 = header.Part6.EntriesById[id]; } // Determine type var type = p2.Data0x0c_ExtractedSize.Value == 0 ? NefsItemType.Directory : NefsItemType.File; // Find parent var parentId = header.GetItemDirectoryId(id); // Offset and size var dataOffset = p1.Data0x00_OffsetToData.Value; var extractedSize = p2.Data0x0c_ExtractedSize.Value; // Data source INefsDataSource dataSource; if (type == NefsItemType.Directory) { // Item is a directory dataSource = new NefsEmptyDataSource(); } else if (p1.IndexIntoPart4 == 0xFFFFFFFFU) { // Item is not compressed var size = new NefsItemSize(extractedSize); dataSource = new NefsItemListDataSource(dataSourceList, dataOffset, size); } else { // Item is compressed var p4 = header.Part4.EntriesByIndex[p1.IndexIntoPart4]; var size = new NefsItemSize(extractedSize, p4.ChunkSizes); dataSource = new NefsItemListDataSource(dataSourceList, dataOffset, size); } // File name and path var fileName = header.GetItemFileName(id); // Gather unknown metadata var unknown = new NefsItemUnknownData { Part6Unknown0x00 = p6?.Byte0 ?? 0, Part6Unknown0x01 = p6?.Byte1 ?? 0, Part6Unknown0x02 = p6?.Byte2 ?? 0, Part6Unknown0x03 = p6?.Byte3 ?? 0, }; // Create item return(new NefsItem(id, fileName, parentId, type, dataSource, unknown)); }
/// <summary> /// Gets the id of the first child for an item. If the item has no children, the item's id /// is returned. The first child id is based on the children being sorted by id, not file name. /// </summary> /// <param name="id">The id of the item.</param> /// <returns>The first child id.</returns> public NefsItemId GetItemFirstChildId(NefsItemId id) { // First child id is based on children items being sorted by id, NOT by file name var item = this.itemsById[id]; return(item.Children.Count > 0 ? item.Children.OrderBy(i => i.Value.Item.Id).First().Value.Item.Id : id); }
/// <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) { var item = this.itemsById[id]; if (item.Parent == null) { return(id); } return(item.Parent.Item.Id); }
/// <summary> /// Gets the id of the next item in the same directory as the specified item. If the /// specified item is that last item in the directory, the sibling id is equal to the item's /// id. Sibling id is based on directory structure with the children sorted by id, not file name. /// </summary> /// <param name="id">The id of the item to get the sibling for.</param> /// <returns>The sibling id.</returns> public NefsItemId GetItemSiblingId(NefsItemId id) { // Sibling id is based on children items being sorted by id, NOT by file name var item = this.itemsById[id]; var parentList = item.Parent?.Children.OrderBy(i => i.Value.Item.Id).Select(i => i.Value.Item.Id).ToList() ?? this.rootItems.OrderBy(i => i.Value.Item.Id).Select(i => i.Value.Item.Id).ToList(); var itemIndex = parentList.IndexOf(item.Item.Id); if (itemIndex == parentList.Count - 1) { // This is the last item in the directory return(id); } // Return id of next item in directory return(parentList[itemIndex + 1]); }
/// <summary> /// Gets the file path of the item within the archive. /// </summary> /// <param name="id">The item id.</param> /// <returns>The item's file path within the archive.</returns> public string GetItemFilePath(NefsItemId id) { var path = this.GetItemFileName(id); var dirId = this.GetItemDirectoryId(id); var prevDirId = id; while (dirId != prevDirId) { var dirName = this.GetItemFileName(dirId); path = Path.Combine(dirName, path); prevDirId = dirId; dirId = this.GetItemDirectoryId(dirId); } return(path); }
/// <summary> /// Initializes a new instance of the <see cref="NefsItem"/> class. /// </summary> /// <param name="guid">The unique identifier for this item.</param> /// <param name="id">The item id.</param> /// <param name="fileName">The file name within the archive.</param> /// <param name="directoryId">The directory id the item is in.</param> /// <param name="dataSource">The data source for the item's data.</param> /// <param name="transform"> /// The transform that is applied to this item's data. Can be null if no transform. /// </param> /// <param name="attributes">Additional attributes.</param> /// <param name="state">The item state.</param> public NefsItem( Guid guid, NefsItemId id, string fileName, NefsItemId directoryId, INefsDataSource dataSource, NefsDataTransform transform, NefsItemAttributes attributes, NefsItemState state = NefsItemState.None) { this.Guid = guid; this.Id = id; this.DirectoryId = directoryId; this.DataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource)); this.State = state; this.Transform = transform; this.Attributes = attributes; // Save file name this.FileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); }
/// <summary> /// Removes the item with the specified id. /// </summary> /// <param name="id">The id of the item to remove.</param> public void Remove(NefsItemId id) { if (!this.itemsById.ContainsKey(id)) { return; } var item = this.itemsById[id]; this.itemsById.Remove(id); // Check if in root if (item.Parent == null) { this.rootItems.Remove(item.Item.FileName); } else { // Remove item from parent item.Parent?.Children.Remove(item.Item.FileName); item.Parent = null; } }
/// <summary> /// Initializes a new instance of the <see cref="NefsItem"/> class. /// </summary> /// <param name="id">The item id (index).</param> /// <param name="fileName">The file name within the archive.</param> /// <param name="directoryId">The directory id the item is in.</param> /// <param name="type">The type of item.</param> /// <param name="dataSource">The data source for the item's data.</param> /// <param name="unknownData">Unknown metadata.</param> /// <param name="state">The item state.</param> public NefsItem( NefsItemId id, string fileName, NefsItemId directoryId, NefsItemType type, INefsDataSource dataSource, NefsItemUnknownData unknownData, NefsItemState state = NefsItemState.None) { this.Id = id; this.DirectoryId = directoryId; this.Type = type; this.DataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource)); this.State = state; // Unknown data this.Part6Unknown0x00 = unknownData.Part6Unknown0x00; this.Part6Unknown0x01 = unknownData.Part6Unknown0x01; this.Part6Unknown0x02 = unknownData.Part6Unknown0x02; this.Part6Unknown0x03 = unknownData.Part6Unknown0x03; // Save file name this.FileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); }
/// <summary> /// Gets the file name of the item. /// </summary> /// <param name="id">The item id.</param> /// <returns>The item's file name.</returns> public string GetItemFileName(NefsItemId id) { return(this.itemsById[id].Item.FileName); }
/// <summary> /// Gets the item with the specified id. Throws an exception if not found. /// </summary> /// <param name="id">The id of the item to get.</param> /// <returns>The <see cref="NefsItem"/>.</returns> public NefsItem GetItem(NefsItemId id) { return(this.itemsById[id].Item); }
/// <summary> /// Enumerates the children of an item. /// </summary> /// <param name="id">The item id.</param> /// <returns>The items children.</returns> public IEnumerable <NefsItem> EnumerateItemChildren(NefsItemId id) { var item = this.itemsById[id]; return(item.Children.Values.Select(v => v.Item)); }
/// <summary> /// Checks if the item list contains an item with the specified id. /// </summary> /// <param name="id">The id to check.</param> /// <returns>True if the list contains the item id.</returns> public bool ContainsKey(NefsItemId id) { return(this.itemsById.ContainsKey(id)); }
/// <summary> /// Gets all items with the specified id. Throws an exception if not found. /// </summary> /// <param name="id">The id of the items to get.</param> /// <returns>The <see cref="NefsItem"/>.</returns> public IReadOnlyList <NefsItem> GetItems(NefsItemId id) { return(this.itemsById[id].Items); }