File: Util\Utf16StringValidator.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <copyright file="Utf16StringValidator.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
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);
        }
 
    }
}