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 ()
56 public bool CanTransformMultipleBlocks {
60 public virtual bool CanReuseTransform {
65 /// Returns the input block size for the Base64 decoder.
68 /// The input block size for Base64 decoder is always 1 byte.
70 public int InputBlockSize {
78 /// Returns the output block size for the Base64 decoder.
81 /// The value returned by this property is always 3.
83 public int OutputBlockSize {
94 void IDisposable.Dispose ()
97 GC.SuppressFinalize (this); // Finalization is now unnecessary
100 protected virtual void Dispose (bool disposing)
103 // dispose unmanaged objects
105 // dispose managed objects
111 private int Filter (byte [] buffer, int offset, int count)
113 int end = offset + count;
114 int len = filterBuffer.Length;
116 byte [] filter = this.filterBuffer;
118 for (int i = offset; i < end; i++) {
120 if (!Char.IsWhiteSpace ((char) b)) {
123 this.filterBuffer = new byte [len];
124 Array.Copy(filter, 0, this.filterBuffer, 0, len >> 1);
125 filter = this.filterBuffer;
134 private byte [] lookupTable;
136 private byte lookup(byte input) {
138 if ((input >= lookupTable.Length) ||
139 ((ret = lookupTable[input]) == Byte.MaxValue))
140 throw new System.FormatException("Invalid character in a Base-64 string.");
144 private int DoTransform (byte [] inputBuffer,
147 byte [] outputBuffer,
150 int full = inputCount >> 2;
151 if (full == 0) return 0;
155 if (inputBuffer[inputCount - 1] == (byte)'=') {
160 if (inputBuffer[inputCount - 2] == (byte)'=') ++rem;
162 lookupTable = Base64Table.DecodeTable;
165 for (int i = 0; i < full; i++) {
166 b0 = lookup (inputBuffer [inputOffset++]);
167 b1 = lookup (inputBuffer [inputOffset++]);
168 b2 = lookup (inputBuffer [inputOffset++]);
169 b3 = lookup (inputBuffer [inputOffset++]);
171 outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
172 outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
173 outputBuffer [outputOffset++] = (byte) ((b2 << 6) | b3);
182 b0 = lookup (inputBuffer [inputOffset++]);
183 b1 = lookup (inputBuffer [inputOffset++]);
184 b2 = lookup (inputBuffer [inputOffset++]);
185 outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
186 outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
190 b0 = lookup (inputBuffer [inputOffset++]);
191 b1 = lookup (inputBuffer [inputOffset++]);
192 outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
205 public int TransformBlock (byte [] inputBuffer,
208 byte [] outputBuffer,
212 throw new ObjectDisposedException ("FromBase64Transform");
219 if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
220 n = Filter (inputBuffer, inputOffset, inputCount);
226 srcOff = inputOffset;
230 int count = accPtr + n;
233 Array.Copy (src, srcOff, accumulator, accPtr, n);
236 byte [] tmpBuff = new byte [count];
237 Array.Copy (accumulator, 0, tmpBuff, 0, accPtr);
238 Array.Copy (src, srcOff, tmpBuff, accPtr, n);
240 Array.Copy (src, srcOff + (n - accPtr), accumulator, 0, accPtr);
241 res = DoTransform (tmpBuff, 0, count & (~3), outputBuffer, outputOffset) ;
250 public byte [] TransformFinalBlock (byte [] inputBuffer,
255 throw new ObjectDisposedException ("FromBase64Transform");
261 if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
262 n = Filter (inputBuffer, inputOffset, inputCount);
268 srcOff = inputOffset;
271 int dataLen = accPtr + n;
272 byte [] tmpBuf = new byte [dataLen];
274 int resLen = ((dataLen) >> 2) * 3;
275 byte [] res = new byte [resLen];
277 Array.Copy (accumulator, 0, tmpBuf, 0, accPtr);
278 Array.Copy (src, srcOff, tmpBuf, accPtr, n);
282 actLen = DoTransform (tmpBuf, 0, dataLen, res, 0);
284 catch (System.FormatException e) {
290 if (actLen < resLen) {
291 byte [] newres = new byte [actLen];
293 Array.Copy (res, newres, actLen);
300 } // FromBase64Transform
302 } // System.Security.Cryptography