2010-06-21 Atsushi Enomoto <atsushi@ximian.com>
[mcs.git] / class / corlib / System.Security.Cryptography / FromBase64Transform.cs
bloba8c3e89e3fe882b33606bc486f4ef4cad571a181
1 //
2 // System.Security.Cryptography.FromBase64Transform.cs
3 //
4 // Authors:
5 // Sergey Chaban (serge@wildwestsoftware.com)
6 // Sebastien Pouliot <sebastien@ximian.com>
7 //
8 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Globalization;
31 using System.Runtime.InteropServices;
33 namespace System.Security.Cryptography {
35 [Serializable]
36 [ComVisible (true)]
37 public enum FromBase64TransformMode : int {
38 IgnoreWhiteSpaces,
39 DoNotIgnoreWhiteSpaces
42 [ComVisible (true)]
43 public class FromBase64Transform : ICryptoTransform {
45 private FromBase64TransformMode mode;
46 private byte[] accumulator;
47 private int accPtr;
48 private bool m_disposed;
50 private const byte TerminatorByte = ((byte) '=');
52 public FromBase64Transform ()
53 : this (FromBase64TransformMode.IgnoreWhiteSpaces)
57 public FromBase64Transform (FromBase64TransformMode whitespaces)
59 this.mode = whitespaces;
60 accumulator = new byte [4];
61 accPtr = 0;
62 m_disposed = false;
65 ~FromBase64Transform ()
67 Dispose (false);
70 public bool CanTransformMultipleBlocks {
71 get { return false; }
74 public virtual bool CanReuseTransform {
75 get { return true; }
78 public int InputBlockSize {
79 get { return 1; }
82 public int OutputBlockSize {
83 get { return 3; }
86 public void Clear()
88 Dispose (true);
91 void IDisposable.Dispose ()
93 Dispose (true);
94 GC.SuppressFinalize (this); // Finalization is now unnecessary
97 protected virtual void Dispose (bool disposing)
99 if (!m_disposed) {
100 // zeroize data
101 if (accumulator != null)
102 Array.Clear (accumulator, 0, accumulator.Length);
104 // dispose unmanaged objects
105 if (disposing) {
106 // dispose managed objects
107 accumulator = null;
109 m_disposed = true;
113 private byte[] lookupTable;
115 private byte lookup (byte input)
117 if (input >= lookupTable.Length) {
118 throw new FormatException (
119 Locale.GetText ("Invalid character in a Base-64 string."));
122 byte ret = lookupTable [input];
123 if (ret == Byte.MaxValue) {
124 throw new FormatException (
125 Locale.GetText ("Invalid character in a Base-64 string."));
128 return ret;
131 private int ProcessBlock (byte[] output, int offset)
133 int rem = 0;
134 if (accumulator [3] == TerminatorByte)
135 rem++;
136 if (accumulator [2] == TerminatorByte)
137 rem++;
139 lookupTable = Base64Constants.DecodeTable;
140 int b0,b1,b2,b3;
142 switch (rem) {
143 case 0:
144 b0 = lookup (accumulator [0]);
145 b1 = lookup (accumulator [1]);
146 b2 = lookup (accumulator [2]);
147 b3 = lookup (accumulator [3]);
148 output [offset++] = (byte) ((b0 << 2) | (b1 >> 4));
149 output [offset++] = (byte) ((b1 << 4) | (b2 >> 2));
150 output [offset] = (byte) ((b2 << 6) | b3);
151 break;
152 case 1:
153 b0 = lookup (accumulator [0]);
154 b1 = lookup (accumulator [1]);
155 b2 = lookup (accumulator [2]);
156 output [offset++] = (byte) ((b0 << 2) | (b1 >> 4));
157 output [offset] = (byte) ((b1 << 4) | (b2 >> 2));
158 break;
159 case 2:
160 b0 = lookup (accumulator [0]);
161 b1 = lookup (accumulator [1]);
162 output [offset] = (byte) ((b0 << 2) | (b1 >> 4));
163 break;
166 return (3 - rem);
169 private void CheckInputParameters (byte[] inputBuffer, int inputOffset, int inputCount)
171 if (inputBuffer == null)
172 throw new ArgumentNullException ("inputBuffer");
173 if (inputOffset < 0)
174 throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
175 if (inputCount > inputBuffer.Length)
176 throw new OutOfMemoryException ("inputCount " + Locale.GetText ("Overflow"));
177 if (inputOffset > inputBuffer.Length - inputCount)
178 throw new ArgumentException ("inputOffset", Locale.GetText ("Overflow"));
179 if (inputCount < 0)
180 throw new OverflowException ("inputCount < 0");
183 public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
185 if (m_disposed)
186 throw new ObjectDisposedException ("FromBase64Transform");
187 // LAMESPEC: undocumented exceptions
188 CheckInputParameters (inputBuffer, inputOffset, inputCount);
189 if ((outputBuffer == null) || (outputOffset < 0))
190 throw new FormatException ("outputBuffer");
192 int res = 0;
194 while (inputCount > 0) {
195 if (accPtr < 4) {
196 byte b = inputBuffer [inputOffset++];
197 if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
198 if (!Char.IsWhiteSpace ((char) b))
199 accumulator [accPtr++] = b;
200 } else {
201 // don't ignore, we'll fail if bad data is provided
202 accumulator [accPtr++] = b;
205 if (accPtr == 4) {
206 res += ProcessBlock (outputBuffer, outputOffset);
207 outputOffset += 3;
208 accPtr = 0;
210 inputCount--;
213 return res;
216 public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
218 if (m_disposed)
219 throw new ObjectDisposedException ("FromBase64Transform");
220 // LAMESPEC: undocumented exceptions
221 CheckInputParameters (inputBuffer, inputOffset, inputCount);
223 int ws = 0;
224 int terminator = 0;
225 if (mode == FromBase64TransformMode.IgnoreWhiteSpaces) {
226 // count whitespace inside string
227 for (int i=inputOffset, j=0; j < inputCount; i++, j++) {
228 if (Char.IsWhiteSpace ((char)inputBuffer [i]))
229 ws++;
231 // no more (useful) data
232 if (ws == inputCount)
233 return new byte [0];
234 // there may be whitespace after the terminator
235 int k = inputOffset + inputCount - 1;
236 int n = Math.Min (2, inputCount);
237 while (n > 0) {
238 char c = (char) inputBuffer [k--];
239 if (c == '=') {
240 terminator++;
241 n--;
242 } else if (Char.IsWhiteSpace (c)) {
243 continue;
244 } else {
245 break;
248 } else {
249 if (inputBuffer [inputOffset + inputCount - 1] == TerminatorByte)
250 terminator++;
251 if (inputBuffer [inputOffset + inputCount - 2] == TerminatorByte)
252 terminator++;
254 // some terminators could already be in the accumulator
255 if ((inputCount < 4) && (terminator < 2)) {
256 if ((accPtr > 2) && (accumulator [3] == TerminatorByte))
257 terminator++;
258 if ((accPtr > 1) && (accumulator [2] == TerminatorByte))
259 terminator++;
262 int count = ((accPtr + inputCount - ws) >> 2) * 3 - terminator;
263 if (count <= 0)
264 return new byte [0];
266 // allocate the "right" ammount (to avoid multiple allocation/copy)
267 byte[] result = new byte [count];
268 TransformBlock (inputBuffer, inputOffset, inputCount, result, 0);
269 return result;