singrdk/base/Applications/MapPointProxy/Base64Decoder.cs

154 lines
4.3 KiB
C#

// ----------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ----------------------------------------------------------------------------
using System;
using Microsoft.Contracts;
internal class Base64Decoder
{
private string fSourceStr;
private int fCurStrIndex;
private bool fDone;
private int fBits;
private int fBitsFilled;
private const string CharsBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
private static readonly byte[] MapBase64 = ConstructMapBase64();
private const int MaxValidChar = (int)'z';
private const byte Invalid = unchecked((byte)-1);
public Base64Decoder(string! sourceString, int startIndex)
{
fSourceStr = sourceString;
fCurStrIndex = startIndex;
fDone = false;
Reset();
}
[Delayed]
public void Reset()
{
fBits = 0;
fBitsFilled = 0;
}
public byte[] Pump(int maxStrIndex, int maxReturnSize)
{
if ((fDone) || (fSourceStr == null)) {
return null;
}
int charsConsumed;
byte[] retval = InternalPump(fSourceStr, fCurStrIndex, maxStrIndex, maxReturnSize,
out charsConsumed, out fDone);
fCurStrIndex += charsConsumed;
return retval;
}
private byte[] InternalPump(string! sourceStr, int startIndex, int maxIndex, int maxReturnSize,
out int charsConsumed, out bool done)
{
// walk hex digits pairing them up and shoving the value of each pair into a byte
byte[] newChunk = new byte[maxReturnSize];
int bytePos = 0;
int charPos = startIndex;
int b = fBits;
int bFilled = fBitsFilled;
while (charPos < maxIndex && bytePos < maxReturnSize) {
char ch = sourceStr[charPos];
// end?
if (ch == '=') {
done = true;
break;
}
charPos++;
// ignore white space
if (char.IsWhiteSpace(ch)) {
continue;
}
int digit;
if (ch > 122 || (digit = MapBase64[ch]) == Invalid) {
throw new Exception("Invalid Base64 character: " + ch);
}
b = ( b << 6 ) | digit;
bFilled += 6;
if (bFilled >= 8) {
// get top eight valid bits
newChunk[bytePos++] = (byte)( ( b >> ( bFilled - 8 ) ) & 0xFF );
bFilled -= 8;
if (bytePos == maxReturnSize) {
break;
}
}
}
if (bytePos < maxReturnSize) {
if (charPos < maxIndex && sourceStr[charPos] == '=') {
bFilled = 0;
// ignore padding chars
do {
charPos++;
} while (charPos < maxIndex && sourceStr[charPos] == '=');
// ignore whitespace after the padding chars
if (charPos < maxIndex) {
while (charPos < maxIndex) {
if (!char.IsWhiteSpace(sourceStr[charPos++]))
throw new Exception("Invalid Base64 character: " + sourceStr[charPos - 1]);
}
}
}
}
fBits = b;
fBitsFilled = bFilled;
charsConsumed = charPos - startIndex;
if (bytePos < maxReturnSize) {
byte[] trimmed = new byte[bytePos];
Buffer.BlockCopy(newChunk, 0, trimmed, 0, bytePos);
newChunk = trimmed;
// We ran out of characters, so we're done
done = true;
}
else {
done = false;
}
return newChunk;
}
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 < CharsBase64.Length; i++) {
mapBase64[(int)CharsBase64[i]] = (byte)i;
}
return mapBase64;
}
}