Bläddra i källkod

Wed Aug 21 20:02:04 CEST 2002 Paolo Molaro <[email protected]>

	* *.cs: imported the code donated by Rhys Weatherley
	<[email protected]>.

svn path=/trunk/mcs/; revision=6863
Paolo Molaro 23 år sedan
förälder
incheckning
feee3a2d52

+ 360 - 166
mcs/class/corlib/System.Text/ASCIIEncoding.cs

@@ -1,166 +1,360 @@
-//
-// System.Text.ASCIIEncoding.cs
-//
-// Author:
-//   Sean MacIsaac ([email protected])
-//   Dietmar Maurer ([email protected])
-//
-// (C) Ximian, Inc.  http://www.ximian.com
-//
-
-
-namespace System.Text {
-        
-	[Serializable]
-	public class ASCIIEncoding : Encoding
-	{
-		public ASCIIEncoding () : base ()
-		{
-			encoding_name = "US-ASCII";
-			body_name = "us-ascii";
-			header_name = "us-ascii";
-			web_name = "us-ascii";
-			is_browser_display = false;
-			is_browser_save = false;
-			is_mail_news_display = true;
-			is_mail_news_save = true;
-		}
-
-		public override int GetByteCount (string chars)
-		{
-			if (chars == null) 
-				throw new ArgumentNullException ();
-
-			return chars.Length;
-		}
-
-		public override int GetByteCount (char[] chars)
-		{
-			if (chars == null) 
-				throw new ArgumentNullException ();
-
-			return chars.Length;
-		}
-
-		public override int GetByteCount (char[] chars, int index, int count)
-		{
-			if (chars == null) 
-				throw new ArgumentNullException ();
-
-			if ((index < 0) || (count <= 0) || ((index + count) > chars.Length))
-				throw new ArgumentOutOfRangeException ();
-
-			return count;
-		}
-
-		public override int GetBytes (char[] chars, int charIndex, int charCount,
-					      byte[] bytes, int byteIndex)
-		{
-			if ((bytes == null) || (chars == null))
-				throw new ArgumentNullException ();
-
-			if ((byteIndex < 0) || (charIndex < 0) || (charCount < 0) ||
-			    ((charIndex + charCount) > chars.Length) ||
-			    (byteIndex >= bytes.Length))
-				throw new ArgumentOutOfRangeException ();
-
-			if ((bytes.Length - byteIndex) < charCount)
-				throw new ArgumentException ();
-
-			for (int i = 0; i < charCount; i++)
-				if (chars[charIndex+i] > 0x7f)
-					bytes[byteIndex+i] = (byte) '?';
-				else
-					bytes[byteIndex+i] = (byte) chars[charIndex+i];
-
-			return charCount;
-		}
-
-		public override int GetBytes (string chars, int charIndex, int charCount,
-					      byte[] bytes, int byteIndex)
-		{
-			return GetBytes (chars.ToCharArray (), charIndex, charCount,
-					 bytes, byteIndex);
-		}
-
-		public override int GetCharCount (byte[] bytes)
-		{
-			if (bytes == null) 
-				throw new ArgumentNullException ();
-
-			return bytes.Length;
-		}
-
-		public override int GetCharCount (byte[] bytes, int index, int count)
-		{
-			if (bytes == null) 
-				throw new ArgumentNullException ();
-
-			if ((index < 0) || (count <= 0) || ((index + count) > bytes.Length))
-				throw new ArgumentOutOfRangeException ();
-
-			return count;
-		}
-
-		public override int GetChars (byte[] bytes, int byteIndex, int byteCount,
-					      char[] chars, int charIndex)
-		{
-			if ((bytes == null) || (chars == null))
-				throw new ArgumentNullException ();
-
-			if ((byteIndex < 0) || (charIndex < 0) || (byteCount < 0) ||
-			    ((byteIndex + byteCount) > bytes.Length) ||
-			    (charIndex + byteCount > chars.Length))
-				throw new ArgumentOutOfRangeException ();
-
-			if ((chars.Length - charIndex) < byteCount)
-				throw new ArgumentException ();
-
-			for (int i = 0; i < byteCount; i++)
-				if (bytes[byteIndex+i] > 0x7f)
-					chars[charIndex+i] = '?';
-				else
-					chars[charIndex+i] = (char) bytes[byteIndex+i];
-
-			return byteCount;
-		}
-
-		public override int GetMaxByteCount (int charCount)
-		{
-			if (charCount < 0) 
-				throw new ArgumentOutOfRangeException ();
-
-			return charCount;
-		}
-
-		public override int GetMaxCharCount (int byteCount)
-		{
-			if (byteCount < 0) 
-				throw new ArgumentOutOfRangeException ();
-
-			return byteCount;
-		}
-
-		public override string GetString (byte[] bytes)
-		{
-			if (bytes == null) 
-				throw new ArgumentNullException ();
-
-			return new String (GetChars (bytes, 0, bytes.Length));
-		}
-
-		public override string GetString (byte[] bytes, int byteIndex, int byteCount)
-		{
-			if (bytes == null) 
-				throw new ArgumentNullException ();
-
-			if ((byteIndex < 0) || (byteCount < 0) || 
-			    ((byteIndex + byteCount) > bytes.Length))
-				throw new ArgumentOutOfRangeException ();
-
-			return new String (GetChars (bytes, byteIndex, byteCount));
-		}
-
-	}
-}
-
+/*
+ * ASCIIEncoding.cs - Implementation of the "System.Text.ASCIIEncoding" class.
+ *
+ * Copyright (c) 2001  Southern Storm Software, Pty Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+namespace System.Text
+{
+
+using System;
+
+public class ASCIIEncoding : Encoding
+{
+	// Magic number used by Windows for "ASCII".
+	internal const int ASCII_CODE_PAGE = 20127;
+
+	// Constructor.
+	public ASCIIEncoding() : base(ASCII_CODE_PAGE) {}
+
+	// Get the number of bytes needed to encode a character buffer.
+	public override int GetByteCount(char[] chars, int index, int count)
+			{
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(index < 0 || index > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (chars.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+				return count;
+			}
+
+	// Convenience wrappers for "GetByteCount".
+	public override int GetByteCount(String s)
+			{
+				if(s == null)
+				{
+					throw new ArgumentNullException("s");
+				}
+				return s.Length;
+			}
+
+	// Get the bytes that result from encoding a character buffer.
+	public override int GetBytes(char[] chars, int charIndex, int charCount,
+								 byte[] bytes, int byteIndex)
+			{
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(charIndex < 0 || charIndex > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_Array"));
+				}
+				if(charCount < 0 || charCount > (chars.Length - charIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_Array"));
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+				if((bytes.Length - byteIndex) < charCount)
+				{
+					throw new ArgumentException
+						(_("Arg_InsufficientSpace"));
+				}
+				int count = charCount;
+				char ch;
+				while(count-- > 0)
+				{
+					ch = chars[charIndex++];
+					if(ch < (char)0x80)
+					{
+						bytes[byteIndex++] = (byte)ch;
+					}
+					else
+					{
+						bytes[byteIndex++] = (byte)'?';
+					}
+				}
+				return charCount;
+			}
+
+	// Convenience wrappers for "GetBytes".
+	public override int GetBytes(String s, int charIndex, int charCount,
+								 byte[] bytes, int byteIndex)
+			{
+				if(s == null)
+				{
+					throw new ArgumentNullException("s");
+				}
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(charIndex < 0 || charIndex > s.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_StringIndex"));
+				}
+				if(charCount < 0 || charCount > (s.Length - charIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_StringRange"));
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+				if((bytes.Length - byteIndex) < charCount)
+				{
+					throw new ArgumentException(_("Arg_InsufficientSpace"));
+				}
+				int count = charCount;
+				char ch;
+				while(count-- > 0)
+				{
+					ch = s[charIndex++];
+					if(ch < (char)0x80)
+					{
+						bytes[byteIndex++] = (byte)ch;
+					}
+					else
+					{
+						bytes[byteIndex++] = (byte)'?';
+					}
+				}
+				return charCount;
+			}
+
+	// Get the number of characters needed to decode a byte buffer.
+	public override int GetCharCount(byte[] bytes, int index, int count)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(index < 0 || index > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (bytes.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+				return count;
+			}
+
+	// Get the characters that result from decoding a byte buffer.
+	public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
+								 char[] chars, int charIndex)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+				if(byteCount < 0 || byteCount > (bytes.Length - byteIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("byteCount", _("ArgRange_Array"));
+				}
+				if(charIndex < 0 || charIndex > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_Array"));
+				}
+				if((chars.Length - charIndex) < byteCount)
+				{
+					throw new ArgumentException(_("Arg_InsufficientSpace"));
+				}
+				int count = byteCount;
+				while(count-- > 0)
+				{
+					chars[charIndex++] = (char)(bytes[byteIndex++]);
+				}
+				return byteCount;
+			}
+
+	// Get the maximum number of bytes needed to encode a
+	// specified number of characters.
+	public override int GetMaxByteCount(int charCount)
+			{
+				if(charCount < 0)
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_NonNegative"));
+				}
+				return charCount;
+			}
+
+	// Get the maximum number of characters needed to decode a
+	// specified number of bytes.
+	public override int GetMaxCharCount(int byteCount)
+			{
+				if(byteCount < 0)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteCount", _("ArgRange_NonNegative"));
+				}
+				return byteCount;
+			}
+
+	// Decode a buffer of bytes into a string.
+	public override String GetString(byte[] bytes, int index, int count)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(index < 0 || index > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (bytes.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+				/*String s = String.NewString(count);
+				int posn = 0;
+				while(count-- > 0)
+				{
+					s.SetChar(posn++, (char)(bytes[index++]));
+				}
+				return s;*/
+				unsafe {
+					fixed (byte *ss = &bytes [0]) {
+						return new String ((sbyte*)ss, index, count);
+					}
+				}
+			}
+	public override String GetString(byte[] bytes)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				int count = bytes.Length;
+				/*int posn = 0;
+				String s = String.NewString(count);
+				while(count-- > 0)
+				{
+					s.SetChar(posn, (char)(bytes[posn]));
+					++posn;
+				}
+				return s;*/
+				unsafe {
+					fixed (byte *ss = &bytes [0]) {
+						return new String ((sbyte*)ss, 0, count);
+					}
+				}
+			}
+
+#if !ECMA_COMPAT
+
+	// Get the mail body name for this encoding.
+	public override String BodyName
+			{
+				get
+				{
+					return "us-ascii";
+				}
+			}
+
+	// Get the human-readable name for this encoding.
+	public override String EncodingName
+			{
+				get
+				{
+					return "US-ASCII";
+				}
+			}
+
+	// Get the mail agent header name for this encoding.
+	public override String HeaderName
+			{
+				get
+				{
+					return "us-ascii";
+				}
+			}
+
+	// Determine if this encoding can be displayed in a mail/news agent.
+	public override bool IsMailNewsDisplay
+			{
+				get
+				{
+					return true;
+				}
+			}
+
+	// Determine if this encoding can be saved from a mail/news agent.
+	public override bool IsMailNewsSave
+			{
+				get
+				{
+					return true;
+				}
+			}
+
+	// Get the IANA-preferred Web name for this encoding.
+	public override String WebName
+			{
+				get
+				{
+					return "us-ascii";
+				}
+			}
+
+#endif // !ECMA_COMPAT
+
+}; // class ASCIIEncoding
+
+}; // namespace System.Text

+ 6 - 0
mcs/class/corlib/System.Text/ChangeLog

@@ -1,3 +1,9 @@
+
+Wed Aug 21 20:02:04 CEST 2002 Paolo Molaro <[email protected]>
+
+	* *.cs: imported the code donated by Rhys Weatherley
+	<[email protected]>.
+
 2002-08-18  Dick Porter  <[email protected]>
 
 	* Encoding.cs: Make GetString() return a useful representation of

+ 35 - 79
mcs/class/corlib/System.Text/Decoder.cs

