2 // System.Security.Cryptography.FromBase64Transform
5 // Sergey Chaban (serge@wildwestsoftware.com)
10 namespace System.Security.Cryptography {
13 public enum FromBase64TransformMode : int {
15 DoNotIgnoreWhiteSpaces
18 public class FromBase64Transform : ICryptoTransform {
20 private FromBase64TransformMode mode;
21 private byte [] accumulator;
22 private byte [] filterBuffer;
24 private bool m_disposed;
28 /// Creates a new instance of the decoder
29 /// with the default transformation mode (IgnoreWhiteSpaces).
31 public FromBase64Transform ()
32 : this (FromBase64TransformMode.IgnoreWhiteSpaces)
38 /// Creates a new instance of the decoder
39 /// with the specified transformation mode.
41 public FromBase64Transform (FromBase64TransformMode mode)
44 accumulator = new byte [4];
45 filterBuffer = new byte [4];
50 ~FromBase64Transform ()
58 public bool CanTransformMultipleBlocks {
64 public virtual bool CanReuseTransform {
69 /// Returns the input block size for the Base64 decoder.
72 /// The input block size for Base64 decoder is always 1 byte.
74 public int InputBlockSize {
82 /// Returns the output block size for the Base64 decoder.
85 /// The value returned by this property is always 3.
87 public int OutputBlockSize {
98 void IDisposable.Dispose ()
101 GC.SuppressFinalize (this); // Finalization is now unnecessary
104 protected virtual void Dispose (bool disposing)
107 // dispose unmanaged objects
109 // dispose managed objects
115 private int Filter (byte [] buffer, int offset, int count)
117 int end = offset + count;
118 int len = filterBuffer.Length;
120 byte [] filter = this.filterBuffer;
122 for (int i = offset; i < end; i++) {
124 if (!Char.IsWhiteSpace ((char) b)) {
127 this.filterBuffer = new byte [len];
128 Array.Copy(filter, 0, this.filterBuffer, 0, len >> 1);
129 filter = this.filterBuffer;
139 private int DoTransform (byte [] inputBuffer,
142 byte [] outputBuffer,
145 int full = inputCount >> 2;
146 if (full == 0) return 0;
150 if (inputBuffer[inputCount - 1] == (byte)'=') {
155 if (inputBuffer[inputCount - 2] == (byte)'=') ++rem;
157 byte [] lookup = Base64Table.DecodeTable;
160 for (int i = 0; i < full; i++) {
161 b0 = lookup [inputBuffer [inputOffset++]];
162 b1 = lookup [inputBuffer [inputOffset++]];
163 b2 = lookup [inputBuffer [inputOffset++]];
164 b3 = lookup [inputBuffer [inputOffset++]];
166 outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
167 outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
168 outputBuffer [outputOffset++] = (byte) ((b2 << 6) | b3);
177 b0 = lookup [inputBuffer [inputOffset++]];
178 b1 = lookup [inputBuffer [inputOffset++]];
179 b2 = lookup [inputBuffer [inputOffset++]];
180 outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
181 outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
185 b0 = lookup [inputBuffer [inputOffset++]];
186 b1 = lookup [inputBuffer [inputOffset++]];
187 outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
200 public int TransformBlock (byte [] inputBuffer,
203 byte [] outputBuffer,
211 if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
212 n = Filter (inputBuffer, inputOffset, inputCount);
218 srcOff = inputOffset;
222 int count = accPtr + n;
225 Array.Copy (src, srcOff, accumulator, accPtr, n);
228 byte [] tmpBuff = new byte [count];
229 Array.Copy (accumulator, 0, tmpBuff, 0, accPtr);
230 Array.Copy (src, srcOff, tmpBuff, accPtr, n);
232 Array.Copy (src, srcOff + (n - accPtr), accumulator, 0, accPtr);
233 res = DoTransform (tmpBuff, 0, count & (~3), outputBuffer, outputOffset);
243 public byte [] TransformFinalBlock (byte [] inputBuffer,
251 if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
252 n = Filter (inputBuffer, inputOffset, inputCount);
258 srcOff = inputOffset;
262 int dataLen = accPtr + n;
263 byte [] tmpBuf = new byte [dataLen];
265 int resLen = ((dataLen) >> 2) * 3;
266 byte [] res = new byte [resLen];
268 Array.Copy (accumulator, 0, tmpBuf, 0, accPtr);
269 Array.Copy (src, srcOff, tmpBuf, accPtr, n);
271 int actLen = DoTransform (tmpBuf, 0, dataLen, res, 0);
275 if (actLen < resLen) {
276 byte [] newres = new byte [actLen];
278 Array.Copy (res, newres, actLen);
284 } // FromBase64Transform
286 } // System.Security.Cryptography