// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== namespace System.Text { using System; //| public class UnicodeEncoding : Encoding { internal bool bigEndian; internal bool byteOrderMark; // Unicode version 2.0 character size in bytes //| public const int CharSize = 2; //| public UnicodeEncoding() : this(false, true) { } //| public UnicodeEncoding(bool bigEndian, bool byteOrderMark) : base(bigEndian? 1201 : 1200) { //Set the data item. this.bigEndian = bigEndian; this.byteOrderMark = byteOrderMark; } //| public override int GetByteCount(char[] chars, int index, int count) { if (chars == null) { throw new ArgumentNullException("chars", "ArgumentNull_Array"); } if (index < 0 || count < 0) { throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), "ArgumentOutOfRange_NeedNonNegNum"); } if (chars.Length - index < count) { throw new ArgumentOutOfRangeException("chars", "ArgumentOutOfRange_IndexCountBuffer"); } int byteCount = count * CharSize; // check for overflow if (byteCount < 0) throw new ArgumentOutOfRangeException("count", "ArgumentOutOfRange_GetByteCountOverflow"); return byteCount; } //| public override int GetByteCount(String s) { if (s == null) throw new ArgumentNullException("s"); int byteCount = s.Length * CharSize; // check for overflow if (byteCount < 0) throw new ArgumentOutOfRangeException("s", "ArgumentOutOfRange_GetByteCountOverflow"); return byteCount; } //| public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { int byteCount = charCount * CharSize; if (chars == null || bytes == null) { throw new ArgumentNullException((chars == null ? "chars" : "bytes"), "ArgumentNull_Array"); } if (charIndex < 0 || charCount < 0) { throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), "ArgumentOutOfRange_NeedNonNegNum"); } if (chars.Length - charIndex < charCount) { throw new ArgumentOutOfRangeException("chars", "ArgumentOutOfRange_IndexCountBuffer"); } if (byteIndex < 0 || byteIndex > bytes.Length) { throw new ArgumentOutOfRangeException("byteIndex", "ArgumentOutOfRange_Index"); } if (bytes.Length - byteIndex < byteCount) { throw new ArgumentException("Argument_ConversionOverflow"); } if (bigEndian) { int charEnd = charIndex + charCount; while (charIndex < charEnd) { char ch = chars[charIndex++]; bytes[byteIndex++] = (byte)(ch >> 8); bytes[byteIndex++] = (byte)ch; } } else { Buffer.InternalBlockCopy(chars, charIndex * CharSize, bytes, byteIndex, byteCount); } return byteCount; } //| public override byte[] GetBytes(String s) { if (s == null) { throw new ArgumentNullException("s", "ArgumentNull_String"); } int byteLen = GetByteCount(s); byte[] bytes = new byte[byteLen]; GetBytes(s, 0, s.Length, bytes, 0); return bytes; } //| public override int GetBytes(String s, int charIndex, int charCount, byte[] bytes, int byteIndex) { int byteCount = charCount * CharSize; if (s == null || bytes == null) { throw new ArgumentNullException((s == null ? "s" : "bytes"), "ArgumentNull_Array"); } if (charIndex < 0 || charCount < 0) { throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), "ArgumentOutOfRange_NeedNonNegNum"); } if (s.Length - charIndex < charCount) { throw new ArgumentOutOfRangeException("s", "ArgumentOutOfRange_IndexCount"); } if (byteIndex < 0 || byteIndex > bytes.Length) { throw new ArgumentOutOfRangeException("byteIndex", "ArgumentOutOfRange_Index"); } if (bytes.Length - byteIndex < byteCount) { throw new ArgumentException("Argument_ConversionOverflow"); } if (bigEndian) { int charEnd = charIndex + charCount; while (charIndex < charEnd) { char ch = s[charIndex++]; bytes[byteIndex++] = (byte)(ch >> 8); bytes[byteIndex++] = (byte)ch; } } else { // @TODO: Consider pinning the String here and then using a managed // memcpy implementation (see VTable). This would // require a C# compiler that can get an interior pointer to a // String, probably via the fixed statement. s.CopyToByteArray(charIndex, bytes, byteIndex, charCount); } return byteCount; } //| public override int GetCharCount(byte[] bytes, int index, int count) { if (bytes == null) { throw new ArgumentNullException("bytes", "ArgumentNull_Array"); } if (index < 0 || count < 0) { throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), "ArgumentOutOfRange_NeedNonNegNum"); } if (bytes.Length - index < count) { throw new ArgumentOutOfRangeException("bytes", "ArgumentOutOfRange_IndexCountBuffer"); } return (count / CharSize); } //| public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { int charCount = byteCount / CharSize; if (bytes == null || chars == null) { throw new ArgumentNullException((bytes == null ? "bytes" : "chars"), "ArgumentNull_Array"); } if (byteIndex < 0 || byteCount < 0) { throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"), "ArgumentOutOfRange_NeedNonNegNum"); } if (bytes.Length - byteIndex < byteCount) { throw new ArgumentOutOfRangeException("bytes", "ArgumentOutOfRange_IndexCountBuffer"); } if (charIndex < 0 || charIndex > chars.Length) { throw new ArgumentOutOfRangeException("charIndex", "ArgumentOutOfRange_Index"); } if (chars.Length - charIndex < charCount) { throw new ArgumentException("Argument_ConversionOverflow"); } byteCount = charCount * CharSize; if (bigEndian) { int byteEnd = byteIndex + byteCount; while (byteIndex < byteEnd) { int hi = bytes[byteIndex++]; int lo = bytes[byteIndex++]; chars[charIndex++] = (char)(hi << 8 | lo); } } else { Buffer.InternalBlockCopy(bytes, byteIndex, chars, charIndex * CharSize, byteCount); } return charCount; } //| public override System.Text.Decoder GetDecoder() { return new Decoder(this); } //| public override byte[] GetPreamble() { if (byteOrderMark) { // Note - we must allocate new byte[]'s here to prevent someone // from modifying a cached byte[]. if (bigEndian) return new byte[2] { 0xfe, 0xff }; else return new byte[2] { 0xff, 0xfe }; } return emptyByteArray; } //| public override int GetMaxByteCount(int charCount) { if (charCount < 0) { throw new ArgumentOutOfRangeException("charCount", "ArgumentOutOfRange_NeedNonNegNum"); } long byteCount = (long)charCount * CharSize; if (byteCount > 0x7fffffff) throw new ArgumentOutOfRangeException("charCount", "ArgumentOutOfRange_GetByteCountOverflow"); return (int)byteCount; } //| public override int GetMaxCharCount(int byteCount) { if (byteCount < 0) { throw new ArgumentOutOfRangeException("byteCount", "ArgumentOutOfRange_NeedNonNegNum"); } long result = ((long)byteCount + 1) / CharSize; if (result > 0x7fffffff) { throw new ArgumentOutOfRangeException("byteCount", "ArgumentOutOfRange_GetCharCountOverflow"); } return (int)result; } //| public override bool Equals(Object value) { UnicodeEncoding uenc = value as UnicodeEncoding; if (uenc != null) { // // Big Endian Unicode has different code page (1201) than small Endian one (1200), // so we still have to check m_codePage here. // return (m_codePage == uenc.m_codePage && byteOrderMark == uenc.byteOrderMark); } return (false); } //| public override int GetHashCode() { return m_codePage; } private class Decoder : System.Text.Decoder { private bool bigEndian; private int lastByte; public Decoder(UnicodeEncoding encoding) { bigEndian = encoding.bigEndian; lastByte = -1; } public override int GetCharCount(byte[] bytes, int index, int count) { if (bytes == null) { throw new ArgumentNullException("bytes", "ArgumentNull_Array"); } if (index < 0 || count < 0) { throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), "ArgumentOutOfRange_NeedNonNegNum"); } if (bytes.Length - index < count) { throw new ArgumentOutOfRangeException("bytes", "ArgumentOutOfRange_IndexCountBuffer"); } if (lastByte >= 0) count++; return count / CharSize; } public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { if (bytes == null || chars == null) { throw new ArgumentNullException((bytes == null ? "bytes" : "chars"), "ArgumentNull_Array"); } if (byteIndex < 0 || byteCount < 0) { throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"), "ArgumentOutOfRange_NeedNonNegNum"); } if (bytes.Length - byteIndex < byteCount) { throw new ArgumentOutOfRangeException("bytes", "ArgumentOutOfRange_IndexCountBuffer"); } if (charIndex < 0 || charIndex > chars.Length) { throw new ArgumentOutOfRangeException("charIndex", "ArgumentOutOfRange_Index"); } int charCount = GetCharCount(bytes, byteIndex, byteCount); if (chars.Length - charIndex < charCount) { throw new ArgumentException("Argument_ConversionOverflow"); } if (lastByte >= 0) { if (byteCount == 0) return charCount; int nextByte = bytes[byteIndex++]; byteCount--; if (bigEndian) { chars[charIndex++] = (char)(lastByte << 8 | nextByte); } else { chars[charIndex++] = (char)(nextByte << 8 | lastByte); } lastByte = -1; } if ((byteCount & 1) != 0) { lastByte = bytes[byteIndex + --byteCount]; } if (bigEndian) { int byteEnd = byteIndex + byteCount; while (byteIndex < byteEnd) { ushort hi = bytes[byteIndex++]; byte lo = bytes[byteIndex++]; chars[charIndex++] = (char)(hi << 8 | lo); } } else { Buffer.InternalBlockCopy(bytes, byteIndex, chars, charIndex * CharSize, byteCount); } return charCount; } } } }