2004-05-05 Sebastien Pouliot <sebastien@ximian.com>
[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 // (C) 2004 Novell (http://www.novell.com)
8 //
9
10 using System;
11 using System.Globalization;
12
13 namespace System.Security.Cryptography {
14
15         public class ToBase64Transform : ICryptoTransform {
16
17                 private bool m_disposed;
18
19                 /// <summary>
20                 ///  Default constructor.
21                 /// </summary>
22                 public ToBase64Transform ()
23                 {
24                 }
25
26                 /* Right now we have nothing to dispose to finalizer isn't required
27                 ~ToBase64Transform () 
28                 {
29                         Dispose (false);
30                 }*/
31
32                 public bool CanTransformMultipleBlocks {
33                         get { return false; }
34                 }
35
36                 public virtual 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 { return 3; }
48                 }
49
50                 /// <summary>
51                 ///  Returns the output block size for the Base64 encoder.
52                 /// </summary>
53                 /// <remarks>
54                 ///  The value returned by this property is always 4.
55                 /// </remarks>
56                 public int OutputBlockSize {
57                         get { return 4; }
58                 }
59
60                 public void Clear() 
61                 {
62                         Dispose (true);
63                 }
64
65                 void IDisposable.Dispose () 
66                 {
67                         Dispose (true);
68                         GC.SuppressFinalize (this);  // Finalization is now unnecessary
69                 }
70
71                 protected virtual void Dispose (bool disposing) 
72                 {
73                         if (!m_disposed) {
74                                 // dispose unmanaged objects
75                                 if (disposing) {
76                                         // dispose managed objects
77                                 }
78                                 m_disposed = true;
79                         }
80                 }
81
82                 public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
83                 {
84                         if (inputCount != this.InputBlockSize)
85                                 throw new CryptographicException (Locale.GetText ("Invalid input length"));
86
87                         byte[] lookup = Base64Constants.EncodeTable;
88
89                         int b1 = inputBuffer [inputOffset];
90                         int b2 = inputBuffer [inputOffset + 1];
91                         int b3 = inputBuffer [inputOffset + 2];
92
93                         outputBuffer [outputOffset] = lookup [b1 >> 2];
94                         outputBuffer [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)];
95                         outputBuffer [outputOffset+2] = lookup [((b2 << 2) & 0x3c) | (b3 >> 6)];
96                         outputBuffer [outputOffset+3] = lookup [b3 & 0x3f];
97
98                         return this.OutputBlockSize;
99                 }
100
101                 // LAMESPEC: It's not clear from Beta2 docs what should be
102                 // happening here if inputCount > InputBlockSize.
103                 // It just "Converts the specified region of the specified
104                 // byte array" and that's all.
105                 // Beta2 implementation throws some strange (and undocumented)
106                 // exception in such case. The exception is thrown by
107                 // System.Convert and not the method itself.
108                 // Anyhow, this implementation just encodes blocks of any size,
109                 // like any usual Base64 encoder.
110
111                 public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
112                 {
113                         int blockLen = this.InputBlockSize;
114                         int outLen = this.OutputBlockSize;
115                         int fullBlocks = inputCount / blockLen;
116                         int tail = inputCount % blockLen;
117
118                         byte[] res = new byte [(inputCount != 0)
119                                                 ? ((inputCount + 2) / blockLen) * outLen
120                                                 : 0];
121
122                         int outputOffset = 0;
123
124                         for (int i = 0; i < fullBlocks; i++) {
125
126                                 TransformBlock (inputBuffer, inputOffset,
127                                                 blockLen, res, outputOffset);
128
129                                 inputOffset += blockLen;
130                                 outputOffset += outLen;
131                         }
132
133                         byte[] lookup = Base64Constants.EncodeTable;
134                         int b1,b2;
135
136                         // When fewer than 24 input bits are available
137                         // in an input group, zero bits are added
138                         // (on the right) to form an integral number of
139                         // 6-bit groups.
140                         switch (tail) {
141                         case 0:
142                                 break;
143                         case 1:
144                                 b1 = inputBuffer [inputOffset];
145                                 res [outputOffset] = lookup [b1 >> 2];
146                                 res [outputOffset+1] = lookup [(b1 << 4) & 0x30];
147
148                                 // padding
149                                 res [outputOffset+2] = (byte)'=';
150                                 res [outputOffset+3] = (byte)'=';
151                                 break;
152
153                         case 2:
154                                 b1 = inputBuffer [inputOffset];
155                                 b2 = inputBuffer [inputOffset + 1];
156                                 res [outputOffset] = lookup [b1 >> 2];
157                                 res [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)];
158                                 res [outputOffset+2] = lookup [(b2 << 2) & 0x3c];
159
160                                 // one-byte padding
161                                 res [outputOffset+3] = (byte)'=';
162                                 break;
163                         }
164
165                         return res;
166                 }
167         }
168 }