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

  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. using System;
  16. using System.Threading;
  17. namespace System.Text
  18. {
  19.     [Serializable()]
  20.     public abstract class EncoderFallback
  21.     {
  22.         internal bool bIsMicrosoftBestFitFallback = false;
  23.        
  24.         private static EncoderFallback replacementFallback;
  25.         // Default fallback, uses no best fit & "?"
  26.         private static EncoderFallback exceptionFallback;
  27.        
  28.         // Private object for locking instead of locking on a public type for SQL reliability work.
  29.         private static object s_InternalSyncObject;
  30.         private static object InternalSyncObject {
  31.             get {
  32.                 if (s_InternalSyncObject == null) {
  33.                     object o = new object();
  34.                     Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
  35.                 }
  36.                 return s_InternalSyncObject;
  37.             }
  38.         }
  39.        
  40.         // Get each of our generic fallbacks.
  41.        
  42.         public static EncoderFallback ReplacementFallback {
  43.             get {
  44.                 if (replacementFallback == null)
  45.                     lock (InternalSyncObject)
  46.                         if (replacementFallback == null)
  47.                             replacementFallback = new EncoderReplacementFallback();
  48.                
  49.                 return replacementFallback;
  50.             }
  51.         }
  52.        
  53.        
  54.         public static EncoderFallback ExceptionFallback {
  55.             get {
  56.                 if (exceptionFallback == null)
  57.                     lock (InternalSyncObject)
  58.                         if (exceptionFallback == null)
  59.                             exceptionFallback = new EncoderExceptionFallback();
  60.                
  61.                 return exceptionFallback;
  62.             }
  63.         }
  64.        
  65.         // Fallback
  66.         //
  67.         // Return the appropriate unicode string alternative to the character that need to fall back.
  68.         // Most implimentations will be:
  69.         // return new MyCustomEncoderFallbackBuffer(this);
  70.        
  71.         public abstract EncoderFallbackBuffer CreateFallbackBuffer();
  72.        
  73.         // Maximum number of characters that this instance of this fallback could return
  74.        
  75.         public abstract int MaxCharCount {
  76.             get;
  77.         }
  78.     }
  79.    
  80.    
  81.     public abstract class EncoderFallbackBuffer
  82.     {
  83.        
  84.        
  85.         public abstract bool Fallback(char charUnknown, int index);
  86.        
  87.         public abstract bool Fallback(char charUnknownHigh, char charUnknownLow, int index);
  88.        
  89.         // Get next character
  90.        
  91.         public abstract char GetNextChar();
  92.        
  93.         // Back up a character
  94.        
  95.         public abstract bool MovePrevious();
  96.        
  97.         // How many chars left in this fallback?
  98.        
  99.         public abstract int Remaining {
  100.             get;
  101.         }
  102.        
  103.         // Not sure if this should be public or not.
  104.         // Clear the buffer
  105.        
  106.         public virtual void Reset()
  107.         {
  108.             while (GetNextChar() != (char)0)
  109.                 ;
  110.         }
  111.        
  112.         // Internal items to help us figure out what we're doing as far as error messages, etc.
  113.         // These help us with our performance and messages internally
  114.         unsafe internal char* charStart = null;
  115.         unsafe internal char* charEnd;
  116.         internal EncoderNLS encoder;
  117.         internal bool setEncoder;
  118.         internal bool bUsedEncoder;
  119.         internal bool bFallingBack = false;
  120.         internal int iRecursionCount = 0;
  121.         private const int iMaxRecursion = 250;
  122.        
  123.         // Internal Reset
  124.         // For example, what if someone fails a conversion and wants to reset one of our fallback buffers?
  125.         unsafe internal void InternalReset()
  126.         {
  127.             charStart = null;
  128.             bFallingBack = false;
  129.             iRecursionCount = 0;
  130.             Reset();
  131.         }
  132.        
  133.         // Set the above values
  134.         // This can't be part of the constructor because EncoderFallbacks would have to know how to impliment these.
  135.         unsafe internal void InternalInitialize(char* charStart, char* charEnd, EncoderNLS encoder, bool setEncoder)
  136.         {
  137.             this.charStart = charStart;
  138.             this.charEnd = charEnd;
  139.             this.encoder = encoder;
  140.             this.setEncoder = setEncoder;
  141.             this.bUsedEncoder = false;
  142.             this.bFallingBack = false;
  143.             this.iRecursionCount = 0;
  144.         }
  145.        
  146.         internal char InternalGetNextChar()
  147.         {
  148.             char ch = GetNextChar();
  149.             bFallingBack = (ch != 0);
  150.             if (ch == 0)
  151.                 iRecursionCount = 0;
  152.             return ch;
  153.         }
  154.        
  155.         // Fallback the current character using the remaining buffer and encoder if necessary
  156.         // This can only be called by our encodings (other have to use the public fallback methods), so
  157.         // we can use our EncoderNLS here too.
  158.         // setEncoder is true if we're calling from a GetBytes method, false if we're calling from a GetByteCount
  159.         //
  160.         // Note that this could also change the contents of this.encoder, which is the same
  161.         // object that the caller is using, so the caller could mess up the encoder for us
  162.         // if they aren't careful.
  163.         unsafe internal virtual bool InternalFallback(char ch, ref char* chars)
  164.         {
  165.             // Shouldn't have null charStart
  166.             BCLDebug.Assert(charStart != null, "[EncoderFallback.InternalFallbackBuffer]Fallback buffer is not initialized");
  167.            
  168.             // Get our index, remember chars was preincremented to point at next char, so have to -1
  169.             int index = (int)(chars - charStart) - 1;
  170.            
  171.             // See if it was a high surrogate
  172.             if (Char.IsHighSurrogate(ch)) {
  173.                 // See if there's a low surrogate to go with it
  174.                 if (chars >= this.charEnd) {
  175.                     // Nothing left in input buffer
  176.                     // No input, return 0 if mustflush is false
  177.                     if (this.encoder != null && !this.encoder.MustFlush) {
  178.                         // Done, nothing to fallback
  179.                         if (this.setEncoder) {
  180.                             bUsedEncoder = true;
  181.                             this.encoder.charLeftOver = ch;
  182.                         }
  183.                         bFallingBack = false;
  184.                         return false;
  185.                     }
  186.                 }
  187.                 else {
  188.                     // Might have a low surrogate
  189.                     char cNext = *chars;
  190.                     if (Char.IsLowSurrogate(cNext)) {
  191.                         // If already falling back then fail
  192.                         if (bFallingBack && iRecursionCount++ > iMaxRecursion)
  193.                             ThrowLastCharRecursive(Char.ConvertToUtf32(ch, cNext));
  194.                        
  195.                         // Next is a surrogate, add it as surrogate pair, and increment chars
  196.                         chars++;
  197.                         bFallingBack = Fallback(ch, cNext, index);
  198.                         return bFallingBack;
  199.                     }
  200.                    
  201.                     // Next isn't a low surrogate, just fallback the high surrogate
  202.                 }
  203.             }
  204.            
  205.             // If already falling back then fail
  206.             if (bFallingBack && iRecursionCount++ > iMaxRecursion)
  207.                 ThrowLastCharRecursive((int)ch);
  208.            
  209.             // Fall back our char
  210.             bFallingBack = Fallback(ch, index);
  211.            
  212.             return bFallingBack;
  213.         }
  214.        
  215.         // private helper methods
  216.         internal void ThrowLastCharRecursive(int charRecursive)
  217.         {
  218.             // Throw it, using our complete character
  219.             throw new ArgumentException(Environment.GetResourceString("Argument_RecursiveFallback", charRecursive), "chars");
  220.         }
  221.        
  222.     }
  223. }

Developer Fusion