2021-09-27 12:42:46 +00:00
|
|
|
using System;
|
|
|
|
using System.Linq;
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
namespace Wabbajack.Paths;
|
|
|
|
|
2022-05-28 22:53:52 +00:00
|
|
|
public struct RelativePath : IPath, IEquatable<RelativePath>, IComparable<RelativePath>
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
internal readonly string[] Parts;
|
|
|
|
|
2022-05-28 22:53:52 +00:00
|
|
|
private int _hashCode = 0;
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
internal RelativePath(string[] parts)
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
Parts = parts;
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public static explicit operator RelativePath(string i)
|
|
|
|
{
|
|
|
|
var splits = i.Split(AbsolutePath.StringSplits, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
if (splits.Length >= 1 && splits[0].Contains(':'))
|
|
|
|
throw new PathException($"Tried to parse `{i} but `:` not valid in a path name");
|
|
|
|
return new RelativePath(splits);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public static explicit operator string(RelativePath i)
|
|
|
|
{
|
|
|
|
return i.ToString();
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public Extension Extension => Extension.FromPath(Parts[^1]);
|
|
|
|
public RelativePath FileName => Parts.Length == 1 ? this : new RelativePath(new[] {Parts[^1]});
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public RelativePath ReplaceExtension(Extension newExtension)
|
|
|
|
{
|
|
|
|
var paths = new string[Parts.Length];
|
|
|
|
Array.Copy(Parts, paths, paths.Length);
|
|
|
|
var oldName = paths[^1];
|
|
|
|
var newName = ReplaceExtension(oldName, newExtension);
|
|
|
|
paths[^1] = newName;
|
|
|
|
return new RelativePath(paths);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
internal static string ReplaceExtension(string oldName, Extension newExtension)
|
|
|
|
{
|
|
|
|
var oldExtLength = oldName.LastIndexOf(".", StringComparison.CurrentCultureIgnoreCase);
|
|
|
|
if (oldExtLength < 0)
|
|
|
|
oldExtLength = 0;
|
|
|
|
else
|
|
|
|
oldExtLength++;
|
|
|
|
|
|
|
|
var newName = oldName[..^oldExtLength] + newExtension;
|
|
|
|
return newName;
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public RelativePath WithExtension(Extension? ext)
|
|
|
|
{
|
|
|
|
var parts = new string[Parts.Length];
|
|
|
|
Array.Copy(Parts, parts, Parts.Length);
|
|
|
|
parts[^1] = parts[^1] + ext;
|
|
|
|
return new RelativePath(parts);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public AbsolutePath RelativeTo(AbsolutePath basePath)
|
|
|
|
{
|
|
|
|
var newArray = new string[basePath.Parts.Length + Parts.Length];
|
|
|
|
Array.Copy(basePath.Parts, 0, newArray, 0, basePath.Parts.Length);
|
|
|
|
Array.Copy(Parts, 0, newArray, basePath.Parts.Length, Parts.Length);
|
|
|
|
return new AbsolutePath(newArray, basePath.PathFormat);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public bool InFolder(RelativePath parent)
|
|
|
|
{
|
2022-07-27 03:56:30 +00:00
|
|
|
return ArrayExtensions.AreEqualIgnoreCase(parent.Parts, 0, Parts, 0, parent.Parts.Length);
|
2021-10-23 16:51:17 +00:00
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public override string ToString()
|
|
|
|
{
|
|
|
|
if (Parts == null || Parts.Length == 0) return "";
|
|
|
|
return string.Join('\\', Parts);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public override int GetHashCode()
|
|
|
|
{
|
2022-05-28 22:53:52 +00:00
|
|
|
if (_hashCode != 0) return _hashCode;
|
|
|
|
|
|
|
|
_hashCode = Parts.Aggregate(0,
|
2021-10-23 16:51:17 +00:00
|
|
|
(current, part) => current ^ part.GetHashCode(StringComparison.CurrentCultureIgnoreCase));
|
2022-05-28 22:53:52 +00:00
|
|
|
return _hashCode;
|
2021-10-23 16:51:17 +00:00
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public bool Equals(RelativePath other)
|
|
|
|
{
|
|
|
|
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
|
|
|
if (other.Parts == default) return other.Parts == Parts;
|
|
|
|
|
|
|
|
if (other.Parts.Length != Parts.Length) return false;
|
|
|
|
for (var idx = 0; idx < Parts.Length; idx++)
|
|
|
|
if (!Parts[idx].Equals(other.Parts[idx], StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public override bool Equals(object? obj)
|
|
|
|
{
|
|
|
|
return obj is RelativePath other && Equals(other);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public static bool operator ==(RelativePath a, RelativePath b)
|
|
|
|
{
|
|
|
|
return a.Equals(b);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public static bool operator !=(RelativePath a, RelativePath b)
|
|
|
|
{
|
|
|
|
return !a.Equals(b);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public int CompareTo(RelativePath other)
|
|
|
|
{
|
|
|
|
return ArrayExtensions.CompareString(Parts, other.Parts);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public int Depth => Parts.Length;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public RelativePath Combine(params object[] paths)
|
|
|
|
{
|
|
|
|
var converted = paths.Select(p =>
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
return p switch
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
string s => (RelativePath) s,
|
|
|
|
RelativePath path => path,
|
|
|
|
_ => throw new PathException($"Cannot cast {p} of type {p.GetType()} to Path")
|
|
|
|
};
|
|
|
|
}).ToArray();
|
|
|
|
return Combine(converted);
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public RelativePath Combine(params RelativePath[] paths)
|
|
|
|
{
|
|
|
|
var newLen = Parts.Length + paths.Sum(p => p.Parts.Length);
|
|
|
|
var newParts = new string[newLen];
|
|
|
|
Array.Copy(Parts, newParts, Parts.Length);
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
var toIdx = Parts.Length;
|
|
|
|
foreach (var p in paths)
|
|
|
|
{
|
|
|
|
Array.Copy(p.Parts, 0, newParts, toIdx, p.Parts.Length);
|
|
|
|
toIdx += p.Parts.Length;
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
return new RelativePath(newParts);
|
|
|
|
}
|
|
|
|
|
|
|
|
public RelativePath Parent
|
|
|
|
{
|
|
|
|
get
|
2021-09-27 12:42:46 +00:00
|
|
|
{
|
2021-10-23 16:51:17 +00:00
|
|
|
if (Parts.Length <= 1)
|
|
|
|
throw new PathException("Can't get parent of a top level path");
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
var newParts = new string[Parts.Length - 1];
|
|
|
|
Array.Copy(Parts, newParts, Parts.Length - 1);
|
|
|
|
return new RelativePath(newParts);
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
2021-10-23 16:51:17 +00:00
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public RelativePath WithoutExtension()
|
|
|
|
{
|
|
|
|
var ext = Extension;
|
|
|
|
return Parts[^1][..^ext.ToString().Length].ToRelativePath();
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2021-10-23 16:51:17 +00:00
|
|
|
public RelativePath TopParent => new(Parts[..1]);
|
|
|
|
public RelativePath FileNameWithoutExtension => Parts[^1][..Extension.ToString().Length].ToRelativePath();
|
2022-05-30 20:50:24 +00:00
|
|
|
public int Level => Parts.Length;
|
2021-09-27 12:42:46 +00:00
|
|
|
|
2022-08-22 15:34:19 +00:00
|
|
|
public readonly bool EndsWith(string postfix)
|
2021-10-23 16:51:17 +00:00
|
|
|
{
|
|
|
|
return Parts[^1].EndsWith(postfix);
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool FileNameStartsWith(string mrkinn)
|
|
|
|
{
|
|
|
|
return Parts[^1].StartsWith(mrkinn);
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|
2022-05-17 22:32:53 +00:00
|
|
|
|
|
|
|
public bool StartsWith(string s)
|
|
|
|
{
|
|
|
|
return ToString().StartsWith(s);
|
|
|
|
}
|
2022-05-30 20:50:24 +00:00
|
|
|
|
|
|
|
public string GetPart(int i)
|
|
|
|
{
|
|
|
|
return Parts[i];
|
|
|
|
}
|
2021-09-27 12:42:46 +00:00
|
|
|
}
|