/// <summary> /// Copies the tree rooted at the given node. /// </summary> /// <param name="p_tndSource">The root of the tree to copy.</param> /// <returns>The root of the copied tree.</returns> private FileSystemTreeNode CopyTree(FileSystemTreeNode p_tndSource) { var tndDest = new FileSystemTreeNode(p_tndSource); CopyTree(p_tndSource, tndDest); return(tndDest); }
/// <summary> /// The recursive method that searches the fomod file structure for files in the specified directory /// matching the given pattern. /// </summary> /// <param name="p_tndRoot">The node from which to being searching.</param> /// <param name="p_queDirectories">The path to the directory in which to search.</param> /// <param name="p_rgxFileNamePattern">The pattern of the files to find.</param> /// <returns> /// Returns pairs of values representing the found files. The key of the pair is the fomod file path, /// and the value is the source path for the file. /// </returns> private List <KeyValuePair <string, string> > FindFomodFiles(FileSystemTreeNode p_tndRoot, Queue <string> p_queDirectories, Regex p_rgxFileNamePattern) { var lstMatches = new List <KeyValuePair <string, string> >(); if (p_tndRoot.IsDirectory && ((p_queDirectories.Count > 0) && p_tndRoot.Name.Equals(p_queDirectories.Peek()))) { p_queDirectories.Dequeue(); PopulateNodeWithChildren(p_tndRoot); var intOriginalDepth = p_queDirectories.Count; foreach (FileSystemTreeNode tndNode in p_tndRoot.Nodes) { lstMatches.AddRange(FindFomodFiles(tndNode, p_queDirectories, p_rgxFileNamePattern)); if (intOriginalDepth != p_queDirectories.Count) { break; } } } else if ((p_queDirectories.Count == 0) && p_rgxFileNamePattern.IsMatch(p_tndRoot.Name)) { lstMatches.Add(new KeyValuePair <string, string>(p_tndRoot.FullPath, p_tndRoot.LastSource)); } return(lstMatches); }
/// <summary> /// Copies the tree rooted at the given source node to the tree rooted /// at the given destination node. /// </summary> /// <param name="p_tndSource">The root of the tree to copy.</param> /// <param name="p_tndDest">The root of the tree to which to copy.</param> private void CopyTree(FileSystemTreeNode p_tndSource, FileSystemTreeNode p_tndDest) { foreach (FileSystemTreeNode tndSourceNode in p_tndSource.Nodes) { var tndCopy = new FileSystemTreeNode(tndSourceNode); p_tndDest.Nodes.Add(tndCopy); CopyTree(tndSourceNode, tndCopy); } }
/// <summary> /// Populates the given node with its children. /// </summary> /// <param name="p_tndNode">The node to populate with children.</param> protected void PopulateNodeWithChildren(FileSystemTreeNode p_tndNode) { if (!p_tndNode.IsDirectory) { return; } foreach (var srcSource in p_tndNode.Sources) { if (srcSource.IsLoaded) { continue; } var strSource = srcSource.Path; srcSource.IsLoaded = true; if (strSource.StartsWith(Archive.ARCHIVE_PREFIX)) { var kvpPath = Archive.ParseArchivePath(strSource); var arcArchive = new Archive(kvpPath.Key); var strFolders = arcArchive.GetDirectories(kvpPath.Value); foreach (var folder in strFolders) { addFomodFile(p_tndNode, Archive.GenerateArchivePath(kvpPath.Key, folder)); } var strFiles = arcArchive.GetFiles(kvpPath.Value); foreach (var file in strFiles) { addFomodFile(p_tndNode, Archive.GenerateArchivePath(kvpPath.Key, file)); } } else if (!strSource.StartsWith(FileSystemTreeNode.NEW_PREFIX)) { var strFolders = Directory.GetDirectories(strSource); foreach (var folder in strFolders) { addFomodFile(p_tndNode, folder); } var strFiles = Directory.GetFiles(strSource); foreach (var file in strFiles) { addFomodFile(p_tndNode, file); } } } }
/// <summary> /// Finds the deepest nod in the fomod file system along the given path. /// </summary> /// <param name="p_strPath">The path for which to find the deepest node.</param> /// <returns>The deepest nod in the fomod file structure that is along the given path.</returns> protected FileSystemTreeNode findNode(string p_strPath) { if (String.IsNullOrEmpty(p_strPath)) { return(null); } var strPath = p_strPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); strPath = strPath.Trim(new[] { Path.DirectorySeparatorChar }); var strPathNodes = strPath.Split(Path.DirectorySeparatorChar); Array.Reverse(strPathNodes); var stkPath = new Stack <string>(strPathNodes); var tncNodes = tvwFomod.Nodes; FileSystemTreeNode tndLastNode = null; var intPathCount = 0; while ((tncNodes.Count > 0) && (intPathCount != stkPath.Count)) { intPathCount = stkPath.Count; foreach (FileSystemTreeNode tndNode in tncNodes) { if (tndNode.Name.Equals(stkPath.Peek(), StringComparison.InvariantCultureIgnoreCase)) { stkPath.Pop(); if (stkPath.Count == 0) { return(tndNode); } PopulateNodeWithChildren(tndNode); tndLastNode = tndNode; tncNodes = tndNode.Nodes; break; } } } return(tndLastNode); }
/// <summary> /// This adds a file/folder to the source file structure. /// </summary> /// <param name="p_tndRoot">The node to which to add the file/folder.</param> /// <param name="p_strFile">The path to add to the source file structure.</param> private void addSourceFile(FileSystemTreeNode p_tndRoot, string p_strFile) { if (!p_strFile.StartsWith(Archive.ARCHIVE_PREFIX) && !p_strFile.StartsWith(FileSystemTreeNode.NEW_PREFIX)) { FileSystemInfo fsiInfo; if (Directory.Exists(p_strFile)) { fsiInfo = new DirectoryInfo(p_strFile); } else if (File.Exists(p_strFile)) { fsiInfo = new FileInfo(p_strFile); } else { return; } if ((fsiInfo.Attributes & FileAttributes.System) > 0) { return; } } FileSystemTreeNode tndFile; var tncSiblings = (p_tndRoot == null) ? tvwSource.Nodes : p_tndRoot.Nodes; if (tncSiblings.ContainsKey(p_strFile)) { tndFile = (FileSystemTreeNode)tncSiblings[p_strFile]; } else { tndFile = new FileSystemTreeNode(Path.GetFileName(p_strFile), p_strFile); tndFile.Name = p_strFile; tncSiblings.Add(tndFile); } if (tndFile.IsDirectory) { tndFile.ImageKey = "folder"; tndFile.SelectedImageKey = "folder"; if ((p_tndRoot == null) || (p_tndRoot.IsExpanded)) { tndFile.Sources[p_strFile].IsLoaded = true; if (p_strFile.StartsWith(Archive.ARCHIVE_PREFIX)) { var kvpPath = Archive.ParseArchivePath(p_strFile); var arcArchive = new Archive(kvpPath.Key); var strFolders = arcArchive.GetDirectories(kvpPath.Value); foreach (var folder in strFolders) { addSourceFile(tndFile, Archive.GenerateArchivePath(kvpPath.Key, folder)); } var strFiles = arcArchive.GetFiles(kvpPath.Value); foreach (var file in strFiles) { addSourceFile(tndFile, Archive.GenerateArchivePath(kvpPath.Key, file)); } } else if (!p_strFile.StartsWith(FileSystemTreeNode.NEW_PREFIX)) { var strFolders = Directory.GetDirectories(p_strFile); foreach (var folder in strFolders) { addSourceFile(tndFile, folder); } var strFiles = Directory.GetFiles(p_strFile); foreach (var file in strFiles) { addSourceFile(tndFile, file); } } } } else { tndFile.Sources[p_strFile].IsLoaded = true; var strExtension = Path.GetExtension(p_strFile).ToLowerInvariant(); if (!imlIcons.Images.ContainsKey(strExtension)) { var strIconPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()) + strExtension; File.CreateText(strIconPath).Close(); imlIcons.Images.Add(strExtension, Icon.ExtractAssociatedIcon(strIconPath)); File.Delete(strIconPath); } tndFile.ImageKey = strExtension; tndFile.SelectedImageKey = strExtension; if (tndFile.IsArchive) { var arcArchive = new Archive(p_strFile); var strFolders = arcArchive.GetDirectories("/"); foreach (var folder in strFolders) { addSourceFile(tndFile, Archive.GenerateArchivePath(p_strFile, folder)); } var strFiles = arcArchive.GetFiles("/"); foreach (var file in strFiles) { addSourceFile(tndFile, Archive.GenerateArchivePath(p_strFile, file)); } } } }
/// <summary> /// This adds a file/folder to the fomod file structure. /// </summary> /// <param name="p_tndRoot">The node to which to add the file/folder.</param> /// <param name="p_strFile">The path to add to the fomod file structure.</param> /// <returns> /// The node that was added for the specified file/folder. <lang langref="null" /> /// is returned if the given path is invalid. /// </returns> private FileSystemTreeNode addFomodFile(TreeNode p_tndRoot, string p_strFile) { if (!p_strFile.StartsWith(Archive.ARCHIVE_PREFIX) && !p_strFile.StartsWith(FileSystemTreeNode.NEW_PREFIX)) { FileSystemInfo fsiInfo; if (Directory.Exists(p_strFile)) { fsiInfo = new DirectoryInfo(p_strFile); } else if (File.Exists(p_strFile)) { fsiInfo = new FileInfo(p_strFile); } else { return(null); } if ((fsiInfo.Attributes & FileAttributes.System) > 0) { return(null); } } var strFileName = Path.GetFileName(p_strFile); FileSystemTreeNode tndFile; var tncSiblings = (p_tndRoot == null) ? tvwFomod.Nodes : p_tndRoot.Nodes; if (tncSiblings.ContainsKey(strFileName.ToLowerInvariant())) { tndFile = (FileSystemTreeNode)tncSiblings[strFileName.ToLowerInvariant()]; tndFile.AddSource(p_strFile, false); } else { tndFile = new FileSystemTreeNode(strFileName, p_strFile); tndFile.ContextMenuStrip = cmsFomodNode; tndFile.Name = strFileName.ToLowerInvariant(); tncSiblings.Add(tndFile); } if (tndFile.IsDirectory) { tndFile.ImageKey = "folder"; tndFile.SelectedImageKey = "folder"; if ((p_tndRoot == null) || (p_tndRoot.IsExpanded)) { PopulateNodeWithChildren(tndFile); } } else { tndFile.Sources[p_strFile].IsLoaded = true; var strExtension = Path.GetExtension(p_strFile).ToLowerInvariant(); if (!imlIcons.Images.ContainsKey(strExtension)) { var strIconPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()) + strExtension; File.CreateText(strIconPath).Close(); imlIcons.Images.Add(strExtension, Icon.ExtractAssociatedIcon(strIconPath)); File.Delete(strIconPath); } tndFile.ImageKey = strExtension; tndFile.SelectedImageKey = strExtension; } return(tndFile); }
/// <summary> /// Processes the tree rooted at the given node to romve any superfluous nodes and sources. /// </summary> /// <remarks> /// This method cleans up the given tree so that the most efficient set of mappings /// needed to create the fomod file structure can be generated. /// </remarks> /// <param name="p_tndNode">The node at which the fomod file structure tree is rooted.</param> private void ProcessTree(FileSystemTreeNode p_tndNode) { if (p_tndNode.Nodes.Count == 0) { for (var j = p_tndNode.Sources.Count - 1; j >= 0; j--) { if (p_tndNode.Sources[j].Path.StartsWith(FileSystemTreeNode.NEW_PREFIX)) { p_tndNode.Sources.RemoveAt(j); } } return; } foreach (FileSystemTreeNode tndNode in p_tndNode.Nodes) { ProcessTree(tndNode); } var lstSubPaths = new List <string>(); for (var j = p_tndNode.Sources.Count - 1; j >= 0; j--) { var srcSource = p_tndNode.Sources[j]; lstSubPaths.Clear(); if (srcSource.Path.StartsWith(Archive.ARCHIVE_PREFIX)) { var kvpPath = Archive.ParseArchivePath(srcSource.Path); var arcArchive = new Archive(kvpPath.Key); foreach (var strPath in arcArchive.GetDirectories(kvpPath.Value)) { lstSubPaths.Add(Archive.GenerateArchivePath(kvpPath.Key, strPath)); } foreach (var strPath in arcArchive.GetFiles(kvpPath.Value)) { lstSubPaths.Add(Archive.GenerateArchivePath(kvpPath.Key, strPath)); } } else if (srcSource.Path.StartsWith(FileSystemTreeNode.NEW_PREFIX)) { p_tndNode.Sources.RemoveAt(j); continue; } else { lstSubPaths.AddRange(Directory.GetDirectories(srcSource.Path)); foreach (var strPath in Directory.GetFiles(srcSource.Path)) { if ((new FileInfo(strPath).Attributes & FileAttributes.System) > 0) { continue; } lstSubPaths.AddRange(Directory.GetFiles(srcSource.Path)); } } //if the source hasn't been loaded, then we treat it as if all // subpaths are present and have already been removed from // the children nodes, so we don't have to do anything if (srcSource.IsLoaded) { //if we find all the current folder's subpaths, and each subpath // has no children in the same source tree, then we can just copy // the current folder instead of copying each child individually var intFoundCount = 0; //so, for each subpath of the current folder... foreach (var strSubPath in lstSubPaths) { //...look through all the children nodes for the subpath... foreach (FileSystemTreeNode tndChild in p_tndNode.Nodes) { //...if we find the subpath... if (tndChild.Sources.Contains(strSubPath)) { //...and the node containing the subpath has no children // containing anything in the same source tree... var booFound = false; foreach (FileSystemTreeNode tndSubNode in tndChild.Nodes) { foreach (string strSubSource in tndSubNode.Sources) { if (strSubSource.StartsWith(strSubPath)) { booFound = true; break; } } if (booFound) { break; } } //...then we found the subpath. // if the node containing the subpath had had children containing // something in the same source tree, that would imply we aren't // copying all the current folder's descendants, so we would have to // copy each descendent individually, instead of just copying this folder if (!booFound) { intFoundCount++; } break; } } } //if we found all the subpaths... if (intFoundCount == lstSubPaths.Count) { //...then remove the subpaths, so we just copy the // current folder instead of copying each child individually foreach (var strSubPath in lstSubPaths) { for (var i = p_tndNode.Nodes.Count - 1; i >= 0; i--) { var tndNode = (FileSystemTreeNode)p_tndNode.Nodes[i]; if (tndNode.Sources.Contains(strSubPath)) { //if we are removing the last source, and there are no // children nodes (implying this node isn't needed in // another source tree), then prune this node away... if ((tndNode.Nodes.Count == 0) && (tndNode.Sources.Count <= 1)) { p_tndNode.Nodes.RemoveAt(i); } else //...otherwise just remove the source { tndNode.Sources.Remove(strSubPath); } break; } } } } else { //...else if we only found some of the subpaths // then remove the current folder from the sources so // it doesn't get copied: the current folder will be // created when the subpaths are copied... //...else if we found no subpaths then we remove the current folder // to prune empty folders p_tndNode.Sources.RemoveAt(j); } } } }