Copied remotely
[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 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Globalization;
35
36 namespace System.Security.Cryptography {
37
38         public class ToBase64Transform : ICryptoTransform {
39
40                 private bool m_disposed;
41
42                 public ToBase64Transform ()
43                 {
44                 }
45
46                 ~ToBase64Transform ()
47                 {
48                         Dispose (false);
49                 }
50
51                 public bool CanTransformMultipleBlocks {
52                         get { return false; }
53                 }
54
55                 public virtual bool CanReuseTransform {
56                         get { return true; }
57                 }
58
59                 public int InputBlockSize {
60                         get { return 3; }
61                 }
62
63                 public int OutputBlockSize {
64                         get { return 4; }
65                 }
66
67                 public void Clear() 
68                 {
69                         Dispose (true);
70                 }
71
72                 void IDisposable.Dispose () 
73                 {
74                         Dispose (true);
75                         GC.SuppressFinalize (this);  // Finalization is now unnecessary
76                 }
77
78                 protected virtual void Dispose (bool disposing) 
79                 {
80                         if (!m_disposed) {
81                                 // dispose unmanaged objects
82                                 if (disposing) {
83                                         // dispose managed objects
84                                 }
85                                 m_disposed = true;
86                         }
87                 }
88
89                 // LAMESPEC: It's not clear from docs what should be happening 
90                 // here if inputCount > InputBlockSize. It just "Converts the 
91                 // specified region of the specified byte array" and that's all.
92                 public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
93                 {
94                         if (m_disposed)
95                                 throw new ObjectDisposedException ("TransformBlock");
96                         if (inputBuffer == null)
97                                 throw new ArgumentNullException ("inputBuffer");
98                         if (outputBuffer == null)
99                                 throw new ArgumentNullException ("outputBuffer");
100                         if (inputCount < 0)
101                                 throw new ArgumentException ("inputCount", "< 0");
102                         if (inputCount > inputBuffer.Length)
103                                 throw new ArgumentException ("inputCount", Locale.GetText ("Overflow"));
104                         if (inputOffset < 0)
105                                 throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
106                         // ordered to avoid possible integer overflow
107                         if (inputOffset > inputBuffer.Length - inputCount)
108                                 throw new ArgumentException ("inputOffset", Locale.GetText ("Overflow"));
109                         // ordered to avoid possible integer overflow
110                         if ((outputOffset < 0) || (outputOffset > outputBuffer.Length - inputCount))
111                                 throw new IndexOutOfRangeException ("outputOffset");
112 /// To match MS implementation
113 //                      if (inputCount != this.InputBlockSize)
114 //                              throw new CryptographicException (Locale.GetText ("Invalid input length"));
115
116                         byte[] lookup = Base64Constants.EncodeTable;
117
118                         int b1 = inputBuffer [inputOffset];
119                         int b2 = inputBuffer [inputOffset + 1];
120                         int b3 = inputBuffer [inputOffset + 2];
121
122                         outputBuffer [outputOffset] = lookup [b1 >> 2];
123                         outputBuffer [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)];
124                         outputBuffer [outputOffset+2] = lookup [((b2 << 2) & 0x3c) | (b3 >> 6)];
125                         outputBuffer [outputOffset+3] = lookup [b3 & 0x3f];
126
127                         return this.OutputBlockSize;
128                 }
129
130                 public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
131                 {
132                         if (m_disposed)
133                                 throw new ObjectDisposedException ("TransformFinalBlock");
134                         if (inputBuffer == null)
135                                 throw new ArgumentNullException ("inputBuffer");
136                         if (inputCount < 0)
137                                 throw new ArgumentException ("inputCount", "< 0");
138                         if (inputOffset > inputBuffer.Length - inputCount)
139                                 throw new ArgumentException ("inputCount", Locale.GetText ("Overflow"));
140                         if (inputCount > this.InputBlockSize)
141                                 throw new ArgumentOutOfRangeException (Locale.GetText ("Invalid input length"));
142                         
143                         return InternalTransformFinalBlock (inputBuffer, inputOffset, inputCount);
144                 }
145                 
146                 // Mono System.Convert depends on the ability to process multiple blocks                
147                 internal byte[] InternalTransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
148                 {
149                         int blockLen = this.InputBlockSize;
150                         int outLen = this.OutputBlockSize;
151                         int fullBlocks = inputCount / blockLen;
152                         int tail = inputCount % blockLen;
153
154                         byte[] res = new byte [(inputCount != 0)
155                                                 ? ((inputCount + 2) / blockLen) * outLen
156                                                 : 0];
157
158                         int outputOffset = 0;
159
160                         for (int i = 0; i < fullBlocks; i++) {
161
162                                 TransformBlock (inputBuffer, inputOffset,
163                                                 blockLen, res, outputOffset);
164
165                                 inputOffset += blockLen;
166                                 outputOffset += outLen;
167                         }
168
169                         byte[] lookup = Base64Constants.EncodeTable;
170                         int b1,b2;
171
172                         // When fewer than 24 input bits are available
173                         // in an input group, zero bits are added
174                         // (on the right) to form an integral number of
175                         // 6-bit groups.
176                         switch (tail) {
177                         case 0:
178                                 break;
179                         case 1:
180                                 b1 = inputBuffer [inputOffset];
181                                 res [outputOffset] = lookup [b1 >> 2];
182                                 res [outputOffset+1] = lookup [(b1 << 4) & 0x30];
183
184                                 // padding
185                                 res [outputOffset+2] = (byte)'=';
186                                 res [outputOffset+3] = (byte)'=';
187                                 break;
188
189                         case 2:
190                                 b1 = inputBuffer [inputOffset];
191                                 b2 = inputBuffer [inputOffset + 1];
192                                 res [outputOffset] = lookup [b1 >> 2];
193                                 res [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)];
194                                 res [outputOffset+2] = lookup [(b2 << 2) & 0x3c];
195
196                                 // one-byte padding
197                                 res [outputOffset+3] = (byte)'=';
198                                 break;
199                         }
200
201                         return res;
202                 }
203         }
204 }