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