1 // ==++== 2 // 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // 5 // ==--== 6 // DecoderReplacementFallback.cs 7 // 8 namespace System.Text 9 { 10 using System; 11 using System.Diagnostics.Contracts; 12 13 [Serializable] 14 public sealed class DecoderReplacementFallback : DecoderFallback 15 { 16 // Our variables 17 private String strDefault; 18 19 // Construction. Default replacement fallback uses no best fit and ? replacement string DecoderReplacementFallback()20 public DecoderReplacementFallback() : this("?") 21 { 22 } 23 DecoderReplacementFallback(String replacement)24 public DecoderReplacementFallback(String replacement) 25 { 26 if (replacement == null) 27 throw new ArgumentNullException("replacement"); 28 Contract.EndContractBlock(); 29 30 // Make sure it doesn't have bad surrogate pairs 31 bool bFoundHigh=false; 32 for (int i = 0; i < replacement.Length; i++) 33 { 34 // Found a surrogate? 35 if (Char.IsSurrogate(replacement,i)) 36 { 37 // High or Low? 38 if (Char.IsHighSurrogate(replacement, i)) 39 { 40 // if already had a high one, stop 41 if (bFoundHigh) 42 break; // break & throw at the bFoundHIgh below 43 bFoundHigh = true; 44 } 45 else 46 { 47 // Low, did we have a high? 48 if (!bFoundHigh) 49 { 50 // Didn't have one, make if fail when we stop 51 bFoundHigh = true; 52 break; 53 } 54 55 // Clear flag 56 bFoundHigh = false; 57 } 58 } 59 // If last was high we're in trouble (not surrogate so not low surrogate, so break) 60 else if (bFoundHigh) 61 break; 62 } 63 if (bFoundHigh) 64 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex", "replacement")); 65 66 strDefault = replacement; 67 } 68 69 public String DefaultString 70 { 71 get 72 { 73 return strDefault; 74 } 75 } 76 CreateFallbackBuffer()77 public override DecoderFallbackBuffer CreateFallbackBuffer() 78 { 79 return new DecoderReplacementFallbackBuffer(this); 80 } 81 82 // Maximum number of characters that this instance of this fallback could return 83 public override int MaxCharCount 84 { 85 get 86 { 87 return strDefault.Length; 88 } 89 } 90 Equals(Object value)91 public override bool Equals(Object value) 92 { 93 DecoderReplacementFallback that = value as DecoderReplacementFallback; 94 if (that != null) 95 { 96 return (this.strDefault == that.strDefault); 97 } 98 return (false); 99 } 100 GetHashCode()101 public override int GetHashCode() 102 { 103 return strDefault.GetHashCode(); 104 } 105 } 106 107 108 109 public sealed class DecoderReplacementFallbackBuffer : DecoderFallbackBuffer 110 { 111 // Store our default string 112 private String strDefault; 113 int fallbackCount = -1; 114 int fallbackIndex = -1; 115 116 // Construction DecoderReplacementFallbackBuffer(DecoderReplacementFallback fallback)117 public DecoderReplacementFallbackBuffer(DecoderReplacementFallback fallback) 118 { 119 this.strDefault = fallback.DefaultString; 120 } 121 122 // Fallback Methods Fallback(byte[] bytesUnknown, int index)123 public override bool Fallback(byte[] bytesUnknown, int index) 124 { 125 // We expect no previous fallback in our buffer 126 // We can't call recursively but others might (note, we don't test on last char!!!) 127 if (fallbackCount >= 1) 128 { 129 ThrowLastBytesRecursive(bytesUnknown); 130 } 131 132 // Go ahead and get our fallback 133 if (strDefault.Length == 0) 134 return false; 135 136 fallbackCount = strDefault.Length; 137 fallbackIndex = -1; 138 139 return true; 140 } 141 GetNextChar()142 public override char GetNextChar() 143 { 144 // We want it to get < 0 because == 0 means that the current/last character is a fallback 145 // and we need to detect recursion. We could have a flag but we already have this counter. 146 fallbackCount--; 147 fallbackIndex++; 148 149 // Do we have anything left? 0 is now last fallback char, negative is nothing left 150 if (fallbackCount < 0) 151 return '\0'; 152 153 // Need to get it out of the buffer. 154 // Make sure it didn't wrap from the fast count-- path 155 if (fallbackCount == int.MaxValue) 156 { 157 fallbackCount = -1; 158 return '\0'; 159 } 160 161 // Now make sure its in the expected range 162 Contract.Assert(fallbackIndex < strDefault.Length && fallbackIndex >= 0, 163 "Index exceeds buffer range"); 164 165 return strDefault[fallbackIndex]; 166 } 167 MovePrevious()168 public override bool MovePrevious() 169 { 170 // Back up one, only if we just processed the last character (or earlier) 171 if (fallbackCount >= -1 && fallbackIndex >= 0) 172 { 173 fallbackIndex--; 174 fallbackCount++; 175 return true; 176 } 177 178 // Return false 'cause we couldn't do it. 179 return false; 180 } 181 182 // How many characters left to output? 183 public override int Remaining 184 { 185 get 186 { 187 // Our count is 0 for 1 character left. 188 return (fallbackCount < 0) ? 0 : fallbackCount; 189 } 190 } 191 192 // Clear the buffer 193 [System.Security.SecuritySafeCritical] // auto-generated Reset()194 public override unsafe void Reset() 195 { 196 fallbackCount = -1; 197 fallbackIndex = -1; 198 byteStart = null; 199 } 200 201 // This version just counts the fallback and doesn't actually copy anything. 202 [System.Security.SecurityCritical] // auto-generated InternalFallback(byte[] bytes, byte* pBytes)203 internal unsafe override int InternalFallback(byte[] bytes, byte* pBytes) 204 // Right now this has both bytes and bytes[], since we might have extra bytes, hence the 205 // array, and we might need the index, hence the byte* 206 { 207 // return our replacement string Length 208 return strDefault.Length; 209 } 210 } 211 } 212 213