The Labs \ Source Viewer \ SSCLI \ System.Xml \ Base64Decoder

  1. //------------------------------------------------------------------------------
  2. // <copyright file="Base64Decoder.cs" company="Microsoft">
  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. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.Diagnostics;
  17. namespace System.Xml
  18. {
  19.    
  20.     internal class Base64Decoder : IncrementalReadDecoder
  21.     {
  22.         //
  23.         // Fields
  24.         //
  25.         byte[] buffer;
  26.         int startIndex;
  27.         int curIndex;
  28.         int endIndex;
  29.        
  30.         int bits;
  31.         int bitsFilled;
  32.        
  33.         private static readonly string CharsBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  34.         private static readonly byte[] MapBase64 = ConstructMapBase64();
  35.         private const int MaxValidChar = (int)'z';
  36.         private const byte Invalid = unchecked((byte)-1);
  37.        
  38.         //
  39.         // IncrementalReadDecoder interface
  40.         //
  41.         internal override int DecodedCount {
  42.             get { return curIndex - startIndex; }
  43.         }
  44.        
  45.         internal override bool IsFull {
  46.             get { return curIndex == endIndex; }
  47.         }
  48.        
  49.         unsafe internal override int Decode(char[] chars, int startPos, int len)
  50.         {
  51.             Debug.Assert(chars != null);
  52.             Debug.Assert(len >= 0);
  53.             Debug.Assert(startPos >= 0);
  54.             Debug.Assert(chars.Length - startPos >= len);
  55.            
  56.             if (len == 0) {
  57.                 return 0;
  58.             }
  59.             int bytesDecoded;
  60.             int charsDecoded;
  61.             fixed (char* pChars = &chars[startPos]) {
  62.                 fixed (byte* pBytes = &buffer[curIndex]) {
  63.                     Decode(pChars, pChars + len, pBytes, pBytes + (endIndex - curIndex), out charsDecoded, out bytesDecoded);
  64.                 }
  65.             }
  66.             curIndex += bytesDecoded;
  67.             return charsDecoded;
  68.         }
  69.        
  70.         unsafe internal override int Decode(string str, int startPos, int len)
  71.         {
  72.             Debug.Assert(str != null);
  73.             Debug.Assert(len >= 0);
  74.             Debug.Assert(startPos >= 0);
  75.             Debug.Assert(str.Length - startPos >= len);
  76.            
  77.             if (len == 0) {
  78.                 return 0;
  79.             }
  80.             int bytesDecoded;
  81.             int charsDecoded;
  82.             fixed (char* pChars = str) {
  83.                 fixed (byte* pBytes = &buffer[curIndex]) {
  84.                     Decode(pChars + startPos, pChars + startPos + len, pBytes, pBytes + (endIndex - curIndex), out charsDecoded, out bytesDecoded);
  85.                 }
  86.             }
  87.             curIndex += bytesDecoded;
  88.             return charsDecoded;
  89.         }
  90.        
  91.         internal override void Reset()
  92.         {
  93.             bitsFilled = 0;
  94.             bits = 0;
  95.         }
  96.        
  97.         internal override void SetNextOutputBuffer(Array buffer, int index, int count)
  98.         {
  99.             Debug.Assert(buffer != null);
  100.             Debug.Assert(count >= 0);
  101.             Debug.Assert(index >= 0);
  102.             Debug.Assert(buffer.Length - index >= count);
  103.             Debug.Assert((buffer as byte[]) != null);
  104.            
  105.             this.buffer = (byte[])buffer;
  106.             this.startIndex = index;
  107.             this.curIndex = index;
  108.             this.endIndex = index + count;
  109.         }
  110.        
  111.         //
  112.         // Private methods
  113.         //
  114.         private static byte[] ConstructMapBase64()
  115.         {
  116.             byte[] mapBase64 = new byte[MaxValidChar + 1];
  117.             for (int i = 0; i < mapBase64.Length; i++) {
  118.                 mapBase64[i] = Invalid;
  119.             }
  120.             for (int i = 0; i < CharsBase64.Length; i++) {
  121.                 mapBase64[(int)CharsBase64[i]] = (byte)i;
  122.             }
  123.             return mapBase64;
  124.         }
  125.        
  126.         unsafe private void Decode(char* pChars, char* pCharsEndPos, byte* pBytes, byte* pBytesEndPos, out int charsDecoded, out int bytesDecoded)
  127.         {
  128.             #if DEBUG
  129.             Debug.Assert(pCharsEndPos - pChars >= 0);
  130.             Debug.Assert(pBytesEndPos - pBytes >= 0);
  131.             #endif
  132.            
  133.             // walk hex digits pairing them up and shoving the value of each pair into a byte
  134.             byte* pByte = pBytes;
  135.             char* pChar = pChars;
  136.             int b = bits;
  137.             int bFilled = bitsFilled;
  138.             XmlCharType xmlCharType = XmlCharType.Instance;
  139.             while (pChar < pCharsEndPos && pByte < pBytesEndPos) {
  140.                 char ch = *pChar;
  141.                 // end?
  142.                 if (ch == '=') {
  143.                     break;
  144.                 }
  145.                 pChar++;
  146.                
  147.                 // ignore white space
  148.                 if ((xmlCharType.charProperties[ch] & XmlCharType.fWhitespace) != 0) {
  149.                     // if ( xmlCharType.IsWhiteSpace(ch) ) {
  150.                     continue;
  151.                 }
  152.                
  153.                 int digit;
  154.                 if (ch > 122 || (digit = MapBase64[ch]) == Invalid) {
  155.                     throw new XmlException(Res.Xml_InvalidBase64Value, new string(pChars, 0, (int)(pCharsEndPos - pChars)));
  156.                 }
  157.                
  158.                 b = (b << 6) | digit;
  159.                 bFilled += 6;
  160.                
  161.                 if (bFilled >= 8) {
  162.                     // get top eight valid bits
  163.                     *pByte++ = (byte)((b >> (bFilled - 8)) & 255);
  164.                     bFilled -= 8;
  165.                    
  166.                     if (pByte == pBytesEndPos) {
  167.                         goto Return;
  168.                     }
  169.                 }
  170.             }
  171.            
  172.             if (pChar < pCharsEndPos && *pChar == '=') {
  173.                 bFilled = 0;
  174.                 // ignore padding chars
  175.                 do {
  176.                     pChar++;
  177.                 }
  178.                 while (pChar < pCharsEndPos && *pChar == '=');
  179.                
  180.                 // ignore whitespace after the padding chars
  181.                 if (pChar < pCharsEndPos) {
  182.                     do {
  183.                         if (!((xmlCharType.charProperties[*pChar++] & XmlCharType.fWhitespace) != 0)) {
  184.                             // if ( !( xmlCharType.IsWhiteSpace( chars[charPos++] ) ) ) {
  185.                             throw new XmlException(Res.Xml_InvalidBase64Value, new string(pChars, 0, (int)(pCharsEndPos - pChars)));
  186.                         }
  187.                     }
  188.                     while (pChar < pCharsEndPos);
  189.                 }
  190.             }
  191.             Return:
  192.            
  193.             bits = b;
  194.             bitsFilled = bFilled;
  195.            
  196.             bytesDecoded = (int)(pByte - pBytes);
  197.             charsDecoded = (int)(pChar - pChars);
  198.         }
  199.     }
  200. }

Developer Fusion