* ToBase64Transform.cs: Uncomment finalizer to fix public API
[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                 public ToBase64Transform ()
20                 {
21                 }
22
23                 ~ToBase64Transform ()
24                 {
25                         Dispose (false);
26                 }
27
28                 public bool CanTransformMultipleBlocks {
29                         get { return false; }
30                 }
31
32                 public virtual bool CanReuseTransform {
33                         get { return true; }
34                 }
35
36                 public int InputBlockSize {
37                         get { return 3; }
38                 }
39
40                 public int OutputBlockSize {
41                         get { return 4; }
42                 }
43
44                 public void Clear() 
45                 {
46                         Dispose (true);
47                 }
48
49                 void IDisposable.Dispose () 
50                 {
51                         Dispose (true);
52                         GC.SuppressFinalize (this);  // Finalization is now unnecessary
53                 }
54
55                 protected virtual void Dispose (bool disposing) 
56                 {
57                         if (!m_disposed) {
58                                 // dispose unmanaged objects
59                                 if (disposing) {
60                                         // dispose managed objects
61                                 }
62                                 m_disposed = true;
63                         }
64                 }
65
66                 // LAMESPEC: It's not clear from docs what should be happening 
67                 // here if inputCount > InputBlockSize. It just "Converts the 
68                 // specified region of the specified byte array" and that's all.
69                 public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
70                 {
71                         if (m_disposed)
72                                 throw new ObjectDisposedException ("TransformBlock");
73                         if (inputBuffer == null)
74                                 throw new ArgumentNullException ("inputBuffer");
75                         if (outputBuffer == null)
76                                 throw new ArgumentNullException ("outputBuffer");
77                         if (inputCount < 0)
78                                 throw new ArgumentException ("inputCount", "< 0");
79                         if (inputCount > inputBuffer.Length)
80                                 throw new ArgumentException ("inputCount", Locale.GetText ("Overflow"));
81                         if (inputOffset < 0)
82                                 throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
83                         // ordered to avoid possible integer overflow
84                         if (inputOffset > inputBuffer.Length - inputCount)
85                                 throw new ArgumentException ("inputOffset", Locale.GetText ("Overflow"));
86                         // ordered to avoid possible integer overflow
87                         if ((outputOffset < 0) || (outputOffset > outputBuffer.Length - inputCount))
88                                 throw new IndexOutOfRangeException ("outputOffset");
89 /// To match MS implementation
90 //                      if (inputCount != this.InputBlockSize)
91 //                              throw new CryptographicException (Locale.GetText ("Invalid input length"));
92
93                         byte[] lookup = Base64Constants.EncodeTable;
94
95                         int b1 = inputBuffer [inputOffset];
96                         int b2 = inputBuffer [inputOffset + 1];
97                         int b3 = inputBuffer [inputOffset + 2];
98
99                         outputBuffer [outputOffset] = lookup [b1 >> 2];
100                         outputBuffer [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)];
101                         outputBuffer [outputOffset+2] = lookup [((b2 << 2) & 0x3c) | (b3 >> 6)];
102                         outputBuffer [outputOffset+3] = lookup [b3 & 0x3f];
103
104                         return this.OutputBlockSize;
105                 }
106
107                 public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
108                 {
109                         if (m_disposed)
110                                 throw new ObjectDisposedException ("TransformFinalBlock");
111                         if (inputBuffer == null)
112                                 throw new ArgumentNullException ("inputBuffer");
113                         if (inputCount < 0)
114                                 throw new ArgumentException ("inputCount", "< 0");
115                         if (inputOffset > inputBuffer.Length - inputCount)
116                                 throw new ArgumentException ("inputCount", Locale.GetText ("Overflow"));
117                         if (inputCount > this.InputBlockSize)
118                                 throw new ArgumentOutOfRangeException (Locale.GetText ("Invalid input length"));
119                         
120                         return InternalTransformFinalBlock (inputBuffer, inputOffset, inputCount);
121                 }
122                 
123                 // Mono System.Convert depends on the ability to process multiple blocks                
124                 internal byte[] InternalTransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
125                 {
126                         int blockLen = this.InputBlockSize;
127                         int outLen = this.OutputBlockSize;
128                         int fullBlocks = inputCount / blockLen;
129                         int tail = inputCount % blockLen;
130
131                         byte[] res = new byte [(inputCount != 0)
132                                                 ? ((inputCount + 2) / blockLen) * outLen
133                                                 : 0];
134
135                         int outputOffset = 0;
136
137                         for (int i = 0; i < fullBlocks; i++) {
138
139                                 TransformBlock (inputBuffer, inputOffset,
140                                                 blockLen, res, outputOffset);
141
142                                 inputOffset += blockLen;
143                                 outputOffset += outLen;
144                         }
145
146                         byte[] lookup = Base64Constants.EncodeTable;
147                         int b1,b2;
148
149                         // When fewer than 24 input bits are available
150                         // in an input group, zero bits are added
151                         // (on the right) to form an integral number of
152                         // 6-bit groups.
153                         switch (tail) {
154                         case 0:
155                                 break;
156                         case 1:
157                                 b1 = inputBuffer [inputOffset];
158                                 res [outputOffset] = lookup [b1 >> 2];
159                                 res [outputOffset+1] = lookup [(b1 << 4) & 0x30];
160
161                                 // padding
162                                 res [outputOffset+2] = (byte)'=';
163                                 res [outputOffset+3] = (byte)'=';
164                                 break;
165
166                         case 2:
167                                 b1 = inputBuffer [inputOffset];
168                                 b2 = inputBuffer [inputOffset + 1];
169                                 res [outputOffset] = lookup [b1 >> 2];
170                                 res [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)];
171                                 res [outputOffset+2] = lookup [(b2 << 2) & 0x3c];
172
173                                 // one-byte padding
174                                 res [outputOffset+3] = (byte)'=';
175                                 break;
176                         }
177
178                         return res;
179                 }
180         }
181 }