From 4dcc6904b9e72ac3567dfafe3824c2de48218b58 Mon Sep 17 00:00:00 2001 From: atravita-mods <94934860+atravita-mods@users.noreply.github.com> Date: Sun, 16 Oct 2022 18:04:19 -0400 Subject: fix issues with subfolders --- src/SMAPI.Tests/Core/AssetNameTests.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/SMAPI.Tests/Core') diff --git a/src/SMAPI.Tests/Core/AssetNameTests.cs b/src/SMAPI.Tests/Core/AssetNameTests.cs index 655e9bae..fe70e330 100644 --- a/src/SMAPI.Tests/Core/AssetNameTests.cs +++ b/src/SMAPI.Tests/Core/AssetNameTests.cs @@ -243,6 +243,20 @@ namespace SMAPI.Tests.Core return result; } + [TestCase("Mods/SomeMod/SomeSubdirectory", "Mods/Some", true, ExpectedResult = true)] + [TestCase("Mods/SomeMod/SomeSubdirectory", "Mods/Some", false, ExpectedResult = false)] + public bool StartsWith_SubfolderWithPartial(string mainAssetName, string otherAssetName, bool allowSubfolder) + { + // arrange + mainAssetName = PathUtilities.NormalizeAssetName(mainAssetName); + + // act + AssetName name = AssetName.Parse(mainAssetName, _ => null); + + // assert value + return name.StartsWith(otherAssetName, allowPartialWord: true, allowSubfolder: allowSubfolder); + } + /**** ** GetHashCode -- cgit From b99dbf53bda9dc1178a3b6e8cbafea609f3ee6dc Mon Sep 17 00:00:00 2001 From: atravita-mods <94934860+atravita-mods@users.noreply.github.com> Date: Tue, 18 Oct 2022 18:58:41 -0400 Subject: fix this case. --- src/SMAPI.Tests/Core/AssetNameTests.cs | 2 ++ src/SMAPI/Framework/Content/AssetName.cs | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'src/SMAPI.Tests/Core') diff --git a/src/SMAPI.Tests/Core/AssetNameTests.cs b/src/SMAPI.Tests/Core/AssetNameTests.cs index fe70e330..fbc94e95 100644 --- a/src/SMAPI.Tests/Core/AssetNameTests.cs +++ b/src/SMAPI.Tests/Core/AssetNameTests.cs @@ -245,6 +245,8 @@ namespace SMAPI.Tests.Core [TestCase("Mods/SomeMod/SomeSubdirectory", "Mods/Some", true, ExpectedResult = true)] [TestCase("Mods/SomeMod/SomeSubdirectory", "Mods/Some", false, ExpectedResult = false)] + [TestCase("Mods/Jasper/Data", "Mods/Jas/Image", true, ExpectedResult = false)] + [TestCase("Mods/Jasper/Data", "Mods/Jas/Image", true, ExpectedResult = false)] public bool StartsWith_SubfolderWithPartial(string mainAssetName, string otherAssetName, bool allowSubfolder) { // arrange diff --git a/src/SMAPI/Framework/Content/AssetName.cs b/src/SMAPI/Framework/Content/AssetName.cs index 9d59f222..7b87c0c5 100644 --- a/src/SMAPI/Framework/Content/AssetName.cs +++ b/src/SMAPI/Framework/Content/AssetName.cs @@ -179,6 +179,10 @@ namespace StardewModdingAPI.Framework.Content } else { + // mismatch: prefix has more beyond this, and this segment isn't an exact match + if (prefixParts.Remainder.Length != 0) + return false; + // mismatch: cur segment doesn't start with prefix if (!curParts.Current.StartsWith(prefixParts.Current, StringComparison.OrdinalIgnoreCase)) return false; -- cgit From 303b3924ae3ef905d77b9d7ef0f9efc70e58c2b8 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 10 Nov 2022 21:50:01 -0500 Subject: fix case where prefix ends with a path separator --- src/SMAPI.Tests/Core/AssetNameTests.cs | 8 +++++++- src/SMAPI/Framework/Content/AssetName.cs | 23 ++++++++++++----------- 2 files changed, 19 insertions(+), 12 deletions(-) (limited to 'src/SMAPI.Tests/Core') diff --git a/src/SMAPI.Tests/Core/AssetNameTests.cs b/src/SMAPI.Tests/Core/AssetNameTests.cs index fbc94e95..fdaa2c01 100644 --- a/src/SMAPI.Tests/Core/AssetNameTests.cs +++ b/src/SMAPI.Tests/Core/AssetNameTests.cs @@ -151,6 +151,12 @@ namespace SMAPI.Tests.Core // with locale codes [TestCase("Data/Achievements.fr-FR", "Data/Achievements", ExpectedResult = true)] + + // prefix ends with path separator + [TestCase("Data/Events/Boop", "Data/Events/", ExpectedResult = true)] + [TestCase("Data/Events/Boop", "Data/Events\\", ExpectedResult = true)] + [TestCase("Data/Events", "Data/Events/", ExpectedResult = false)] + [TestCase("Data/Events", "Data/Events\\", ExpectedResult = false)] public bool StartsWith_SimpleCases(string mainAssetName, string prefix) { // arrange @@ -247,7 +253,7 @@ namespace SMAPI.Tests.Core [TestCase("Mods/SomeMod/SomeSubdirectory", "Mods/Some", false, ExpectedResult = false)] [TestCase("Mods/Jasper/Data", "Mods/Jas/Image", true, ExpectedResult = false)] [TestCase("Mods/Jasper/Data", "Mods/Jas/Image", true, ExpectedResult = false)] - public bool StartsWith_SubfolderWithPartial(string mainAssetName, string otherAssetName, bool allowSubfolder) + public bool StartsWith_PartialMatchInPathSegment(string mainAssetName, string otherAssetName, bool allowSubfolder) { // arrange mainAssetName = PathUtilities.NormalizeAssetName(mainAssetName); diff --git a/src/SMAPI/Framework/Content/AssetName.cs b/src/SMAPI/Framework/Content/AssetName.cs index 7b87c0c5..99968299 100644 --- a/src/SMAPI/Framework/Content/AssetName.cs +++ b/src/SMAPI/Framework/Content/AssetName.cs @@ -138,37 +138,38 @@ namespace StardewModdingAPI.Framework.Content return false; // get initial values - ReadOnlySpan trimmed = prefix.AsSpan().Trim(); - if (trimmed.Length == 0) + ReadOnlySpan trimmedPrefix = prefix.AsSpan().Trim(); + if (trimmedPrefix.Length == 0) return true; ReadOnlySpan pathSeparators = new(ToolkitPathUtilities.PossiblePathSeparators); // just to simplify calling other span APIs // asset keys can't have a leading slash, but AssetPathYielder will trim them - if (pathSeparators.Contains(trimmed[0])) + if (pathSeparators.Contains(trimmedPrefix[0])) return false; // compare segments AssetNamePartEnumerator curParts = new(this.Name); - AssetNamePartEnumerator prefixParts = new(trimmed); + AssetNamePartEnumerator prefixParts = new(trimmedPrefix); while (true) { bool curHasMore = curParts.MoveNext(); bool prefixHasMore = prefixParts.MoveNext(); - // reached end of prefix or asset name + // reached end for one side if (prefixHasMore != curHasMore) { // mismatch: prefix is longer if (prefixHasMore) return false; - // possible match: all prefix segments matched. - return allowSubfolder || (pathSeparators.Contains(trimmed[^1]) ? curParts.Remainder.Length == 0 : curParts.Current.Length == 0); + // match if subfolder paths are fine (e.g. prefix 'Data/Events' with target 'Data/Events/Beach') + return allowSubfolder; } - // match: previous segments matched exactly and both reached the end + // previous segments matched exactly and both reached the end + // match if prefix doesn't end with '/' (which should only match subfolders) if (!prefixHasMore) - return true; + return !pathSeparators.Contains(trimmedPrefix[^1]); // compare segment if (curParts.Current.Length == prefixParts.Current.Length) @@ -188,7 +189,7 @@ namespace StardewModdingAPI.Framework.Content return false; // mismatch: something like "Maps/" would need an exact match - if (pathSeparators.Contains(trimmed[^1])) + if (pathSeparators.Contains(trimmedPrefix[^1])) return false; // mismatch: partial word match not allowed, and the first or last letter of the suffix isn't a word separator @@ -196,7 +197,7 @@ namespace StardewModdingAPI.Framework.Content return false; // possible match - return allowSubfolder || (pathSeparators.Contains(trimmed[^1]) ? curParts.Remainder.IndexOfAny(ToolkitPathUtilities.PossiblePathSeparators) < 0 : curParts.Remainder.Length == 0); + return allowSubfolder || (pathSeparators.Contains(trimmedPrefix[^1]) ? curParts.Remainder.IndexOfAny(ToolkitPathUtilities.PossiblePathSeparators) < 0 : curParts.Remainder.Length == 0); } } } -- cgit