@@ -1,89 +1,45 @@
-//
-// System.Text.Decoder.cs
-//
-// Authors:
-//   Dietmar Maurer ([email protected])
-//
-// (C) 2001 Ximian, Inc.  http://www.ximian.com
-//
+/*
+ * Decoder.cs - Implementation of the "System.Text.Decoder" class.
+ *
+ * Copyright (c) 2001  Southern Storm Software, Pty Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
 
 namespace System.Text
 {
 
-	[Serializable]
-	public abstract class Decoder
-	{
-		
-		protected Decoder ()
-		{
-			// fixme: dont know what do do here
-		}
+using System;
 
-		public abstract int GetCharCount (byte[] bytes, int index, int count);
-
-		public abstract int GetChars (byte[] bytes, int byteIndex, int byteCount,
-					      char[] chars, int charIndex);
-	}
-
-	internal class DefaultDecoder : Decoder {
-
-		public Encoding encoding;
-
-		public DefaultDecoder (Encoding enc)
-		{
-			encoding = enc;
-		}
-
-		public override int GetCharCount (byte[] bytes, int index, int count)
-		{
-			return encoding.GetCharCount (bytes, index, count);
-		}
-
-		public override int GetChars (byte[] bytes, int byteIndex, int byteCount,
-					      char[] chars, int charIndex)
-		{
-			return encoding.GetChars (bytes, byteIndex, byteCount, chars, charIndex);
-		}
-
-	}
-	
-	internal class IConvDecoder : Decoder {
-		
-		private IntPtr converter;
-
-		public IConvDecoder (string name, bool big_endian)
-		{
-			converter = Encoding.IConvNewDecoder (name, big_endian);
-		}
-
-		public override int GetCharCount (byte[] bytes, int index, int count)
-		{
-			if (bytes == null)
-				throw new ArgumentNullException ();
-
-			if (index + count > bytes.Length)
-				throw new ArgumentOutOfRangeException ();
-
-			return Encoding.IConvGetCharCount (converter, bytes, index, count);
-		}
+public abstract class Decoder
+{
 
-		public override int GetChars (byte[] bytes, int byteIndex, int byteCount,
-					      char[] chars, int charIndex)
-		{
-			if ((bytes == null) || (chars == null))
-				throw new ArgumentNullException ();
+	// Constructor.
+	protected Decoder() {}
 
-			if ((byteIndex < 0) || (byteCount < 0) || (charIndex < 0))
-				throw new ArgumentOutOfRangeException ();
+	// Get the number of characters needed to decode a buffer.
+	public abstract int GetCharCount(byte[] bytes, int index, int count);
 
-			if (byteIndex + byteCount > bytes.Length)
-				throw new ArgumentOutOfRangeException ();
+	// Get the characters that result from decoding a buffer.
+	public abstract int GetChars(byte[] bytes, int byteIndex, int byteCount,
+								 char[] chars, int charIndex);
 
-			if (charIndex > chars.Length)
-				throw new ArgumentOutOfRangeException ();
+}; // class Decoder
 
-			return Encoding.IConvGetChars (converter, bytes, byteIndex, byteCount,
-						       chars, charIndex);
-		}
-	}	
-}
+}; // namespace System.Text

+ 307 - 0
mcs/class/corlib/System.Text/DefaultEncoding.cs

@@ -0,0 +1,307 @@
+/*
+ * DefaultEncoding.cs - Implementation of the
+ *		"System.Text.DefaultEncoding" class.
+ *
+ * Copyright (c) 2001  Southern Storm Software, Pty Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+namespace System.Text
+{
+
+using System;
+using System.Runtime.CompilerServices;
+
+internal sealed class DefaultEncoding : Encoding
+{
+	// Constructor.
+	public DefaultEncoding() : base(0) {}
+
+	// Get the number of bytes needed to encode a character buffer.
+	unsafe public override int GetByteCount(char[] chars, int index, int count)
+			{
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(index < 0 || index > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (chars.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+				return InternalGetByteCount(chars, index, count);
+			}
+
+	// Convenience wrappers for "GetByteCount".
+	public override int GetByteCount(String s)
+			{
+				if(s == null)
+				{
+					throw new ArgumentNullException("s");
+				}
+				return InternalGetByteCount(s, 0, s.Length);
+			}
+
+	// Get the bytes that result from encoding a character buffer.
+	public override int GetBytes(char[] chars, int charIndex, int charCount,
+								 byte[] bytes, int byteIndex)
+			{
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(charIndex < 0 || charIndex > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_Array"));
+				}
+				if(charCount < 0 || charCount > (chars.Length - charIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_Array"));
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+				int result = InternalGetBytes(chars, charIndex, charCount,
+											  bytes, byteIndex);
+				if(result != -1)
+				{
+					return result;
+				}
+				throw new ArgumentException(_("Arg_InsufficientSpace"));
+			}
+
+	// Convenience wrappers for "GetBytes".
+	public override int GetBytes(String s, int charIndex, int charCount,
+								 byte[] bytes, int byteIndex)
+			{
+				if(s == null)
+				{
+					throw new ArgumentNullException("s");
+				}
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(charIndex < 0 || charIndex > s.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_StringIndex"));
+				}
+				if(charCount < 0 || charCount > (s.Length - charIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_StringRange"));
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+				int result = InternalGetBytes(s, charIndex, charCount,
+											  bytes, byteIndex);
+				if(result != -1)
+				{
+					return result;
+				}
+				throw new ArgumentException(_("Arg_InsufficientSpace"));
+			}
+	public override byte[] GetBytes(String s)
+			{
+				if(s == null)
+				{
+					throw new ArgumentNullException("s");
+				}
+				byte[] bytes = new byte [InternalGetByteCount(s, 0, s.Length)];
+				InternalGetBytes(s, 0, s.Length, bytes, 0);
+				return bytes;
+			}
+
+	// Get the number of characters needed to decode a byte buffer.
+	public override int GetCharCount(byte[] bytes, int index, int count)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(index < 0 || index > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (bytes.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+				return InternalGetCharCount(bytes, index, count);
+			}
+
+	// Get the characters that result from decoding a byte buffer.
+	public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
+								 char[] chars, int charIndex)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+				if(byteCount < 0 || byteCount > (bytes.Length - byteIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("byteCount", _("ArgRange_Array"));
+				}
+				if(charIndex < 0 || charIndex > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_Array"));
+				}
+				int result = InternalGetChars(bytes, byteIndex, byteCount,
+											  chars, charIndex);
+				if(result != -1)
+				{
+					return result;
+				}
+				throw new ArgumentException(_("Arg_InsufficientSpace"));
+			}
+
+	// Get the maximum number of bytes needed to encode a
+	// specified number of characters.
+	public override int GetMaxByteCount(int charCount)
+			{
+				if(charCount < 0)
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_NonNegative"));
+				}
+				return InternalGetMaxByteCount(charCount);
+			}
+
+	// Get the maximum number of characters needed to decode a
+	// specified number of bytes.
+	public override int GetMaxCharCount(int byteCount)
+			{
+				if(byteCount < 0)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteCount", _("ArgRange_NonNegative"));
+				}
+				return InternalGetMaxCharCount(byteCount);
+			}
+
+	// Decode a buffer of bytes into a string.
+	public override String GetString(byte[] bytes, int index, int count)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(index < 0 || index > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (bytes.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+				return InternalGetString(bytes, index, count);
+			}
+	public override String GetString(byte[] bytes)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				return InternalGetString(bytes, 0, bytes.Length);
+			}
+
+	// Internal methods that are used by the runtime engine to
+	// provide the default encoding.  These may assume that their
+	// arguments have been fully validated.
+
+	[MethodImpl(MethodImplOptions.InternalCall)]
+	extern private static int InternalGetByteCount
+				(char[] chars, int index, int count);
+
+	[MethodImpl(MethodImplOptions.InternalCall)]
+	extern private static int InternalGetByteCount
+				(String s, int index, int count);
+
+	// Returns -1 if insufficient space in "bytes".
+	[MethodImpl(MethodImplOptions.InternalCall)]
+	extern private static int InternalGetBytes
+				(char[] chars, int charIndex, int charCount,
+				 byte[] bytes, int byteIndex);
+
+	// Returns -1 if insufficient space in "bytes".
+	[MethodImpl(MethodImplOptions.InternalCall)]
+	extern private static int InternalGetBytes
+				(String s, int charIndex, int charCount,
+				 byte[] bytes, int byteIndex);
+
+	[MethodImpl(MethodImplOptions.InternalCall)]
+	extern private static int InternalGetCharCount
+				(byte[] bytes, int index, int count);
+
+	// Returns -1 if insufficient space in "chars".
+	[MethodImpl(MethodImplOptions.InternalCall)]
+	extern private static int InternalGetChars
+				(byte[] bytes, int byteIndex, int byteCount,
+				 char[] chars, int charIndex);
+
+	[MethodImpl(MethodImplOptions.InternalCall)]
+	extern private static int InternalGetMaxByteCount(int charCount);
+
+	[MethodImpl(MethodImplOptions.InternalCall)]
+	extern private static int InternalGetMaxCharCount(int byteCount);
+
+	[MethodImpl(MethodImplOptions.InternalCall)]
+	extern private static String InternalGetString
+				(byte[] bytes, int index, int count);
+
+	// Get the default code page number.  Zero if unknown.
+	[MethodImpl(MethodImplOptions.InternalCall)]
+	extern internal static int InternalCodePage();
+
+}; // class DefaultEncoding
+
+}; // namespace System.Text

+ 36 - 89
mcs/class/corlib/System.Text/Encoder.cs

@@ -1,99 +1,46 @@
-//
-// System.Text.Encoder.cs
-//
-// Authors:
-//   Dietmar Maurer ([email protected])
-//
-// (C) 2001 Ximian, Inc.  http://www.ximian.com
-//
+/*
+ * Encoder.cs - Implementation of the "System.Text.Encoder" class.
+ *
+ * Copyright (c) 2001  Southern Storm Software, Pty Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
 
 namespace System.Text
 {
 
-	[Serializable]
-	public abstract class Encoder
-	{
+using System;
 
-		protected Encoder()
-		{
-			// fixme: dont know what do do here
-		}
-
-		public abstract int GetByteCount (char[] chars, int index, int count, bool flush);
-
-		public abstract int GetBytes (char[] chars, int charIndex, int charCount,
-					      byte[] bytes, int byteIndex, bool flush);
-	}
-
-	internal class DefaultEncoder : Encoder {
-
-		public Encoding encoding;
-		
-		public DefaultEncoder (Encoding enc)
-		{
-			encoding = enc;
-		}
-
-		public override int GetByteCount (char[] chars, int index, int count, bool flush)
-		{
-			return encoding.GetByteCount (chars, index, count);
-		}
-
-		public override int GetBytes (char[] chars, int charIndex, int charCount,
-					      byte[] bytes, int byteIndex, bool flush)
-		{
-			return encoding.GetBytes (chars, charIndex, charCount, bytes, byteIndex);
-		}
-
-	}
-	
-	internal class IConvEncoder : Encoder {
-
-		private IntPtr converter;
-
-		public IConvEncoder (string name, bool big_endian)
-		{
-			converter = Encoding.IConvNewEncoder (name, big_endian);
-		}
-
-		public override int GetByteCount (char[] chars, int index, int count, bool flush)
-		{
-			if (chars == null)
-				throw new ArgumentNullException ();
-
-			if (index + count > chars.Length)
-				throw new ArgumentOutOfRangeException ();
-
-			int res = Encoding.IConvGetByteCount (converter, chars, index, count);
-			
-			if (flush)
-				Encoding.IConvReset (converter);
-
-			return res;
-		}
-
-		public override int GetBytes (char[] chars, int charIndex, int charCount,
-					      byte[] bytes, int byteIndex, bool flush)
-		{
-			if ((chars == null) || (bytes == null))
-				throw new ArgumentNullException ();
+public abstract class Encoder
+{
 
-			if ((charIndex < 0) || (charCount < 0) || (byteIndex < 0))
-				throw new ArgumentOutOfRangeException ();
+	// Constructor.
+	protected Encoder() {}
 
-			if (charIndex + charCount > chars.Length)
-				throw new ArgumentOutOfRangeException ();
+	// Get the number of bytes needed to encode a buffer.
+	public abstract int GetByteCount(char[] chars, int index,
+									 int count, bool flush);
 
-			if (byteIndex + charCount > bytes.Length)
-				throw new ArgumentOutOfRangeException ();
+	// Get the bytes that result from decoding a buffer.
+	public abstract int GetBytes(char[] chars, int charIndex, int charCount,
+								 byte[] bytes, int byteIndex, bool flush);
 
-			int res = Encoding.IConvGetBytes (converter, chars, charIndex, charCount,
-							  bytes, byteIndex);
-			
-			if (flush)
-				Encoding.IConvReset (converter);
+}; // class Encoder
 
-			return res;
-		}
-	}
-}
+}; // namespace System.Text

+ 815 - 384
mcs/class/corlib/System.Text/Encoding.cs

@@ -1,384 +1,815 @@
-// -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
-//
-// System.Text.Encoding.cs
-//
-// Author:
-//   Sean MacIsaac ([email protected])
-//   Dietmar Maurer ([email protected])
-//
-// (C) Ximian, Inc.  http://www.ximian.com
-//
-
-using System.Runtime.CompilerServices;
-
-namespace System.Text {
-
-	[Serializable]
-	public abstract class Encoding {
-                private static ASCIIEncoding ascii_encoding;
-                private static UnicodeEncoding big_endian_unicode;
-                private static UnicodeEncoding unicode_encoding;
-                private static UTF7Encoding utf7_encoding;
-                private static UTF8Encoding utf8_encoding;
-
-                private int codepage;
-   
-                protected string body_name;
-                protected string encoding_name;
-                protected string header_name;
-                protected string web_name;
-
-		protected bool is_browser_display = false;
-		protected bool is_browser_save = false;
-		protected bool is_mail_news_display = false;
-		protected bool is_mail_news_save = false;
-		
-		private Encoder default_encoder = null;
-		private Decoder default_decoder = null;
-		
-		// used for iconv 
-		private string  iconv_name;
-		private bool    big_endian;
-		private Encoder iconv_encoder = null;
-		private Decoder iconv_decoder = null;
-
-                protected Encoding()
-		{
-                }
-
-                protected Encoding (int codepage)
-		{
-                        this.codepage = codepage;
-                }
-
-		internal protected Encoding (string name, bool big_endian)
-		{
-			this.iconv_name = name;
-			this.big_endian = big_endian;
-			
-			iconv_decoder = new IConvDecoder (iconv_name, big_endian);
-			iconv_encoder = new IConvEncoder (iconv_name, big_endian);
-		}
-
-                public static Encoding Unicode {
-                        get {
-                                if (unicode_encoding == null) {
-                                        unicode_encoding = new UnicodeEncoding();
-                                }
-                                return unicode_encoding;
-                        }
-                }
-
-                public static Encoding UTF7 {
-                        get {
-                                if (utf7_encoding == null) {
-                                        utf7_encoding = new UTF7Encoding();
-                                }
-                                return utf7_encoding;
-                        }
-                }
-
-                public static Encoding UTF8 {
-                        get {
-                                if (utf8_encoding == null) {
-                                        utf8_encoding = new UTF8Encoding();
-                                }
-                                return utf8_encoding;
-                        }
-                }
-
-                public static Encoding ASCII {
-                        get {
-                                if (ascii_encoding == null)
-                                        ascii_encoding = new ASCIIEncoding ();
-                                return ascii_encoding;
-                        }
-                }
-
-                public static Encoding BigEndianUnicode {
-                        get {
-                                if (big_endian_unicode == null)
-                                        big_endian_unicode = new UnicodeEncoding (true, true);
-                                return big_endian_unicode;
-                        }
-                }
-
-                public virtual string BodyName {
-                        get {
-                                return body_name;
-                        }
-                }
-
-                public virtual int CodePage {
-                        get {
-                                return codepage;
-                        }
-                }
-
-                public static Encoding Default {
-                        get {
-                                return ASCII;
-                        }
-                }
-
-                public virtual string EncodingName {
-                        get {
-                                return encoding_name;
-                        }
-                }
-
-                public virtual string HeaderName {
-                        get {
-                                return header_name;
-                        }
-                }
-
-                public virtual bool IsBrowserDisplay {
-                        get {
-                                return is_browser_display;
-                        }
-                }
-
-                public virtual bool IsBrowserSave {
-                        get {
-				return is_browser_save;
-                        }
-                }
-
-                public virtual bool IsMailNewsDisplay {
-                        get {
-                                return is_mail_news_display;
-                        }
-                }
-
-                public virtual bool IsMailNewsSave {
-                        get {
-                                return is_mail_news_save;
-                        }
-                }
-
-                public virtual string WebName {
-                        get {
-                                return web_name;
-                        }
-                }
-
-		[MonoTODO]
-                public virtual int WindowsCodePage {
-                        get {
-                                // FIXME
-                                return 0;
-                        }
-                }
-
-                public static byte[] Convert(Encoding srcEncoding, Encoding dstEncoding, byte[] bytes)
-		{
-			return dstEncoding.GetBytes (srcEncoding.GetChars (bytes));
-                }
-
-                public static byte[] Convert(Encoding srcEncoding, Encoding dstEncoding,
-					     byte[] bytes, int index, int count)
-		{
-			return dstEncoding.GetBytes (srcEncoding.GetChars (bytes, index, count));
-                }
-
-                public override bool Equals (object value)
-		{
-			if (!(value is Encoding))
-				return false;
-
-			Encoding e = (Encoding) value;
-
-			if (e.codepage != codepage)
-				return false;
-
-			if (e.body_name != body_name)
-				return false;
-
-			if (e.encoding_name != encoding_name)
-				return false;
-
-			if (e.header_name != header_name)
-				return false;
-			
-                        return true;
-                }
-
-                public virtual int GetByteCount (char[] chars)
-		{
-			return GetByteCount (chars, 0, chars.Length);
-                }
-
-                public virtual int GetByteCount (string s)
-		{
-			char [] chars = s.ToCharArray ();
-			
- 			return GetByteCount (chars, 0, chars.Length);
-                }
-
-                public virtual int GetByteCount (char[] chars, int index, int count)
-		{
-			return iconv_encoder.GetByteCount (chars, index, count, false);
-		}
-
-                public virtual byte[] GetBytes(char[] chars)
-		{
-			return GetBytes (chars, 0, chars.Length);
-                }
-
-                public virtual byte[] GetBytes(string s)
-		{
-                        char [] chars = s.ToCharArray (); 
-                        return GetBytes (chars, 0, chars.Length);
-                }
-
-                public virtual byte[] GetBytes(char[] chars, int index, int count)
-		{
-			int bc = GetByteCount (chars, index, count);
-			byte [] bytes = new byte [bc];
-			
-			int len = GetBytes (chars, index, count, bytes, 0);
-			byte [] res = new byte [len];
-
-			Array.Copy (bytes, res, len);
-			
-			return res;
-                }
-
-                public virtual int GetBytes (char[] chars, int charIndex, int charCount,
-					     byte[] bytes, int byteIndex)
-		{
-			return iconv_encoder.GetBytes (chars, charIndex, charCount, bytes, byteIndex, true);
-		}
-
-                public virtual int GetBytes(string s, int charIndex, int charCount,
-					    byte[] bytes, int byteIndex)
-		{
-			return GetBytes (s.ToCharArray (), charIndex, charCount, bytes, byteIndex);
-                }
-
-                public virtual int GetCharCount (byte[] bytes)
-		{
-			return GetCharCount (bytes, 0, bytes.Length);
-                }
-
-                public virtual int GetCharCount (byte[] bytes, int index, int count)
-		{
-			return iconv_decoder.GetCharCount (bytes, index, count);
-		}
-
-                public virtual char[] GetChars (byte[] bytes)
-		{
-			return GetChars (bytes, 0, bytes.Length);
-                }
-
-                public virtual char[] GetChars (byte[] bytes, int index, int count)
-		{
-			int cc = GetMaxCharCount (count);
-			char [] chars = new char [cc];
-
-			int len = GetChars (bytes, index, count, chars, 0);
-			char [] res = new char [len];
-			
-			Array.Copy (chars, res, len);
-
-			return res;
-		}
-
-                public virtual int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
-		{
-			return iconv_decoder.GetChars (bytes, byteIndex, byteCount, chars, charIndex);
-		}
-
-                public virtual Decoder GetDecoder()
-		{
-			if (iconv_name != null)
-				return new IConvDecoder (iconv_name, big_endian);
-			
-			if (default_decoder == null)
-				default_decoder = new DefaultDecoder (this);
-			
-                        return default_decoder;
-                }
-
-                public virtual Encoder GetEncoder() 
-		{
-			if (iconv_name != null)
-				return new IConvEncoder (iconv_name, big_endian);
-
-			if (default_encoder == null)
-				default_encoder = new DefaultEncoder (this);
-			
-                        return default_encoder;
-                }
-
-		[MonoTODO]
-                public static Encoding GetEncoding (int codepage)
-		{
-                        // FIXME
-                        return null;
-                }
-		
-		[MonoTODO]
-                public static Encoding GetEncoding (string name)
-		{
-                        // FIXME
-                        return null;
-                }
-
-		[MonoTODO]
-                public override int GetHashCode()
-		{
-                        // FIXME
-                        return 0;
-                }
-
-                public abstract int GetMaxByteCount (int charCount);
-
-                public abstract int GetMaxCharCount (int byteCount);
-
-		[MonoTODO]
-                public virtual byte[] GetPreamble()
-		{
-                        // FIXME
-                        return null;
-                }
-
-                public virtual string GetString(byte[] bytes)
-		{
-                        return GetString (bytes, 0, bytes.Length);
-                }
-
-                public virtual string GetString(byte[] bytes, int index, int count)
-		{
-			char [] chars = GetChars (bytes, index, count);
-
-                        return new String (chars);
-                }
-
-		[MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
-		internal extern static IntPtr IConvNewEncoder (string name, bool big_endian);
-
-		[MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
-		internal extern static IntPtr IConvNewDecoder (string name, bool big_endian);
-
-		[MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
-		internal extern static void IConvReset (IntPtr converter);
-
-		[MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
-		internal extern static int IConvGetByteCount (IntPtr converter, char[] chars,
-							      int index, int count);
-
-		[MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
-		internal extern static int IConvGetBytes (IntPtr converter, char[] chars, int charIndex,
-							  int charCount, byte[] bytes, int byteIndex);
-		
-		[MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
-		internal extern static int IConvGetCharCount (IntPtr converter, byte[] bytes,
-							      int index, int count);
-
-		[MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
-		internal extern static int IConvGetChars (IntPtr converter, byte[] bytes, int byteIndex,
-							  int byteCount, char[] chars, int charIndex);
-        }
-}
+/*
+ * Encoding.cs - Implementation of the "System.Text.Encoding" class.
+ *
+ * Copyright (c) 2001, 2002  Southern Storm Software, Pty Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+namespace System.Text
+{
+
+using System;
+using System.Reflection;
+using System.Globalization;
+using System.Security;
+
+public abstract class Encoding
+{
+	// Code page used by this encoding.
+	internal int codePage;
+
+	// Constructor.
+	protected Encoding()
+			{
+				codePage = 0;
+			}
+#if ECMA_COMPAT
+	protected internal
+#else
+	protected
+#endif
+	Encoding(int codePage)
+			{
+				this.codePage = codePage;
+			}
+
+	// until we change the callers:
+	internal static string _ (string arg) {
+		return arg;
+	}
+
+	// Convert between two encodings.
+	public static byte[] Convert(Encoding srcEncoding, Encoding dstEncoding,
+								 byte[] bytes)
+			{
+				if(srcEncoding == null)
+				{
+					throw new ArgumentNullException("srcEncoding");
+				}
+				if(dstEncoding == null)
+				{
+					throw new ArgumentNullException("dstEncoding");
+				}
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				return dstEncoding.GetBytes(srcEncoding.GetChars
+							(bytes, 0, bytes.Length));
+			}
+	public static byte[] Convert(Encoding srcEncoding, Encoding dstEncoding,
+								 byte[] bytes, int index, int count)
+			{
+				if(srcEncoding == null)
+				{
+					throw new ArgumentNullException("srcEncoding");
+				}
+				if(dstEncoding == null)
+				{
+					throw new ArgumentNullException("dstEncoding");
+				}
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(index < 0 || index > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || (bytes.Length - index) < count)
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+				return dstEncoding.GetBytes(srcEncoding.GetChars
+							(bytes, index, count));
+			}
+
+	// Determine if two Encoding objects are equal.
+	public override bool Equals(Object obj)
+			{
+				Encoding enc = (obj as Encoding);
+				if(enc != null)
+				{
+					return (codePage == enc.codePage);
+				}
+				else
+				{
+					return false;
+				}
+			}
+
+	// Get the number of characters needed to encode a character buffer.
+	public abstract int GetByteCount(char[] chars, int index, int count);
+
+	// Convenience wrappers for "GetByteCount".
+	public virtual int GetByteCount(String s)
+			{
+				if(s != null)
+				{
+					char[] chars = s.ToCharArray();
+					return GetByteCount(chars, 0, chars.Length);
+				}
+				else
+				{
+					throw new ArgumentNullException("s");
+				}
+			}
+	public virtual int GetByteCount(char[] chars)
+			{
+				if(chars != null)
+				{
+					return GetByteCount(chars, 0, chars.Length);
+				}
+				else
+				{
+					throw new ArgumentNullException("chars");
+				}
+			}
+
+	// Get the bytes that result from encoding a character buffer.
+	public abstract int GetBytes(char[] chars, int charIndex, int charCount,
+								 byte[] bytes, int byteIndex);
+
+	// Convenience wrappers for "GetBytes".
+	public virtual int GetBytes(String s, int charIndex, int charCount,
+								byte[] bytes, int byteIndex)
+			{
+				if(s == null)
+				{
+					throw new ArgumentNullException("s");
+				}
+				return GetBytes(s.ToCharArray(), charIndex, charCount,
+								bytes, byteIndex);
+			}
+	public virtual byte[] GetBytes(String s)
+			{
+				if(s == null)
+				{
+					throw new ArgumentNullException("s");
+				}
+				char[] chars = s.ToCharArray();
+				int numBytes = GetByteCount(chars, 0, chars.Length);
+				byte[] bytes = new byte [numBytes];
+				GetBytes(chars, 0, chars.Length, bytes, 0);
+				return bytes;
+			}
+	public virtual byte[] GetBytes(char[] chars, int index, int count)
+			{
+				int numBytes = GetByteCount(chars, index, count);
+				byte[] bytes = new byte [numBytes];
+				GetBytes(chars, index, count, bytes, 0);
+				return bytes;
+			}
+	public virtual byte[] GetBytes(char[] chars)
+			{
+				int numBytes = GetByteCount(chars, 0, chars.Length);
+				byte[] bytes = new byte [numBytes];
+				GetBytes(chars, 0, chars.Length, bytes, 0);
+				return bytes;
+			}
+
+	// Get the number of characters needed to decode a byte buffer.
+	public abstract int GetCharCount(byte[] bytes, int index, int count);
+
+	// Convenience wrappers for "GetCharCount".
+	public virtual int GetCharCount(byte[] bytes)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				return GetCharCount(bytes, 0, bytes.Length);
+			}
+
+	// Get the characters that result from decoding a byte buffer.
+	public abstract int GetChars(byte[] bytes, int byteIndex, int byteCount,
+								 char[] chars, int charIndex);
+
+	// Convenience wrappers for "GetChars".
+	public virtual char[] GetChars(byte[] bytes, int index, int count)
+			{
+				int numChars = GetCharCount(bytes, index, count);
+				char[] chars = new char [numChars];
+				GetChars(bytes, index, count, chars, 0);
+				return chars;
+			}
+	public virtual char[] GetChars(byte[] bytes)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				int numChars = GetCharCount(bytes, 0, bytes.Length);
+				char[] chars = new char [numChars];
+				GetChars(bytes, 0, bytes.Length, chars, 0);
+				return chars;
+			}
+
+	// Get a decoder that forwards requests to this object.
+	public virtual Decoder GetDecoder()
+			{
+				return new ForwardingDecoder(this);
+			}
+
+	// Get an encoder that forwards requests to this object.
+	public virtual Encoder GetEncoder()
+			{
+				return new ForwardingEncoder(this);
+			}
+
+	// Loaded copy of the "I18N" assembly.  We need to move
+	// this into a class in "System.Private" eventually.
+	private static Assembly i18nAssembly;
+	private static bool i18nDisabled;
+
+	// Invoke a specific method on the "I18N" manager object.
+	// Returns NULL if the method failed.
+	private static Object InvokeI18N(String name, params Object[] args)
+			{
+				lock(typeof(Encoding))
+				{
+					// Bail out if we previously detected that there
+					// is insufficent engine support for I18N handling.
+					if(i18nDisabled)
+					{
+						return null;
+					}
+
+					// Find or load the "I18N" assembly.
+					if(i18nAssembly == null)
+					{
+						try
+						{
+							try
+							{
+								i18nAssembly = Assembly.Load("I18N");
+							}
+							catch(NotImplementedException)
+							{
+								// Assembly loading unsupported by the engine.
+								i18nDisabled = true;
+								return null;
+							}
+							if(i18nAssembly == null)
+							{
+								return null;
+							}
+						}
+						catch(SystemException)
+						{
+							return null;
+						}
+					}
+
+					// Find the "I18N.Common.Manager" class.
+					Type managerClass;
+					try
+					{
+						managerClass =
+							i18nAssembly.GetType("I18N.Common.Manager");
+					}
+					catch(NotImplementedException)
+					{
+						// "GetType" is not supported by the engine.
+						i18nDisabled = true;
+						return null;
+					}
+					if(managerClass == null)
+					{
+						return null;
+					}
+
+					// Get the value of the "PrimaryManager" property.
+					Object manager;
+					try
+					{
+						manager = managerClass.InvokeMember
+								("PrimaryManager",
+								 BindingFlags.GetProperty |
+								 	BindingFlags.Static |
+									BindingFlags.Public,
+								 null, null, null, null, null, null);
+						if(manager == null)
+						{
+							return null;
+						}
+					}
+					catch(MissingMethodException)
+					{
+						return null;
+					}
+					catch(SecurityException)
+					{
+						return null;
+					}
+					catch(NotImplementedException)
+					{
+						// "InvokeMember" is not supported by the engine.
+						i18nDisabled = true;
+						return null;
+					}
+
+					// Invoke the requested method on the manager.
+					try
+					{
+						return managerClass.InvokeMember
+								(name,
+								 BindingFlags.InvokeMethod |
+								 	BindingFlags.Instance |
+									BindingFlags.Public,
+								 null, manager, args, null, null, null);
+					}
+					catch(MissingMethodException)
+					{
+						return null;
+					}
+					catch(SecurityException)
+					{
+						return null;
+					}
+				}
+			}
+
+	// Get an encoder for a specific code page.
+#if ECMA_COMPAT
+	private
+#else
+	public
+#endif
+	static Encoding GetEncoding(int codePage)
+			{
+				// Check for the builtin code pages first.
+				switch(codePage)
+				{
+					case 0: return Default;
+
+					case ASCIIEncoding.ASCII_CODE_PAGE:
+						return ASCII;
+
+					case UTF7Encoding.UTF7_CODE_PAGE:
+						return UTF7;
+
+					case UTF8Encoding.UTF8_CODE_PAGE:
+						return UTF8;
+
+					case UnicodeEncoding.UNICODE_CODE_PAGE:
+						return Unicode;
+
+					case UnicodeEncoding.BIG_UNICODE_CODE_PAGE:
+						return BigEndianUnicode;
+
+					case Latin1Encoding.ISOLATIN_CODE_PAGE:
+						return ISOLatin1;
+
+					default: break;
+				}
+
+				// Try to obtain a code page handler from the I18N handler.
+				Encoding enc = (Encoding)(InvokeI18N("GetEncoding", codePage));
+				if(enc != null)
+				{
+					return enc;
+				}
+
+#if false
+				// Build a code page class name.
+				String cpName = "System.Text.CP" + codePage.ToString();
+
+				// Look for a code page converter in this assembly.
+				Assembly assembly = Assembly.GetExecutingAssembly();
+				Type type = assembly.GetType(cpName);
+				if(type != null)
+				{
+					return (Encoding)(Activator.CreateInstance(type));
+				}
+
+				// Look in any assembly, in case the application
+				// has provided its own code page handler.
+				type = Type.GetType(cpName);
+				if(type != null)
+				{
+					return (Encoding)(Activator.CreateInstance(type));
+				}
+#endif
+
+				// We have no idea how to handle this code page.
+				throw new NotSupportedException
+					(String.Format
+						(_("NotSupp_CodePage"), codePage.ToString()));
+			}
+
+#if !ECMA_COMPAT
+
+	// Table of builtin web encoding names and the corresponding code pages.
+	private static readonly String[] encodingNames =
+		{"us-ascii", "utf-7", "utf-8", "utf-16",
+		 "unicodeFFFE", "iso-8859-1"};
+	private static readonly int[] encodingCodePages =
+		{ASCIIEncoding.ASCII_CODE_PAGE,
+		 UTF7Encoding.UTF7_CODE_PAGE,
+		 UTF8Encoding.UTF8_CODE_PAGE,
+		 UnicodeEncoding.UNICODE_CODE_PAGE,
+		 UnicodeEncoding.BIG_UNICODE_CODE_PAGE,
+		 Latin1Encoding.ISOLATIN_CODE_PAGE};
+
+	// Get an encoding object for a specific web encoding name.
+	public static Encoding GetEncoding(String name)
+			{
+				// Validate the parameters.
+				if(name == null)
+				{
+					throw new ArgumentNullException("name");
+				}
+
+				// Search the table for a name match.
+				int posn;
+				for(posn = 0; posn < encodingNames.Length; ++posn)
+				{
+					if(String.Compare(name, encodingNames[posn], true,
+									  CultureInfo.InvariantCulture) == 0)
+					{
+						return GetEncoding(encodingCodePages[posn]);
+					}
+				}
+
+				// Try to obtain a web encoding handler from the I18N handler.
+				Encoding enc = (Encoding)(InvokeI18N("GetEncoding", name));
+				if(enc != null)
+				{
+					return enc;
+				}
+
+#if false
+				// Build a web encoding class name.
+				String encName = "System.Text.ENC" +
+								 name.ToLower(CultureInfo.InvariantCulture)
+								 	.Replace('-', '_');
+
+				// Look for a code page converter in this assembly.
+				Assembly assembly = Assembly.GetExecutingAssembly();
+				Type type = assembly.GetType(encName);
+				if(type != null)
+				{
+					return (Encoding)(Activator.CreateInstance(type));
+				}
+
+				// Look in any assembly, in case the application
+				// has provided its own code page handler.
+				type = Type.GetType(encName);
+				if(type != null)
+				{
+					return (Encoding)(Activator.CreateInstance(type));
+				}
+#endif
+
+				// We have no idea how to handle this encoding name.
+				throw new NotSupportedException
+					(String.Format(_("NotSupp_EncodingName"), name));
+			}
+
+#endif // !ECMA_COMPAT
+
+	// Get a hash code for this instance.
+	public override int GetHashCode()
+			{
+				return codePage;
+			}
+
+	// Get the maximum number of bytes needed to encode a
+	// specified number of characters.
+	public abstract int GetMaxByteCount(int charCount);
+
+	// Get the maximum number of characters needed to decode a
+	// specified number of bytes.
+	public abstract int GetMaxCharCount(int byteCount);
+
+	// Get the identifying preamble for this encoding.
+	public virtual byte[] GetPreamble()
+			{
+				return new byte [0];
+			}
+
+	// Decode a buffer of bytes into a string.
+	public virtual String GetString(byte[] bytes, int index, int count)
+			{
+				return new String(GetChars(bytes, index, count));
+			}
+	public virtual String GetString(byte[] bytes)
+			{
+				return new String(GetChars(bytes));
+			}
+
+#if !ECMA_COMPAT
+
+	// Get the mail body name for this encoding.
+	public virtual String BodyName
+			{
+				get
+				{
+					return null;
+				}
+			}
+
+	// Get the code page represented by this object.
+	public virtual int CodePage
+			{
+				get
+				{
+					return codePage;
+				}
+			}
+
+	// Get the human-readable name for this encoding.
+	public virtual String EncodingName
+			{
+				get
+				{
+					return null;
+				}
+			}
+
+	// Get the mail agent header name for this encoding.
+	public virtual String HeaderName
+			{
+				get
+				{
+					return null;
+				}
+			}
+
+	// Determine if this encoding can be displayed in a Web browser.
+	public virtual bool IsBrowserDisplay
+			{
+				get
+				{
+					return false;
+				}
+			}
+
+	// Determine if this encoding can be saved from a Web browser.
+	public virtual bool IsBrowserSave
+			{
+				get
+				{
+					return false;
+				}
+			}
+
+	// Determine if this encoding can be displayed in a mail/news agent.
+	public virtual bool IsMailNewsDisplay
+			{
+				get
+				{
+					return false;
+				}
+			}
+
+	// Determine if this encoding can be saved from a mail/news agent.
+	public virtual bool IsMailNewsSave
+			{
+				get
+				{
+					return false;
+				}
+			}
+
+	// Get the IANA-preferred Web name for this encoding.
+	public virtual String WebName
+			{
+				get
+				{
+					return null;
+				}
+			}
+
+	// Get the Windows code page represented by this object.
+	public virtual int WindowsCodePage
+			{
+				get
+				{
+					// We make no distinction between normal and
+					// Windows code pages in this implementation.
+					return codePage;
+				}
+			}
+
+#endif // !ECMA_COMPAT
+
+	// Storage for standard encoding objects.
+	private static Encoding asciiEncoding = null;
+	private static Encoding bigEndianEncoding = null;
+	private static Encoding defaultEncoding = null;
+	private static Encoding utf7Encoding = null;
+	private static Encoding utf8Encoding = null;
+	private static Encoding unicodeEncoding = null;
+	private static Encoding isoLatin1Encoding = null;
+
+	// Get the standard ASCII encoding object.
+	public static Encoding ASCII
+			{
+				get
+				{
+					lock(typeof(Encoding))
+					{
+						if(asciiEncoding == null)
+						{
+							asciiEncoding = new ASCIIEncoding();
+						}
+						return asciiEncoding;
+					}
+				}
+			}
+
+	// Get the standard big-endian Unicode encoding object.
+	public static Encoding BigEndianUnicode
+			{
+				get
+				{
+					lock(typeof(Encoding))
+					{
+						if(bigEndianEncoding == null)
+						{
+							bigEndianEncoding = new UnicodeEncoding(true, true);
+						}
+						return bigEndianEncoding;
+					}
+				}
+			}
+
+	// Get the default encoding object.
+	public static Encoding Default
+			{
+				get
+				{
+					lock(typeof(Encoding))
+					{
+						if(defaultEncoding == null)
+						{
+							// See if the underlying system knows what
+							// code page handler we should be using.
+							int codePage = DefaultEncoding.InternalCodePage();
+							if(codePage != 0)
+							{
+								try
+								{
+									defaultEncoding = GetEncoding(codePage);
+								}
+								catch(NotSupportedException)
+								{
+									defaultEncoding = new DefaultEncoding();
+								}
+							}
+							else
+							{
+								defaultEncoding = new DefaultEncoding();
+							}
+						}
+						return defaultEncoding;
+					}
+				}
+			}
+
+	// Get the ISO Latin1 encoding object.
+	private static Encoding ISOLatin1
+			{
+				get
+				{
+					lock(typeof(Encoding))
+					{
+						if(isoLatin1Encoding == null)
+						{
+							isoLatin1Encoding = new Latin1Encoding();
+						}
+						return isoLatin1Encoding;
+					}
+				}
+			}
+
+	// Get the standard UTF-7 encoding object.
+#if ECMA_COMPAT
+	private
+#else
+	public
+#endif
+	static Encoding UTF7
+			{
+				get
+				{
+					lock(typeof(Encoding))
+					{
+						if(utf7Encoding == null)
+						{
+							utf7Encoding = new UTF7Encoding();
+						}
+						return utf7Encoding;
+					}
+				}
+			}
+
+	// Get the standard UTF-8 encoding object.
+	public static Encoding UTF8
+			{
+				get
+				{
+					lock(typeof(Encoding))
+					{
+						if(utf8Encoding == null)
+						{
+							utf8Encoding = new UTF8Encoding();
+						}
+						return utf8Encoding;
+					}
+				}
+			}
+
+	// Get the standard little-endian Unicode encoding object.
+	public static Encoding Unicode
+			{
+				get
+				{
+					lock(typeof(Encoding))
+					{
+						if(unicodeEncoding == null)
+						{
+							unicodeEncoding = new UnicodeEncoding();
+						}
+						return unicodeEncoding;
+					}
+				}
+			}
+
+	// Forwarding decoder implementation.
+	private sealed class ForwardingDecoder : Decoder
+	{
+		private Encoding encoding;
+
+		// Constructor.
+		public ForwardingDecoder(Encoding enc)
+				{
+					encoding = enc;
+				}
+
+		// Override inherited methods.
+		public override int GetCharCount(byte[] bytes, int index, int count)
+				{
+					return encoding.GetCharCount(bytes, index, count);
+				}
+		public override int GetChars(byte[] bytes, int byteIndex,
+									 int byteCount, char[] chars,
+									 int charIndex)
+				{
+					return encoding.GetChars(bytes, byteIndex, byteCount,
+											 chars, charIndex);
+				}
+
+	} // class ForwardingDecoder
+
+	// Forwarding encoder implementation.
+	private sealed class ForwardingEncoder : Encoder
+	{
+		private Encoding encoding;
+
+		// Constructor.
+		public ForwardingEncoder(Encoding enc)
+				{
+					encoding = enc;
+				}
+
+		// Override inherited methods.
+		public override int GetByteCount(char[] chars, int index,
+										 int count, bool flush)
+				{
+					return encoding.GetByteCount(chars, index, count);
+				}
+		public override int GetBytes(char[] chars, int charIndex,
+									 int charCount, byte[] bytes,
+									 int byteCount, bool flush)
+				{
+					return encoding.GetBytes(chars, charIndex, charCount,
+											 bytes, byteCount);
+				}
+
+	} // class ForwardingEncoder
+
+}; // class Encoding
+
+}; // namespace System.Text

+ 796 - 37
mcs/class/corlib/System.Text/UTF7Encoding.cs

@@ -1,42 +1,801 @@
-//
-// System.Text.UTF7Encoding.cs
-//
-// Author:
-//   Sean MacIsaac ([email protected])
-//   Dietmar Maurer ([email protected])
-//
-// (C) Ximian, Inc.  http://www.ximian.com
-//
+/*
+ * UTF7Encoding.cs - Implementation of the
+ *		"System.Text.UTF7Encoding" class.
+ *
+ * Copyright (c) 2002  Southern Storm Software, Pty Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
 
+namespace System.Text
+{
 
-namespace System.Text {
+using System;
 
-	public class UTF7Encoding : Encoding
+#if ECMA_COMPAT
+internal
+#else
+public
+#endif
+class UTF7Encoding : Encoding
+{
+	// Magic number used by Windows for UTF-7.
+	internal const int UTF7_CODE_PAGE = 65000;
+
+	// Internal state.
+	private bool allowOptionals;
+
+	// Encoding rule table for 0x00-0x7F.
+	// 0 - full encode, 1 - direct, 2 - optional, 3 - encode plus.
+	private static readonly byte[] encodingRules = {
+		0, 0, 0, 0, 0, 0, 0, 0,   0, 1, 1, 0, 0, 1, 0, 0,	// 00
+		0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,	// 10
+		1, 2, 2, 2, 2, 2, 2, 1,   1, 1, 2, 3, 1, 1, 1, 1,	// 20
+		1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 2, 2, 2, 2, 1,	// 30
+
+		2, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,	// 40
+		1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 2, 0, 2, 2, 2,	// 50
+		2, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,	// 60
+		1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 2, 2, 2, 0, 0,	// 70
+	};
+
+	// Characters to use to encode 6-bit values in base64.
+	private const String base64Chars =
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+	// Map bytes in base64 to 6-bit values.
+	private static readonly sbyte[] base64Values = {
+		-1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1, // 00
+		-1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1, // 10
+		-1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, 62, -1, -1, 63, // 20
+		52, 53, 54, 55, 56, 57, 58, 59,   60, 61, -1, -1, -1, -1, -1, -1, // 30
+
+		 0,  1,  2,  3,  4,  5,  6,  7,    8,  9, 10, 11, 12, 13, 14, 15, // 40
+		16, 17, 18, 19, 20, 21, 22, 23,   24, 25, -1, -1, -1, -1, -1, -1, // 50
+		26, 27, 28, 29, 30, 31, 32, 33,   34, 35, 36, 37, 38, 39, 40, 41, // 60
+		42, 43, 44, 45, 46, 47, 48, 49,   50, 51, -1, -1, -1, -1, -1, -1, // 70
+
+		-1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1, // 80
+		-1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1, // 90
+		-1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1, // A0
+		-1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1, // B0
+
+		-1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1, // C0
+		-1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1, // D0
+		-1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1, // E0
+		-1, -1, -1, -1, -1, -1, -1, -1,   -1, -1, -1, -1, -1, -1, -1, -1, // F0
+	};
+
+	// Constructors.
+	public UTF7Encoding()
+			: base(UTF7_CODE_PAGE)
+			{
+				allowOptionals = false;
+			}
+	public UTF7Encoding(bool allowOptionals)
+			: base(UTF7_CODE_PAGE)
+			{
+				this.allowOptionals = allowOptionals;
+			}
+
+	// Internal version of "GetByteCount" that can handle
+	// a rolling state between calls.
+	private static int InternalGetByteCount
+				(char[] chars, int index, int count, bool flush,
+				 int leftOver, bool allowOptionals)
+			{
+				// Validate the parameters.
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(index < 0 || index > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (chars.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+
+				// Determine the length of the output.
+				int length = 0;
+				int leftOverSize = (leftOver >> 8);
+				byte[] rules = encodingRules;
+				int ch, rule;
+				while(count > 0)
+				{
+					ch = (int)(chars[index++]);
+					--count;
+					if(ch < 0x0080)
+					{
+						rule = rules[ch];
+					}
+					else
+					{
+						rule = 0;
+					}
+					switch(rule)
+					{
+						case 0:
+						{
+							// Handle characters that must be fully encoded.
+							if(leftOverSize == 0)
+							{
+								++length;
+							}
+							leftOverSize += 16;
+							while(leftOverSize >= 6)
+							{
+								++length;
+								leftOverSize -= 6;
+							}
+						}
+						break;
+
+						case 1:
+						{
+							// The character is encoded as itself.
+							if(leftOverSize != 0)
+							{
+								// Flush the previous encoded sequence.
+								length += 2;
+								leftOverSize = 0;
+							}
+							++length;
+						}
+						break;
+
+						case 2:
+						{
+							// The character may need to be encoded.
+							if(allowOptionals)
+							{
+								goto case 1;
+							}
+							else
+							{
+								goto case 0;
+							}
+						}
+						// Not reached.
+
+						case 3:
+						{
+							// Encode the plus sign as "+-".
+							if(leftOverSize != 0)
+							{
+								// Flush the previous encoded sequence.
+								length += 2;
+								leftOverSize = 0;
+							}
+							length += 2;
+						}
+						break;
+					}
+				}
+				if(leftOverSize != 0 && flush)
+				{
+					length += 2;
+				}
+
+				// Return the length to the caller.
+				return length;
+			}
+
+	// Get the number of bytes needed to encode a character buffer.
+	public override int GetByteCount(char[] chars, int index, int count)
+			{
+				return InternalGetByteCount(chars, index, count,
+											true, 0, allowOptionals);
+			}
+
+	// Internal version of "GetBytes" that can handle a
+	// rolling state between calls.
+	private static int InternalGetBytes
+				(char[] chars, int charIndex, int charCount,
+				 byte[] bytes, int byteIndex, bool flush,
+				 ref int leftOver, bool allowOptionals)
+			{
+				// Validate the parameters.
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(charIndex < 0 || charIndex > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_Array"));
+				}
+				if(charCount < 0 || charCount > (chars.Length - charIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_Array"));
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+
+				// Convert the characters.
+				int posn = byteIndex;
+				int byteLength = bytes.Length;
+				int leftOverSize = (leftOver >> 8);
+				int leftOverBits = (leftOver & 0xFF);
+				byte[] rules = encodingRules;
+				String base64 = base64Chars;
+				int ch, rule;
+				while(charCount > 0)
+				{
+					ch = (int)(chars[charIndex++]);
+					--charCount;
+					if(ch < 0x0080)
+					{
+						rule = rules[ch];
+					}
+					else
+					{
+						rule = 0;
+					}
+					switch(rule)
+					{
+						case 0:
+						{
+							// Handle characters that must be fully encoded.
+							if(leftOverSize == 0)
+							{
+								if(posn >= byteLength)
+								{
+									throw new ArgumentException
+										(_("Arg_InsufficientSpace"), "bytes");
+								}
+								bytes[posn++] = (byte)'+';
+							}
+							leftOverBits = ((leftOverBits << 16) | ch);
+							leftOverSize += 16;
+							while(leftOverSize >= 6)
+							{
+								if(posn >= byteLength)
+								{
+									throw new ArgumentException
+										(_("Arg_InsufficientSpace"), "bytes");
+								}
+								leftOverSize -= 6;
+								bytes[posn++] = (byte)(base64
+									[leftOverBits >> leftOverSize]);
+								leftOverBits &= ((1 << leftOverSize) - 1);
+							}
+						}
+						break;
+
+						case 1:
+						{
+							// The character is encoded as itself.
+							if(leftOverSize != 0)
+							{
+								// Flush the previous encoded sequence.
+								if((posn + 2) > byteLength)
+								{
+									throw new ArgumentException
+										(_("Arg_InsufficientSpace"), "bytes");
+								}
+								bytes[posn++] = (byte)(base64
+									[leftOverBits << (6 - leftOverSize)]);
+								bytes[posn++] = (byte)'-';
+								leftOverSize = 0;
+								leftOverBits = 0;
+							}
+							if(posn >= byteLength)
+							{
+								throw new ArgumentException
+									(_("Arg_InsufficientSpace"), "bytes");
+							}
+							bytes[posn++] = (byte)ch;
+						}
+						break;
+
+						case 2:
+						{
+							// The character may need to be encoded.
+							if(allowOptionals)
+							{
+								goto case 1;
+							}
+							else
+							{
+								goto case 0;
+							}
+						}
+						// Not reached.
+
+						case 3:
+						{
+							// Encode the plus sign as "+-".
+							if(leftOverSize != 0)
+							{
+								// Flush the previous encoded sequence.
+								if((posn + 2) > byteLength)
+								{
+									throw new ArgumentException
+										(_("Arg_InsufficientSpace"), "bytes");
+								}
+								bytes[posn++] = (byte)(base64
+									[leftOverBits << (6 - leftOverSize)]);
+								bytes[posn++] = (byte)'-';
+								leftOverSize = 0;
+								leftOverBits = 0;
+							}
+							if((posn + 2) > byteLength)
+							{
+								throw new ArgumentException
+									(_("Arg_InsufficientSpace"), "bytes");
+							}
+							bytes[posn++] = (byte)'+';
+							bytes[posn++] = (byte)'-';
+						}
+						break;
+					}
+				}
+				if(leftOverSize != 0 && flush)
+				{
+					if((posn + 2) > byteLength)
+					{
+						throw new ArgumentException
+							(_("Arg_InsufficientSpace"), "bytes");
+					}
+					bytes[posn++] = (byte)(base64
+						[leftOverBits << (6 - leftOverSize)]);
+					bytes[posn++] = (byte)'-';
+					leftOverSize = 0;
+					leftOverBits = 0;
+				}
+				leftOver = ((leftOverSize << 8) | leftOverBits);
+
+				// Return the length to the caller.
+				return posn - byteIndex;
+			}
+
+	// Get the bytes that result from encoding a character buffer.
+	public override int GetBytes(char[] chars, int charIndex, int charCount,
+								 byte[] bytes, int byteIndex)
+			{
+				int leftOver = 0;
+				return InternalGetBytes(chars, charIndex, charCount,
+									    bytes, byteIndex, true,
+										ref leftOver, allowOptionals);
+			}
+
+	// Internal version of "GetCharCount" that can handle
+	// a rolling state between call.s
+	private static int InternalGetCharCount
+					(byte[] bytes, int index, int count, int leftOver)
+			{
+				// Validate the parameters.
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(index < 0 || index > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (bytes.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+
+				// Determine the length of the result.
+				int length = 0;
+				int byteval, b64value;
+				bool normal = ((leftOver & 0x01000000) == 0);
+				bool prevIsPlus = ((leftOver & 0x02000000) != 0);
+				int leftOverSize = ((leftOver >> 16) & 0xFF);
+				sbyte[] base64 = base64Values;
+				while(count > 0)
+				{
+					byteval = (int)(bytes[index++]);
+					--count;
+					if(normal)
+					{
+						if(byteval != '+')
+						{
+							// Directly-encoded character.
+							++length;
+						}
+						else
+						{
+							// Start of a base64-encoded character.
+							normal = false;
+							prevIsPlus = true;
+						}
+					}
+					else
+					{
+						// Process the next byte in a base64 sequence.
+						if(byteval == (int)'-')
+						{
+							// End of a base64 sequence.
+							if(prevIsPlus || leftOverSize > 0)
+							{
+								++length;
+								leftOverSize = 0;
+							}
+							normal = true;
+						}
+						else if((b64value = base64[byteval]) != -1)
+						{
+							// Extra character in a base64 sequence.
+							leftOverSize += 6;
+							if(leftOverSize >= 16)
+							{
+								++length;
+								leftOverSize -= 16;
+							}
+						}
+						else
+						{
+							// Normal character terminating a base64 sequence.
+							if(leftOverSize > 0)
+							{
+								++length;
+								leftOverSize = 0;
+							}
+							++length;
+							normal = true;
+						}
+						prevIsPlus = false;
+					}
+				}
+
+				// Return the final length to the caller.
+				return length;
+			}
+
+	// Get the number of characters needed to decode a byte buffer.
+	public override int GetCharCount(byte[] bytes, int index, int count)
+			{
+				return InternalGetCharCount(bytes, index, count, 0);
+			}
+
+	// Internal version of "GetChars" that can handle a
+	// rolling state between calls.
+	private static int InternalGetChars
+				(byte[] bytes, int byteIndex, int byteCount,
+				 char[] chars, int charIndex, ref int leftOver)
+			{
+				// Validate the parameters.
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+				if(byteCount < 0 || byteCount > (bytes.Length - byteIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("byteCount", _("ArgRange_Array"));
+				}
+				if(charIndex < 0 || charIndex > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_Array"));
+				}
+
+				// Convert the bytes into characters.
+				int posn = charIndex;
+				int charLength = chars.Length;
+				int byteval, b64value;
+				bool normal = ((leftOver & 0x01000000) == 0);
+				bool prevIsPlus = ((leftOver & 0x02000000) != 0);
+				int leftOverSize = ((leftOver >> 16) & 0xFF);
+				int leftOverBits = (leftOver & 0xFFFF);
+				sbyte[] base64 = base64Values;
+				while(byteCount > 0)
+				{
+					byteval = (int)(bytes[byteIndex++]);
+					--byteCount;
+					if(normal)
+					{
+						if(byteval != '+')
+						{
+							// Directly-encoded character.
+							if(posn >= charLength)
+							{
+								throw new ArgumentException
+									(_("Arg_InsufficientSpace"), "chars");
+							}
+							chars[posn++] = (char)byteval;
+						}
+						else
+						{
+							// Start of a base64-encoded character.
+							normal = false;
+							prevIsPlus = true;
+						}
+					}
+					else
+					{
+						// Process the next byte in a base64 sequence.
+						if(byteval == (int)'-')
+						{
+							// End of a base64 sequence.
+							if(prevIsPlus)
+							{
+								if(posn >= charLength)
+								{
+									throw new ArgumentException
+										(_("Arg_InsufficientSpace"), "chars");
+								}
+								chars[posn++] = '+';
+							}
+							else if(leftOverSize > 0)
+							{
+								if(posn >= charLength)
+								{
+									throw new ArgumentException
+										(_("Arg_InsufficientSpace"), "chars");
+								}
+								chars[posn++] =
+									(char)(leftOverBits << (16 - leftOverSize));
+								leftOverSize = 0;
+								leftOverBits = 0;
+							}
+							normal = true;
+						}
+						else if((b64value = base64[byteval]) != -1)
+						{
+							// Extra character in a base64 sequence.
+							leftOverBits = (leftOverBits << 6) | b64value;
+							leftOverSize += 6;
+							if(leftOverSize >= 16)
+							{
+								if(posn >= charLength)
+								{
+									throw new ArgumentException
+										(_("Arg_InsufficientSpace"), "chars");
+								}
+								leftOverSize -= 16;
+								chars[posn++] =
+									(char)(leftOverBits >> leftOverSize);
+								leftOverBits &= ((1 << leftOverSize) - 1);
+							}
+						}
+						else
+						{
+							// Normal character terminating a base64 sequence.
+							if(leftOverSize > 0)
+							{
+								if(posn >= charLength)
+								{
+									throw new ArgumentException
+										(_("Arg_InsufficientSpace"), "chars");
+								}
+								chars[posn++] =
+									(char)(leftOverBits << (16 - leftOverSize));
+								leftOverSize = 0;
+								leftOverBits = 0;
+							}
+							if(posn >= charLength)
+							{
+								throw new ArgumentException
+									(_("Arg_InsufficientSpace"), "chars");
+							}
+							chars[posn++] = (char)byteval;
+							normal = true;
+						}
+						prevIsPlus = false;
+					}
+				}
+				leftOver = (leftOverBits | (leftOverSize << 16) |
+						    (normal ? 0 : 0x01000000) |
+						    (prevIsPlus ? 0x02000000 : 0));
+
+				// Return the final length to the caller.
+				return posn - charIndex;
+			}
+
+	// Get the characters that result from decoding a byte buffer.
+	public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
+								 char[] chars, int charIndex)
+			{
+				int leftOver = 0;
+				return InternalGetChars(bytes, byteIndex, byteCount,
+										chars, charIndex, ref leftOver);
+			}
+
+	// Get the maximum number of bytes needed to encode a
+	// specified number of characters.
+	public override int GetMaxByteCount(int charCount)
+			{
+				if(charCount < 0)
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_NonNegative"));
+				}
+				return charCount * 5;
+			}
+
+	// Get the maximum number of characters needed to decode a
+	// specified number of bytes.
+	public override int GetMaxCharCount(int byteCount)
+			{
+				if(byteCount < 0)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteCount", _("ArgRange_NonNegative"));
+				}
+				return byteCount;
+			}
+
+	// Get a UTF7-specific decoder that is attached to this instance.
+	public override Decoder GetDecoder()
+			{
+				return new UTF7Decoder();
+			}
+
+	// Get a UTF7-specific encoder that is attached to this instance.
+	public override Encoder GetEncoder()
+			{
+				return new UTF7Encoder(allowOptionals);
+			}
+
+#if !ECMA_COMPAT
+
+	// Get the mail body name for this encoding.
+	public override String BodyName
+			{
+				get
+				{
+					return "utf-7";
+				}
+			}
+
+	// Get the human-readable name for this encoding.
+	public override String EncodingName
+			{
+				get
+				{
+					return "Unicode (UTF-7)";
+				}
+			}
+
+	// Get the mail agent header name for this encoding.
+	public override String HeaderName
+			{
+				get
+				{
+					return "utf-7";
+				}
+			}
+
+	// Determine if this encoding can be displayed in a mail/news agent.
+	public override bool IsMailNewsDisplay
+			{
+				get
+				{
+					return true;
+				}
+			}
+
+	// Determine if this encoding can be saved from a mail/news agent.
+	public override bool IsMailNewsSave
+			{
+				get
+				{
+					return true;
+				}
+			}
+
+	// Get the IANA-preferred Web name for this encoding.
+	public override String WebName
+			{
+				get
+				{
+					return "utf-7";
+				}
+			}
+
+	// Get the Windows code page represented by this object.
+	public override int WindowsCodePage
+			{
+				get
+				{
+					return UnicodeEncoding.UNICODE_CODE_PAGE;
+				}
+			}
+
+#endif // !ECMA_COMPAT
+
+	// UTF-7 decoder implementation.
+	private sealed class UTF7Decoder : Decoder
 	{
-		public UTF7Encoding () : base ("UTF-7", false)
-		{
-			encoding_name = "Unicode (UTF-7)";
-			body_name = "utf-7";
-			header_name = "utf-7";
-			web_name = "utf-7";
-			is_browser_display = false;
-			is_browser_save = false;
-			is_mail_news_display = true;
-			is_mail_news_save = true;
-
-		}
-
-		[MonoTODO]
-		public override int GetMaxByteCount (int charCount)
-		{
-			// FIXME: dont know if this is right
-			return charCount*6;
-		}
-
-		public override int GetMaxCharCount (int byteCount)
-		{
-			return byteCount;
-		}
-	}
-}
+		// Internal state.
+		private int leftOver;
+
+		// Constructor.
+		public UTF7Decoder()
+				{
+					leftOver = 0;
+				}
+
+		// Override inherited methods.
+		public override int GetCharCount(byte[] bytes, int index, int count)
+				{
+					return InternalGetCharCount(bytes, index, count, leftOver);
+				}
+		public override int GetChars(byte[] bytes, int byteIndex,
+									 int byteCount, char[] chars,
+									 int charIndex)
+				{
+					return InternalGetChars(bytes, byteIndex, byteCount,
+											chars, charIndex, ref leftOver);
+				}
+
+	} // class UTF7Decoder
+
+	// UTF-7 encoder implementation.
+	private sealed class UTF7Encoder : Encoder
+	{
+		private bool allowOptionals;
+		private int leftOver;
+
+		// Constructor.
+		public UTF7Encoder(bool allowOptionals)
+				{
+					this.allowOptionals = allowOptionals;
+					this.leftOver = 0;
+				}
+
+		// Override inherited methods.
+		public override int GetByteCount(char[] chars, int index,
+										 int count, bool flush)
+				{
+					return InternalGetByteCount
+						(chars, index, count, flush, leftOver, allowOptionals);
+				}
+		public override int GetBytes(char[] chars, int charIndex,
+									 int charCount, byte[] bytes,
+									 int byteIndex, bool flush)
+				{
+					return InternalGetBytes(chars, charIndex, charCount,
+											bytes, byteIndex, flush,
+											ref leftOver, allowOptionals);
+				}
+
+	} // class UTF7Encoder
+
+}; // class UTF7Encoding
 
+}; // namespace System.Text

+ 1035 - 34
mcs/class/corlib/System.Text/UTF8Encoding.cs

@@ -1,38 +1,1039 @@
-//
-// System.Text.UTF8Encoding.cs
-//
-// Authors:
-//   Sean MacIsaac ([email protected])
-//   Dietmar Maurer ([email protected])
-//
-// (C) Ximian, Inc.  http://www.ximian.com
-//
+/*
+ * UTF8Encoding.cs - Implementation of the "System.Text.UTF8Encoding" class.
+ *
+ * Copyright (c) 2001, 2002  Southern Storm Software, Pty Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
 
 namespace System.Text
 {
-	[Serializable]
-	public class UTF8Encoding : Encoding
+
+using System;
+
+public class UTF8Encoding : Encoding
+{
+	// Magic number used by Windows for UTF-8.
+	internal const int UTF8_CODE_PAGE = 65001;
+
+	// Internal state.
+	private bool emitIdentifier;
+	private bool throwOnInvalid;
+
+	// Constructors.
+	public UTF8Encoding()
+			: this(false, false) {}
+	public UTF8Encoding(bool encoderShouldEmitUTF8Identifier)
+			: this(encoderShouldEmitUTF8Identifier, false) {}
+	public UTF8Encoding(bool encoderShouldEmitUTF8Identifier,
+						bool throwOnInvalidBytes)
+			: base(UTF8_CODE_PAGE)
+			{
+				emitIdentifier = encoderShouldEmitUTF8Identifier;
+				throwOnInvalid = throwOnInvalidBytes;
+			}
+
+	// Internal version of "GetByteCount" which can handle a rolling
+	// state between multiple calls to this method.
+	private static int InternalGetByteCount(char[] chars, int index,
+											int count, uint leftOver,
+											bool emitIdentifier, bool flush)
+			{
+				// Validate the parameters.
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(index < 0 || index > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (chars.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+
+				// Determine the lengths of all characters.
+				char ch;
+				int length = 0;
+				uint pair = leftOver;
+				while(count > 0)
+				{
+					ch = chars[index];
+					if(pair == 0)
+					{
+						if(ch < '\u0080')
+						{
+							++length;
+						}
+						else if(ch < '\u0800')
+						{
+							length += 2;
+						}
+						else if(ch >= '\uD800' && ch <= '\uDBFF')
+						{
+							// This is the start of a surrogate pair.
+							pair = (uint)ch;
+						}
+						else
+						{
+							length += 3;
+						}
+					}
+					else if(ch >= '\uDC00' && ch <= '\uDFFF')
+					{
+						// We have a surrogate pair.
+						length += 4;
+						pair = 0;
+					}
+					else
+					{
+						// We have a surrogate start followed by a
+						// regular character.  Technically, this is
+						// invalid, but we have to do something.
+						// We write out the surrogate start and then
+						// re-visit the current character again.
+						length += 3;
+						pair = 0;
+						continue;
+					}
+					++index;
+					--count;
+				}
+				if(flush && pair != 0)
+				{
+					// Flush the left-over surrogate pair start.
+					length += 3;
+				}
+
+				// Return the final length to the caller.
+				return length + (emitIdentifier ? 3 : 0);
+			}
+
+	// Get the number of bytes needed to encode a character buffer.
+	public override int GetByteCount(char[] chars, int index, int count)
+			{
+				return InternalGetByteCount(chars, index, count, 0,
+										    emitIdentifier, true);
+			}
+
+	// Convenience wrappers for "GetByteCount".
+	public override int GetByteCount(String s)
+			{
+				// Validate the parameters.
+				if(s == null)
+				{
+					throw new ArgumentNullException("s");
+				}
+
+				// Determine the lengths of all characters.
+				char ch;
+				int index = 0;
+				int count = s.Length;
+				int length = 0;
+				uint pair;
+				while(count > 0)
+				{
+					ch = s[index++];
+					if(ch < '\u0080')
+					{
+						++length;
+					}
+					else if(ch < '\u0800')
+					{
+						length += 2;
+					}
+					else if(ch >= '\uD800' && ch <= '\uDBFF' && count > 1)
+					{
+						// This may be the start of a surrogate pair.
+						pair = (uint)(s[index]);
+						if(pair >= (uint)0xDC00 && pair <= (uint)0xDFFF)
+						{
+							length += 4;
+							++index;
+							--count;
+						}
+						else
+						{
+							length += 3;
+						}
+					}
+					else
+					{
+						length += 3;
+					}
+					--count;
+				}
+
+				// Return the final length to the caller.
+				return length + (emitIdentifier ? 3 : 0);
+			}
+
+	// Internal version of "GetBytes" which can handle a rolling
+	// state between multiple calls to this method.
+	private static int InternalGetBytes(char[] chars, int charIndex,
+									    int charCount, byte[] bytes,
+									    int byteIndex, ref uint leftOver,
+										bool emitIdentifier, bool flush)
+			{
+				// Validate the parameters.
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(charIndex < 0 || charIndex > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_Array"));
+				}
+				if(charCount < 0 || charCount > (chars.Length - charIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_Array"));
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+
+				// Convert the characters into bytes.
+				char ch;
+				int length = bytes.Length;
+				uint pair;
+				uint left = leftOver;
+				int posn = byteIndex;
+				if(emitIdentifier)
+				{
+					if((posn + 3) > length)
+					{
+						throw new ArgumentException
+							(_("Arg_InsufficientSpace"), "bytes");
+					}
+					bytes[posn++] = (byte)0xEF;
+					bytes[posn++] = (byte)0xBB;
+					bytes[posn++] = (byte)0xBF;
+				}
+				while(charCount > 0)
+				{
+					// Fetch the next UTF-16 character pair value.
+					ch = chars[charIndex++];
+					--charCount;
+					if(left == 0)
+					{
+						if(ch >= '\uD800' && ch <= '\uDBFF')
+						{
+							// This is the start of a surrogate pair.
+							left = (uint)ch;
+							continue;
+						}
+						else
+						{
+							// This is a regular character.
+							pair = (uint)ch;
+						}
+					}
+					else if(ch >= '\uDC00' && ch <= '\uDFFF')
+					{
+						// We have a surrogate pair.
+						pair = ((left - (uint)0xD800) << 10) +
+							   (((uint)ch) - (uint)0xDC00) +
+							   (uint)0x10000;
+						left = 0;
+					}
+					else
+					{
+						// We have a surrogate start followed by a
+						// regular character.  Technically, this is
+						// invalid, but we have to do something.
+						// We write out the surrogate start and then
+						// re-visit the current character again.
+						pair = (uint)left;
+						left = 0;
+						--charIndex;
+						++charCount;
+					}
+
+					// Encode the character pair value.
+					if(pair < (uint)0x0080)
+					{
+						if(posn >= length)
+						{
+							throw new ArgumentException
+								(_("Arg_InsufficientSpace"), "bytes");
+						}
+						bytes[posn++] = (byte)pair;
+					}
+					else if(pair < (uint)0x0800)
+					{
+						if((posn + 2) > length)
+						{
+							throw new ArgumentException
+								(_("Arg_InsufficientSpace"), "bytes");
+						}
+						bytes[posn++] = (byte)(0xC0 | (pair >> 6));
+						bytes[posn++] = (byte)(0x80 | (pair & 0x3F));
+					}
+					else if(pair < (uint)0x10000)
+					{
+						if((posn + 3) > length)
+						{
+							throw new ArgumentException
+								(_("Arg_InsufficientSpace"), "bytes");
+						}
+						bytes[posn++] = (byte)(0xE0 | (pair >> 12));
+						bytes[posn++] = (byte)(0x80 | ((pair >> 6) & 0x3F));
+						bytes[posn++] = (byte)(0x80 | (pair & 0x3F));
+					}
+					else
+					{
+						if((posn + 4) > length)
+						{
+							throw new ArgumentException
+								(_("Arg_InsufficientSpace"), "bytes");
+						}
+						bytes[posn++] = (byte)(0xF0 | (pair >> 18));
+						bytes[posn++] = (byte)(0x80 | ((pair >> 12) & 0x3F));
+						bytes[posn++] = (byte)(0x80 | ((pair >> 6) & 0x3F));
+						bytes[posn++] = (byte)(0x80 | (pair & 0x3F));
+					}
+				}
+				if(flush && left != 0)
+				{
+					// Flush the left-over surrogate pair start.
+					if((posn + 3) > length)
+					{
+						throw new ArgumentException
+							(_("Arg_InsufficientSpace"), "bytes");
+					}
+					bytes[posn++] = (byte)(0xE0 | (left >> 12));
+					bytes[posn++] = (byte)(0x80 | ((left >> 6) & 0x3F));
+					bytes[posn++] = (byte)(0x80 | (left & 0x3F));
+					left = 0;
+				}
+				leftOver = left;
+
+				// Return the final count to the caller.
+				return posn - byteIndex;
+			}
+
+	// Get the bytes that result from encoding a character buffer.
+	public override int GetBytes(char[] chars, int charIndex, int charCount,
+								 byte[] bytes, int byteIndex)
+			{
+				uint leftOver = 0;
+				return InternalGetBytes(chars, charIndex, charCount,
+									    bytes, byteIndex, ref leftOver,
+										emitIdentifier, true);
+			}
+
+	// Convenience wrappers for "GetBytes".
+	public override int GetBytes(String s, int charIndex, int charCount,
+								 byte[] bytes, int byteIndex)
+			{
+				// Validate the parameters.
+				if(s == null)
+				{
+					throw new ArgumentNullException("s");
+				}
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(charIndex < 0 || charIndex > s.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_StringIndex"));
+				}
+				if(charCount < 0 || charCount > (s.Length - charIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_StringRange"));
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+
+				// Convert the characters into bytes.
+				char ch;
+				int length = bytes.Length;
+				uint pair;
+				int posn = byteIndex;
+				if(emitIdentifier)
+				{
+					if((posn + 3) > length)
+					{
+						throw new ArgumentException
+							(_("Arg_InsufficientSpace"), "bytes");
+					}
+					bytes[posn++] = (byte)0xEF;
+					bytes[posn++] = (byte)0xBB;
+					bytes[posn++] = (byte)0xBF;
+				}
+				while(charCount > 0)
+				{
+					// Fetch the next UTF-16 character pair value.
+					ch = s[charIndex++];
+					--charCount;
+					if(ch >= '\uD800' && ch <= '\uDBFF' && charCount > 1)
+					{
+						// This may be the start of a surrogate pair.
+						pair = (uint)(s[charIndex]);
+						if(pair >= (uint)0xDC00 && pair <= (uint)0xDFFF)
+						{
+							pair = (pair - (uint)0xDC00) +
+								   ((((uint)ch) - (uint)0xD800) << 10) +
+								   (uint)0x10000;
+							++charIndex;
+							--charCount;
+						}
+						else
+						{
+							pair = (uint)ch;
+						}
+					}
+					else
+					{
+						pair = (uint)ch;
+					}
+
+					// Encode the character pair value.
+					if(pair < (uint)0x0080)
+					{
+						if(posn >= length)
+						{
+							throw new ArgumentException
+								(_("Arg_InsufficientSpace"), "bytes");
+						}
+						bytes[posn++] = (byte)pair;
+					}
+					else if(pair < (uint)0x0800)
+					{
+						if((posn + 2) > length)
+						{
+							throw new ArgumentException
+								(_("Arg_InsufficientSpace"), "bytes");
+						}
+						bytes[posn++] = (byte)(0xC0 | (pair >> 6));
+						bytes[posn++] = (byte)(0x80 | (pair & 0x3F));
+					}
+					else if(pair < (uint)0x10000)
+					{
+						if((posn + 3) > length)
+						{
+							throw new ArgumentException
+								(_("Arg_InsufficientSpace"), "bytes");
+						}
+						bytes[posn++] = (byte)(0xE0 | (pair >> 12));
+						bytes[posn++] = (byte)(0x80 | ((pair >> 6) & 0x3F));
+						bytes[posn++] = (byte)(0x80 | (pair & 0x3F));
+					}
+					else
+					{
+						if((posn + 4) > length)
+						{
+							throw new ArgumentException
+								(_("Arg_InsufficientSpace"), "bytes");
+						}
+						bytes[posn++] = (byte)(0xF0 | (pair >> 18));
+						bytes[posn++] = (byte)(0x80 | ((pair >> 12) & 0x3F));
+						bytes[posn++] = (byte)(0x80 | ((pair >> 6) & 0x3F));
+						bytes[posn++] = (byte)(0x80 | (pair & 0x3F));
+					}
+				}
+
+				// Return the final count to the caller.
+				return posn - byteIndex;
+			}
+
+	// Internal version of "GetCharCount" which can handle a rolling
+	// state between multiple calls to this method.
+	private static int InternalGetCharCount(byte[] bytes, int index, int count,
+										   uint leftOverBits,
+										   uint leftOverCount,
+										   bool throwOnInvalid, bool flush)
+			{
+				// Validate the parameters.
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(index < 0 || index > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (bytes.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+
+				// Determine the number of characters that we have.
+				uint ch;
+				int length = 0;
+				uint leftBits = leftOverBits;
+				uint leftSoFar = (leftOverCount & (uint)0x0F);
+				uint leftSize = ((leftOverCount >> 4) & (uint)0x0F);
+				while(count > 0)
+				{
+					ch = (uint)(bytes[index++]);
+					--count;
+					if(leftSize == 0)
+					{
+						// Process a UTF-8 start character.
+						if(ch < (uint)0x0080)
+						{
+							// Single-byte UTF-8 character.
+							++length;
+						}
+						else if((ch & (uint)0xE0) == (uint)0xC0)
+						{
+							// Double-byte UTF-8 character.
+							leftBits = (ch & (uint)0x1F);
+							leftSoFar = 1;
+							leftSize = 2;
+						}
+						else if((ch & (uint)0xF0) == (uint)0xE0)
+						{
+							// Three-byte UTF-8 character.
+							leftBits = (ch & (uint)0x0F);
+							leftSoFar = 1;
+							leftSize = 3;
+						}
+						else if((ch & (uint)0xF8) == (uint)0xF0)
+						{
+							// Four-byte UTF-8 character.
+							leftBits = (ch & (uint)0x07);
+							leftSoFar = 1;
+							leftSize = 4;
+						}
+						else if((ch & (uint)0xFC) == (uint)0xF8)
+						{
+							// Five-byte UTF-8 character.
+							leftBits = (ch & (uint)0x03);
+							leftSoFar = 1;
+							leftSize = 5;
+						}
+						else if((ch & (uint)0xFC) == (uint)0xFC)
+						{
+							// Six-byte UTF-8 character.
+							leftBits = (ch & (uint)0x03);
+							leftSoFar = 1;
+							leftSize = 6;
+						}
+						else
+						{
+							// Invalid UTF-8 start character.
+							if(throwOnInvalid)
+							{
+								throw new ArgumentException
+									(_("Arg_InvalidUTF8"), "bytes");
+							}
+						}
+					}
+					else
+					{
+						// Process an extra byte in a multi-byte sequence.
+						if((ch & (uint)0xC0) == (uint)0x80)
+						{
+							leftBits = ((leftBits << 6) | (ch & (uint)0x3F));
+							if(++leftSoFar >= leftSize)
+							{
+								// We have a complete character now.
+								if(leftBits < (uint)0x10000)
+								{
+									if(leftBits != (uint)0xFEFF)
+									{
+										++length;
+									}
+								}
+								else if(leftBits < (uint)0x110000)
+								{
+									length += 2;
+								}
+								else if(throwOnInvalid)
+								{
+									throw new ArgumentException
+										(_("Arg_InvalidUTF8"), "bytes");
+								}
+								leftSize = 0;
+							}
+						}
+						else
+						{
+							// Invalid UTF-8 sequence: clear and restart.
+							if(throwOnInvalid)
+							{
+								throw new ArgumentException
+									(_("Arg_InvalidUTF8"), "bytes");
+							}
+							leftSize = 0;
+							--index;
+							++count;
+						}
+					}
+				}
+				if(flush && leftSize != 0 && throwOnInvalid)
+				{
+					// We had left-over bytes that didn't make up
+					// a complete UTF-8 character sequence.
+					throw new ArgumentException
+						(_("Arg_InvalidUTF8"), "bytes");
+				}
+
+				// Return the final length to the caller.
+				return length;
+			}
+
+	// Get the number of characters needed to decode a byte buffer.
+	public override int GetCharCount(byte[] bytes, int index, int count)
+			{
+				return InternalGetCharCount(bytes, index, count, 0, 0,
+											throwOnInvalid, true);
+			}
+
+	// Get the characters that result from decoding a byte buffer.
+	private static int InternalGetChars(byte[] bytes, int byteIndex,
+									   int byteCount, char[] chars,
+									   int charIndex, ref uint leftOverBits,
+									   ref uint leftOverCount,
+									   bool throwOnInvalid, bool flush)
+			{
+				// Validate the parameters.
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+				if(byteCount < 0 || byteCount > (bytes.Length - byteIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("byteCount", _("ArgRange_Array"));
+				}
+				if(charIndex < 0 || charIndex > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_Array"));
+				}
+
+				// Convert the bytes into the output buffer.
+				uint ch;
+				int length = chars.Length;
+				int posn = charIndex;
+				uint leftBits = leftOverBits;
+				uint leftSoFar = (leftOverCount & (uint)0x0F);
+				uint leftSize = ((leftOverCount >> 4) & (uint)0x0F);
+				while(byteCount > 0)
+				{
+					// Fetch the next character from the byte buffer.
+					ch = (uint)(bytes[byteIndex++]);
+					--byteCount;
+					if(leftSize == 0)
+					{
+						// Process a UTF-8 start character.
+						if(ch < (uint)0x0080)
+						{
+							// Single-byte UTF-8 character.
+							if(posn >= length)
+							{
+								throw new ArgumentException
+									(_("Arg_InsufficientSpace"), "chars");
+							}
+							chars[posn++] = (char)ch;
+						}
+						else if((ch & (uint)0xE0) == (uint)0xC0)
+						{
+							// Double-byte UTF-8 character.
+							leftBits = (ch & (uint)0x1F);
+							leftSoFar = 1;
+							leftSize = 2;
+						}
+						else if((ch & (uint)0xF0) == (uint)0xE0)
+						{
+							// Three-byte UTF-8 character.
+							leftBits = (ch & (uint)0x0F);
+							leftSoFar = 1;
+							leftSize = 3;
+						}
+						else if((ch & (uint)0xF8) == (uint)0xF0)
+						{
+							// Four-byte UTF-8 character.
+							leftBits = (ch & (uint)0x07);
+							leftSoFar = 1;
+							leftSize = 4;
+						}
+						else if((ch & (uint)0xFC) == (uint)0xF8)
+						{
+							// Five-byte UTF-8 character.
+							leftBits = (ch & (uint)0x03);
+							leftSoFar = 1;
+							leftSize = 5;
+						}
+						else if((ch & (uint)0xFC) == (uint)0xFC)
+						{
+							// Six-byte UTF-8 character.
+							leftBits = (ch & (uint)0x03);
+							leftSoFar = 1;
+							leftSize = 6;
+						}
+						else
+						{
+							// Invalid UTF-8 start character.
+							if(throwOnInvalid)
+							{
+								throw new ArgumentException
+									(_("Arg_InvalidUTF8"), "bytes");
+							}
+						}
+					}
+					else
+					{
+						// Process an extra byte in a multi-byte sequence.
+						if((ch & (uint)0xC0) == (uint)0x80)
+						{
+							leftBits = ((leftBits << 6) | (ch & (uint)0x3F));
+							if(++leftSoFar >= leftSize)
+							{
+								// We have a complete character now.
+								if(leftBits < (uint)0x10000)
+								{
+									if(leftBits != (uint)0xFEFF)
+									{
+										if(posn >= length)
+										{
+											throw new ArgumentException
+												(_("Arg_InsufficientSpace"),
+												 "chars");
+										}
+										chars[posn++] = (char)leftBits;
+									}
+								}
+								else if(leftBits < (uint)0x110000)
+								{
+									if((posn + 2) > length)
+									{
+										throw new ArgumentException
+											(_("Arg_InsufficientSpace"),
+											 "chars");
+									}
+									leftBits -= (uint)0x10000;
+									chars[posn++] = (char)((leftBits >> 10) +
+														   (uint)0xD800);
+									chars[posn++] =
+										(char)((leftBits & (uint)0x3FF) +
+										       (uint)0xDC00);
+								}
+								else if(throwOnInvalid)
+								{
+									throw new ArgumentException
+										(_("Arg_InvalidUTF8"), "bytes");
+								}
+								leftSize = 0;
+							}
+						}
+						else
+						{
+							// Invalid UTF-8 sequence: clear and restart.
+							if(throwOnInvalid)
+							{
+								throw new ArgumentException
+									(_("Arg_InvalidUTF8"), "bytes");
+							}
+							leftSize = 0;
+							--byteIndex;
+							++byteCount;
+						}
+					}
+				}
+				if(flush && leftSize != 0 && throwOnInvalid)
+				{
+					// We had left-over bytes that didn't make up
+					// a complete UTF-8 character sequence.
+					throw new ArgumentException
+						(_("Arg_InvalidUTF8"), "bytes");
+				}
+				leftOverBits = leftBits;
+				leftOverCount = (leftSoFar | (leftSize << 4));
+
+				// Return the final length to the caller.
+				return posn - charIndex;
+			}
+
+	// Get the characters that result from decoding a byte buffer.
+	public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
+								 char[] chars, int charIndex)
+			{
+				uint leftOverBits = 0;
+				uint leftOverCount = 0;
+				return InternalGetChars(bytes, byteIndex, byteCount,
+										chars, charIndex, ref leftOverBits,
+										ref leftOverCount, throwOnInvalid,
+										true);
+			}
+
+	// Get the maximum number of bytes needed to encode a
+	// specified number of characters.
+	public override int GetMaxByteCount(int charCount)
+			{
+				if(charCount < 0)
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_NonNegative"));
+				}
+				return charCount * 4 + (emitIdentifier ? 3 : 0);
+			}
+
+	// Get the maximum number of characters needed to decode a
+	// specified number of bytes.
+	public override int GetMaxCharCount(int byteCount)
+			{
+				if(byteCount < 0)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteCount", _("ArgRange_NonNegative"));
+				}
+				return byteCount;
+			}
+
+	// Get a UTF8-specific decoder that is attached to this instance.
+	public override Decoder GetDecoder()
+			{
+				return new UTF8Decoder(throwOnInvalid);
+			}
+
+	// Get a UTF8-specific encoder that is attached to this instance.
+	public override Encoder GetEncoder()
+			{
+				return new UTF8Encoder(emitIdentifier);
+			}
+
+	// Get the UTF8 preamble.
+	public override byte[] GetPreamble()
+			{
+				if(emitIdentifier)
+				{
+					byte[] pre = new byte [3];
+					pre[0] = (byte)0xEF;
+					pre[1] = (byte)0xBB;
+					pre[2] = (byte)0xBF;
+					return pre;
+				}
+				else
+				{
+					return new byte [0];
+				}
+			}
+
+	// Determine if this object is equal to another.
+	public override bool Equals(Object value)
+			{
+				UTF8Encoding enc = (value as UTF8Encoding);
+				if(enc != null)
+				{
+					return (codePage == enc.codePage &&
+							emitIdentifier == enc.emitIdentifier &&
+							throwOnInvalid == enc.throwOnInvalid);
+				}
+				else
+				{
+					return false;
+				}
+			}
+
+	// Get the hash code for this object.
+	public override int GetHashCode()
+			{
+				return base.GetHashCode();
+			}
+
+#if !ECMA_COMPAT
+
+	// Get the mail body name for this encoding.
+	public override String BodyName
+			{
+				get
+				{
+					return "utf-8";
+				}
+			}
+
+	// Get the human-readable name for this encoding.
+	public override String EncodingName
+			{
+				get
+				{
+					return "Unicode (UTF-8)";
+				}
+			}
+
+	// Get the mail agent header name for this encoding.
+	public override String HeaderName
+			{
+				get
+				{
+					return "utf-8";
+				}
+			}
+
+	// Determine if this encoding can be displayed in a Web browser.
+	public override bool IsBrowserDisplay
+			{
+				get
+				{
+					return true;
+				}
+			}
+
+	// Determine if this encoding can be saved from a Web browser.
+	public override bool IsBrowserSave
+			{
+				get
+				{
+					return true;
+				}
+			}
+
+	// Determine if this encoding can be displayed in a mail/news agent.
+	public override bool IsMailNewsDisplay
+			{
+				get
+				{
+					return true;
+				}
+			}
+
+	// Determine if this encoding can be saved from a mail/news agent.
+	public override bool IsMailNewsSave
+			{
+				get
+				{
+					return true;
+				}
+			}
+
+	// Get the IANA-preferred Web name for this encoding.
+	public override String WebName
+			{
+				get
+				{
+					return "utf-8";
+				}
+			}
+
+	// Get the Windows code page represented by this object.
+	public override int WindowsCodePage
+			{
+				get
+				{
+					return UnicodeEncoding.UNICODE_CODE_PAGE;
+				}
+			}
+
+#endif // !ECMA_COMPAT
+
+	// UTF-8 decoder implementation.
+	private sealed class UTF8Decoder : Decoder
+	{
+		private bool throwOnInvalid;
+		private uint leftOverBits;
+		private uint leftOverCount;
+
+		// Constructor.
+		public UTF8Decoder(bool throwOnInvalid)
+				{
+					this.throwOnInvalid = throwOnInvalid;
+					leftOverBits = 0;
+					leftOverCount = 0;
+				}
+
+		// Override inherited methods.
+		public override int GetCharCount(byte[] bytes, int index, int count)
+				{
+					return InternalGetCharCount(bytes, index, count,
+												leftOverBits, leftOverCount,
+												throwOnInvalid, false);
+				}
+		public override int GetChars(byte[] bytes, int byteIndex,
+									 int byteCount, char[] chars,
+									 int charIndex)
+				{
+					return InternalGetChars(bytes, byteIndex, byteCount,
+											chars, charIndex,
+											ref leftOverBits,
+											ref leftOverCount,
+											throwOnInvalid, false);
+				}
+
+	} // class UTF8Decoder
+
+	// UTF-8 encoder implementation.
+	private sealed class UTF8Encoder : Encoder
 	{
-		public UTF8Encoding () : base ("UTF-8", false)
-		{
-			encoding_name = "Unicode (UTF-8)";
-			body_name = "utf-8";
-			header_name = "utf-8";
-			web_name = "utf-8";
-			is_browser_display = true;
-			is_browser_save = true;
-			is_mail_news_display = true;
-			is_mail_news_save = true;
-		}
-		
-		public override int GetMaxByteCount (int charCount)
-		{
-			return charCount*6;
-		}
-
-		public override int GetMaxCharCount (int byteCount)
-		{
-			return byteCount;
-		}
-	}
-}
+		private bool emitIdentifier;
+		private uint leftOver;
+
+		// Constructor.
+		public UTF8Encoder(bool emitIdentifier)
+				{
+					this.emitIdentifier = emitIdentifier;
+					leftOver = 0;
+				}
+
+		// Override inherited methods.
+		public override int GetByteCount(char[] chars, int index,
+										 int count, bool flush)
+				{
+					return InternalGetByteCount
+						(chars, index, count, leftOver,
+						 emitIdentifier, flush);
+				}
+		public override int GetBytes(char[] chars, int charIndex,
+									 int charCount, byte[] bytes,
+									 int byteCount, bool flush)
+				{
+					int result;
+					result = InternalGetBytes
+						(chars, charIndex, charCount, bytes, byteCount,
+						 ref leftOver, emitIdentifier, flush);
+					emitIdentifier = false;
+					return result;
+				}
+
+	} // class UTF8Encoder
+
+}; // class UTF8Encoding
+
+}; // namespace System.Text

+ 642 - 54
mcs/class/corlib/System.Text/UnicodeEncoding.cs

@@ -1,55 +1,643 @@
-// -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
-//
-// System.Text.UnicodeEncoding.cs
-//
-// Author:
-//   Sean MacIsaac ([email protected])
-//   Dietmar Maurer ([email protected])
-//
-// (C) Ximian, Inc.  http://www.ximian.com
-//
-
-// FIXME: implement byteOrderMark
-
-namespace System.Text {
-      
-	[MonoTODO]
-	[Serializable]
-	public class UnicodeEncoding : Encoding
+/*
+ * UnicodeEncoding.cs - Implementation of the
+ *		"System.Text.UnicodeEncoding" class.
+ *
+ * Copyright (c) 2001, 2002  Southern Storm Software, Pty Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+namespace System.Text
+{
+
+using System;
+
+public class UnicodeEncoding : Encoding
+{
+	// Magic numbers used by Windows for Unicode.
+	internal const int UNICODE_CODE_PAGE     = 1200;
+	internal const int BIG_UNICODE_CODE_PAGE = 1201;
+
+#if !ECMA_COMPAT
+	// Size of characters in this encoding.
+	public const int CharSize = 2;
+#endif
+
+	// Internal state.
+	private bool bigEndian;
+	private bool byteOrderMark;
+
+	// Constructors.
+	public UnicodeEncoding() : base(UNICODE_CODE_PAGE)
+			{
+				bigEndian = false;
+				byteOrderMark = true;
+			}
+	public UnicodeEncoding(bool bigEndian, bool byteOrderMark)
+			: base((bigEndian ? BIG_UNICODE_CODE_PAGE : UNICODE_CODE_PAGE))
+			{
+				this.bigEndian = bigEndian;
+				this.byteOrderMark = byteOrderMark;
+			}
+
+	// Get the number of bytes needed to encode a character buffer.
+	public override int GetByteCount(char[] chars, int index, int count)
+			{
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(index < 0 || index > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (chars.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+				return count * 2 + (byteOrderMark ? 2 : 0);
+			}
+
+	// Convenience wrappers for "GetByteCount".
+	public override int GetByteCount(String s)
+			{
+				if(s == null)
+				{
+					throw new ArgumentNullException("s");
+				}
+				return s.Length * 2 + (byteOrderMark ? 2 : 0);
+			}
+
+	// Get the bytes that result from encoding a character buffer.
+	public override int GetBytes(char[] chars, int charIndex, int charCount,
+								 byte[] bytes, int byteIndex)
+			{
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(charIndex < 0 || charIndex > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_Array"));
+				}
+				if(charCount < 0 || charCount > (chars.Length - charIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_Array"));
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+				if((bytes.Length - byteIndex) <
+					(charCount * 2 + (byteOrderMark ? 2 : 0)))
+				{
+					throw new ArgumentException
+						(_("Arg_InsufficientSpace"));
+				}
+				int posn = byteIndex;
+				char ch;
+				if(bigEndian)
+				{
+					if(byteOrderMark)
+					{
+						bytes[posn++] = (byte)0xFE;
+						bytes[posn++] = (byte)0xFF;
+					}
+					while(charCount-- > 0)
+					{
+						ch = chars[charIndex++];
+						bytes[posn++] = (byte)(ch >> 8);
+						bytes[posn++] = (byte)ch;
+					}
+				}
+				else
+				{
+					if(byteOrderMark)
+					{
+						bytes[posn++] = (byte)0xFF;
+						bytes[posn++] = (byte)0xFE;
+					}
+					while(charCount-- > 0)
+					{
+						ch = chars[charIndex++];
+						bytes[posn++] = (byte)ch;
+						bytes[posn++] = (byte)(ch >> 8);
+					}
+				}
+				return posn - byteIndex;
+			}
+
+	// Convenience wrappers for "GetBytes".
+	public override int GetBytes(String s, int charIndex, int charCount,
+								 byte[] bytes, int byteIndex)
+			{
+				if(s == null)
+				{
+					throw new ArgumentNullException("s");
+				}
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(charIndex < 0 || charIndex > s.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_StringIndex"));
+				}
+				if(charCount < 0 || charCount > (s.Length - charIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_StringRange"));
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+				if((bytes.Length - byteIndex) <
+					(charCount * 2 + (byteOrderMark ? 2 : 0)))
+				{
+					throw new ArgumentException
+						(_("Arg_InsufficientSpace"));
+				}
+				int posn = byteIndex;
+				char ch;
+				if(bigEndian)
+				{
+					if(byteOrderMark)
+					{
+						bytes[posn++] = (byte)0xFE;
+						bytes[posn++] = (byte)0xFF;
+					}
+					while(charCount-- > 0)
+					{
+						ch = s[charIndex++];
+						bytes[posn++] = (byte)(ch >> 8);
+						bytes[posn++] = (byte)ch;
+					}
+				}
+				else
+				{
+					if(byteOrderMark)
+					{
+						bytes[posn++] = (byte)0xFF;
+						bytes[posn++] = (byte)0xFE;
+					}
+					while(charCount-- > 0)
+					{
+						ch = s[charIndex++];
+						bytes[posn++] = (byte)ch;
+						bytes[posn++] = (byte)(ch >> 8);
+					}
+				}
+				return posn - byteIndex;
+			}
+
+	// Get the number of characters needed to decode a byte buffer.
+	public override int GetCharCount(byte[] bytes, int index, int count)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(index < 0 || index > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("index", _("ArgRange_Array"));
+				}
+				if(count < 0 || count > (bytes.Length - index))
+				{
+					throw new ArgumentOutOfRangeException
+						("count", _("ArgRange_Array"));
+				}
+				if(count >= 2)
+				{
+					if((bytes[0] == (byte)0xFE && bytes[1] == (byte)0xFF) ||
+					   (bytes[0] == (byte)0xFF && bytes[1] == (byte)0xFE))
+					{
+						return ((count - 1) / 2);
+					}
+				}
+				return count / 2;
+			}
+
+	// Get the characters that result from decoding a byte buffer.
+	public override int GetChars(byte[] bytes, int byteIndex, int byteCount,
+								 char[] chars, int charIndex)
+			{
+				if(bytes == null)
+				{
+					throw new ArgumentNullException("bytes");
+				}
+				if(chars == null)
+				{
+					throw new ArgumentNullException("chars");
+				}
+				if(byteIndex < 0 || byteIndex > bytes.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteIndex", _("ArgRange_Array"));
+				}
+				if(byteCount < 0 || byteCount > (bytes.Length - byteIndex))
+				{
+					throw new ArgumentOutOfRangeException
+						("byteCount", _("ArgRange_Array"));
+				}
+				if(charIndex < 0 || charIndex > chars.Length)
+				{
+					throw new ArgumentOutOfRangeException
+						("charIndex", _("ArgRange_Array"));
+				}
+
+				// Determine the byte order in the incoming buffer.
+				bool isBigEndian;
+				if(byteCount >= 2)
+				{
+					if(bytes[0] == (byte)0xFE && bytes[1] == (byte)0xFF)
+					{
+						isBigEndian = true;
+						byteCount -= 2;
+						byteIndex += 2;
+					}
+					else if(bytes[0] == (byte)0xFF && bytes[1] == (byte)0xFE)
+					{
+						isBigEndian = false;
+						byteCount -= 2;
+						byteIndex += 2;
+					}
+					else
+					{
+						isBigEndian = bigEndian;
+					}
+				}
+				else
+				{
+					isBigEndian = bigEndian;
+				}
+
+				// Validate that we have sufficient space in "chars".
+				if((chars.Length - charIndex) < (byteCount / 2))
+				{
+					throw new ArgumentException
+						(_("Arg_InsufficientSpace"));
+				}
+
+				// Convert the characters.
+				int posn = charIndex;
+				if(isBigEndian)
+				{
+					while(byteCount >= 2)
+					{
+						chars[posn++] =
+							((char)((((int)(bytes[byteIndex])) << 8) |
+									 ((int)(bytes[byteIndex + 1]))));
+						byteIndex += 2;
+						byteCount -= 2;
+					}
+				}
+				else
+				{
+					while(byteCount >= 2)
+					{
+						chars[posn++] =
+							((char)((((int)(bytes[byteIndex + 1])) << 8) |
+									 ((int)(bytes[byteIndex]))));
+						byteIndex += 2;
+						byteCount -= 2;
+					}
+				}
+				return posn - charIndex;
+			}
+
+	// Get the maximum number of bytes needed to encode a
+	// specified number of characters.
+	public override int GetMaxByteCount(int charCount)
+			{
+				if(charCount < 0)
+				{
+					throw new ArgumentOutOfRangeException
+						("charCount", _("ArgRange_NonNegative"));
+				}
+				return charCount * 2 + (byteOrderMark ? 2 : 0);
+			}
+
+	// Get the maximum number of characters needed to decode a
+	// specified number of bytes.
+	public override int GetMaxCharCount(int byteCount)
+			{
+				if(byteCount < 0)
+				{
+					throw new ArgumentOutOfRangeException
+						("byteCount", _("ArgRange_NonNegative"));
+				}
+				return byteCount / 2;
+			}
+
+	// Get a Unicode-specific decoder that is attached to this instance.
+	public override Decoder GetDecoder()
+			{
+				return new UnicodeDecoder(bigEndian);
+			}
+
+	// Get the Unicode preamble.
+	public override byte[] GetPreamble()
+			{
+				if(byteOrderMark)
+				{
+					byte[] preamble = new byte[2];
+					if(bigEndian)
+					{
+						preamble[0] = (byte)0xFE;
+						preamble[1] = (byte)0xFF;
+					}
+					else
+					{
+						preamble[0] = (byte)0xFF;
+						preamble[1] = (byte)0xFE;
+					}
+					return preamble;
+				}
+				else
+				{
+					return new byte [0];
+				}
+			}
+
+	// Determine if this object is equal to another.
+	public override bool Equals(Object value)
+			{
+				UnicodeEncoding enc = (value as UnicodeEncoding);
+				if(enc != null)
+				{
+					return (codePage == enc.codePage &&
+							bigEndian == enc.bigEndian &&
+							byteOrderMark == enc.byteOrderMark);
+				}
+				else
+				{
+					return false;
+				}
+			}
+
+	// Get the hash code for this object.
+	public override int GetHashCode()
+			{
+				return base.GetHashCode();
+			}
+
+#if !ECMA_COMPAT
+
+	// Get the mail body name for this encoding.
+	public override String BodyName
+			{
+				get
+				{
+					if(bigEndian)
+					{
+						return "unicodeFFFE";
+					}
+					else
+					{
+						return "utf-16";
+					}
+				}
+			}
+
+	// Get the human-readable name for this encoding.
+	public override String EncodingName
+			{
+				get
+				{
+					if(bigEndian)
+					{
+						return "Unicode (Big-Endian)";
+					}
+					else
+					{
+						return "Unicode";
+					}
+				}
+			}
+
+	// Get the mail agent header name for this encoding.
+	public override String HeaderName
+			{
+				get
+				{
+					if(bigEndian)
+					{
+						return "unicodeFFFE";
+					}
+					else
+					{
+						return "utf-16";
+					}
+				}
+			}
+
+	// Determine if this encoding can be saved from a Web browser.
+	public override bool IsBrowserSave
+			{
+				get
+				{
+					return !bigEndian;
+				}
+			}
+
+	// Get the IANA-preferred Web name for this encoding.
+	public override String WebName
+			{
+				get
+				{
+					if(bigEndian)
+					{
+						return "unicodeFFFE";
+					}
+					else
+					{
+						return "utf-16";
+					}
+				}
+			}
+
+	// Get the Windows code page represented by this object.
+	public override int WindowsCodePage
+			{
+				get
+				{
+					// Windows reports the same code page number for
+					// both the little-endian and big-endian forms.
+					return UNICODE_CODE_PAGE;
+				}
+			}
+
+#endif // !ECMA_COMPAT
+
+	// Unicode decoder implementation.
+	private sealed class UnicodeDecoder : Decoder
 	{
-		private bool byteOrderMark;
-		
-		private void init (bool byteOrderMark)
-		{
-			this.byteOrderMark = byteOrderMark;
-			encoding_name = "Unicode";
-			body_name = "utf-16";
-			header_name = "utf-16";
-			web_name = "utf-16";
-			is_browser_display = false;
-			is_browser_save = true;
-			is_mail_news_display = false;
-			is_mail_news_save = false;
-		}
-		
-		public UnicodeEncoding () : base ("UNICODE", false)
-		{
-			init (false);
-		}
-		
-                public UnicodeEncoding (bool bigEndian, bool byteOrderMark) : base ("UNICODE", bigEndian)
-		{
-			init (byteOrderMark);
-		}
-		
-		public override int GetMaxByteCount (int charCount)
-		{
-			return charCount;
-		}
-
-		public override int GetMaxCharCount (int byteCount)
-		{
-			return byteCount / 2;
-		}
-	}
-}
+		private bool bigEndian;
+		private int leftOverByte;
+
+		// Constructor.
+		public UnicodeDecoder(bool bigEndian)
+				{
+					this.bigEndian = bigEndian;
+					leftOverByte = -1;
+				}
+
+		// Override inherited methods.
+		public override int GetCharCount(byte[] bytes, int index, int count)
+				{
+					if(bytes == null)
+					{
+						throw new ArgumentNullException("bytes");
+					}
+					if(index < 0 || index > bytes.Length)
+					{
+						throw new ArgumentOutOfRangeException
+							("index", _("ArgRange_Array"));
+					}
+					if(count < 0 || count > (bytes.Length - index))
+					{
+						throw new ArgumentOutOfRangeException
+							("count", _("ArgRange_Array"));
+					}
+					if(leftOverByte != -1)
+					{
+						return (count + 1) / 2;
+					}
+					else
+					{
+						return count / 2;
+					}
+				}
+		public override int GetChars(byte[] bytes, int byteIndex,
+									 int byteCount, char[] chars,
+									 int charIndex)
+				{
+					if(bytes == null)
+					{
+						throw new ArgumentNullException("bytes");
+					}
+					if(chars == null)
+					{
+						throw new ArgumentNullException("chars");
+					}
+					if(byteIndex < 0 || byteIndex > bytes.Length)
+					{
+						throw new ArgumentOutOfRangeException
+							("byteIndex", _("ArgRange_Array"));
+					}
+					if(byteCount < 0 || byteCount > (bytes.Length - byteIndex))
+					{
+						throw new ArgumentOutOfRangeException
+							("byteCount", _("ArgRange_Array"));
+					}
+					if(charIndex < 0 || charIndex > chars.Length)
+					{
+						throw new ArgumentOutOfRangeException
+							("charIndex", _("ArgRange_Array"));
+					}
+	
+					// Convert the characters.
+					int posn = charIndex;
+					bool isBigEndian = bigEndian;
+					int leftOver = leftOverByte;
+					int length = chars.Length;
+					char ch;
+					while(byteCount > 0)
+					{
+						if(leftOver != -1)
+						{
+							if(isBigEndian)
+							{
+								ch = ((char)((leftOver << 8) |
+										    ((int)(bytes[byteIndex]))));
+							}
+							else
+							{
+								ch = ((char)(leftOver |
+									    	 (((int)(bytes[byteIndex])) << 8)));
+							}
+							leftOver = -1;
+							++byteIndex;
+							--byteCount;
+						}
+						else if(byteCount > 1)
+						{
+							if(isBigEndian)
+							{
+								ch = ((char)((((int)(bytes[byteIndex])) << 8) |
+											  ((int)(bytes[byteIndex + 1]))));
+							}
+							else
+							{
+								ch = ((char)((((int)(bytes[byteIndex + 1]))
+													<< 8) |
+										      ((int)(bytes[byteIndex]))));
+							}
+							byteIndex += 2;
+							byteCount -= 2;
+						}
+						else
+						{
+							leftOver = (int)(bytes[byteIndex]);
+							break;
+						}
+						if(ch == '\uFFFE')
+						{
+							// Switch byte orders.
+							bigEndian = !bigEndian;
+						}
+						else if(ch != '\uFEFF')
+						{
+							// Ordinary character.
+							if(posn < length)
+							{
+								chars[posn++] = ch;
+							}
+							else
+							{
+								throw new ArgumentException
+									(_("Arg_InsufficientSpace"));
+							}
+						}
+					}
+					leftOverByte = leftOver;
+					bigEndian = isBigEndian;
+
+					// Finished - return the converted length.
+					return posn - charIndex;
+				}
+
+	} // class UnicodeDecoder
+
+}; // class UnicodeEncoding
+
+}; // namespace System.Text

+ 2 - 0
mcs/class/corlib/unix.args

@@ -685,8 +685,10 @@ System.Security.Principal/WindowsAccountType.cs
 System.Security.Principal/WindowsBuiltInRole.cs
 System.Text/ASCIIEncoding.cs
 System.Text/Decoder.cs
+System.Text/DefaultEncoding.cs
 System.Text/Encoder.cs
 System.Text/Encoding.cs
+System.Text/Latin1Encoding.cs
 System.Text/StringBuilder.cs
 System.Text/UnicodeEncoding.cs
 System.Text/UTF7Encoding.cs