From 8add7e439af3c55c6fd7a669974dbf87048bc3cc Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Wed, 30 Oct 2019 20:00:25 -0400 Subject: [PATCH] Clean up Uri.UnescapeDataString (dotnet/corefx#42225) - Use string.IndexOf rather than an open-coded, unsafe loop. - Avoid an unnecessary SequenceEquals at the end: we're only at this point if a `%` was found highlighting that something escaped was found. - Use stack memory for smaller inputs if possible, to avoid unnecessary ArrayPool interaction - Remove an unnecessary argument to a helper function. - Fix ValueStringBuilder.Grow to only copy the contained data. Commit migrated from https://github.com/dotnet/corefx/commit/04f79d96e8ce89e738e7f8f595f43a52e9cdd4a4 --- .../System.Private.Uri/src/System/UriExt.cs | 39 +++++++++------------- .../System.Private.Uri/src/System/UriHelper.cs | 7 ++-- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/libraries/System.Private.Uri/src/System/UriExt.cs b/src/libraries/System.Private.Uri/src/System/UriExt.cs index 9fc6bd5..321b008 100644 --- a/src/libraries/System.Private.Uri/src/System/UriExt.cs +++ b/src/libraries/System.Private.Uri/src/System/UriExt.cs @@ -546,30 +546,21 @@ namespace System if (stringToUnescape.Length == 0) return string.Empty; - unsafe - { - fixed (char* pStr = stringToUnescape) - { - int position; - for (position = 0; position < stringToUnescape.Length; ++position) - if (pStr[position] == '%') - break; - - if (position == stringToUnescape.Length) - return stringToUnescape; - - UnescapeMode unescapeMode = UnescapeMode.Unescape | UnescapeMode.UnescapeAll; - position = 0; - ValueStringBuilder vsb = new ValueStringBuilder(stringToUnescape.Length); - UriHelper.UnescapeString(stringToUnescape, 0, stringToUnescape.Length, ref vsb, ref position, - c_DummyChar, c_DummyChar, c_DummyChar, unescapeMode, null, false); - - ReadOnlySpan resultSpan = vsb.AsSpan(0, position); - string result = resultSpan.SequenceEqual(stringToUnescape) ? stringToUnescape : resultSpan.ToString(); - vsb.Dispose(); - return result; - } - } + int position = stringToUnescape.IndexOf('%'); + if (position == -1) + return stringToUnescape; + + var vsb = new ValueStringBuilder(stackalloc char[256]); + vsb.EnsureCapacity(stringToUnescape.Length); + + vsb.Append(stringToUnescape.AsSpan(0, position)); + UriHelper.UnescapeString( + stringToUnescape, position, stringToUnescape.Length, ref vsb, + c_DummyChar, c_DummyChar, c_DummyChar, + UnescapeMode.Unescape | UnescapeMode.UnescapeAll, + syntax: null, isQuery: false); + + return vsb.ToString(); } // Where stringToEscape is intended to be a completely unescaped URI string. diff --git a/src/libraries/System.Private.Uri/src/System/UriHelper.cs b/src/libraries/System.Private.Uri/src/System/UriHelper.cs index 3bfb7b9..c903f47 100644 --- a/src/libraries/System.Private.Uri/src/System/UriHelper.cs +++ b/src/libraries/System.Private.Uri/src/System/UriHelper.cs @@ -342,14 +342,11 @@ namespace System // For this reason it returns a char[] that is usually the same ref as the input "dest" value. // internal static unsafe void UnescapeString(string input, int start, int end, ref ValueStringBuilder dest, - ref int destPosition, char rsvd1, char rsvd2, char rsvd3, UnescapeMode unescapeMode, UriParser? syntax, - bool isQuery) + char rsvd1, char rsvd2, char rsvd3, UnescapeMode unescapeMode, UriParser? syntax, bool isQuery) { fixed (char* pStr = input) { - UnescapeString(pStr, start, end, ref dest, rsvd1, rsvd2, rsvd3, unescapeMode, - syntax, isQuery); - destPosition = dest.Length; + UnescapeString(pStr, start, end, ref dest, rsvd1, rsvd2, rsvd3, unescapeMode, syntax, isQuery); } } internal static unsafe void UnescapeString(char* pStr, int start, int end, ref ValueStringBuilder dest, -- 2.7.4