Compare commits

...

3 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
fbb8fbea3b Add more robust error handling for SanitizeAndNormalize
- Check return value of second NormalizeString call
- Add check for empty normalized result after processing
- Return sanitized input if normalized result is empty

Co-authored-by: moooyo <42196638+moooyo@users.noreply.github.com>
2026-01-22 09:33:38 +00:00
copilot-swe-agent[bot]
ea6f3e0bff Fix PowerRename regex $ not working due to normalization bug
The SanitizeAndNormalize function was treating single-character inputs
like '$' as empty strings when NormalizeString returned size=1.
Added check to return sanitized input unchanged when size==1.

Co-authored-by: moooyo <42196638+moooyo@users.noreply.github.com>
2026-01-22 09:33:05 +00:00
copilot-swe-agent[bot]
a6870d776d Initial plan 2026-01-22 09:25:21 +00:00
2 changed files with 55 additions and 1 deletions

View File

@@ -39,10 +39,23 @@ static std::wstring SanitizeAndNormalize(const std::wstring& input)
return sanitized; // Return unaltered if normalization fails.
}
// If size is 1, it means the normalized form is just a null terminator (empty string).
// Return the sanitized input unchanged to preserve the original input.
if (size == 1)
{
return sanitized;
}
// Perform the normalization.
std::wstring normalized;
normalized.resize(size);
NormalizeString(NormalizationC, sanitized.c_str(), -1, &normalized[0], size);
int actualSize = NormalizeString(NormalizationC, sanitized.c_str(), -1, &normalized[0], size);
// If normalization failed on the second call, return sanitized input.
if (actualSize <= 0)
{
return sanitized;
}
// Remove the explicit null terminator added by NormalizeString.
if (!normalized.empty() && normalized.back() == L'\0')
@@ -50,6 +63,13 @@ static std::wstring SanitizeAndNormalize(const std::wstring& input)
normalized.pop_back();
}
// If normalization resulted in an empty string, return the sanitized input instead.
// This can happen with certain edge-case inputs where the normalized form is empty.
if (normalized.empty())
{
return sanitized;
}
return normalized;
}

View File

@@ -695,6 +695,40 @@ TEST_METHOD(VerifyUnicodeAndWhitespaceNormalizationRegex)
VerifyNormalizationHelper(UseRegularExpressions);
}
TEST_METHOD(VerifyDollarSignEndOfLineRegex)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
// Test that $ matches end of line and allows appending text
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"$") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L" X") == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foobar X", result);
CoTaskMemFree(result);
}
TEST_METHOD(VerifyDollarSignWithTextRegex)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
// Test that word$ matches end of specific word
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"bar$") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"baz") == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foobaz", result);
CoTaskMemFree(result);
}
#ifndef TESTS_PARTIAL
};
}