// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tools.DotNETCommon
{
///
/// Representation of an absolute directory path. Allows fast hashing and comparisons.
///
[Serializable]
public class DirectoryReference : FileSystemReference, IEquatable
{
///
/// Special value used to invoke the non-sanitizing constructor overload
///
public enum Sanitize
{
None
}
///
/// Default constructor.
///
/// Path to this directory.
public DirectoryReference(string InPath)
: base(FixTrailingPathSeparator(Path.GetFullPath(InPath)))
{
}
///
/// Construct a DirectoryReference from a DirectoryInfo object.
///
/// Path to this file
public DirectoryReference(DirectoryInfo InInfo)
: base(FixTrailingPathSeparator(InInfo.FullName))
{
}
///
/// Constructor for creating a directory object directly from two strings.
///
/// The full, sanitized path name
/// Dummy argument used to resolve this overload
public DirectoryReference(string InFullName, Sanitize InSanitize)
: base(InFullName)
{
}
///
/// Ensures that the correct trailing path separator is appended. On Windows, the root directory (eg. C:\) always has a trailing path separator, but no other
/// path does.
///
/// Absolute path to the directory
/// Path to the directory, with the correct trailing path separator
private static string FixTrailingPathSeparator(string DirName)
{
if(DirName.Length == 2 && DirName[1] == ':')
{
return DirName + Path.DirectorySeparatorChar;
}
else if(DirName.Length == 3 && DirName[1] == ':' && DirName[2] == Path.DirectorySeparatorChar)
{
return DirName;
}
else if(DirName.Length > 1 && DirName[DirName.Length - 1] == Path.DirectorySeparatorChar)
{
return DirName.TrimEnd(Path.DirectorySeparatorChar);
}
else
{
return DirName;
}
}
///
/// Gets the top level directory name
///
/// The name of the directory
public string GetDirectoryName()
{
return Path.GetFileName(FullName);
}
///
/// Gets the directory containing this object
///
/// A new directory object representing the directory containing this object
public DirectoryReference ParentDirectory
{
get
{
if (IsRootDirectory())
{
return null;
}
int ParentLength = FullName.LastIndexOf(Path.DirectorySeparatorChar);
if (ParentLength == 2 && FullName[1] == ':')
{
ParentLength++;
}
return new DirectoryReference(FullName.Substring(0, ParentLength), Sanitize.None);
}
}
///
/// Gets the parent directory for a file
///
/// The file to get directory for
/// The full directory name containing the given file
public static DirectoryReference GetParentDirectory(FileReference File)
{
int ParentLength = File.FullName.LastIndexOf(Path.DirectorySeparatorChar);
if(ParentLength == 2 && File.FullName[1] == ':')
{
ParentLength++;
}
return new DirectoryReference(File.FullName.Substring(0, ParentLength), Sanitize.None);
}
///
/// Gets the path for a special folder
///
/// The folder to receive the path for
/// Directory reference for the given folder, or null if it is not available
public static DirectoryReference GetSpecialFolder(Environment.SpecialFolder Folder)
{
string FolderPath = Environment.GetFolderPath(Folder);
return String.IsNullOrEmpty(FolderPath)? null : new DirectoryReference(FolderPath);
}
///
/// Determines whether this path represents a root directory in the filesystem
///
/// True if this path is a root directory, false otherwise
public bool IsRootDirectory()
{
return FullName[FullName.Length - 1] == Path.DirectorySeparatorChar;
}
///
/// Combine several fragments with a base directory, to form a new directory name
///
/// The base directory
/// Fragments to combine with the base directory
/// The new directory name
public static DirectoryReference Combine(DirectoryReference BaseDirectory, params string[] Fragments)
{
string FullName = FileSystemReference.CombineStrings(BaseDirectory, Fragments);
return new DirectoryReference(FullName, Sanitize.None);
}
///
/// Compares two filesystem object names for equality. Uses the canonical name representation, not the display name representation.
///
/// First object to compare.
/// Second object to compare.
/// True if the names represent the same object, false otherwise
public static bool operator ==(DirectoryReference A, DirectoryReference B)
{
if ((object)A == null)
{
return (object)B == null;
}
else
{
return (object)B != null && A.FullName.Equals(B.FullName, Comparison);
}
}
///
/// Compares two filesystem object names for inequality. Uses the canonical name representation, not the display name representation.
///
/// First object to compare.
/// Second object to compare.
/// False if the names represent the same object, true otherwise
public static bool operator !=(DirectoryReference A, DirectoryReference B)
{
return !(A == B);
}
///
/// Compares against another object for equality.
///
/// other instance to compare.
/// True if the names represent the same object, false otherwise
public override bool Equals(object Obj)
{
return (Obj is DirectoryReference) && ((DirectoryReference)Obj) == this;
}
///
/// Compares against another object for equality.
///
/// other instance to compare.
/// True if the names represent the same object, false otherwise
public bool Equals(DirectoryReference Obj)
{
return Obj == this;
}
///
/// Returns a hash code for this object
///
///
public override int GetHashCode()
{
return Comparer.GetHashCode(FullName);
}
///
/// Helper function to create a remote directory reference. Unlike normal DirectoryReference objects, these aren't converted to a full path in the local filesystem.
///
/// The absolute path in the remote file system
/// New directory reference
public static DirectoryReference MakeRemote(string AbsolutePath)
{
return new DirectoryReference(AbsolutePath, Sanitize.None);
}
///
/// Gets the parent directory for a file, or returns null if it's null.
///
/// The file to create a directory reference for
/// The directory containing the file
public static DirectoryReference FromFile(FileReference File)
{
if(File == null)
{
return null;
}
else
{
return File.Directory;
}
}
///
/// Create a DirectoryReference from a string. If the string is null, returns a null DirectoryReference.
///
/// Path for the new object
/// Returns a FileReference representing the given string, or null.
public static DirectoryReference FromString(string DirectoryName)
{
if(String.IsNullOrEmpty(DirectoryName))
{
return null;
}
else
{
return new DirectoryReference(DirectoryName);
}
}
#region System.IO.Directory Wrapper Methods
///
/// Finds the current directory
///
/// The current directory
public static DirectoryReference GetCurrentDirectory()
{
return new DirectoryReference(Directory.GetCurrentDirectory());
}
///
/// Creates a directory
///
/// Location of the directory
public static void CreateDirectory(DirectoryReference Location)
{
Directory.CreateDirectory(Location.FullName);
}
///
/// Deletes a directory
///
/// Location of the directory
public static void Delete(DirectoryReference Location)
{
Directory.Delete(Location.FullName);
}
///
/// Deletes a directory
///
/// Location of the directory
/// Whether to remove directories recursively
public static void Delete(DirectoryReference Location, bool bRecursive)
{
Directory.Delete(Location.FullName, bRecursive);
}
///
/// Checks whether the directory exists
///
/// Location of the directory
/// True if this directory exists
public static bool Exists(DirectoryReference Location)
{
return Directory.Exists(Location.FullName);
}
///
/// Enumerate files from a given directory
///
/// Base directory to search in
/// Sequence of file references
public static IEnumerable EnumerateFiles(DirectoryReference BaseDir)
{
foreach (string FileName in Directory.EnumerateFiles(BaseDir.FullName))
{
yield return new FileReference(FileName, FileReference.Sanitize.None);
}
}
///
/// Enumerate files from a given directory
///
/// Base directory to search in
/// Pattern for matching files
/// Sequence of file references
public static IEnumerable EnumerateFiles(DirectoryReference BaseDir, string Pattern)
{
foreach (string FileName in Directory.EnumerateFiles(BaseDir.FullName, Pattern))
{
yield return new FileReference(FileName, FileReference.Sanitize.None);
}
}
///
/// Enumerate files from a given directory
///
/// Base directory to search in
/// Pattern for matching files
/// Options for the search
/// Sequence of file references
public static IEnumerable EnumerateFiles(DirectoryReference BaseDir, string Pattern, SearchOption Option)
{
foreach (string FileName in Directory.EnumerateFiles(BaseDir.FullName, Pattern, Option))
{
yield return new FileReference(FileName, FileReference.Sanitize.None);
}
}
///
/// Enumerate subdirectories in a given directory
///
/// Base directory to search in
/// Sequence of directory references
public static IEnumerable EnumerateDirectories(DirectoryReference BaseDir)
{
foreach (string DirectoryName in Directory.EnumerateDirectories(BaseDir.FullName))
{
yield return new DirectoryReference(DirectoryName, Sanitize.None);
}
}
///
/// Enumerate subdirectories in a given directory
///
/// Base directory to search in
/// Pattern for matching directories
/// Sequence of directory references
public static IEnumerable EnumerateDirectories(DirectoryReference BaseDir, string Pattern)
{
foreach (string DirectoryName in Directory.EnumerateDirectories(BaseDir.FullName, Pattern))
{
yield return new DirectoryReference(DirectoryName, Sanitize.None);
}
}
///
/// Enumerate subdirectories in a given directory
///
/// Base directory to search in
/// Pattern for matching files
/// Options for the search
/// Sequence of directory references
public static IEnumerable EnumerateDirectories(DirectoryReference BaseDir, string Pattern, SearchOption Option)
{
foreach (string DirectoryName in Directory.EnumerateDirectories(BaseDir.FullName, Pattern, Option))
{
yield return new DirectoryReference(DirectoryName, Sanitize.None);
}
}
///
/// Sets the current directory
///
/// Location of the new current directory
public static void SetCurrentDirectory(DirectoryReference Location)
{
Directory.SetCurrentDirectory(Location.FullName);
}
#endregion
}
///
/// Extension methods for passing DirectoryReference arguments
///
public static class DirectoryReferenceExtensionMethods
{
///
/// Manually serialize a file reference to a binary stream.
///
/// Binary writer to write to
/// The directory reference to write
public static void Write(this BinaryWriter Writer, DirectoryReference Directory)
{
Writer.Write((Directory == null) ? String.Empty : Directory.FullName);
}
///
/// Manually deserialize a directory reference from a binary stream.
///
/// Binary reader to read from
/// New DirectoryReference object
public static DirectoryReference ReadDirectoryReference(this BinaryReader Reader)
{
string FullName = Reader.ReadString();
return (FullName.Length == 0) ? null : new DirectoryReference(FullName, DirectoryReference.Sanitize.None);
}
///
/// Writes a directory reference to a binary archive
///
/// The writer to output data to
/// The item to write
public static void WriteDirectoryReference(this BinaryArchiveWriter Writer, DirectoryReference Directory)
{
if(Directory == null)
{
Writer.WriteString(null);
}
else
{
Writer.WriteString(Directory.FullName);
}
}
///
/// Reads a directory reference from a binary archive
///
/// Reader to serialize data from
/// New directory reference instance
public static DirectoryReference ReadDirectoryReference(this BinaryArchiveReader Reader)
{
string FullName = Reader.ReadString();
if(FullName == null)
{
return null;
}
else
{
return new DirectoryReference(FullName, DirectoryReference.Sanitize.None);
}
}
}
}