//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ namespace System.Web.Util { using System; // This class contains utility methods for dealing with security contexts when crossing AppDomain boundaries. internal static class Utf16StringValidator { private const char UNICODE_NULL_CHAR = '\0'; private const char UNICODE_REPLACEMENT_CHAR = '\uFFFD'; private static readonly bool _skipUtf16Validation = AppSettings.AllowRelaxedUnicodeDecoding; public static string ValidateString(string input) { return ValidateString(input, _skipUtf16Validation); } // only internal for unit testing internal static string ValidateString(string input, bool skipUtf16Validation) { if (skipUtf16Validation || String.IsNullOrEmpty(input)) { return input; } // locate the first surrogate character int idxOfFirstSurrogate = -1; for (int i = 0; i < input.Length; i++) { if (Char.IsSurrogate(input[i])) { idxOfFirstSurrogate = i; break; } } // fast case: no surrogates = return input string if (idxOfFirstSurrogate < 0) { return input; } // slow case: surrogates exist, so we need to validate them char[] chars = input.ToCharArray(); for (int i = idxOfFirstSurrogate; i < chars.Length; i++) { char thisChar = chars[i]; // If this character is a low surrogate, then it was not preceded by // a high surrogate, so we'll replace it. if (Char.IsLowSurrogate(thisChar)) { chars[i] = UNICODE_REPLACEMENT_CHAR; continue; } if (Char.IsHighSurrogate(thisChar)) { // If this character is a high surrogate and it is followed by a // low surrogate, allow both to remain. if (i + 1 < chars.Length && Char.IsLowSurrogate(chars[i + 1])) { i++; // skip the low surrogate also continue; } // If this character is a high surrogate and it is not followed // by a low surrogate, replace it. chars[i] = UNICODE_REPLACEMENT_CHAR; continue; } // Otherwise, this is a non-surrogate character and just move to the // next character. } return new String(chars); } } }