BinHexDecoder.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. //------------------------------------------------------------------------------
  2. // <copyright file="BinHexDecoder.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. {
  11. internal class BinHexDecoder : IncrementalReadDecoder {
  12. //
  13. // Fields
  14. //
  15. byte[] buffer;
  16. int startIndex;
  17. int curIndex;
  18. int endIndex;
  19. bool hasHalfByteCached;
  20. byte cachedHalfByte;
  21. //
  22. // IncrementalReadDecoder interface
  23. //
  24. internal override int DecodedCount {
  25. get {
  26. return curIndex - startIndex;
  27. }
  28. }
  29. internal override bool IsFull {
  30. get {
  31. return curIndex == endIndex;
  32. }
  33. }
  34. #if SILVERLIGHT && !SILVERLIGHT_DISABLE_SECURITY
  35. [System.Security.SecuritySafeCritical]
  36. #endif
  37. internal override unsafe int Decode(char[] chars, int startPos, int len) {
  38. if ( chars == null ) {
  39. throw new ArgumentNullException( "chars" );
  40. }
  41. if ( len < 0 ) {
  42. throw new ArgumentOutOfRangeException( "len" );
  43. }
  44. if ( startPos < 0 ) {
  45. throw new ArgumentOutOfRangeException( "startPos" );
  46. }
  47. if ( chars.Length - startPos < len ) {
  48. throw new ArgumentOutOfRangeException( "len" );
  49. }
  50. if ( len == 0 ) {
  51. return 0;
  52. }
  53. int bytesDecoded, charsDecoded;
  54. fixed ( char* pChars = &chars[startPos] ) {
  55. fixed ( byte* pBytes = &buffer[curIndex] ) {
  56. Decode( pChars, pChars + len, pBytes, pBytes + ( endIndex - curIndex ),
  57. ref this.hasHalfByteCached, ref this.cachedHalfByte, out charsDecoded, out bytesDecoded );
  58. }
  59. }
  60. curIndex += bytesDecoded;
  61. return charsDecoded;
  62. }
  63. #if SILVERLIGHT && !SILVERLIGHT_DISABLE_SECURITY
  64. [System.Security.SecuritySafeCritical]
  65. #endif
  66. internal override unsafe int Decode(string str, int startPos, int len) {
  67. if ( str == null ) {
  68. throw new ArgumentNullException( "str" );
  69. }
  70. if ( len < 0 ) {
  71. throw new ArgumentOutOfRangeException( "len" );
  72. }
  73. if ( startPos < 0 ) {
  74. throw new ArgumentOutOfRangeException( "startPos" );
  75. }
  76. if ( str.Length - startPos < len ) {
  77. throw new ArgumentOutOfRangeException( "len" );
  78. }
  79. if ( len == 0 ) {
  80. return 0;
  81. }
  82. int bytesDecoded, charsDecoded;
  83. fixed ( char* pChars = str ) {
  84. fixed ( byte* pBytes = &buffer[curIndex] ) {
  85. Decode( pChars + startPos, pChars + startPos + len, pBytes, pBytes + ( endIndex - curIndex ),
  86. ref this.hasHalfByteCached, ref this.cachedHalfByte, out charsDecoded, out bytesDecoded );
  87. }
  88. }
  89. curIndex += bytesDecoded;
  90. return charsDecoded;
  91. }
  92. internal override void Reset() {
  93. this.hasHalfByteCached = false;
  94. this.cachedHalfByte = 0;
  95. }
  96. internal override void SetNextOutputBuffer( Array buffer, int index, int count ) {
  97. Debug.Assert( buffer != null );
  98. Debug.Assert( count >= 0 );
  99. Debug.Assert( index >= 0 );
  100. Debug.Assert( buffer.Length - index >= count );
  101. Debug.Assert( ( buffer as byte[] ) != null );
  102. this.buffer = (byte[])buffer;
  103. this.startIndex = index;
  104. this.curIndex = index;
  105. this.endIndex = index + count;
  106. }
  107. //
  108. // Static methods
  109. //
  110. #if SILVERLIGHT && !SILVERLIGHT_DISABLE_SECURITY
  111. [System.Security.SecuritySafeCritical]
  112. #endif
  113. public static unsafe byte[] Decode(char[] chars, bool allowOddChars) {
  114. if ( chars == null ) {
  115. throw new ArgumentNullException( "chars" );
  116. }
  117. int len = chars.Length;
  118. if ( len == 0 ) {
  119. return new byte[0];
  120. }
  121. byte[] bytes = new byte[ ( len + 1 ) / 2 ];
  122. int bytesDecoded, charsDecoded;
  123. bool hasHalfByteCached = false;
  124. byte cachedHalfByte = 0;
  125. fixed ( char* pChars = &chars[0] ) {
  126. fixed ( byte* pBytes = &bytes[0] ) {
  127. Decode( pChars, pChars + len, pBytes, pBytes + bytes.Length, ref hasHalfByteCached, ref cachedHalfByte, out charsDecoded, out bytesDecoded );
  128. }
  129. }
  130. if ( hasHalfByteCached && !allowOddChars ) {
  131. throw new XmlException( Res.Xml_InvalidBinHexValueOddCount, new string( chars ) );
  132. }
  133. if ( bytesDecoded < bytes.Length ) {
  134. byte[] tmp = new byte[ bytesDecoded ];
  135. Array.Copy( bytes, 0, tmp, 0, bytesDecoded );
  136. bytes = tmp;
  137. }
  138. return bytes;
  139. }
  140. //
  141. // Private methods
  142. //
  143. #if SILVERLIGHT && !SILVERLIGHT_DISABLE_SECURITY
  144. [System.Security.SecurityCritical]
  145. #endif
  146. private static unsafe void Decode(char* pChars, char* pCharsEndPos,
  147. byte* pBytes, byte* pBytesEndPos,
  148. ref bool hasHalfByteCached, ref byte cachedHalfByte,
  149. out int charsDecoded, out int bytesDecoded ) {
  150. #if DEBUG
  151. Debug.Assert( pCharsEndPos - pChars >= 0 );
  152. Debug.Assert( pBytesEndPos - pBytes >= 0 );
  153. #endif
  154. char* pChar = pChars;
  155. byte* pByte = pBytes;
  156. XmlCharType xmlCharType = XmlCharType.Instance;
  157. while ( pChar < pCharsEndPos && pByte < pBytesEndPos ) {
  158. byte halfByte;
  159. char ch = *pChar++;
  160. if ( ch >= 'a' && ch <= 'f' ) {
  161. halfByte = (byte)(ch - 'a' + 10);
  162. }
  163. else if ( ch >= 'A' && ch <= 'F' ) {
  164. halfByte = (byte)(ch - 'A' + 10);
  165. }
  166. else if ( ch >= '0' && ch <= '9' ) {
  167. halfByte = (byte)(ch - '0');
  168. }
  169. else if ( ( xmlCharType.charProperties[ch] & XmlCharType.fWhitespace ) != 0 ) { // else if ( xmlCharType.IsWhiteSpace( ch ) ) {
  170. continue;
  171. }
  172. else {
  173. throw new XmlException( Res.Xml_InvalidBinHexValue, new string( pChars, 0, (int)( pCharsEndPos - pChars ) ) );
  174. }
  175. if ( hasHalfByteCached ) {
  176. *pByte++ = (byte)( ( cachedHalfByte << 4 ) + halfByte );
  177. hasHalfByteCached = false;
  178. }
  179. else {
  180. cachedHalfByte = halfByte;
  181. hasHalfByteCached = true;
  182. }
  183. }
  184. bytesDecoded = (int)(pByte - pBytes);
  185. charsDecoded = (int)(pChar - pChars);
  186. }
  187. }
  188. }