// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.IO;
using System.Linq;
using UltimateXR.Core;
using UltimateXR.Core.Settings;
using UnityEngine;
namespace UltimateXR.Extensions.System.IO
{
public static class PathExt
{
#region Public Methods
///
/// Like .NET's but addressing some issues discussed in
/// https://www.davidboike.dev/2020/06/path-combine-isnt-as-cross-platform-as-you-think-it-is/
///
/// Base path
/// Additional segments or multi-segment paths
/// Path result of combining the base path and the additional segments or multi-segment paths
public static string Combine(string basePath, params string[] additional)
{
string[][] splits = additional.Select(s => s.Split(PathSplitCharacters)).ToArray();
int totalLength = splits.Sum(arr => arr.Length);
string[] segments = new string[totalLength + 1];
segments[0] = basePath;
var i = 0;
foreach (string[] split in splits)
{
foreach (string value in split)
{
i++;
segments[i] = value;
}
}
return Path.Combine(segments);
}
///
/// Normalizes a path or sub-path so that any wrong directory separator char is fixed for the current platform.
///
/// pathOrSubPath
/// Normalized path
public static string Normalize(string pathOrSubPath)
{
if (Path.IsPathFullyQualified(pathOrSubPath))
{
return Path.GetFullPath(new Uri(pathOrSubPath).LocalPath).TrimEnd(PathSplitCharacters);
}
foreach (char separator in PathSplitCharacters.Where(c => c != Path.DirectorySeparatorChar))
{
pathOrSubPath = pathOrSubPath.Replace(separator, Path.DirectorySeparatorChar);
}
return pathOrSubPath;
}
///
/// Checks if a path is a child of another path.
/// Adapted from https://stackoverflow.com/questions/8091829/how-to-check-if-one-path-is-a-child-of-another-path
///
/// Path candidate
/// Path to check against
/// Whether to also consider the same directory as valid
/// Whether the path is child of the parent path
public static bool IsSubDirectoryOf(string candidate, string other, bool canBeSame = true)
{
var isChild = false;
try
{
// Some initial corrections to avoid false negatives:
var candidateInfo = new DirectoryInfo(candidate.Replace(@"\", @"/").TrimEnd('/'));
var otherInfo = new DirectoryInfo(other.Replace(@"\", @"/").TrimEnd('/'));
// Check if same directory
if (canBeSame && string.Compare(candidateInfo.FullName, otherInfo.FullName, StringComparison.OrdinalIgnoreCase) == 0)
{
return true;
}
// Start traversing upwards
while (candidateInfo.Parent != null)
{
if (string.Equals(candidateInfo.Parent.FullName, otherInfo.FullName, StringComparison.OrdinalIgnoreCase))
{
isChild = true;
break;
}
candidateInfo = candidateInfo.Parent;
}
}
catch (Exception error)
{
if (UxrGlobalSettings.Instance.LogLevelCore >= UxrLogLevel.Errors)
{
Debug.LogError($"{UxrConstants.CoreModule} Unable to check directories {candidate} and {other}: {error}");
}
}
return isChild;
}
#endregion
#region Private Types & Data
private static readonly char[] PathSplitCharacters = { '/', '\\' };
#endregion
}
}