/// <summary> /// Create a element of the TreeView /// </summary> public TreeViewItem CreateNode(RecordTreeNode rtn) { var tvi = new TreeViewItem { Tag = rtn }; var stack = new StackPanel { Orientation = Orientation.Horizontal }; stack.Children.Add(new Image // Icon { Source = rtn is IFileRecord ? IconFile : IconDir, Width = 20, Height = 20, Margin = new Thickness(0, 0, 2, 0) }); stack.Children.Add(new TextBlock { Text = rtn.Name, FontSize = 16 }); // File/Directory Name tvi.Header = stack; if (!(rtn is IFileRecord)) { tvi.Items.Add("Loading . . ."); // Add expand button } tvi.ContextMenu = TreeMenu; return(tvi); }
/// <summary> /// Find the record with a <paramref name="path"/> /// </summary> /// <param name="path">Path in GGPK under <paramref name="parent"/></param> /// <param name="parent">Where to start searching, null for ROOT directory in GGPK</param> /// <returns>null if not found</returns> public virtual RecordTreeNode FindRecord(string path, RecordTreeNode parent = null) { parent ??= rootDirectory; var SplittedPath = path.Split('/', '\\'); foreach (var name in SplittedPath) { var next = parent.GetChildItem(name); if (next == null) { return(null); } parent = next; } return(parent); }
/// <summary> /// Find the record with a <paramref name="path"/> /// <param name="path">Path in GGPK from <paramref name="parent"/></param> /// <param name="parent">null for ROOT directory in GGPK</param> /// </summary> public virtual RecordTreeNode FindRecord(string path, RecordTreeNode parent = null) { var SplittedPath = Regex.Replace(path, @"^ROOT(/|\\)", "").Split('/', '\\'); parent ??= rootDirectory; foreach (var name in SplittedPath) { var next = parent.GetChildItem(name); if (next == null) { return(null); } parent = next; } return(parent); }
/// <summary> /// Get the file list under a node /// </summary> /// <param name="record">File/Directory Record</param> /// <param name="list">File list (use <see cref="BundleSortComparer"/> when reading)</param> /// <param name="regex">Regular Expression for filtering files by their path</param> public static void RecursiveFileList(RecordTreeNode record, ICollection <IFileRecord> list, string regex = null) { if (record is IFileRecord fr) { if (regex == null || Regex.IsMatch(record.GetPath(), regex)) { list.Add(fr); } } else { foreach (var f in record.Children) { RecursiveFileList(f, list, regex); } } }
/// <summary> /// Get the file list under a node to export/replace /// </summary> /// <param name="record">File/Directory Record to export</param> /// <param name="path">Path to save</param> /// <param name="list">File list (use <see cref="BundleSortComparer"/> when reading)</param> /// <param name="export">True for export False for replace</param> /// <param name="regex">Regular Expression for filtering files by their path</param> public static void RecursiveFileList(RecordTreeNode record, string path, ICollection <KeyValuePair <IFileRecord, string> > list, bool export, string regex = null) { if (record is IFileRecord fr) { if ((export || File.Exists(path)) && (regex == null || Regex.IsMatch(record.GetPath(), regex))) { list.Add(new(fr, path)); } } else { foreach (var f in record.Children) { RecursiveFileList(f, path + "\\" + f.Name, list, export, regex); } } }
public virtual void BuildBundleTree(LibBundle.Records.FileRecord fr, RecordTreeNode parent) { var SplittedPath = fr.path.Split('/'); var path = ""; for (var i = 0; i < SplittedPath.Length; i++) { var name = SplittedPath[i]; var isFile = (i + 1 == SplittedPath.Length); var parentOfFile = (i + 2 == SplittedPath.Length); var next = parent.GetChildItem(name); path += name; if (!isFile) { path += "/"; } if (next == null) { // No exist node, Build a new node if (isFile) { next = new BundleFileNode(name, fr, this); } else if (parentOfFile) { next = new BundleDirectoryNode(name, path, fr.parent.NameHash, fr.parent.Offset, fr.parent.Size, this); } else { next = new BundleDirectoryNode(name, path, 0, 0, 0, this); } parent.Children.Add(next); next.Parent = parent; } else if (parentOfFile && next.Offset == 0) { ((BundleDirectoryNode)next).Hash = fr.parent.NameHash; next.Offset = fr.parent.Offset; next.Length = fr.parent.Size; } parent = next; } }
/// <summary> /// Find the record with a <paramref name="path"/> /// </summary> public RecordTreeNode FindRecord(string path, RecordTreeNode parent = null) { var SplittedPath = path.Split(new char[] { '/', '\\' }); if (parent == null) { parent = rootDirectory; } for (int i = 0; i < SplittedPath.Length; i++) { var name = SplittedPath[i]; var next = parent.GetChildItem(name); if (next == null) { return(null); } parent = next; } return(parent); }
/// <summary> /// Load GGPK /// </summary> /// <param name="path">Path to GGPK file</param> public GGPKContainer(string path, bool BundleMode = false, bool SteamMode = false, bool BuildTree = true) { // Steam Mode (No GGPK) if (SteamMode) { if (BundleMode) { throw new NotSupportedException("BundleMode and SteamMode cannot be both true"); } Environment.CurrentDirectory = Directory.GetParent(path).FullName; Index = new IndexContainer(path); if (BuildTree) { rootDirectory = FakeBundles2 = new BundleDirectoryNode("Bundles2", "", MurmurHash2Unsafe.Hash("bundles2", 0), 0, 0, this); foreach (var f in Index.Files) { BuildBundleTree(f, rootDirectory); } } return; } // Open File fileStream = File.Open(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); Reader = new BinaryReader(fileStream); Writer = new BinaryWriter(fileStream); // Read ROOT Directory Record BaseRecord ggpk; while ((ggpk = GetRecord()) is not GGPKRecord) { ; } ggpkRecord = ggpk as GGPKRecord; rootDirectory = GetRecord(ggpkRecord.RootDirectoryOffset) as DirectoryRecord; rootDirectory.Name = "ROOT"; // Build Linked FreeRecord List LinkedFreeRecords = new LinkedList <FreeRecord>(); var NextFreeOffset = ggpkRecord.FirstFreeRecordOffset; while (NextFreeOffset > 0) { FreeRecord current = GetRecord(NextFreeOffset) as FreeRecord; LinkedFreeRecords.AddLast(current); NextFreeOffset = current.NextFreeOffset; } // Read Bundles OriginalBundles2 = rootDirectory.Children.FirstOrDefault(d => d.GetNameHash() == MurmurHash2Unsafe.Hash("bundles2", 0)) as DirectoryRecord; if (OriginalBundles2?.Children.FirstOrDefault(r => r.Name == "_.index.bin") is FileRecord _index) { IndexRecord = _index; if (BundleMode) { return; } fileStream.Seek(_index.DataBegin, SeekOrigin.Begin); Index = new IndexContainer(Reader); if (BuildTree) { FakeBundles2 = new BundleDirectoryNode("Bundles2", "", MurmurHash2Unsafe.Hash("bundles2", 0), (int)OriginalBundles2.Offset, OriginalBundles2.Length, this); rootDirectory.Children.Remove(OriginalBundles2); rootDirectory.Children.Add(FakeBundles2); foreach (var f in Index.Files) { BuildBundleTree(f, FakeBundles2); } } _RecordOfBundle = new Dictionary <LibBundle.Records.BundleRecord, FileRecord>(Index.Bundles.Length); } // else BundleMode = true; }