2002-11-15 Sebastien Pouliot <spouliot@videotron.ca>
[mono.git] / mcs / class / corlib / System.Security.Cryptography / ToBase64Transform.cs
1 //
2 // System.Security.Cryptography.ToBase64Transform
3 //
4 // Author:
5 //   Sergey Chaban (serge@wildwestsoftware.com)
6 //
7
8 using System;
9
10 namespace System.Security.Cryptography {
11
12         public class ToBase64Transform : ICryptoTransform {
13
14                 private bool m_disposed;
15
16                 /// <summary>
17                 ///  Default constructor.
18                 /// </summary>
19                 public ToBase64Transform ()
20                 {
21                 }
22
23                 ~ToBase64Transform () 
24                 {
25                         Dispose (false);
26                 }
27
28                 /// <summary>
29                 /// </summary>
30                 public bool CanTransformMultipleBlocks {
31                         get {
32                                 return false;
33                         }
34                 }
35
36                 public bool CanReuseTransform {
37                         get { return false; }
38                 }
39
40                 /// <summary>
41                 ///  Returns the input block size for the Base64 encoder.
42                 /// </summary>
43                 /// <remarks>
44                 ///  The returned value is always 3.
45                 /// </remarks>
46                 public int InputBlockSize {
47                         get {
48                                 return 3;
49                         }
50                 }
51
52
53                 /// <summary>
54                 ///  Returns the output block size for the Base64 encoder.
55                 /// </summary>
56                 /// <remarks>
57                 ///  The value returned by this property is always 4.
58                 /// </remarks>
59                 public int OutputBlockSize {
60                         get {
61                                 return 4;
62                         }
63                 }
64
65                 public void Clear() 
66                 {
67                         Dispose (true);
68                 }
69
70                 void IDisposable.Dispose () 
71                 {
72                         Dispose (true);
73                         GC.SuppressFinalize (this);  // Finalization is now unnecessary
74                 }
75
76                 protected virtual void Dispose (bool disposing) 
77                 {
78                         if (!m_disposed) {
79                                 // dispose unmanaged objects
80                                 if (disposing) {
81                                         // dispose managed objects
82                                 }
83                                 m_disposed = true;
84                         }
85                 }
86
87                 /// <summary>
88                 /// </summary>
89                 public int TransformBlock (byte [] inputBuffer,
90                                                    int inputOffset,
91                                                    int inputCount,
92                                                    byte [] outputBuffer,
93                                                    int outputOffset)
94                 {
95                         if (inputCount != this.InputBlockSize)
96                                 throw new CryptographicException();
97
98                         byte [] lookup = Base64Table.EncodeTable;
99
100                         int b1 = inputBuffer [inputOffset];
101                         int b2 = inputBuffer [inputOffset + 1];
102                         int b3 = inputBuffer [inputOffset + 2];
103
104                         outputBuffer [outputOffset] = lookup [b1 >> 2];
105                         outputBuffer [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)];
106                         outputBuffer [outputOffset+2] = lookup [((b2 << 2) & 0x3c) | (b3 >> 6)];
107                         outputBuffer [outputOffset+3] = lookup [b3 & 0x3f];
108
109                         return this.OutputBlockSize;
110                 }
111
112
113
114
115                 // LAMESPEC: It's not clear from Beta2 docs what should be
116                 // happening here if inputCount > InputBlockSize.
117                 // It just "Converts the specified region of the specified
118                 // byte array" and that's all.
119                 // Beta2 implementation throws some strange (and undocumented)
120                 // exception in such case. The exception is thrown by
121                 // System.Convert and not the method itself.
122                 // Anyhow, this implementation just encodes blocks of any size,
123                 // like any usual Base64 encoder.
124
125                 /// <summary>
126                 /// </summary>
127                 public byte [] TransformFinalBlock (byte [] inputBuffer,
128                                                             int inputOffset,
129                                                             int inputCount)
130                 {
131                         int blockLen = this.InputBlockSize;
132                         int outLen = this.OutputBlockSize;
133                         int fullBlocks = inputCount / blockLen;
134                         int tail = inputCount % blockLen;
135
136                         byte [] res = new byte [(inputCount != 0)
137                                                 ? ((inputCount + 2) / blockLen) * outLen
138                                                 : 0];
139
140                         int outputOffset = 0;
141
142                         for (int i = 0; i < fullBlocks; i++) {
143
144                                 TransformBlock (inputBuffer, inputOffset,
145                                                 blockLen, res, outputOffset);
146
147                                 inputOffset += blockLen;
148                                 outputOffset += outLen;
149                         }
150
151
152                         byte [] lookup = Base64Table.EncodeTable;
153                         int b1,b2;
154
155
156                         // When fewer than 24 input bits are available
157                         // in an input group, zero bits are added
158                         // (on the right) to form an integral number of
159                         // 6-bit groups.
160                         switch (tail) {
161                         case 0:
162                                 break;
163                         case 1:
164                                 b1 = inputBuffer [inputOffset];
165                                 res [outputOffset] = lookup [b1 >> 2];
166                                 res [outputOffset+1] = lookup [(b1 << 4) & 0x30];
167
168                                 // padding
169                                 res [outputOffset+2] = (byte)'=';
170                                 res [outputOffset+3] = (byte)'=';
171                                 break;
172
173                         case 2:
174                                 b1 = inputBuffer [inputOffset];
175                                 b2 = inputBuffer [inputOffset + 1];
176                                 res [outputOffset] = lookup [b1 >> 2];
177                                 res [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)];
178                                 res [outputOffset+2] = lookup [(b2 << 2) & 0x3c];
179
180                                 // one-byte padding
181                                 res [outputOffset+3] = (byte)'=';
182                                 break;
183
184                         default:
185                                 break;
186                         }
187
188                         return res;
189                 }
190
191         } // ToBase64Transform
192
193
194
195         
196         [MonoTODO ("Put me in a separate file")]
197         internal sealed class Base64Table {
198
199                 // This is the Base64 alphabet as described in RFC 2045
200                 // (Table 1, page 25).
201                 private static string ALPHABET =
202                         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
203
204                 private static byte[] encodeTable;
205                 private static byte[] decodeTable;
206
207
208                 static Base64Table ()
209                 {
210                         int len = ALPHABET.Length;
211
212                         encodeTable = new byte [len];
213
214                         for (int i=0; i < len; i++) {
215                                 encodeTable [i] = (byte) ALPHABET [i];
216                         }
217
218
219                         decodeTable = new byte [1 + (int)'z'];
220
221                         for (int i=0; i < decodeTable.Length; i++) {
222                                 decodeTable [i] = Byte.MaxValue;
223                         }
224
225                         for (int i=0; i < len; i++) {
226                                 char ch = ALPHABET [i];
227                                 decodeTable [(int)ch] = (byte) i;
228                         }
229                 }
230
231
232                 private Base64Table ()
233                 {
234                         // Never instantiated.
235                 }
236
237
238                 internal static byte [] EncodeTable {
239                         get {
240                                 return encodeTable;
241                         }
242                 }
243
244                 internal static byte [] DecodeTable {
245                         get {
246                                 return decodeTable;
247                         }
248                 }
249
250         } // Base64Table
251
252 } // System.Security.Cryptography