375c42d5510e7d73d84d3c7504fbb611d3a461eb
[mono.git] / mcs / class / corlib / System.Security.Cryptography / FromBase64Transform.cs
1 //
2 // System.Security.Cryptography.FromBase64Transform
3 //
4 // Author:
5 //   Sergey Chaban (serge@wildwestsoftware.com)
6 //
7
8 using System;
9
10 namespace System.Security.Cryptography {
11
12         [Serializable]
13         public enum FromBase64TransformMode : int {
14                 IgnoreWhiteSpaces,
15                 DoNotIgnoreWhiteSpaces
16         }
17
18         public class FromBase64Transform : ICryptoTransform {
19
20                 private FromBase64TransformMode mode;
21                 private byte [] accumulator;
22                 private byte [] filterBuffer;
23                 private int accPtr;
24                 private bool m_disposed;
25
26
27                 /// <summary>
28                 ///  Creates a new instance of the decoder
29                 ///  with the default transformation mode (IgnoreWhiteSpaces).
30                 /// </summary>
31                 public FromBase64Transform ()
32                         : this (FromBase64TransformMode.IgnoreWhiteSpaces)
33                 {
34                 }
35
36
37                 /// <summary>
38                 ///  Creates a new instance of the decoder
39                 ///  with the specified transformation mode.
40                 /// </summary>
41                 public FromBase64Transform (FromBase64TransformMode mode)
42                 {
43                         this.mode = mode;
44                         accumulator = new byte [4];
45                         filterBuffer = new byte [4];
46                         accPtr = 0;
47                         m_disposed = false;
48                 }
49
50                 ~FromBase64Transform () 
51                 {
52                         Dispose (false);
53                 }
54
55
56                 /// <summary>
57                 /// </summary>
58                 public bool CanTransformMultipleBlocks {
59                         get {
60                                 return false;
61                         }
62                 }
63
64                 public virtual bool CanReuseTransform {
65                         get { return false; }
66                 }
67
68                 /// <summary>
69                 ///  Returns the input block size for the Base64 decoder.
70                 /// </summary>
71                 /// <remarks>
72                 ///  The input block size for Base64 decoder is always 1 byte.
73                 /// </remarks>
74                 public int InputBlockSize {
75                         get {
76                                 return 1;
77                         }
78                 }
79
80
81                 /// <summary>
82                 ///  Returns the output block size for the Base64 decoder.
83                 /// </summary>
84                 /// <remarks>
85                 ///  The value returned by this property is always 3.
86                 /// </remarks>
87                 public int OutputBlockSize {
88                         get {
89                                 return 3;
90                         }
91                 }
92
93                 public void Clear() 
94                 {
95                         Dispose (true);
96                 }
97
98                 void IDisposable.Dispose () 
99                 {
100                         Dispose (true);
101                         GC.SuppressFinalize (this);  // Finalization is now unnecessary
102                 }
103
104                 protected virtual void Dispose (bool disposing) 
105                 {
106                         if (!m_disposed) {
107                                 // dispose unmanaged objects
108                                 if (disposing) {
109                                         // dispose managed objects
110                                 }
111                                 m_disposed = true;
112                         }
113                 }
114
115                 private int Filter (byte [] buffer, int offset, int count)
116                 {
117                         int end = offset + count;
118                         int len = filterBuffer.Length;
119                         int ptr = 0;
120                         byte [] filter = this.filterBuffer;
121
122                         for (int i = offset; i < end; i++) {
123                                 byte b = buffer [i];
124                                 if (!Char.IsWhiteSpace ((char) b)) {
125                                         if (ptr >= len) {
126                                                 len <<= 1;
127                                                 this.filterBuffer = new byte [len];
128                                                 Array.Copy(filter, 0, this.filterBuffer, 0, len >> 1);
129                                                 filter = this.filterBuffer;
130                                         }
131                                         filter [ptr++] = b;
132                                 }
133                         }
134
135                         return ptr;
136                 }
137
138
139                 private int DoTransform (byte [] inputBuffer,
140                                          int inputOffset,
141                                          int inputCount,
142                                          byte [] outputBuffer,
143                                          int outputOffset)
144                 {
145                         int full = inputCount >> 2;
146                         if (full == 0) return 0;
147
148                         int rem = 0;
149
150                         if (inputBuffer[inputCount - 1] == (byte)'=') {
151                                 ++rem;
152                                 --full;
153                         }
154
155                         if (inputBuffer[inputCount - 2] == (byte)'=') ++rem;
156
157                         byte [] lookup = Base64Table.DecodeTable;
158                         int b0,b1,b2,b3;
159
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++]];
165
166                                 outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
167                                 outputBuffer [outputOffset++] = (byte) ((b1 << 4) | (b2 >> 2));
168                                 outputBuffer [outputOffset++] = (byte) ((b2 << 6) | b3);
169                         }
170
171                         int res = full * 3;
172
173                         switch (rem) {
174                         case 0:
175                                 break;
176                         case 1:
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));
182                                 res += 2;
183                                 break;
184                         case 2:
185                                 b0 = lookup [inputBuffer [inputOffset++]];
186                                 b1 = lookup [inputBuffer [inputOffset++]];
187                                 outputBuffer [outputOffset++] = (byte) ((b0 << 2) | (b1 >> 4));
188                                 ++res;
189                                 break;
190                         default:
191                                 break;
192                         }
193
194                         return res;
195                 }
196
197
198                 /// <summary>
199                 /// </summary>
200                 public int TransformBlock (byte [] inputBuffer,
201                                                    int inputOffset,
202                                                    int inputCount,
203                                                    byte [] outputBuffer,
204                                                    int outputOffset)
205                 {
206                         int n;
207                         byte [] src;
208                         int srcOff;
209                         int res = 0;
210
211                         if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
212                                 n = Filter (inputBuffer, inputOffset, inputCount);
213                                 src = filterBuffer;
214                                 srcOff = 0;
215                         } else {
216                                 n = inputCount;
217                                 src = inputBuffer;
218                                 srcOff = inputOffset;
219                         }
220
221
222                         int count = accPtr + n;
223
224                         if (count < 4) {
225                                 Array.Copy (src, srcOff, accumulator, accPtr, n);
226                                 accPtr = count;
227                         } else {
228                                 byte [] tmpBuff = new byte [count];
229                                 Array.Copy (accumulator, 0, tmpBuff, 0, accPtr);
230                                 Array.Copy (src, srcOff, tmpBuff, accPtr, n);
231                                 accPtr = count & 3;
232                                 Array.Copy (src, srcOff + (n - accPtr), accumulator, 0, accPtr);
233                                 res = DoTransform (tmpBuff, 0, count & (~3), outputBuffer, outputOffset);
234                         }
235
236
237                         return res;
238                 }
239
240
241                 /// <summary>
242                 /// </summary>
243                 public byte [] TransformFinalBlock (byte [] inputBuffer,
244                                                             int inputOffset,
245                                                             int inputCount)
246                 {
247                         byte [] src;
248                         int srcOff;
249                         int n;
250
251                         if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
252                                 n = Filter (inputBuffer, inputOffset, inputCount);
253                                 src = filterBuffer;
254                                 srcOff = 0;
255                         } else {
256                                 n = inputCount;
257                                 src = inputBuffer;
258                                 srcOff = inputOffset;
259                         }
260
261
262                         int dataLen = accPtr + n;
263                         byte [] tmpBuf = new byte [dataLen];
264
265                         int resLen = ((dataLen) >> 2) * 3;
266                         byte [] res = new byte [resLen];
267
268                         Array.Copy (accumulator, 0, tmpBuf, 0, accPtr);
269                         Array.Copy (src, srcOff, tmpBuf, accPtr, n);
270
271                         int actLen = DoTransform (tmpBuf, 0, dataLen, res, 0);
272
273                         accPtr = 0;
274
275                         if (actLen < resLen) {
276                                 byte [] newres = new byte [actLen];
277
278                                 Array.Copy (res, newres, actLen);
279                                 return newres;
280                         } else
281                         return res;
282                 }
283
284         } // FromBase64Transform
285
286 } // System.Security.Cryptography