From bc50064e76c88449a0418e11bdc3fb3f67a93003 Mon Sep 17 00:00:00 2001 From: Martin Karing Date: Sat, 18 Dec 2021 23:34:27 +0100 Subject: [PATCH] #413 Fix handling of relative paths Relative paths are now correctly resolved. Files not inside of the base directory are just copied to the output root directory, without any sub directory structure. --- Confuser.Core/ConfuserEngine.cs | 13 +++++++--- Confuser.Core/Utils.cs | 34 +++++++++++++++++-------- ConfuserEx/ViewModel/UI/ProjectTabVM.cs | 2 +- Tests/Confuser.Core.Test/UtilsTest.cs | 27 ++++++++++++++++++++ 4 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 Tests/Confuser.Core.Test/UtilsTest.cs diff --git a/Confuser.Core/ConfuserEngine.cs b/Confuser.Core/ConfuserEngine.cs index 0f33c2886..519f85851 100644 --- a/Confuser.Core/ConfuserEngine.cs +++ b/Confuser.Core/ConfuserEngine.cs @@ -379,10 +379,17 @@ static void OptimizeMethods(ConfuserContext context) { static void EndModule(ConfuserContext context) { string output = context.Modules[context.CurrentModuleIndex].Location; - if (output != null) { + if (!(output is null)) { if (!Path.IsPathRooted(output)) - output = Path.Combine(Environment.CurrentDirectory, output); - output = Utils.GetRelativePath(output, context.BaseDirectory); + output = Path.Combine(context.BaseDirectory, output); + string relativeOutput = Utils.GetRelativePath(output, context.BaseDirectory); + if (relativeOutput is null) { + context.Logger.WarnFormat("Input file is not inside the base directory. Relative path can't be created. Placing file into output root." + + Environment.NewLine + "Responsible file is: {0}", output); + output = Path.GetFileName(output); + } else { + output = relativeOutput; + } } else { output = context.CurrentModule.Name; diff --git a/Confuser.Core/Utils.cs b/Confuser.Core/Utils.cs index e3b3af78a..323b2833c 100644 --- a/Confuser.Core/Utils.cs +++ b/Confuser.Core/Utils.cs @@ -71,19 +71,33 @@ public static void AddListEntry(this IDictionary /// Obtains the relative path from the specified base path. /// - /// The file path. - /// The base path. + /// The file path. + /// The base path. /// The path of relative to . - public static string GetRelativePath(string filespec, string folder) { - //http://stackoverflow.com/a/703292/462805 + public static string GetRelativePath(string fileSpec, string baseDirectory) { + if (fileSpec is null) throw new ArgumentNullException(nameof(fileSpec)); + if (baseDirectory is null) throw new ArgumentNullException(nameof(fileSpec)); - var pathUri = new Uri(filespec); - // Folders must end in a slash - if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString())) { - folder += Path.DirectorySeparatorChar; + return GetRelativePath(new FileInfo(fileSpec), new DirectoryInfo(baseDirectory)); + } + + public static string GetRelativePath(FileInfo fileSpec, DirectoryInfo baseDirectory) { + if (fileSpec is null) throw new ArgumentNullException(nameof(fileSpec)); + if (baseDirectory is null) throw new ArgumentNullException(nameof(fileSpec)); + + if (baseDirectory.FullName.EndsWith(Path.DirectorySeparatorChar.ToString())) { + baseDirectory = new DirectoryInfo(baseDirectory.FullName.TrimEnd(Path.DirectorySeparatorChar)); } - var folderUri = new Uri(folder); - return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar)); + + var relativePath = fileSpec.Name; + var currentDirectory = fileSpec.Directory; + while (!(currentDirectory is null) && !string.Equals(currentDirectory.FullName, baseDirectory.FullName, StringComparison.OrdinalIgnoreCase)) { + relativePath = currentDirectory.Name + Path.DirectorySeparatorChar + relativePath; + currentDirectory = currentDirectory.Parent; + } + + if (currentDirectory is null) return null; //file is not inside the base directory + return relativePath; } /// diff --git a/ConfuserEx/ViewModel/UI/ProjectTabVM.cs b/ConfuserEx/ViewModel/UI/ProjectTabVM.cs index 26eb74763..899dd5f9f 100644 --- a/ConfuserEx/ViewModel/UI/ProjectTabVM.cs +++ b/ConfuserEx/ViewModel/UI/ProjectTabVM.cs @@ -117,7 +117,7 @@ void AddModule(string file) { } var module = new ProjectModuleVM(App.Project, new ProjectModule()); try { - module.Path = Confuser.Core.Utils.GetRelativePath(file, App.Project.BaseDirectory); + module.Path = Confuser.Core.Utils.GetRelativePath(file, App.Project.BaseDirectory) ?? file; } catch { module.Path = file; diff --git a/Tests/Confuser.Core.Test/UtilsTest.cs b/Tests/Confuser.Core.Test/UtilsTest.cs new file mode 100644 index 000000000..5a1217b96 --- /dev/null +++ b/Tests/Confuser.Core.Test/UtilsTest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Xunit; + +namespace Confuser.Core.Test { + public class UtilsTest { + [Theory] + [MemberData(nameof(BuildRelativePathTestData))] + [Trait("Issue", "https://github.com/mkaring/ConfuserEx/issues/413")] + public void BuildRelativePath(string baseDirectory, string fileReference, string expectedRelativePath) => + Assert.Equal(expectedRelativePath, Utils.GetRelativePath(fileReference, baseDirectory), ignoreCase: true); + + public static IEnumerable BuildRelativePathTestData() { + yield return new object[] { "C:\\Test", "C:\\Test\\Asm.dll", "Asm.dll" }; + yield return new object[] { "C:\\Test\\", "C:\\Test\\Asm.dll", "Asm.dll" }; + yield return new object[] { "C:\\Test", "C:\\Test\\Test2\\Asm.dll", "Test2\\Asm.dll" }; + yield return new object[] { "C:\\Test\\", "C:\\Test\\Test2\\Asm.dll", "Test2\\Asm.dll" }; + yield return new object[] { "C:\\Test", "C:\\Test\\Test2\\Test3\\Asm.dll", "Test2\\Test3\\Asm.dll" }; + yield return new object[] { "C:\\Test\\", "C:\\Test\\Test2\\Test3\\Asm.dll", "Test2\\Test3\\Asm.dll" }; + yield return new object[] { "C:\\Test", "C:\\Test2\\Asm.dll", null }; + yield return new object[] { "C:\\Test\\", "C:\\Test2\\Asm.dll", null }; + + // Only for case insensitive file systems (windows) + yield return new object[] { "C:\\Test", "c:\\test\\test2\\test3\\asm.dll", "Test2\\Test3\\Asm.dll" }; + yield return new object[] { "C:\\Test", "C:\\TEST\\TEST2\\TEST3\\ASM.DLL", "Test2\\Test3\\Asm.dll" }; + } + } +}