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

  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. // DecoderBestFitFallback.cs
  16. //
  17. // This is used internally to create best fit behavior as per the original windows best fit behavior.
  18. //
  19. namespace System.Text
  20. {
  21.     using System;
  22.     using System.Text;
  23.     using System.Threading;
  24.    
  25.     [Serializable()]
  26.     internal sealed class InternalDecoderBestFitFallback : DecoderFallback
  27.     {
  28.         // Our variables
  29.         internal Encoding encoding = null;
  30.         internal char[] arrayBestFit = null;
  31.         internal char cReplacement = '?';
  32.        
  33.         internal InternalDecoderBestFitFallback(Encoding encoding)
  34.         {
  35.             // Need to load our replacement characters table.
  36.             this.encoding = encoding;
  37.             this.bIsMicrosoftBestFitFallback = true;
  38.         }
  39.        
  40.         public override DecoderFallbackBuffer CreateFallbackBuffer()
  41.         {
  42.             return new InternalDecoderBestFitFallbackBuffer(this);
  43.         }
  44.        
  45.         // Maximum number of characters that this instance of this fallback could return
  46.         public override int MaxCharCount {
  47.             get { return 1; }
  48.         }
  49.        
  50.         public override bool Equals(object value)
  51.         {
  52.             InternalDecoderBestFitFallback that = value as InternalDecoderBestFitFallback;
  53.             if (that != null) {
  54.                 return (this.encoding.CodePage == that.encoding.CodePage);
  55.             }
  56.             return (false);
  57.         }
  58.        
  59.         public override int GetHashCode()
  60.         {
  61.             return this.encoding.CodePage;
  62.         }
  63.     }
  64.    
  65.     internal sealed class InternalDecoderBestFitFallbackBuffer : DecoderFallbackBuffer
  66.     {
  67.         // Our variables
  68.         internal char cBestFit = '\0';
  69.         internal int iCount = -1;
  70.         internal int iSize;
  71.         private InternalDecoderBestFitFallback oFallback;
  72.        
  73.         // Private object for locking instead of locking on a public type for SQL reliability work.
  74.         private static object s_InternalSyncObject;
  75.         private static object InternalSyncObject {
  76.             get {
  77.                 if (s_InternalSyncObject == null) {
  78.                     object o = new object();
  79.                     Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
  80.                 }
  81.                 return s_InternalSyncObject;
  82.             }
  83.         }
  84.        
  85.         // Constructor
  86.         public InternalDecoderBestFitFallbackBuffer(InternalDecoderBestFitFallback fallback)
  87.         {
  88.             this.oFallback = fallback;
  89.            
  90.             if (oFallback.arrayBestFit == null) {
  91.                 // Lock so we don't confuse ourselves.
  92.                 lock (InternalSyncObject) {
  93.                     // Double check before we do it again.
  94.                     if (oFallback.arrayBestFit == null)
  95.                         oFallback.arrayBestFit = fallback.encoding.GetBestFitBytesToUnicodeData();
  96.                 }
  97.             }
  98.         }
  99.        
  100.         // Fallback methods
  101.         public override bool Fallback(byte[] bytesUnknown, int index)
  102.         {
  103.             // We expect no previous fallback in our buffer
  104.             BCLDebug.Assert(iCount < 1, "[DecoderReplacementFallbackBuffer.Fallback] Calling fallback without a previously empty buffer");
  105.            
  106.             cBestFit = TryBestFit(bytesUnknown);
  107.             if (cBestFit == '\0')
  108.                 cBestFit = oFallback.cReplacement;
  109.            
  110.             iCount = iSize = 1;
  111.            
  112.             return true;
  113.         }
  114.        
  115.         // Default version is overridden in DecoderReplacementFallback.cs
  116.         public override char GetNextChar()
  117.         {
  118.             // Just return cReturn, which is 0 if there's no best fit for it.
  119.             return (iCount-- > 0) ? cBestFit : '\0';
  120.         }
  121.        
  122.         public override bool MovePrevious()
  123.         {
  124.             // Exception fallback doesn't have anywhere to back up to.
  125.             if (iCount >= 0)
  126.                 iCount++;
  127.            
  128.             // Return true if we could do it.
  129.             return (iCount >= 0 && iCount <= iSize);
  130.         }
  131.        
  132.         // How many characters left to output?
  133.         public override int Remaining {
  134.             get { return (iCount > 0) ? iCount : 0; }
  135.         }
  136.        
  137.         // Clear the buffer
  138.         unsafe public override void Reset()
  139.         {
  140.             iCount = -1;
  141.             byteStart = null;
  142.         }
  143.        
  144.         // This version just counts the fallback and doesn't actually copy anything.
  145.         unsafe internal override int InternalFallback(byte[] bytes, byte* pBytes)
  146.         {
  147.             // return our replacement string Length (always 1 for InternalDecoderBestFitFallback, either
  148.             // a best fit char or ?
  149.             return 1;
  150.         }
  151.        
  152.         // private helper methods
  153.         private char TryBestFit(byte[] bytesCheck)
  154.         {
  155.             // Need to figure out our best fit character, low is beginning of array, high is 1 AFTER end of array
  156.             int lowBound = 0;
  157.             int highBound = oFallback.arrayBestFit.Length;
  158.             int index;
  159.             char cCheck;
  160.            
  161.             // Check trivial case first (no best fit)
  162.             if (highBound == 0)
  163.                 return '\0';
  164.            
  165.             // If our array is too small or too big we can't check
  166.             if (bytesCheck.Length == 0 || bytesCheck.Length > 2)
  167.                 return '\0';
  168.            
  169.             if (bytesCheck.Length == 1)
  170.                 cCheck = unchecked((char)bytesCheck[0]);
  171.             else
  172.                 cCheck = unchecked((char)((bytesCheck[0] << 8) + bytesCheck[1]));
  173.            
  174.             // Check trivial out of range case
  175.             if (cCheck < oFallback.arrayBestFit[0] || cCheck > oFallback.arrayBestFit[highBound - 2])
  176.                 return '\0';
  177.            
  178.             // Binary search the array
  179.             int iDiff;
  180.             while ((iDiff = (highBound - lowBound)) > 6) {
  181.                 // Look in the middle, which is complicated by the fact that we have 2 #s for each pair,
  182.                 // so we don't want index to be odd because it must be word aligned.
  183.                 // Also note that index can never == highBound (because diff is rounded down)
  184.                 index = ((iDiff / 2) + lowBound) & 65534;
  185.                
  186.                 char cTest = oFallback.arrayBestFit[index];
  187.                 if (cTest == cCheck) {
  188.                     // We found it
  189.                     BCLDebug.Assert(index + 1 < oFallback.arrayBestFit.Length, "[InternalDecoderBestFitFallbackBuffer.TryBestFit]Expected replacement character at end of array");
  190.                     return oFallback.arrayBestFit[index + 1];
  191.                 }
  192.                 else if (cTest < cCheck) {
  193.                     // We weren't high enough
  194.                     lowBound = index;
  195.                 }
  196.                 else {
  197.                     // We weren't low enough
  198.                     highBound = index;
  199.                 }
  200.             }
  201.            
  202.             for (index = lowBound; index < highBound; index += 2) {
  203.                 if (oFallback.arrayBestFit[index] == cCheck) {
  204.                     // We found it
  205.                     BCLDebug.Assert(index + 1 < oFallback.arrayBestFit.Length, "[InternalDecoderBestFitFallbackBuffer.TryBestFit]Expected replacement character at end of array");
  206.                     return oFallback.arrayBestFit[index + 1];
  207.                 }
  208.             }
  209.            
  210.             // Char wasn't in our table
  211.             return '\0';
  212.         }
  213.     }
  214. }

Developer Fusion