TeamCity.CSharpInteractive/MSBuildArgumentsTool.cs (54 lines of code) (raw):
// ReSharper disable InconsistentNaming
namespace TeamCity.CSharpInteractive;
using System.Text;
internal class MSBuildArgumentsTool : IMSBuildArgumentsTool
{
private const char Marker = '%';
public string Unescape(string escaped)
{
if (string.IsNullOrEmpty(escaped))
{
return escaped;
}
var markerIndex = escaped.IndexOf(Marker);
if (markerIndex == -1)
{
return escaped;
}
var unescaped = new StringBuilder(escaped.Length);
var length = escaped.Length;
var position = 0;
while (markerIndex != -1)
{
if (
markerIndex <= length - 3
&& TryDecode(escaped[markerIndex + 1], out var first)
&& TryDecode(escaped[markerIndex + 2], out var second))
{
unescaped.Append(escaped, position, markerIndex - position);
unescaped.Append((char)((first << 4) + second));
position = markerIndex + 3;
}
markerIndex = escaped.IndexOf(Marker, markerIndex + 1);
}
unescaped.Append(escaped, position, length - position);
return unescaped.ToString();
}
private static bool TryDecode(char ch, out int value)
{
switch (ch)
{
case >= '0' and <= '9':
value = ch - '0';
return true;
case >= 'A' and <= 'F':
value = ch - 'A' + 10;
return true;
case >= 'a' and <= 'f':
value = ch - 'a' + 10;
return true;
default:
value = default;
return false;
}
}
}