Browse Source

[corlib] Fix ASCIIEncoding with custom DecoderFallback.

Only pass one single byte to DecoderFallback.Fallback(),
throw if there's not enough space in the char array.
Martin Baulig 13 years ago
parent
commit
cd8ca2f658

+ 11 - 3
mcs/class/corlib/System.Text/ASCIIEncoding.cs

@@ -216,9 +216,17 @@ public class ASCIIEncoding : Encoding
 			else {
 				if (buffer == null)
 					buffer = DecoderFallback.CreateFallbackBuffer ();
-				buffer.Fallback (bytes, byteIndex);
-				while (buffer.Remaining > 0)
-					chars [charIndex++] = buffer.GetNextChar ();
+				var thisByte = new byte[] { bytes [byteIndex-1] };
+				buffer.Fallback (thisByte, 0);
+				while (buffer.Remaining > 0) {
+					if (charIndex < chars.Length) {
+						chars [charIndex++] = buffer.GetNextChar ();
+						continue;
+					}
+					throw new ArgumentException (
+							"The output char buffer is too small to contain the " +
+							"decoded characters.");
+				}
 			}
 		}
 		return byteCount;

+ 95 - 2
mcs/class/corlib/Test/System.Text/ASCIIEncodingTest.cs

@@ -8,6 +8,8 @@ using System;
 using System.Text;
 
 using NUnit.Framework;
+using NUnit.Framework.Constraints;
+using NUnit.Framework.SyntaxHelpers;
 
 namespace MonoTests.System.Text
 {
@@ -210,7 +212,6 @@ namespace MonoTests.System.Text
 			Assert.AreEqual (string.Empty, encoding.GetString (new byte [0], 0, 0), "#2");
 		}
 
-#if NET_2_0
 		[Test]
 		[ExpectedException (typeof (DecoderFallbackException))]
 		public void DecoderFallback ()
@@ -219,6 +220,98 @@ namespace MonoTests.System.Text
 			e.DecoderFallback = new DecoderExceptionFallback ();
 			e.GetChars (new byte [] {0x80});
 		}
-#endif
+
+		[Test]
+		[ExpectedException (typeof (ArgumentException))]
+		public void DecoderFallback2 ()
+		{
+			var bytes = new byte[] {
+				0x30, 0xa0, 0x31, 0xa8
+			};
+			var enc = (ASCIIEncoding)Encoding.ASCII.Clone ();
+			enc.DecoderFallback = new TestFallbackDecoder ();
+			
+			var chars = new char [7];
+			var ret = enc.GetChars (bytes, 0, bytes.Length, chars, 0);
+			Console.WriteLine (ret);
+			
+			for (int i = 0; i < chars.Length; i++) {
+				Console.Write ("{0:x2} ", (int)chars [i]);
+			}
+			Console.WriteLine ();
+		}
+		
+		[Test]
+		public void DecoderFallback3 ()
+		{
+			var bytes = new byte[] {
+				0x30, 0xa0, 0x31, 0xa8
+			};
+			var enc = (ASCIIEncoding)Encoding.ASCII.Clone ();
+			enc.DecoderFallback = new TestFallbackDecoder ();
+			
+			var chars = new char [10];
+			var ret = enc.GetChars (bytes, 0, bytes.Length, chars, 0);
+			
+			Assert.That (ret, Is.EqualTo (6), "ret");
+			Assert.That (chars [0], Is.EqualTo ((char)0x30), "chars[0]");
+			Assert.That (chars [1], Is.EqualTo ((char)0xa0), "chars[1]");
+			Assert.That (chars [2], Is.EqualTo ((char)0xa1), "chars[2]");
+			Assert.That (chars [3], Is.EqualTo ((char)0x31), "chars[3]");
+			Assert.That (chars [4], Is.EqualTo ((char)0xa8), "chars[4]");
+			Assert.That (chars [5], Is.EqualTo ((char)0xa9), "chars[5]");
+		}
+		
+		class TestFallbackDecoder : DecoderFallback {
+			const int count = 2;
+			
+			public override int MaxCharCount {
+				get { return count; }
+			}
+			
+			public override DecoderFallbackBuffer CreateFallbackBuffer ()
+			{
+				return new Buffer ();
+			}
+			
+			class Buffer : DecoderFallbackBuffer {
+				char[] queue;
+				int index;
+				
+				public override int Remaining {
+					get {
+						return queue.Length - index;
+					}
+				}
+				
+				public override char GetNextChar ()
+				{
+					return index < queue.Length ? queue [index++] : '\0';
+				}
+				
+				public override bool Fallback (byte[] bytes, int unused)
+				{
+					queue = new char[bytes.Length * count];
+					index = 0;
+					for (int i = 0; i < bytes.Length; i++) {
+						for (int j = 0; j < count; j++)
+							queue [index++] = (char)(bytes [i]+j);
+					}
+					return true;
+				}
+				
+				public override bool MovePrevious ()
+				{
+					throw new NotImplementedException ();
+				}
+				
+				public override void Reset ()
+				{
+					base.Reset ();
+				}
+			}
+		}
+		
+
 	}
 }