//
// System.Security.Cryptography.FromBase64Transform
//
// Author:
// Sergey Chaban (serge@wildwestsoftware.com)
//
using System;
using System.Security.Cryptography;
namespace System.Security.Cryptography {
public enum FromBase64TransformMode : int {
IgnoreWhiteSpaces,
DoNotIgnoreWhiteSpaces
}
public class FromBase64Transform : ICryptoTransform {
private FromBase64TransformMode mode;
private byte [] accumulator;
private byte [] filterBuffer;
private int accPtr;
///
/// Creates a new instance of the decoder
/// with the default transformation mode (IgnoreWhiteSpaces).
///
public FromBase64Transform ()
: this (FromBase64TransformMode.IgnoreWhiteSpaces)
{
}
///
/// Creates a new instance of the decoder
/// with the specified transformation mode.
///
public FromBase64Transform (FromBase64TransformMode mode)
{
this.mode = mode;
accumulator = new byte [4];
filterBuffer = new byte [4];
accPtr = 0;
}
///
///
public virtual bool CanTransformMultipleBlocks {
get {
return false;
}
}
///
/// Returns the input block size for the Base64 decoder.
///
///
/// The input block size for Base64 decoder is always 1 byte.
///
public virtual int InputBlockSize {
get {
return 1;
}
}
///
/// Returns the output block size for the Base64 decoder.
///
///
/// The value returned by this property is always 3.
///
public virtual int OutputBlockSize {
get {
return 3;
}
}
private int Filter (byte [] buffer, int offset, int count)
{
int end = offset + count;
int len = filterBuffer.Length;
int ptr = 0;
byte [] filter = this.filterBuffer;
for (int i = offset; i < end; i++) {
byte b = buffer [i];
if (!Char.IsWhiteSpace ((char) b)) {
if (ptr >= len) {
len <<= 1;
this.filterBuffer = new byte [len];
Array.Copy(filter, 0, this.filterBuffer, 0, len >> 1);
filter = this.filterBuffer;
}
filter [ptr++] = b;
}
}
return ptr;
}
private int DoTransform (byte [] inputBuffer,
int inputOffset,
int inputCount,
byte [] outputBuffer,
int outputOffset)
{
int full = inputCount >> 2;
if (full == 0) return 0;
int rem = 0;
if (inputBuffer[inputCount - 1] == (byte)'=') {
++rem;
--full;
}
if (inputBuffer[inputCount - 2] == (byte)'=') ++rem;
byte [] lookup = Base64Table.DecodeTable;
int b0,b1,b2,b3;
for (int i = 0; i < full; i++) {
b0 = lookup [inputBuffer [inputOffset++]];
b1 = lookup [inputBuffer [inputOffset++]];
b2 = lookup [inputBuffer [inputOffset++]];
b3 = lookup [inputBuffer [inputOffset++]];
outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
outputBuffer [outputOffset++] = (byte) ((b2 << 6) | b3);
}
int res = full * 3;
switch (rem) {
case 0:
break;
case 1:
b0 = lookup [inputBuffer [inputOffset++]];
b1 = lookup [inputBuffer [inputOffset++]];
b2 = lookup [inputBuffer [inputOffset++]];
outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
res += 2;
break;
case 2:
b0 = lookup [inputBuffer [inputOffset++]];
b1 = lookup [inputBuffer [inputOffset++]];
outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
++res;
break;
default:
break;
}
return res;
}
///
///
public virtual int TransformBlock (byte [] inputBuffer,
int inputOffset,
int inputCount,
byte [] outputBuffer,
int outputOffset)
{
int n;
byte [] src;
int srcOff;
int res = 0;
if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
n = Filter (inputBuffer, inputOffset, inputCount);
src = filterBuffer;
srcOff = 0;
} else {
n = inputCount;
src = inputBuffer;
srcOff = inputOffset;
}
int count = accPtr + n;
if (count < 4) {
Array.Copy (src, srcOff, accumulator, accPtr, n);
accPtr = count;
} else {
byte [] tmpBuff = new byte [count];
Array.Copy (accumulator, 0, tmpBuff, 0, accPtr);
Array.Copy (src, srcOff, tmpBuff, accPtr, n);
accPtr = count & 3;
Array.Copy (src, srcOff + (n - accPtr), accumulator, 0, accPtr);
res = DoTransform (tmpBuff, 0, count & (~3), outputBuffer, outputOffset);
}
return res;
}
///
///
public virtual byte [] TransformFinalBlock (byte [] inputBuffer,
int inputOffset,
int inputCount)
{
byte [] src;
int srcOff;
int n;
if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
n = Filter (inputBuffer, inputOffset, inputCount);
src = filterBuffer;
srcOff = 0;
} else {
n = inputCount;
src = inputBuffer;
srcOff = inputOffset;
}
int dataLen = accPtr + n;
byte [] tmpBuf = new byte [dataLen];
int resLen = ((dataLen) >> 2) * 3;
byte [] res = new byte [resLen];
Array.Copy (accumulator, 0, tmpBuf, 0, accPtr);
Array.Copy (src, srcOff, tmpBuf, accPtr, n);
DoTransform (tmpBuf, 0, dataLen, res, 0);
accPtr = 0;
return res;
}
///
///
public override string ToString ()
{
return "mono::System.Security.Cryptography.FromBase64Transform";
}
} // FromBase64Transform
} // System.Security.Cryptography