Improve OSC 8 Hyperlink parsing logic (#7962)
This PR improves the OSC 8 Hyperlink parsing logic, by adding support to `:` in params. ## Validation Steps Performed Tests added & passed.
This commit is contained in:
parent
60f1b0b285
commit
3181b6a517
|
@ -884,11 +884,16 @@ try
|
|||
}
|
||||
CATCH_LOG_RETURN_FALSE()
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26445) // Suppress lifetime check for a reference to gsl::span or std::string_view
|
||||
|
||||
// Routine Description:
|
||||
// - Given a hyperlink string, attempts to parse the URI encoded. An 'id' parameter
|
||||
// may be provided.
|
||||
// If there is a URI, the well formatted string looks like:
|
||||
// "<params>;<URI>"
|
||||
// To be specific, params is an optional list of key=value assignments, separated by the ':'. Example:
|
||||
// "id=xyz123:foo=bar:baz=value"
|
||||
// If there is no URI, we need to close the hyperlink and the string looks like:
|
||||
// ";"
|
||||
// Arguments:
|
||||
|
@ -903,18 +908,24 @@ bool OutputStateMachineEngine::_ParseHyperlink(const std::wstring_view string,
|
|||
{
|
||||
params.clear();
|
||||
uri.clear();
|
||||
const auto len = string.size();
|
||||
|
||||
if (string == L";")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const size_t midPos = string.find(';');
|
||||
if (midPos != std::wstring::npos)
|
||||
{
|
||||
if (len != 1)
|
||||
uri = string.substr(midPos + 1);
|
||||
const auto paramStr = string.substr(0, midPos);
|
||||
const auto paramParts = Utils::SplitString(paramStr, ':');
|
||||
for (const auto& part : paramParts)
|
||||
{
|
||||
uri = string.substr(midPos + 1);
|
||||
const auto paramStr = string.substr(0, midPos);
|
||||
const auto idPos = paramStr.find(hyperlinkIDParameter);
|
||||
const auto idPos = part.find(hyperlinkIDParameter);
|
||||
if (idPos != std::wstring::npos)
|
||||
{
|
||||
params = paramStr.substr(idPos + hyperlinkIDParameter.size());
|
||||
params = part.substr(idPos + hyperlinkIDParameter.size());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -922,6 +933,8 @@ bool OutputStateMachineEngine::_ParseHyperlink(const std::wstring_view string,
|
|||
return false;
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
// Routine Description:
|
||||
// - OSC 10, 11, 12 ; spec ST
|
||||
// spec: The colors are specified by name or RGB specification as per XParseColor
|
||||
|
|
|
@ -3239,6 +3239,54 @@ class StateMachineExternalTest final
|
|||
VERIFY_IS_FALSE(pDispatch->_hyperlinkMode);
|
||||
VERIFY_IS_TRUE(pDispatch->_uri.empty());
|
||||
|
||||
// Let's try more complicated params and URLs
|
||||
mach.ProcessString(L"\x1b]8;id=testId;https://example.com\x9c");
|
||||
VERIFY_IS_TRUE(pDispatch->_hyperlinkMode);
|
||||
VERIFY_ARE_EQUAL(pDispatch->_uri, L"https://example.com");
|
||||
VERIFY_ARE_EQUAL(pDispatch->_customId, L"testId");
|
||||
|
||||
mach.ProcessString(L"\x1b]8;;\x9c");
|
||||
VERIFY_IS_FALSE(pDispatch->_hyperlinkMode);
|
||||
VERIFY_IS_TRUE(pDispatch->_uri.empty());
|
||||
|
||||
// Multiple params
|
||||
mach.ProcessString(L"\x1b]8;id=testId:foo=bar;https://example.com\x9c");
|
||||
VERIFY_IS_TRUE(pDispatch->_hyperlinkMode);
|
||||
VERIFY_ARE_EQUAL(pDispatch->_uri, L"https://example.com");
|
||||
VERIFY_ARE_EQUAL(pDispatch->_customId, L"testId");
|
||||
|
||||
mach.ProcessString(L"\x1b]8;;\x9c");
|
||||
VERIFY_IS_FALSE(pDispatch->_hyperlinkMode);
|
||||
VERIFY_IS_TRUE(pDispatch->_uri.empty());
|
||||
|
||||
mach.ProcessString(L"\x1b]8;foo=bar:id=testId;https://example.com\x9c");
|
||||
VERIFY_IS_TRUE(pDispatch->_hyperlinkMode);
|
||||
VERIFY_ARE_EQUAL(pDispatch->_uri, L"https://example.com");
|
||||
VERIFY_ARE_EQUAL(pDispatch->_customId, L"testId");
|
||||
|
||||
mach.ProcessString(L"\x1b]8;;\x9c");
|
||||
VERIFY_IS_FALSE(pDispatch->_hyperlinkMode);
|
||||
VERIFY_IS_TRUE(pDispatch->_uri.empty());
|
||||
|
||||
// URIs with query strings
|
||||
mach.ProcessString(L"\x1b]8;id=testId;https://example.com?query1=value1\x9c");
|
||||
VERIFY_IS_TRUE(pDispatch->_hyperlinkMode);
|
||||
VERIFY_ARE_EQUAL(pDispatch->_uri, L"https://example.com?query1=value1");
|
||||
VERIFY_ARE_EQUAL(pDispatch->_customId, L"testId");
|
||||
|
||||
mach.ProcessString(L"\x1b]8;;\x9c");
|
||||
VERIFY_IS_FALSE(pDispatch->_hyperlinkMode);
|
||||
VERIFY_IS_TRUE(pDispatch->_uri.empty());
|
||||
|
||||
mach.ProcessString(L"\x1b]8;id=testId;https://example.com?query1=value1;value2;value3\x9c");
|
||||
VERIFY_IS_TRUE(pDispatch->_hyperlinkMode);
|
||||
VERIFY_ARE_EQUAL(pDispatch->_uri, L"https://example.com?query1=value1;value2;value3");
|
||||
VERIFY_ARE_EQUAL(pDispatch->_customId, L"testId");
|
||||
|
||||
mach.ProcessString(L"\x1b]8;;\x9c");
|
||||
VERIFY_IS_FALSE(pDispatch->_hyperlinkMode);
|
||||
VERIFY_IS_TRUE(pDispatch->_uri.empty());
|
||||
|
||||
pDispatch->ClearState();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace Microsoft::Console::Utils
|
|||
|
||||
bool HexToUint(const wchar_t wch, unsigned int& value) noexcept;
|
||||
bool StringToUint(const std::wstring_view wstr, unsigned int& value);
|
||||
std::vector<std::wstring_view> SplitString(const std::wstring_view wstr, const wchar_t delimiter);
|
||||
std::vector<std::wstring_view> SplitString(const std::wstring_view wstr, const wchar_t delimiter) noexcept;
|
||||
|
||||
constexpr uint16_t EndianSwap(uint16_t value)
|
||||
{
|
||||
|
|
|
@ -104,6 +104,8 @@ void UtilsTests::TestSplitString()
|
|||
VERIFY_ARE_EQUAL(0u, result.size());
|
||||
result = SplitString(L"1", L';');
|
||||
VERIFY_ARE_EQUAL(1u, result.size());
|
||||
result = SplitString(L";", L';');
|
||||
VERIFY_ARE_EQUAL(2u, result.size());
|
||||
result = SplitString(L"123", L';');
|
||||
VERIFY_ARE_EQUAL(1u, result.size());
|
||||
|
||||
|
|
|
@ -391,7 +391,8 @@ bool Utils::StringToUint(const std::wstring_view wstr,
|
|||
// Return Value:
|
||||
// - a vector containing the result string parts.
|
||||
std::vector<std::wstring_view> Utils::SplitString(const std::wstring_view wstr,
|
||||
const wchar_t delimiter)
|
||||
const wchar_t delimiter) noexcept
|
||||
try
|
||||
{
|
||||
std::vector<std::wstring_view> result;
|
||||
size_t current = 0;
|
||||
|
@ -421,6 +422,11 @@ std::vector<std::wstring_view> Utils::SplitString(const std::wstring_view wstr,
|
|||
|
||||
return result;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_CAUGHT_EXCEPTION();
|
||||
return {};
|
||||
}
|
||||
|
||||
// Routine Description:
|
||||
// - Shorthand check if a handle value is null or invalid.
|
||||
|
|
Loading…
Reference in a new issue