Base64Decoder.cs 7.2 KB

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