/// <summary> /// Replaces all instances of %XX in the input string with the character represented /// by the hexadecimal number XX. /// </summary> /// <param name="escapedString">The string to unescape.</param> /// <param name="escapingWasNecessary">Whether any replacements were made.</param> /// <returns>unescaped string</returns> internal static string UnescapeAll ( string escapedString, out bool escapingWasNecessary ) { escapingWasNecessary = false; // If the string doesn't contain anything, then by definition it doesn't // need unescaping. if (String.IsNullOrEmpty(escapedString)) { return(escapedString); } // If there are no percent signs, just return the original string immediately. // Don't even instantiate the StringBuilder. int indexOfPercent = escapedString.IndexOf('%'); if (indexOfPercent == -1) { return(escapedString); } // This is where we're going to build up the final string to return to the caller. StringBuilder unescapedString = StringBuilderCache.Acquire(escapedString.Length); int currentPosition = 0; // Loop until there are no more percent signs in the input string. while (indexOfPercent != -1) { // There must be two hex characters following the percent sign // for us to even consider doing anything with this. if ( (indexOfPercent <= (escapedString.Length - 3)) && IsHexDigit(escapedString[indexOfPercent + 1]) && IsHexDigit(escapedString[indexOfPercent + 2]) ) { // First copy all the characters up to the current percent sign into // the destination. unescapedString.Append(escapedString, currentPosition, indexOfPercent - currentPosition); // Convert the %XX to an actual real character. string hexString = escapedString.Substring(indexOfPercent + 1, 2); char unescapedCharacter = (char)int.Parse(hexString, System.Globalization.NumberStyles.HexNumber, CultureInfo.InvariantCulture); // if the unescaped character is not on the exception list, append it unescapedString.Append(unescapedCharacter); // Advance the current pointer to reflect the fact that the destination string // is up to date with everything up to and including this escape code we just found. currentPosition = indexOfPercent + 3; escapingWasNecessary = true; } // Find the next percent sign. indexOfPercent = escapedString.IndexOf('%', indexOfPercent + 1); } // Okay, there are no more percent signs in the input string, so just copy the remaining // characters into the destination. unescapedString.Append(escapedString, currentPosition, escapedString.Length - currentPosition); return(StringBuilderCache.GetStringAndRelease(unescapedString)); }
/// <summary> /// Replaces all instances of %XX in the input string with the character represented /// by the hexadecimal number XX. /// </summary> /// <param name="escapedString">The string to unescape.</param> /// <param name="trim">If the string should be trimmed before being unescaped.</param> /// <returns>unescaped string</returns> internal static string UnescapeAll(string escapedString, bool trim = false) { // If the string doesn't contain anything, then by definition it doesn't // need unescaping. if (String.IsNullOrEmpty(escapedString)) { return(escapedString); } // If there are no percent signs, just return the original string immediately. // Don't even instantiate the StringBuilder. int indexOfPercent = escapedString.IndexOf('%'); if (indexOfPercent == -1) { return(trim ? escapedString.Trim() : escapedString); } // This is where we're going to build up the final string to return to the caller. StringBuilder unescapedString = StringBuilderCache.Acquire(escapedString.Length); int currentPosition = 0; int escapedStringLength = escapedString.Length; if (trim) { while (currentPosition < escapedString.Length && Char.IsWhiteSpace(escapedString[currentPosition])) { currentPosition++; } if (currentPosition == escapedString.Length) { return(String.Empty); } while (Char.IsWhiteSpace(escapedString[escapedStringLength - 1])) { escapedStringLength--; } } // Loop until there are no more percent signs in the input string. while (indexOfPercent != -1) { // There must be two hex characters following the percent sign // for us to even consider doing anything with this. if ( (indexOfPercent <= (escapedStringLength - 3)) && TryDecodeHexDigit(escapedString[indexOfPercent + 1], out int digit1) && TryDecodeHexDigit(escapedString[indexOfPercent + 2], out int digit2) ) { // First copy all the characters up to the current percent sign into // the destination. unescapedString.Append(escapedString, currentPosition, indexOfPercent - currentPosition); // Convert the %XX to an actual real character. char unescapedCharacter = (char)((digit1 << 4) + digit2); // if the unescaped character is not on the exception list, append it unescapedString.Append(unescapedCharacter); // Advance the current pointer to reflect the fact that the destination string // is up to date with everything up to and including this escape code we just found. currentPosition = indexOfPercent + 3; } // Find the next percent sign. indexOfPercent = escapedString.IndexOf('%', indexOfPercent + 1); } // Okay, there are no more percent signs in the input string, so just copy the remaining // characters into the destination. unescapedString.Append(escapedString, currentPosition, escapedStringLength - currentPosition); return(StringBuilderCache.GetStringAndRelease(unescapedString)); }