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

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

Developer Fusion