Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mcs / class / referencesource / System.Web / Util / Utf16StringValidator.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="Utf16StringValidator.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6
7 namespace System.Web.Util {
8     using System;
9
10     // This class contains utility methods for dealing with security contexts when crossing AppDomain boundaries.
11
12     internal static class Utf16StringValidator {
13
14         private const char UNICODE_NULL_CHAR = '\0';
15         private const char UNICODE_REPLACEMENT_CHAR = '\uFFFD';
16
17         private static readonly bool _skipUtf16Validation = AppSettings.AllowRelaxedUnicodeDecoding;
18
19         public static string ValidateString(string input) {
20             return ValidateString(input, _skipUtf16Validation);
21         }
22
23         // only internal for unit testing
24         internal static string ValidateString(string input, bool skipUtf16Validation) {
25             if (skipUtf16Validation || String.IsNullOrEmpty(input)) {
26                 return input;
27             }
28
29             // locate the first surrogate character
30             int idxOfFirstSurrogate = -1;
31             for (int i = 0; i < input.Length; i++) {
32                 if (Char.IsSurrogate(input[i])) {
33                     idxOfFirstSurrogate = i;
34                     break;
35                 }
36             }
37
38             // fast case: no surrogates = return input string
39             if (idxOfFirstSurrogate < 0) {
40                 return input;
41             }
42
43             // slow case: surrogates exist, so we need to validate them
44             char[] chars = input.ToCharArray();
45             for (int i = idxOfFirstSurrogate; i < chars.Length; i++) {
46                 char thisChar = chars[i];
47
48                 // If this character is a low surrogate, then it was not preceded by
49                 // a high surrogate, so we'll replace it.
50                 if (Char.IsLowSurrogate(thisChar)) {
51                     chars[i] = UNICODE_REPLACEMENT_CHAR;
52                     continue;
53                 }
54
55                 if (Char.IsHighSurrogate(thisChar)) {
56                     // If this character is a high surrogate and it is followed by a
57                     // low surrogate, allow both to remain.
58                     if (i + 1 < chars.Length && Char.IsLowSurrogate(chars[i + 1])) {
59                         i++; // skip the low surrogate also
60                         continue;
61                     }
62
63                     // If this character is a high surrogate and it is not followed
64                     // by a low surrogate, replace it.
65                     chars[i] = UNICODE_REPLACEMENT_CHAR;
66                     continue;
67                 }
68
69                 // Otherwise, this is a non-surrogate character and just move to the
70                 // next character.
71             }
72             return new String(chars);
73         }
74
75     }
76 }