In System:
authorSebastien Pouliot <sebastien@ximian.com>
Thu, 7 Jan 2010 15:22:08 +0000 (15:22 -0000)
committerSebastien Pouliot <sebastien@ximian.com>
Thu, 7 Jan 2010 15:22:08 +0000 (15:22 -0000)
2010-01-07  Sebastien Pouliot  <sebastien@ximian.com>

* Convert.cs: Fix line endings in ToBase64String (bug #568778)
and also the default line length. Code changed to not require
a BinaryReader over a MemoryStream to reduce memory requirements.

In Test/System:
2010-01-07  Sebastien Pouliot  <sebastien@ximian.com>

* ConvertTest.cs: Add test case for #568778 and the default
line length.

In System.Security.Cryptography:
2010-01-07  Sebastien Pouliot  <sebastien@ximian.com>

* ToBase64Transform.cs: Static-ify some methods to make it easier
to use from System.Convert

svn path=/trunk/mcs/; revision=149171

mcs/class/corlib/System.Security.Cryptography/ChangeLog
mcs/class/corlib/System.Security.Cryptography/ToBase64Transform.cs
mcs/class/corlib/System/ChangeLog
mcs/class/corlib/System/Convert.cs
mcs/class/corlib/Test/System/ChangeLog
mcs/class/corlib/Test/System/ConvertTest.cs

index 649948596c0257be0c9a969091cf287739a6a3e3..77dde0efef8bfd6581a99a5f284398ed17dd5069 100644 (file)
@@ -1,3 +1,8 @@
+2010-01-07  Sebastien Pouliot  <sebastien@ximian.com>
+
+       * ToBase64Transform.cs: Static-ify some methods to make it easier 
+       to use from System.Convert
+
 2009-12-01  Sebastien Pouliot  <sebastien@ximian.com>
 
        * CryptoConfig_2_1.cs: Add mapping for SHA256 since it's used 
index 38680a2e367b4b78d73f76097fa86d1d5b578d01..ce5a95e8763309608ba09cd82bbf87c994e767e4 100644 (file)
@@ -35,6 +35,8 @@ namespace System.Security.Cryptography {
        [ComVisible (true)]
        public class ToBase64Transform : ICryptoTransform {
 
+               private const int inputBlockSize = 3;
+               private const int outputBlockSize = 4;
                private bool m_disposed;
 
                public ToBase64Transform ()
@@ -55,11 +57,11 @@ namespace System.Security.Cryptography {
                }
 
                public int InputBlockSize {
-                       get { return 3; }
+                       get { return inputBlockSize; }
                }
 
                public int OutputBlockSize {
-                       get { return 4; }
+                       get { return outputBlockSize; }
                }
 
                public void Clear() 
@@ -113,6 +115,12 @@ namespace System.Security.Cryptography {
 //                     if (inputCount != this.InputBlockSize)
 //                             throw new CryptographicException (Locale.GetText ("Invalid input length"));
 
+                       InternalTransformBlock (inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
+                       return this.OutputBlockSize;
+               }
+
+               internal static void InternalTransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
+               {
                        byte[] lookup = Base64Constants.EncodeTable;
 
                        int b1 = inputBuffer [inputOffset];
@@ -123,8 +131,6 @@ namespace System.Security.Cryptography {
                        outputBuffer [outputOffset+1] = lookup [((b1 << 4) & 0x30) | (b2 >> 4)];
                        outputBuffer [outputOffset+2] = lookup [((b2 << 2) & 0x3c) | (b3 >> 6)];
                        outputBuffer [outputOffset+3] = lookup [b3 & 0x3f];
-
-                       return this.OutputBlockSize;
                }
 
                public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
@@ -144,10 +150,10 @@ namespace System.Security.Cryptography {
                }
                
                // Mono System.Convert depends on the ability to process multiple blocks                
-               internal byte[] InternalTransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
+               internal static byte[] InternalTransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
                {
-                       int blockLen = this.InputBlockSize;
-                       int outLen = this.OutputBlockSize;
+                       int blockLen = inputBlockSize;
+                       int outLen = outputBlockSize;
                        int fullBlocks = inputCount / blockLen;
                        int tail = inputCount % blockLen;
 
@@ -158,10 +164,7 @@ namespace System.Security.Cryptography {
                        int outputOffset = 0;
 
                        for (int i = 0; i < fullBlocks; i++) {
-
-                               TransformBlock (inputBuffer, inputOffset,
-                                               blockLen, res, outputOffset);
-
+                               InternalTransformBlock (inputBuffer, inputOffset, blockLen, res, outputOffset);
                                inputOffset += blockLen;
                                outputOffset += outLen;
                        }
index 42b8d925c368d422944818cf5949567b209f0990..22ea702b8d5260a9308b7e1e6de8aaaf59f704d3 100644 (file)
@@ -1,3 +1,9 @@
+2010-01-07  Sebastien Pouliot  <sebastien@ximian.com>
+
+       * Convert.cs: Fix line endings in ToBase64String (bug #568778)
+       and also the default line length. Code changed to not require
+       a BinaryReader over a MemoryStream to reduce memory requirements.
+
 2010-01-07  Zoltan Varga  <vargaz@gmail.com>
 
        * TermInfoDriver.cs (GetCursorPosition): Avoid waiting 1 sec here.
index c5c966c97af564e324d178d42f56ae8df43e0bea..85e860b225dbd62120c9b1701002fbd66ecd32a1 100644 (file)
@@ -104,7 +104,6 @@ namespace System {
 
                // Fields
                public static readonly object DBNull = System.DBNull.Value;
-               static ToBase64Transform toBase64Transform = new ToBase64Transform();
        
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                extern static byte [] InternalFromBase64String (string str, bool allowWhitespaceOnly);
@@ -169,7 +168,7 @@ namespace System {
                                throw new ArgumentOutOfRangeException ("offsetIn + length > array.Length");
 
                        // note: normally ToBase64Transform doesn't support multiple block processing
-                       byte[] outArr = toBase64Transform.InternalTransformFinalBlock (inArray, offsetIn, length);
+                       byte[] outArr = ToBase64Transform.InternalTransformFinalBlock (inArray, offsetIn, length);
                        
                        char[] cOutArr = new ASCIIEncoding ().GetChars (outArr);
                        
@@ -201,7 +200,7 @@ namespace System {
                                throw new ArgumentOutOfRangeException ("offset + length > array.Length");
                        
                        // note: normally ToBase64Transform doesn't support multiple block processing
-                       byte[] outArr = toBase64Transform.InternalTransformFinalBlock (inArray, offset, length);
+                       byte[] outArr = ToBase64Transform.InternalTransformFinalBlock (inArray, offset, length);
                        
                        return (new ASCIIEncoding ().GetString (outArr));
                }
@@ -225,10 +224,13 @@ namespace System {
                        if (offset > inArray.Length - length)
                                throw new ArgumentOutOfRangeException ("offset + length > array.Length");
 
+                       if (length == 0)
+                               return String.Empty;
+
                        if (options == Base64FormattingOptions.InsertLineBreaks)
                                return ToBase64StringBuilderWithLine (inArray, offset, length).ToString ();
                        else
-                               return Encoding.ASCII.GetString (toBase64Transform.InternalTransformFinalBlock (inArray, offset, length));
+                               return Encoding.ASCII.GetString (ToBase64Transform.InternalTransformFinalBlock (inArray, offset, length));
                }
 
                [ComVisible (false)]
@@ -245,13 +247,16 @@ namespace System {
                        if (offsetIn > inArray.Length - length)
                                throw new ArgumentOutOfRangeException ("offsetIn + length > array.Length");
 
+                       if (length == 0)
+                               return 0;
+
                        // note: normally ToBase64Transform doesn't support multiple block processing
                        if (options == Base64FormattingOptions.InsertLineBreaks) {
                                StringBuilder sb = ToBase64StringBuilderWithLine (inArray, offsetIn, length);
                                sb.CopyTo (0, outArray, offsetOut, sb.Length);
                                return sb.Length;
                        } else {
-                               byte[] outArr = toBase64Transform.InternalTransformFinalBlock (inArray, offsetIn, length);
+                               byte[] outArr = ToBase64Transform.InternalTransformFinalBlock (inArray, offsetIn, length);
                        
                                char[] cOutArr = Encoding.ASCII.GetChars (outArr);
                        
@@ -264,18 +269,27 @@ namespace System {
                        }
                }
 
+               private const int MaxBytesPerLine = 57;
+
                static StringBuilder ToBase64StringBuilderWithLine (byte [] inArray, int offset, int length)
                {
-                       BinaryReader reader = new BinaryReader (new MemoryStream (inArray, offset, length));
-                       byte[] b = null;
-
                        StringBuilder sb = new StringBuilder ();
-                       do {
-                               // 54 bytes of input makes for 72 bytes of output.
-                               b = reader.ReadBytes (54);
-                               if (b.Length > 0)
-                                       sb.AppendLine (Encoding.ASCII.GetString (toBase64Transform.InternalTransformFinalBlock (b, 0, b.Length)));
-                       } while (b.Length > 0);
+
+                       int remainder;
+                       int full = Math.DivRem (length, MaxBytesPerLine, out remainder);
+                       for (int i = 0; i < full; i ++) {
+                               byte[] data = ToBase64Transform.InternalTransformFinalBlock (inArray, offset, MaxBytesPerLine);
+                               sb.AppendLine (Encoding.ASCII.GetString (data));
+                               offset += MaxBytesPerLine;
+                       }
+                       // we never complete (i.e. the last line) with a new line
+                       if (remainder == 0) {
+                               int nll = Environment.NewLine.Length;
+                               sb.Remove (sb.Length - nll, nll);
+                       } else {
+                               byte[] data = ToBase64Transform.InternalTransformFinalBlock (inArray, offset, remainder);
+                               sb.Append (Encoding.ASCII.GetString (data));
+                       }
                        return sb;
                }
                
index a66896fb0387d2c05ed7fd2213a04a139b469cc4..f52dc6715fc7356defb1d108ce170ce2dc692987 100644 (file)
@@ -1,3 +1,8 @@
+2010-01-07  Sebastien Pouliot  <sebastien@ximian.com>
+
+       * ConvertTest.cs: Add test case for #568778 and the default
+       line length.
+
 2010-01-03  Zoltan Varga  <vargaz@gmail.com>
 
        * ArrayTest.cs: Add a test for #564095.
index a06b91ac19d472f9b658cc3caaeceb8516394ec8..0598692b65bac280623c211efb2c47aa1b1e8973 100644 (file)
@@ -2835,6 +2835,53 @@ namespace MonoTests.System {
                        string s = Convert.ToBase64String (bs, Base64FormattingOptions.None);
                        Assert.IsTrue (!s.Contains ("\n"), "no new line");
                }
+
+               static string ToBase64 (int len, Base64FormattingOptions options)
+               {
+                       return Convert.ToBase64String (new byte [len], options);
+               }
+
+               [Test]
+               public void Base64String_LineEnds_InsertLineBreaks ()
+               {
+                       string base64 = ToBase64 (0, Base64FormattingOptions.InsertLineBreaks);
+                       Assert.IsFalse (base64.EndsWith (Environment.NewLine), "0-le");
+                       Assert.AreEqual (String.Empty, base64, "0");
+
+                       base64 = ToBase64 (1, Base64FormattingOptions.InsertLineBreaks);
+                       Assert.IsFalse (base64.EndsWith (Environment.NewLine), "1-le");
+                       Assert.AreEqual ("AA==", base64, "1");
+
+                       base64 = ToBase64 (57, Base64FormattingOptions.InsertLineBreaks);
+                       Assert.IsFalse (base64.Contains (Environment.NewLine), "57-nl"); // one lines
+                       Assert.IsFalse (base64.EndsWith (Environment.NewLine), "57-le");
+                       Assert.AreEqual ("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", base64, "55");
+
+                       base64 = ToBase64 (58, Base64FormattingOptions.InsertLineBreaks);
+                       Assert.IsTrue (base64.Contains (Environment.NewLine), "58-nl"); // two lines
+                       Assert.IsTrue (base64.EndsWith ("AA=="), "58-le"); // no NewLine
+               }
+
+               [Test]
+               public void Base64String_LineEnds_None ()
+               {
+                       string base64 = ToBase64 (0, Base64FormattingOptions.None);
+                       Assert.IsFalse (base64.EndsWith (Environment.NewLine), "0-le");
+                       Assert.AreEqual (String.Empty, base64, "0");
+
+                       base64 = ToBase64 (1, Base64FormattingOptions.None);
+                       Assert.IsFalse (base64.EndsWith (Environment.NewLine), "1-le");
+                       Assert.AreEqual ("AA==", base64, "1");
+
+                       base64 = ToBase64 (57, Base64FormattingOptions.None);
+                       Assert.IsFalse (base64.Contains (Environment.NewLine), "57-nl"); // one lines
+                       Assert.IsFalse (base64.EndsWith (Environment.NewLine), "57-le");
+                       Assert.AreEqual ("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", base64, "55");
+
+                       base64 = ToBase64 (58, Base64FormattingOptions.None);
+                       Assert.IsFalse (base64.Contains (Environment.NewLine), "58-nl"); // one lines
+                       Assert.IsTrue (base64.EndsWith ("AA=="), "58-le"); // no NewLine
+               }
 #endif
                /* Have experienced some problems with FromBase64CharArray using mono. Something 
                 * about error in a unicode file.