The Labs \ Source Viewer \ SSCLI \ System.Text \ EncoderReplacementFallbackBuffer

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. // EncoderReplacementFallback.cs
  16. //
  17. namespace System.Text
  18. {
  19.     using System;
  20.    
  21.     [Serializable()]
  22.     public sealed class EncoderReplacementFallback : EncoderFallback
  23.     {
  24.         // Our variables
  25.         private string strDefault;
  26.        
  27.         // Construction. Default replacement fallback uses no best fit and ? replacement string
  28.         public EncoderReplacementFallback() : this("?")
  29.         {
  30.         }
  31.        
  32.         public EncoderReplacementFallback(string replacement)
  33.         {
  34.             // Must not be null
  35.             if (replacement == null)
  36.                 throw new ArgumentNullException("replacement");
  37.            
  38.             // Make sure it doesn't have bad surrogate pairs
  39.             bool bFoundHigh = false;
  40.             for (int i = 0; i < replacement.Length; i++) {
  41.                 // Found a surrogate?
  42.                 if (Char.IsSurrogate(replacement, i)) {
  43.                     // High or Low?
  44.                     if (Char.IsHighSurrogate(replacement, i)) {
  45.                         // if already had a high one, stop
  46.                         if (bFoundHigh)
  47.                             break;
  48.                         // break & throw at the bFoundHIgh below
  49.                         bFoundHigh = true;
  50.                     }
  51.                     else {
  52.                         // Low, did we have a high?
  53.                         if (!bFoundHigh) {
  54.                             // Didn't have one, make if fail when we stop
  55.                             bFoundHigh = true;
  56.                             break;
  57.                         }
  58.                        
  59.                         // Clear flag
  60.                         bFoundHigh = false;
  61.                     }
  62.                 }
  63.                 else if (bFoundHigh)
  64.                     // If last was high we're in trouble (not surrogate so not low surrogate, so break)
  65.                     break;
  66.             }
  67.             if (bFoundHigh)
  68.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex", "replacement"));
  69.            
  70.             strDefault = replacement;
  71.         }
  72.        
  73.         public string DefaultString {
  74.             get { return strDefault; }
  75.         }
  76.        
  77.         public override EncoderFallbackBuffer CreateFallbackBuffer()
  78.         {
  79.             return new EncoderReplacementFallbackBuffer(this);
  80.         }
  81.        
  82.         // Maximum number of characters that this instance of this fallback could return
  83.         public override int MaxCharCount {
  84.             get { return strDefault.Length; }
  85.         }
  86.        
  87.         public override bool Equals(object value)
  88.         {
  89.             EncoderReplacementFallback that = value as EncoderReplacementFallback;
  90.             if (that != null) {
  91.                 return (this.strDefault == that.strDefault);
  92.             }
  93.             return (false);
  94.         }
  95.        
  96.         public override int GetHashCode()
  97.         {
  98.             return strDefault.GetHashCode();
  99.         }
  100.     }
  101.    
  102.    
  103.    
  104.     public sealed class EncoderReplacementFallbackBuffer : EncoderFallbackBuffer
  105.     {
  106.         // Store our default string
  107.         private string strDefault;
  108.         int fallbackCount = -1;
  109.         int fallbackIndex = -1;
  110.        
  111.         // Construction
  112.         public EncoderReplacementFallbackBuffer(EncoderReplacementFallback fallback)
  113.         {
  114.             // 2X in case we're a surrogate pair
  115.             this.strDefault = fallback.DefaultString + fallback.DefaultString;
  116.         }
  117.        
  118.         // Fallback Methods
  119.         public override bool Fallback(char charUnknown, int index)
  120.         {
  121.             // If we had a buffer already we're being recursive, throw, it's probably at the suspect
  122.             // character in our array.
  123.             if (fallbackCount >= 1) {
  124.                 // If we're recursive we may still have something in our buffer that makes this a surrogate
  125.                 if (char.IsHighSurrogate(charUnknown) && fallbackCount >= 0 && char.IsLowSurrogate(strDefault[fallbackIndex + 1]))
  126.                     ThrowLastCharRecursive(Char.ConvertToUtf32(charUnknown, strDefault[fallbackIndex + 1]));
  127.                
  128.                 // Nope, just one character
  129.                 ThrowLastCharRecursive(unchecked((int)charUnknown));
  130.             }
  131.            
  132.             // Go ahead and get our fallback
  133.             // Divide by 2 because we aren't a surrogate pair
  134.             fallbackCount = strDefault.Length / 2;
  135.             fallbackIndex = -1;
  136.            
  137.             return fallbackCount != 0;
  138.         }
  139.        
  140.         public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index)
  141.         {
  142.             // Double check input surrogate pair
  143.             if (!Char.IsHighSurrogate(charUnknownHigh))
  144.                 throw new ArgumentOutOfRangeException("charUnknownHigh", Environment.GetResourceString("ArgumentOutOfRange_Range", 55296, 56319));
  145.            
  146.             if (!Char.IsLowSurrogate(charUnknownLow))
  147.                 throw new ArgumentOutOfRangeException("CharUnknownLow", Environment.GetResourceString("ArgumentOutOfRange_Range", 56320, 57343));
  148.            
  149.             // If we had a buffer already we're being recursive, throw, it's probably at the suspect
  150.             // character in our array.
  151.             if (fallbackCount >= 1)
  152.                 ThrowLastCharRecursive(Char.ConvertToUtf32(charUnknownHigh, charUnknownLow));
  153.            
  154.             // Go ahead and get our fallback
  155.             fallbackCount = strDefault.Length;
  156.             fallbackIndex = -1;
  157.            
  158.             return fallbackCount != 0;
  159.         }
  160.        
  161.         public override char GetNextChar()
  162.         {
  163.             // We want it to get < 0 because == 0 means that the current/last character is a fallback
  164.             // and we need to detect recursion. We could have a flag but we already have this counter.
  165.             fallbackCount--;
  166.             fallbackIndex++;
  167.            
  168.             // Do we have anything left? 0 is now last fallback char, negative is nothing left
  169.             if (fallbackCount < 0)
  170.                 return (char)0;
  171.            
  172.             // Need to get it out of the buffer.
  173.             BCLDebug.Assert(fallbackIndex < strDefault.Length && fallbackIndex >= 0, "Index exceeds buffer range");
  174.             return strDefault[fallbackIndex];
  175.         }
  176.        
  177.         public override bool MovePrevious()
  178.         {
  179.             // Back up one, only if we just processed the last character (or earlier)
  180.             if (fallbackCount >= -1 && fallbackIndex >= 0) {
  181.                 fallbackIndex--;
  182.                 fallbackCount++;
  183.                 return true;
  184.             }
  185.            
  186.             // Return false 'cause we couldn't do it.
  187.             return false;
  188.         }
  189.        
  190.         // How many characters left to output?
  191.         public override int Remaining {
  192. // Our count is 0 for 1 character left.
  193.             get { return (fallbackCount < 0) ? 0 : fallbackCount; }
  194.         }
  195.        
  196.         // Clear the buffer
  197.         unsafe public override void Reset()
  198.         {
  199.             fallbackCount = -1;
  200.             fallbackIndex = 0;
  201.             charStart = null;
  202.             bFallingBack = false;
  203.         }
  204.     }
  205. }

Developer Fusion