| File: FrameworkFork\Microsoft.Xml\Xml\Base64Decoder.cs | Web Access |
| Project: src\src\dotnet-svcutil\lib\src\dotnet-svcutil-lib.csproj (dotnet-svcutil-lib) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Diagnostics; namespace Microsoft.Xml { using System; internal class Base64Decoder : IncrementalReadDecoder { // // Fields // private byte[] _buffer; private int _startIndex; private int _curIndex; private int _endIndex; private int _bits; private int _bitsFilled; private static readonly String s_charsBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; private static readonly byte[] s_mapBase64 = ConstructMapBase64(); private const int MaxValidChar = (int)'z'; private const byte Invalid = unchecked((byte)-1); // // IncrementalReadDecoder interface // internal override int DecodedCount { get { return _curIndex - _startIndex; } } internal override bool IsFull { get { return _curIndex == _endIndex; } } internal override unsafe int Decode(char[] chars, int startPos, int len) { if (chars == null) { throw new ArgumentNullException("chars"); } if (len < 0) { throw new ArgumentOutOfRangeException("len"); } if (startPos < 0) { throw new ArgumentOutOfRangeException("startPos"); } if (chars.Length - startPos < len) { throw new ArgumentOutOfRangeException("len"); } if (len == 0) { return 0; } int bytesDecoded, charsDecoded; fixed (char* pChars = &chars[startPos]) { fixed (byte* pBytes = &_buffer[_curIndex]) { Decode(pChars, pChars + len, pBytes, pBytes + (_endIndex - _curIndex), out charsDecoded, out bytesDecoded); } } _curIndex += bytesDecoded; return charsDecoded; } internal override unsafe int Decode(string str, int startPos, int len) { if (str == null) { throw new ArgumentNullException("str"); } if (len < 0) { throw new ArgumentOutOfRangeException("len"); } if (startPos < 0) { throw new ArgumentOutOfRangeException("startPos"); } if (str.Length - startPos < len) { throw new ArgumentOutOfRangeException("len"); } if (len == 0) { return 0; } int bytesDecoded, charsDecoded; fixed (char* pChars = str) { fixed (byte* pBytes = &_buffer[_curIndex]) { Decode(pChars + startPos, pChars + startPos + len, pBytes, pBytes + (_endIndex - _curIndex), out charsDecoded, out bytesDecoded); } } _curIndex += bytesDecoded; return charsDecoded; } internal override void Reset() { _bitsFilled = 0; _bits = 0; } internal override void SetNextOutputBuffer(Array buffer, int index, int count) { Debug.Assert(buffer != null); Debug.Assert(count >= 0); Debug.Assert(index >= 0); Debug.Assert(buffer.Length - index >= count); Debug.Assert((buffer as byte[]) != null); _buffer = (byte[])buffer; _startIndex = index; _curIndex = index; _endIndex = index + count; } // // Private methods // private static byte[] ConstructMapBase64() { byte[] mapBase64 = new byte[MaxValidChar + 1]; for (int i = 0; i < mapBase64.Length; i++) { mapBase64[i] = Invalid; } for (int i = 0; i < s_charsBase64.Length; i++) { mapBase64[(int)s_charsBase64[i]] = (byte)i; } return mapBase64; } private unsafe void Decode(char* pChars, char* pCharsEndPos, byte* pBytes, byte* pBytesEndPos, out int charsDecoded, out int bytesDecoded) { #if DEBUG Debug.Assert(pCharsEndPos - pChars >= 0); Debug.Assert(pBytesEndPos - pBytes >= 0); #endif // walk hex digits pairing them up and shoving the value of each pair into a byte byte* pByte = pBytes; char* pChar = pChars; int b = _bits; int bFilled = _bitsFilled; XmlCharType xmlCharType = XmlCharType.Instance; while (pChar < pCharsEndPos && pByte < pBytesEndPos) { char ch = *pChar; // end? if (ch == '=') { break; } pChar++; // ignore white space if ((xmlCharType.charProperties[ch] & XmlCharType.fWhitespace) != 0) { // if ( xmlCharType.IsWhiteSpace(ch) ) { continue; } int digit; if (ch > 122 || (digit = s_mapBase64[ch]) == Invalid) { throw new XmlException(ResXml.Xml_InvalidBase64Value, new string(pChars, 0, (int)(pCharsEndPos - pChars))); } b = (b << 6) | digit; bFilled += 6; if (bFilled >= 8) { // get top eight valid bits *pByte++ = (byte)((b >> (bFilled - 8)) & 0xFF); bFilled -= 8; if (pByte == pBytesEndPos) { goto Return; } } } if (pChar < pCharsEndPos && *pChar == '=') { bFilled = 0; // ignore padding chars do { pChar++; } while (pChar < pCharsEndPos && *pChar == '='); // ignore whitespace after the padding chars if (pChar < pCharsEndPos) { do { if (!((xmlCharType.charProperties[*pChar++] & XmlCharType.fWhitespace) != 0)) { // if ( !( xmlCharType.IsWhiteSpace( chars[charPos++] ) ) ) { throw new XmlException(ResXml.Xml_InvalidBase64Value, new string(pChars, 0, (int)(pCharsEndPos - pChars))); } } while (pChar < pCharsEndPos); } } Return: _bits = b; _bitsFilled = bFilled; bytesDecoded = (int)(pByte - pBytes); charsDecoded = (int)(pChar - pChars); } } }