From 8123965bcc3bf75c1dc0d597957f244ec7e200b2 Mon Sep 17 00:00:00 2001 From: Tarek Mahmoud Sayed Date: Sat, 8 Apr 2017 13:06:48 -0700 Subject: [PATCH] Revert EncodingForwarder (#10805) * Revert "Remove TODO on throwing exception" This reverts commit 467f06d6f01deb4905a901a9d337a8dfdef817e1. * Revert "Move the SecuritySafeCritical attributes to EncodingForwarder" This reverts commit a64020c8825770ccc8a83d200783a979fbac6434. * Revert "Add note on UTF8Encoding.GetByteCount to EncodingForwarder" This reverts commit a4192dc80352345be2c250b4c33b5b72680069d6. * Revert "Fix CoreFX test failures" This reverts commit 4fd1bfef80fbd4ccb7625196cd841f4fa6415282. * Revert "[UTF8Encoding] Remove unncessary comments" This reverts commit 1f9cd6744fcc4c14ee402ba24e26a1b9e4ce8fcc. * Revert "[UTF7Encoding] Remove unncessary comments" This reverts commit e1818e622933da083a241963e69f36d5d6d89063. * Revert "[UTF32Encoding] Remove unncessary comments" This reverts commit ad1ad35dc03aad4822db57bcbbe1ce7b9f4958ce. * Revert "[UnicodeEncoding] Remove unncessary comments" This reverts commit f09b521e334fcdf6c279466724a2e6b8f4642cce. * Revert "[EncodingNLS] Remove unncessary comments" This reverts commit 95ff597b07cf40532f6af52beab076bd80332b0f. * Revert "[ASCIIEncoding] Remove unncessary comments" This reverts commit 77fa0fb69c9113909fbbe3f896779eab26d9e250. * Revert "Use EncodingForwarder for GetString(byte[], int, int)" This reverts commit 372fcd3cfc8115233040a787e36d020edd919a22. * Revert "Use EncodingForwarder for GetChars(byte*, int, char*, int)" This reverts commit ab47c2281299f464ecddb1d04c292a37b96646dc. * Revert "Use EncodingForwarder for GetChars(byte[], int, int, char[], int)" This reverts commit 860434db541daf533b43491280774dc4274590b8. * Revert "Use EncodingForwarder for GetCharCount(byte*, int)" This reverts commit f83ecbead207000825555393287dafbca8259137. * Revert "Use EncodingForwarder for GetCharCount(byte[], int, int)" This reverts commit 6de8ede4e8ca98a382b066ba45a172e3f8ce2821. * Revert "Use EncodingForwarder for GetBytes(char*, int, byte*, int)" This reverts commit 7c771b8b8462d0b95130cabfe0de5efbf64278bc. * Revert "Use EncodingForwarder for GetBytes(char[], int, int, byte[], int)" This reverts commit 088943185a0469d936a8c0b6e235bdc715e6fc25. * Revert "Use EncodingForwarder for GetBytes(string, int, int, byte[], int)" This reverts commit fa55fd74ae3e9374468d32db7371c82e6ae13593. * Revert "Use EncodingForwarder for GetByteCount(char*, int)" This reverts commit 56c687e0afefc6c223dc0d296a4c64ab5465ebdd. * Revert "Rename the chars parameter in a comment" This reverts commit 9668b5f6275f9dbf24ecd0767d5d4817cde16322. * Revert "Use EncodingForwarder for GetByteCount(string)" This reverts commit e61479088e1ba1f1d8756b8da1a352d518c015c8. * Revert "Use EncodingForwarder for GetByteCount(char[], int, int)" This reverts commit ebfc3ce64205a2a5b14c9fe487659ed02c1f3486. --- src/mscorlib/mscorlib.shared.sources.props | 1 - src/mscorlib/src/System/Text/ASCIIEncoding.cs | 328 +++++++++++++++-- .../src/System/Text/EncodingForwarder.cs | 339 ------------------ src/mscorlib/src/System/Text/EncodingNLS.cs | 320 +++++++++++++++-- src/mscorlib/src/System/Text/UTF32Encoding.cs | 326 +++++++++++++++-- src/mscorlib/src/System/Text/UTF7Encoding.cs | 323 +++++++++++++++-- src/mscorlib/src/System/Text/UTF8Encoding.cs | 322 +++++++++++++++-- .../src/System/Text/UnicodeEncoding.cs | 323 +++++++++++++++-- 8 files changed, 1723 insertions(+), 559 deletions(-) delete mode 100644 src/mscorlib/src/System/Text/EncodingForwarder.cs diff --git a/src/mscorlib/mscorlib.shared.sources.props b/src/mscorlib/mscorlib.shared.sources.props index fc5153f06234..6f3ea268af72 100644 --- a/src/mscorlib/mscorlib.shared.sources.props +++ b/src/mscorlib/mscorlib.shared.sources.props @@ -991,7 +991,6 @@ - diff --git a/src/mscorlib/src/System/Text/ASCIIEncoding.cs b/src/mscorlib/src/System/Text/ASCIIEncoding.cs index bf1a62df5598..825a917b607f 100644 --- a/src/mscorlib/src/System/Text/ASCIIEncoding.cs +++ b/src/mscorlib/src/System/Text/ASCIIEncoding.cs @@ -39,49 +39,127 @@ internal override void SetDefaultFallbacks() this.decoderFallback = DecoderFallback.ReplacementFallback; } + // // WARNING: GetByteCount(string chars), GetBytes(string chars,...), and GetString(byte[] byteIndex...) // WARNING: have different variable names than EncodingNLS.cs, so this can't just be cut & pasted, // WARNING: or it'll break VB's way of calling these. + // + // The following methods are copied from EncodingNLS.cs. + // Unfortunately EncodingNLS.cs is internal and we're public, so we have to reimpliment them here. + // These should be kept in sync for the following classes: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // - // NOTE: Many methods in this class forward to EncodingForwarder for - // validating arguments/wrapping the unsafe methods in this class - // which do the actual work. That class contains - // shared logic for doing this which is used by - // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding, - // UTF7Encoding, and UTF8Encoding. - // The reason the code is separated out into a static class, rather - // than a base class which overrides all of these methods for us - // (which is what EncodingNLS is for internal Encodings) is because - // that's really more of an implementation detail so it's internal. - // At the same time, C# doesn't allow a public class subclassing an - // internal/private one, so we end up having to re-override these - // methods in all of the public Encodings + EncodingNLS. - // Returns the number of bytes required to encode a range of characters in // a character array. - - public override int GetByteCount(char[] chars, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetByteCount(char[] chars, int index, int count) { - return EncodingForwarder.GetByteCount(this, chars, index, count); + // Validate input parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - index < count) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input, return 0, avoid fixed empty array problem + if (count == 0) + return 0; + + // Just call the pointer version + fixed (char* pChars = chars) + return GetByteCount(pChars + index, count, null); } - public override int GetByteCount(String chars) + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetByteCount(String chars) { - return EncodingForwarder.GetByteCount(this, chars); + // Validate input + if (chars==null) + throw new ArgumentNullException("chars"); + Contract.EndContractBlock(); + + fixed (char* pChars = chars) + return GetByteCount(pChars, chars.Length, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetByteCount(char* chars, int count) { - return EncodingForwarder.GetByteCount(this, chars, count); + // Validate Parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + // Call it with empty encoder + return GetByteCount(chars, count, null); } - public override int GetBytes(String chars, int charIndex, int charCount, + // Parent method is safe. + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetBytes(String chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex); + if (chars == null || bytes == null) + throw new ArgumentNullException((chars == null ? "chars" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCount")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + int byteCount = bytes.Length - byteIndex; + + // Fixed doesn't like empty byte arrays + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = chars) + fixed ( byte* pBytes = bytes) + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } // Encodes a range of characters in a character array into a range of bytes @@ -92,60 +170,234 @@ public override int GetBytes(String chars, int charIndex, int charCount, // Alternatively, the GetMaxByteCount method can be used to // determine the maximum number of bytes that will be produced for a given // number of characters, regardless of the actual character values. - - public override int GetBytes(char[] chars, int charIndex, int charCount, + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex); + // Validate parameters + if (chars == null || bytes == null) + throw new ArgumentNullException((chars == null ? "chars" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If nothing to encode return 0, avoid fixed problem + if (charCount == 0) + return 0; + + // Just call pointer version + int byteCount = bytes.Length - byteIndex; + + // Fixed doesn't like empty byte arrays + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = chars) + fixed (byte* pBytes = bytes) + // Remember that byteCount is # to decode, not size of array. + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount) { - return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetBytes(chars, charCount, bytes, byteCount, null); } // Returns the number of characters produced by decoding a range of bytes // in a byte array. - - public override int GetCharCount(byte[] bytes, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetCharCount(byte[] bytes, int index, int count) { - return EncodingForwarder.GetCharCount(this, bytes, index, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (bytes.Length - index < count) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input just return 0, fixed doesn't like 0 length arrays + if (count == 0) + return 0; + + // Just call pointer version + fixed (byte* pBytes = bytes) + return GetCharCount(pBytes + index, count, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetCharCount(byte* bytes, int count) { - return EncodingForwarder.GetCharCount(this, bytes, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetCharCount(bytes, count, null); } - public override int GetChars(byte[] bytes, int byteIndex, int byteCount, + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { - return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (byteIndex < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if ( bytes.Length - byteIndex < byteCount) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (charIndex < 0 || charIndex > chars.Length) + throw new ArgumentOutOfRangeException("charIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If no input, return 0 & avoid fixed problem + if (byteCount == 0) + return 0; + + // Just call pointer version + int charCount = chars.Length - charIndex; + + // Fixed doesn't like empty char arrays + if (chars.Length == 0) + chars = new char[1]; + + fixed (byte* pBytes = bytes) + fixed (char* pChars = chars) + // Remember that charCount is # to decode, not size of array + return GetChars(pBytes + byteIndex, byteCount, + pChars + charIndex, charCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount) { - return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetChars(bytes, byteCount, chars, charCount, null); } // Returns a string containing the decoded representation of a range of // bytes in a byte array. - - public override String GetString(byte[] bytes, int byteIndex, int byteCount) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe String GetString(byte[] bytes, int byteIndex, int byteCount) { - return EncodingForwarder.GetString(this, bytes, byteIndex, byteCount); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (byteIndex < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + + if (bytes.Length - byteIndex < byteCount) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // Avoid problems with empty input buffer + if (byteCount == 0) return String.Empty; + + fixed (byte* pBytes = bytes) + return String.CreateStringFromEncoding( + pBytes + byteIndex, byteCount, this); } - - // End of overridden methods which use EncodingForwarder + + // + // End of standard methods copied from EncodingNLS.cs + // // GetByteCount // Note: We start by assuming that the output will be the same as count. Having diff --git a/src/mscorlib/src/System/Text/EncodingForwarder.cs b/src/mscorlib/src/System/Text/EncodingForwarder.cs deleted file mode 100644 index d4bcf800e373..000000000000 --- a/src/mscorlib/src/System/Text/EncodingForwarder.cs +++ /dev/null @@ -1,339 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics.Contracts; -using System.Security; - -namespace System.Text -{ - // Shared implementations for commonly overriden Encoding methods - - internal static class EncodingForwarder - { - // We normally have to duplicate a lot of code between UTF8Encoding, - // UTF7Encoding, EncodingNLS, etc. because we want to override many - // of the methods in all of those classes to just forward to the unsafe - // version. (e.g. GetBytes(char[])) - // Ideally, everything would just derive from EncodingNLS, but that's - // not exposed in the public API, and C# prohibits a public class from - // inheriting from an internal one. So, we have to override each of the - // methods in question and repeat the argument validation/logic. - - // These set of methods exist so instead of duplicating code, we can - // simply have those overriden methods call here to do the actual work. - - // NOTE: This class should ONLY be called from Encodings that override - // the internal methods which accept an Encoder/DecoderNLS. The reason - // for this is that by default, those methods just call the same overload - // except without the encoder/decoder parameter. If an overriden method - // without that parameter calls this class, which calls the overload with - // the parameter, it will call the same method again, which will eventually - // lead to a StackOverflowException. - - [SecuritySafeCritical] - public unsafe static int GetByteCount(Encoding encoding, char[] chars, int index, int count) - { - // Validate parameters - - Contract.Assert(encoding != null); // this parameter should only be affected internally, so just do a debug check here - if (chars == null) - { - throw new ArgumentNullException("chars", Environment.GetResourceString("ArgumentNull_Array")); - } - if (index < 0 || count < 0) - { - throw new ArgumentOutOfRangeException(index < 0 ? "index" : "count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); - } - if (chars.Length - index < count) - { - throw new ArgumentOutOfRangeException("chars", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); - } - Contract.EndContractBlock(); - - // If no input, return 0, avoid fixed empty array problem - if (count == 0) - return 0; - - // Just call the (internal) pointer version - fixed (char* pChars = chars) - return encoding.GetByteCount(pChars + index, count, encoder: null); - } - - [SecuritySafeCritical] - public unsafe static int GetByteCount(Encoding encoding, string s) - { - Contract.Assert(encoding != null); - if (s == null) - { - string paramName = encoding is ASCIIEncoding ? "chars" : "s"; // ASCIIEncoding calls the string chars - // UTF8Encoding does this as well, but it originally threw an ArgumentNull for "s" so don't check for that - throw new ArgumentNullException(paramName); - } - Contract.EndContractBlock(); - - // NOTE: The behavior of fixed *is* defined by - // the spec for empty strings, although not for - // null strings/empty char arrays. See - // http://stackoverflow.com/q/37757751/4077294 - // Regardless, we may still want to check - // for if (s.Length == 0) in the future - // and short-circuit as an optimization (TODO). - - fixed (char* pChars = s) - return encoding.GetByteCount(pChars, s.Length, encoder: null); - } - - [SecurityCritical] - public unsafe static int GetByteCount(Encoding encoding, char* chars, int count) - { - Contract.Assert(encoding != null); - if (chars == null) - { - throw new ArgumentNullException("chars", Environment.GetResourceString("ArgumentNull_Array")); - } - if (count < 0) - { - throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); - } - Contract.EndContractBlock(); - - // Call the internal version, with an empty encoder - return encoding.GetByteCount(chars, count, encoder: null); - } - - [SecuritySafeCritical] - public unsafe static int GetBytes(Encoding encoding, string s, int charIndex, int charCount, byte[] bytes, int byteIndex) - { - Contract.Assert(encoding != null); - if (s == null || bytes == null) - { - string stringName = encoding is ASCIIEncoding ? "chars" : "s"; // ASCIIEncoding calls the first parameter chars - throw new ArgumentNullException(s == null ? stringName : "bytes", Environment.GetResourceString("ArgumentNull_Array")); - } - if (charIndex < 0 || charCount < 0) - { - throw new ArgumentOutOfRangeException(charIndex < 0 ? "charIndex" : "charCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); - } - if (s.Length - charIndex < charCount) - { - string stringName = encoding is ASCIIEncoding ? "chars" : "s"; // ASCIIEncoding calls the first parameter chars - // Duplicate the above check since we don't want the overhead of a type check on the general path - throw new ArgumentOutOfRangeException(stringName, Environment.GetResourceString("ArgumentOutOfRange_IndexCount")); - } - if (byteIndex < 0 || byteIndex > bytes.Length) - { - throw new ArgumentOutOfRangeException("byteIndex", Environment.GetResourceString("ArgumentOutOfRange_Index")); - } - Contract.EndContractBlock(); - - int byteCount = bytes.Length - byteIndex; - - // Fixed doesn't like empty arrays - if (bytes.Length == 0) - bytes = new byte[1]; - - fixed (char* pChars = s) fixed (byte* pBytes = bytes) - { - return encoding.GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, encoder: null); - } - } - - [SecuritySafeCritical] - public unsafe static int GetBytes(Encoding encoding, char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) - { - Contract.Assert(encoding != null); - if (chars == null || bytes == null) - { - throw new ArgumentNullException(chars == null ? "chars" : "bytes", Environment.GetResourceString("ArgumentNull_Array")); - } - if (charIndex < 0 || charCount < 0) - { - throw new ArgumentOutOfRangeException(charIndex < 0 ? "charIndex" : "charCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); - } - if (chars.Length - charIndex < charCount) - { - throw new ArgumentOutOfRangeException("chars", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); - } - if (byteIndex < 0 || byteIndex > bytes.Length) - { - throw new ArgumentOutOfRangeException("byteIndex", Environment.GetResourceString("ArgumentOutOfRange_Index")); - } - Contract.EndContractBlock(); - - // If nothing to encode return 0, avoid fixed problem - if (charCount == 0) - return 0; - - // Note that this is the # of bytes to decode, - // not the size of the array - int byteCount = bytes.Length - byteIndex; - - // Fixed doesn't like 0 length arrays. - if (bytes.Length == 0) - bytes = new byte[1]; - - // Just call the (internal) pointer version - fixed (char* pChars = chars) fixed (byte* pBytes = bytes) - { - return encoding.GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, encoder: null); - } - } - - [SecurityCritical] - public unsafe static int GetBytes(Encoding encoding, char* chars, int charCount, byte* bytes, int byteCount) - { - Contract.Assert(encoding != null); - if (bytes == null || chars == null) - { - throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array")); - } - if (charCount < 0 || byteCount < 0) - { - throw new ArgumentOutOfRangeException(charCount < 0 ? "charCount" : "byteCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); - } - Contract.EndContractBlock(); - - return encoding.GetBytes(chars, charCount, bytes, byteCount, encoder: null); - } - - [SecuritySafeCritical] - public unsafe static int GetCharCount(Encoding encoding, byte[] bytes, int index, int count) - { - Contract.Assert(encoding != null); - if (bytes == null) - { - throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array")); - } - if (index < 0 || count < 0) - { - throw new ArgumentOutOfRangeException(index < 0 ? "index" : "count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); - } - if (bytes.Length - index < count) - { - throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); - } - Contract.EndContractBlock(); - - // If no input just return 0, fixed doesn't like 0 length arrays. - if (count == 0) - return 0; - - // Just call pointer version - fixed (byte* pBytes = bytes) - return encoding.GetCharCount(pBytes + index, count, decoder: null); - } - - [SecurityCritical] - public unsafe static int GetCharCount(Encoding encoding, byte* bytes, int count) - { - Contract.Assert(encoding != null); - if (bytes == null) - { - throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array")); - } - if (count < 0) - { - throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); - } - Contract.EndContractBlock(); - - return encoding.GetCharCount(bytes, count, decoder: null); - } - - [SecuritySafeCritical] - public unsafe static int GetChars(Encoding encoding, byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) - { - Contract.Assert(encoding != null); - if (bytes == null || chars == null) - { - throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array")); - } - if (byteIndex < 0 || byteCount < 0) - { - throw new ArgumentOutOfRangeException(byteIndex < 0 ? "byteIndex" : "byteCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); - } - if (bytes.Length - byteIndex < byteCount) - { - throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); - } - if (charIndex < 0 || charIndex > chars.Length) - { - throw new ArgumentOutOfRangeException("charIndex", Environment.GetResourceString("ArgumentOutOfRange_Index")); - } - Contract.EndContractBlock(); - - if (byteCount == 0) - return 0; - - // NOTE: This is the # of chars we can decode, - // not the size of the array - int charCount = chars.Length - charIndex; - - // Fixed doesn't like 0 length arrays. - if (chars.Length == 0) - chars = new char[1]; - - fixed (byte* pBytes = bytes) fixed (char* pChars = chars) - { - return encoding.GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, decoder: null); - } - } - - [SecurityCritical] - public unsafe static int GetChars(Encoding encoding, byte* bytes, int byteCount, char* chars, int charCount) - { - Contract.Assert(encoding != null); - if (bytes == null || chars == null) - { - throw new ArgumentNullException(bytes == null ? "bytes" : "chars", Environment.GetResourceString("ArgumentNull_Array")); - } - if (charCount < 0 || byteCount < 0) - { - throw new ArgumentOutOfRangeException(charCount < 0 ? "charCount" : "byteCount", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); - } - Contract.EndContractBlock(); - - return encoding.GetChars(bytes, byteCount, chars, charCount, decoder: null); - } - - [SecuritySafeCritical] - public unsafe static string GetString(Encoding encoding, byte[] bytes, int index, int count) - { - Contract.Assert(encoding != null); - if (bytes == null) - { - throw new ArgumentNullException("bytes", Environment.GetResourceString("ArgumentNull_Array")); - } - if (index < 0 || count < 0) - { - // ASCIIEncoding has different names for its parameters here (byteIndex, byteCount) - bool ascii = encoding is ASCIIEncoding; - string indexName = ascii ? "byteIndex" : "index"; - string countName = ascii ? "byteCount" : "count"; - throw new ArgumentOutOfRangeException(index < 0 ? indexName : countName, Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); - } - if (bytes.Length - index < count) - { - throw new ArgumentOutOfRangeException("bytes", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); - } - Contract.EndContractBlock(); - - // Avoid problems with empty input buffer - if (count == 0) - return string.Empty; - - // Call string.CreateStringFromEncoding here, which - // allocates a string and lets the Encoding modify - // it in place. This way, we don't have to allocate - // an intermediary char[] to decode into and then - // call the string constructor; instead we decode - // directly into the string. - - fixed (byte* pBytes = bytes) - { - return string.CreateStringFromEncoding(pBytes + index, count, encoding); - } - } - } -} diff --git a/src/mscorlib/src/System/Text/EncodingNLS.cs b/src/mscorlib/src/System/Text/EncodingNLS.cs index d670d6daa7a7..73aba3df9533 100644 --- a/src/mscorlib/src/System/Text/EncodingNLS.cs +++ b/src/mscorlib/src/System/Text/EncodingNLS.cs @@ -14,7 +14,18 @@ namespace System.Text using Win32Native = Microsoft.Win32.Win32Native; // This class overrides Encoding with the things we need for our NLS Encodings - + // + // All of the GetBytes/Chars GetByte/CharCount methods are just wrappers for the pointer + // plus decoder/encoder method that is our real workhorse. Note that this is an internal + // class, so our public classes cannot derive from this class. Because of this, all of the + // GetBytes/Chars GetByte/CharCount wrapper methods are duplicated in all of our public + // encodings, which currently include: + // + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, & UnicodeEncoding + // + // So if you change the wrappers in this class, you must change the wrappers in the other classes + // as well because they should have the same behavior. + // [System.Runtime.InteropServices.ComVisible(true)] [Serializable] internal abstract class EncodingNLS : Encoding @@ -23,43 +34,110 @@ protected EncodingNLS(int codePage) : base(codePage) { } - // NOTE: Many methods in this class forward to EncodingForwarder for - // validating arguments/wrapping the unsafe methods in this class - // which do the actual work. That class contains - // shared logic for doing this which is used by - // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding, - // UTF7Encoding, and UTF8Encoding. - // The reason the code is separated out into a static class, rather - // than a base class which overrides all of these methods for us - // (which is what EncodingNLS is for internal Encodings) is because - // that's really more of an implementation detail so it's internal. - // At the same time, C# doesn't allow a public class subclassing an - // internal/private one, so we end up having to re-override these - // methods in all of the public Encodings + EncodingNLS. - // Returns the number of bytes required to encode a range of characters in // a character array. - - public override int GetByteCount(char[] chars, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + [System.Security.SecuritySafeCritical] // overrides public transparent member + public override unsafe int GetByteCount(char[] chars, int index, int count) { - return EncodingForwarder.GetByteCount(this, chars, index, count); + // Validate input parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - index < count) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input, return 0, avoid fixed empty array problem + if (count == 0) + return 0; + + // Just call the pointer version + fixed (char* pChars = chars) + return GetByteCount(pChars + index, count, null); } - - public override int GetByteCount(String s) + + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + [System.Security.SecuritySafeCritical] // overrides public transparent member + public override unsafe int GetByteCount(String s) { - return EncodingForwarder.GetByteCount(this, s); - } + // Validate input + if (s==null) + throw new ArgumentNullException("s"); + Contract.EndContractBlock(); + fixed (char* pChars = s) + return GetByteCount(pChars, s.Length, null); + } + + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding [System.Security.SecurityCritical] // auto-generated public override unsafe int GetByteCount(char* chars, int count) { - return EncodingForwarder.GetByteCount(this, chars, count); + // Validate Parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + // Call it with empty encoder + return GetByteCount(chars, count, null); } - public override int GetBytes(String s, int charIndex, int charCount, + // Parent method is safe. + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecuritySafeCritical] // overrides public transparent member + public override unsafe int GetBytes(String s, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, s, charIndex, charCount, bytes, byteIndex); + if (s == null || bytes == null) + throw new ArgumentNullException((s == null ? "s" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (s.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("s", + Environment.GetResourceString("ArgumentOutOfRange_IndexCount")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + int byteCount = bytes.Length - byteIndex; + + // Fixed doesn't like empty arrays + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = s) + fixed ( byte* pBytes = bytes) + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } // Encodes a range of characters in a character array into a range of bytes @@ -70,51 +148,215 @@ public override int GetBytes(String s, int charIndex, int charCount, // Alternatively, the GetMaxByteCount method can be used to // determine the maximum number of bytes that will be produced for a given // number of characters, regardless of the actual character values. - - public override int GetBytes(char[] chars, int charIndex, int charCount, + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + [System.Security.SecuritySafeCritical] // overrides public transparent member + public override unsafe int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex); + // Validate parameters + if (chars == null || bytes == null) + throw new ArgumentNullException((chars == null ? "chars" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If nothing to encode return 0, avoid fixed problem + if (charCount == 0) + return 0; + + // Just call pointer version + int byteCount = bytes.Length - byteIndex; + + // Fixed doesn't like empty arrays + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = chars) + fixed (byte* pBytes = bytes) + // Remember that byteCount is # to decode, not size of array. + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding [System.Security.SecurityCritical] // auto-generated public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount) { - return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetBytes(chars, charCount, bytes, byteCount, null); } // Returns the number of characters produced by decoding a range of bytes // in a byte array. - - public override int GetCharCount(byte[] bytes, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + [System.Security.SecuritySafeCritical] // overrides public transparent member + public override unsafe int GetCharCount(byte[] bytes, int index, int count) { - return EncodingForwarder.GetCharCount(this, bytes, index, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (bytes.Length - index < count) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input just return 0, fixed doesn't like 0 length arrays + if (count == 0) + return 0; + + // Just call pointer version + fixed (byte* pBytes = bytes) + return GetCharCount(pBytes + index, count, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding [System.Security.SecurityCritical] // auto-generated public override unsafe int GetCharCount(byte* bytes, int count) { - return EncodingForwarder.GetCharCount(this, bytes, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetCharCount(bytes, count, null); } - public override int GetChars(byte[] bytes, int byteIndex, int byteCount, + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + [System.Security.SecuritySafeCritical] // overrides public transparent member + public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { - return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (byteIndex < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if ( bytes.Length - byteIndex < byteCount) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (charIndex < 0 || charIndex > chars.Length) + throw new ArgumentOutOfRangeException("charIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If no input, return 0 & avoid fixed problem + if (byteCount == 0) + return 0; + + // Just call pointer version + int charCount = chars.Length - charIndex; + + // Fixed doesn't like empty arrays + if (chars.Length == 0) + chars = new char[1]; + + fixed (byte* pBytes = bytes) + fixed (char* pChars = chars) + // Remember that charCount is # to decode, not size of array + return GetChars(pBytes + byteIndex, byteCount, + pChars + charIndex, charCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding [System.Security.SecurityCritical] // auto-generated public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount) { - return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetChars(bytes, byteCount, chars, charCount, null); } // Returns a string containing the decoded representation of a range of // bytes in a byte array. - - public override String GetString(byte[] bytes, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + [System.Security.SecuritySafeCritical] // overrides public transparent member + public override unsafe String GetString(byte[] bytes, int index, int count) { - return EncodingForwarder.GetString(this, bytes, index, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (bytes.Length - index < count) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // Avoid problems with empty input buffer + if (count == 0) return String.Empty; + + fixed (byte* pBytes = bytes) + return String.CreateStringFromEncoding( + pBytes + index, count, this); } public override Decoder GetDecoder() diff --git a/src/mscorlib/src/System/Text/UTF32Encoding.cs b/src/mscorlib/src/System/Text/UTF32Encoding.cs index 0bdbaefbf29e..fcf30b4d937c 100644 --- a/src/mscorlib/src/System/Text/UTF32Encoding.cs +++ b/src/mscorlib/src/System/Text/UTF32Encoding.cs @@ -82,44 +82,123 @@ internal override void SetDefaultFallbacks() } } - // NOTE: Many methods in this class forward to EncodingForwarder for - // validating arguments/wrapping the unsafe methods in this class - // which do the actual work. That class contains - // shared logic for doing this which is used by - // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding, - // UTF7Encoding, and UTF8Encoding. - // The reason the code is separated out into a static class, rather - // than a base class which overrides all of these methods for us - // (which is what EncodingNLS is for internal Encodings) is because - // that's really more of an implementation detail so it's internal. - // At the same time, C# doesn't allow a public class subclassing an - // internal/private one, so we end up having to re-override these - // methods in all of the public Encodings + EncodingNLS. + + // + // The following methods are copied from EncodingNLS.cs. + // Unfortunately EncodingNLS.cs is internal and we're public, so we have to reimpliment them here. + // These should be kept in sync for the following classes: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // // Returns the number of bytes required to encode a range of characters in // a character array. - - public override int GetByteCount(char[] chars, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetByteCount(char[] chars, int index, int count) { - return EncodingForwarder.GetByteCount(this, chars, index, count); + // Validate input parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - index < count) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input, return 0, avoid fixed empty array problem + if (count == 0) + return 0; + + // Just call the pointer version + fixed (char* pChars = chars) + return GetByteCount(pChars + index, count, null); } - public override int GetByteCount(String s) + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetByteCount(String s) { - return EncodingForwarder.GetByteCount(this, s); + // Validate input + if (s==null) + throw new ArgumentNullException("s"); + Contract.EndContractBlock(); + + fixed (char* pChars = s) + return GetByteCount(pChars, s.Length, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] public override unsafe int GetByteCount(char* chars, int count) { - return EncodingForwarder.GetByteCount(this, chars, count); + // Validate Parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + // Call it with empty encoder + return GetByteCount(chars, count, null); } - public override int GetBytes(String s, int charIndex, int charCount, + // Parent method is safe. + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetBytes(String s, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, s, charIndex, charCount, bytes, byteIndex); + if (s == null || bytes == null) + throw new ArgumentNullException((s == null ? "s" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (s.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("s", + Environment.GetResourceString("ArgumentOutOfRange_IndexCount")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + int byteCount = bytes.Length - byteIndex; + + // Fix our input array if 0 length because fixed doesn't like 0 length arrays + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = s) + fixed ( byte* pBytes = bytes) + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } // Encodes a range of characters in a character array into a range of bytes @@ -130,57 +209,230 @@ public override int GetBytes(String s, int charIndex, int charCount, // Alternatively, the GetMaxByteCount method can be used to // determine the maximum number of bytes that will be produced for a given // number of characters, regardless of the actual character values. - - public override int GetBytes(char[] chars, int charIndex, int charCount, + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex); + // Validate parameters + if (chars == null || bytes == null) + throw new ArgumentNullException((chars == null ? "chars" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If nothing to encode return 0, avoid fixed problem + if (charCount == 0) + return 0; + + // Just call pointer version + int byteCount = bytes.Length - byteIndex; + + // Fix our input array if 0 length because fixed doesn't like 0 length arrays + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = chars) + fixed (byte* pBytes = bytes) + // Remember that byteCount is # to decode, not size of array. + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount) { - return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetBytes(chars, charCount, bytes, byteCount, null); } // Returns the number of characters produced by decoding a range of bytes // in a byte array. - - public override int GetCharCount(byte[] bytes, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetCharCount(byte[] bytes, int index, int count) { - return EncodingForwarder.GetCharCount(this, bytes, index, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (bytes.Length - index < count) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input just return 0, fixed doesn't like 0 length arrays. + if (count == 0) + return 0; + + // Just call pointer version + fixed (byte* pBytes = bytes) + return GetCharCount(pBytes + index, count, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] public override unsafe int GetCharCount(byte* bytes, int count) { - return EncodingForwarder.GetCharCount(this, bytes, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetCharCount(bytes, count, null); } - public override int GetChars(byte[] bytes, int byteIndex, int byteCount, + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { - return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (byteIndex < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if ( bytes.Length - byteIndex < byteCount) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (charIndex < 0 || charIndex > chars.Length) + throw new ArgumentOutOfRangeException("charIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If no input, return 0 & avoid fixed problem + if (byteCount == 0) + return 0; + + // Just call pointer version + int charCount = chars.Length - charIndex; + + // Fix our input array if 0 length because fixed doesn't like 0 length arrays + if (chars.Length == 0) + chars = new char[1]; + + fixed (byte* pBytes = bytes) + fixed (char* pChars = chars) + // Remember that charCount is # to decode, not size of array + return GetChars(pBytes + byteIndex, byteCount, + pChars + charIndex, charCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount) { - return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetChars(bytes, byteCount, chars, charCount, null); } // Returns a string containing the decoded representation of a range of // bytes in a byte array. - - public override String GetString(byte[] bytes, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe String GetString(byte[] bytes, int index, int count) { - return EncodingForwarder.GetString(this, bytes, index, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (bytes.Length - index < count) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // Avoid problems with empty input buffer + if (count == 0) return String.Empty; + + fixed (byte* pBytes = bytes) + return String.CreateStringFromEncoding( + pBytes + index, count, this); } - - // End of overridden methods which use EncodingForwarder + + // + // End of standard methods copied from EncodingNLS.cs + // [System.Security.SecurityCritical] // auto-generated internal override unsafe int GetByteCount(char *chars, int count, EncoderNLS encoder) diff --git a/src/mscorlib/src/System/Text/UTF7Encoding.cs b/src/mscorlib/src/System/Text/UTF7Encoding.cs index 654fb8b80fb4..63e07feb7d8e 100644 --- a/src/mscorlib/src/System/Text/UTF7Encoding.cs +++ b/src/mscorlib/src/System/Text/UTF7Encoding.cs @@ -147,47 +147,125 @@ public override int GetHashCode() return this.CodePage + this.EncoderFallback.GetHashCode() + this.DecoderFallback.GetHashCode(); } - // NOTE: Many methods in this class forward to EncodingForwarder for - // validating arguments/wrapping the unsafe methods in this class - // which do the actual work. That class contains - // shared logic for doing this which is used by - // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding, - // UTF7Encoding, and UTF8Encoding. - // The reason the code is separated out into a static class, rather - // than a base class which overrides all of these methods for us - // (which is what EncodingNLS is for internal Encodings) is because - // that's really more of an implementation detail so it's internal. - // At the same time, C# doesn't allow a public class subclassing an - // internal/private one, so we end up having to re-override these - // methods in all of the public Encodings + EncodingNLS. + // + // The following methods are copied from EncodingNLS.cs. + // Unfortunately EncodingNLS.cs is internal and we're public, so we have to reimpliment them here. + // These should be kept in sync for the following classes: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // // Returns the number of bytes required to encode a range of characters in // a character array. - - public override int GetByteCount(char[] chars, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetByteCount(char[] chars, int index, int count) { - return EncodingForwarder.GetByteCount(this, chars, index, count); + // Validate input parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - index < count) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input, return 0, avoid fixed empty array problem + if (count == 0) + return 0; + + // Just call the pointer version + fixed (char* pChars = chars) + return GetByteCount(pChars + index, count, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated [System.Runtime.InteropServices.ComVisible(false)] - public override int GetByteCount(String s) + public override unsafe int GetByteCount(String s) { - return EncodingForwarder.GetByteCount(this, s); + // Validate input + if (s==null) + throw new ArgumentNullException("s"); + Contract.EndContractBlock(); + + fixed (char* pChars = s) + return GetByteCount(pChars, s.Length, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetByteCount(char* chars, int count) { - return EncodingForwarder.GetByteCount(this, chars, count); + // Validate Parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + // Call it with empty encoder + return GetByteCount(chars, count, null); } + // Parent method is safe. + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + + [System.Security.SecuritySafeCritical] // auto-generated [System.Runtime.InteropServices.ComVisible(false)] - public override int GetBytes(String s, int charIndex, int charCount, + public override unsafe int GetBytes(String s, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, s, charIndex, charCount, bytes, byteIndex); + if (s == null || bytes == null) + throw new ArgumentNullException((s == null ? "s" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (s.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("s", + Environment.GetResourceString("ArgumentOutOfRange_IndexCount")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + int byteCount = bytes.Length - byteIndex; + + // Fixed doesn't like empty arrays + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = s) + fixed ( byte* pBytes = bytes) + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } // Encodes a range of characters in a character array into a range of bytes @@ -198,61 +276,234 @@ public override int GetBytes(String s, int charIndex, int charCount, // Alternatively, the GetMaxByteCount method can be used to // determine the maximum number of bytes that will be produced for a given // number of characters, regardless of the actual character values. - - public override int GetBytes(char[] chars, int charIndex, int charCount, + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex); + // Validate parameters + if (chars == null || bytes == null) + throw new ArgumentNullException((chars == null ? "chars" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If nothing to encode return 0, avoid fixed problem + if (charCount == 0) + return 0; + + // Just call pointer version + int byteCount = bytes.Length - byteIndex; + + // Fixed doesn't like empty arrays + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = chars) + fixed (byte* pBytes = bytes) + // Remember that byteCount is # to decode, not size of array. + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount) { - return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetBytes(chars, charCount, bytes, byteCount, null); } // Returns the number of characters produced by decoding a range of bytes // in a byte array. - - public override int GetCharCount(byte[] bytes, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetCharCount(byte[] bytes, int index, int count) { - return EncodingForwarder.GetCharCount(this, bytes, index, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (bytes.Length - index < count) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input just return 0, fixed doesn't like 0 length arrays. + if (count == 0) + return 0; + + // Just call pointer version + fixed (byte* pBytes = bytes) + return GetCharCount(pBytes + index, count, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetCharCount(byte* bytes, int count) { - return EncodingForwarder.GetCharCount(this, bytes, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetCharCount(bytes, count, null); } - public override int GetChars(byte[] bytes, int byteIndex, int byteCount, + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { - return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (byteIndex < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if ( bytes.Length - byteIndex < byteCount) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (charIndex < 0 || charIndex > chars.Length) + throw new ArgumentOutOfRangeException("charIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If no input, return 0 & avoid fixed problem + if (byteCount == 0) + return 0; + + // Just call pointer version + int charCount = chars.Length - charIndex; + + // Fixed doesn't like empty arrays + if (chars.Length == 0) + chars = new char[1]; + + fixed (byte* pBytes = bytes) + fixed (char* pChars = chars) + // Remember that charCount is # to decode, not size of array + return GetChars(pBytes + byteIndex, byteCount, + pChars + charIndex, charCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount) { - return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetChars(bytes, byteCount, chars, charCount, null); } // Returns a string containing the decoded representation of a range of // bytes in a byte array. + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + [System.Security.SecuritySafeCritical] // auto-generated [System.Runtime.InteropServices.ComVisible(false)] - public override String GetString(byte[] bytes, int index, int count) + public override unsafe String GetString(byte[] bytes, int index, int count) { - return EncodingForwarder.GetString(this, bytes, index, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (bytes.Length - index < count) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // Avoid problems with empty input buffer + if (count == 0) return String.Empty; + + fixed (byte* pBytes = bytes) + return String.CreateStringFromEncoding( + pBytes + index, count, this); } - - // End of overridden methods which use EncodingForwarder + + // + // End of standard methods copied from EncodingNLS.cs + // [System.Security.SecurityCritical] // auto-generated internal override unsafe int GetByteCount(char* chars, int count, EncoderNLS baseEncoder) diff --git a/src/mscorlib/src/System/Text/UTF8Encoding.cs b/src/mscorlib/src/System/Text/UTF8Encoding.cs index a527de7b61fb..f6a7909ccc7c 100644 --- a/src/mscorlib/src/System/Text/UTF8Encoding.cs +++ b/src/mscorlib/src/System/Text/UTF8Encoding.cs @@ -102,45 +102,128 @@ internal override void SetDefaultFallbacks() } } - // NOTE: Many methods in this class forward to EncodingForwarder for - // validating arguments/wrapping the unsafe methods in this class - // which do the actual work. That class contains - // shared logic for doing this which is used by - // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding, - // UTF7Encoding, and UTF8Encoding. - // The reason the code is separated out into a static class, rather - // than a base class which overrides all of these methods for us - // (which is what EncodingNLS is for internal Encodings) is because - // that's really more of an implementation detail so it's internal. - // At the same time, C# doesn't allow a public class subclassing an - // internal/private one, so we end up having to re-override these - // methods in all of the public Encodings + EncodingNLS. + + // + // WARNING: GetByteCount(string chars) + // WARNING: has different variable names than EncodingNLS.cs, so this can't just be cut & pasted, + // WARNING: otherwise it'll break VB's way of declaring these. + // + // The following methods are copied from EncodingNLS.cs. + // Unfortunately EncodingNLS.cs is internal and we're public, so we have to reimpliment them here. + // These should be kept in sync for the following classes: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // // Returns the number of bytes required to encode a range of characters in // a character array. + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe - public override int GetByteCount(char[] chars, int index, int count) + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetByteCount(char[] chars, int index, int count) { - return EncodingForwarder.GetByteCount(this, chars, index, count); + // Validate input parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - index < count) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input, return 0, avoid fixed empty array problem + if (count == 0) + return 0; + + // Just call the pointer version + fixed (char* pChars = chars) + return GetByteCount(pChars + index, count, null); } - public override int GetByteCount(String chars) + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetByteCount(String chars) { - return EncodingForwarder.GetByteCount(this, chars); + // Validate input + if (chars==null) + throw new ArgumentNullException("s"); + Contract.EndContractBlock(); + + fixed (char* pChars = chars) + return GetByteCount(pChars, chars.Length, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetByteCount(char* chars, int count) { - return EncodingForwarder.GetByteCount(this, chars, count); + // Validate Parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + // Call it with empty encoder + return GetByteCount(chars, count, null); } - public override int GetBytes(String s, int charIndex, int charCount, + // Parent method is safe. + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetBytes(String s, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, s, charIndex, charCount, bytes, byteIndex); + if (s == null || bytes == null) + throw new ArgumentNullException((s == null ? "s" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (s.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("s", + Environment.GetResourceString("ArgumentOutOfRange_IndexCount")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + int byteCount = bytes.Length - byteIndex; + + // Fixed doesn't like 0 length arrays. + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = s) + fixed ( byte* pBytes = bytes) + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } // Encodes a range of characters in a character array into a range of bytes @@ -151,61 +234,234 @@ public override int GetBytes(String s, int charIndex, int charCount, // Alternatively, the GetMaxByteCount method can be used to // determine the maximum number of bytes that will be produced for a given // number of characters, regardless of the actual character values. + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe - public override int GetBytes(char[] chars, int charIndex, int charCount, + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex); + // Validate parameters + if (chars == null || bytes == null) + throw new ArgumentNullException((chars == null ? "chars" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If nothing to encode return 0, avoid fixed problem + if (charCount == 0) + return 0; + + // Just call pointer version + int byteCount = bytes.Length - byteIndex; + + // Fixed doesn't like 0 length arrays. + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = chars) + fixed (byte* pBytes = bytes) + // Remember that byteCount is # to decode, not size of array. + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount) { - return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetBytes(chars, charCount, bytes, byteCount, null); } // Returns the number of characters produced by decoding a range of bytes // in a byte array. + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe - public override int GetCharCount(byte[] bytes, int index, int count) + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetCharCount(byte[] bytes, int index, int count) { - return EncodingForwarder.GetCharCount(this, bytes, index, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (bytes.Length - index < count) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input just return 0, fixed doesn't like 0 length arrays. + if (count == 0) + return 0; + + // Just call pointer version + fixed (byte* pBytes = bytes) + return GetCharCount(pBytes + index, count, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetCharCount(byte* bytes, int count) { - return EncodingForwarder.GetCharCount(this, bytes, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetCharCount(bytes, count, null); } - public override int GetChars(byte[] bytes, int byteIndex, int byteCount, + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { - return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (byteIndex < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if ( bytes.Length - byteIndex < byteCount) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (charIndex < 0 || charIndex > chars.Length) + throw new ArgumentOutOfRangeException("charIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If no input, return 0 & avoid fixed problem + if (byteCount == 0) + return 0; + + // Just call pointer version + int charCount = chars.Length - charIndex; + + // Fixed doesn't like 0 length arrays. + if (chars.Length == 0) + chars = new char[1]; + + fixed (byte* pBytes = bytes) + fixed (char* pChars = chars) + // Remember that charCount is # to decode, not size of array + return GetChars(pBytes + byteIndex, byteCount, + pChars + charIndex, charCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount) { - return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetChars(bytes, byteCount, chars, charCount, null); } // Returns a string containing the decoded representation of a range of // bytes in a byte array. + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + [System.Security.SecuritySafeCritical] // auto-generated [System.Runtime.InteropServices.ComVisible(false)] - public override String GetString(byte[] bytes, int index, int count) + public override unsafe String GetString(byte[] bytes, int index, int count) { - return EncodingForwarder.GetString(this, bytes, index, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (bytes.Length - index < count) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // Avoid problems with empty input buffer + if (count == 0) return String.Empty; + + fixed (byte* pBytes = bytes) + return String.CreateStringFromEncoding( + pBytes + index, count, this); } - - // End of overridden methods which use EncodingForwarder + + // + // End of standard methods copied from EncodingNLS.cs + // // To simplify maintenance, the structure of GetByteCount and GetBytes should be // kept the same as much as possible diff --git a/src/mscorlib/src/System/Text/UnicodeEncoding.cs b/src/mscorlib/src/System/Text/UnicodeEncoding.cs index 41d4f3b5ea2a..7465d200223a 100644 --- a/src/mscorlib/src/System/Text/UnicodeEncoding.cs +++ b/src/mscorlib/src/System/Text/UnicodeEncoding.cs @@ -82,45 +82,123 @@ internal override void SetDefaultFallbacks() } } - // NOTE: Many methods in this class forward to EncodingForwarder for - // validating arguments/wrapping the unsafe methods in this class - // which do the actual work. That class contains - // shared logic for doing this which is used by - // ASCIIEncoding, EncodingNLS, UnicodeEncoding, UTF32Encoding, - // UTF7Encoding, and UTF8Encoding. - // The reason the code is separated out into a static class, rather - // than a base class which overrides all of these methods for us - // (which is what EncodingNLS is for internal Encodings) is because - // that's really more of an implementation detail so it's internal. - // At the same time, C# doesn't allow a public class subclassing an - // internal/private one, so we end up having to re-override these - // methods in all of the public Encodings + EncodingNLS. + // + // The following methods are copied from EncodingNLS.cs. + // Unfortunately EncodingNLS.cs is internal and we're public, so we have to reimpliment them here. + // These should be kept in sync for the following classes: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // // Returns the number of bytes required to encode a range of characters in // a character array. - - public override int GetByteCount(char[] chars, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetByteCount(char[] chars, int index, int count) { - return EncodingForwarder.GetByteCount(this, chars, index, count); + // Validate input parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - index < count) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input, return 0, avoid fixed empty array problem + if (count == 0) + return 0; + + // Just call the pointer version + fixed (char* pChars = chars) + return GetByteCount(pChars + index, count, null); } - public override int GetByteCount(String s) + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetByteCount(String s) { - return EncodingForwarder.GetByteCount(this, s); + // Validate input + if (s==null) + throw new ArgumentNullException("s"); + Contract.EndContractBlock(); + + fixed (char* pChars = s) + return GetByteCount(pChars, s.Length, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetByteCount(char* chars, int count) { - return EncodingForwarder.GetByteCount(this, chars, count); + // Validate Parameters + if (chars == null) + throw new ArgumentNullException("chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + // Call it with empty encoder + return GetByteCount(chars, count, null); } - public override int GetBytes(String s, int charIndex, int charCount, + // Parent method is safe. + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetBytes(String s, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, s, charIndex, charCount, bytes, byteIndex); + if (s == null || bytes == null) + throw new ArgumentNullException((s == null ? "s" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (s.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("s", + Environment.GetResourceString("ArgumentOutOfRange_IndexCount")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + int byteCount = bytes.Length - byteIndex; + + // Fixed doesn't like 0 length arrays. + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = s) + fixed ( byte* pBytes = bytes) + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } // Encodes a range of characters in a character array into a range of bytes @@ -131,61 +209,234 @@ public override int GetBytes(String s, int charIndex, int charCount, // Alternatively, the GetMaxByteCount method can be used to // determine the maximum number of bytes that will be produced for a given // number of characters, regardless of the actual character values. - - public override int GetBytes(char[] chars, int charIndex, int charCount, + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { - return EncodingForwarder.GetBytes(this, chars, charIndex, charCount, bytes, byteIndex); + // Validate parameters + if (chars == null || bytes == null) + throw new ArgumentNullException((chars == null ? "chars" : "bytes"), + Environment.GetResourceString("ArgumentNull_Array")); + + if (charIndex < 0 || charCount < 0) + throw new ArgumentOutOfRangeException((charIndex<0 ? "charIndex" : "charCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (chars.Length - charIndex < charCount) + throw new ArgumentOutOfRangeException("chars", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (byteIndex < 0 || byteIndex > bytes.Length) + throw new ArgumentOutOfRangeException("byteIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If nothing to encode return 0, avoid fixed problem + if (charCount == 0) + return 0; + + // Just call pointer version + int byteCount = bytes.Length - byteIndex; + + // Fixed doesn't like 0 length arrays. + if (bytes.Length == 0) + bytes = new byte[1]; + + fixed (char* pChars = chars) + fixed (byte* pBytes = bytes) + // Remember that byteCount is # to decode, not size of array. + return GetBytes(pChars + charIndex, charCount, + pBytes + byteIndex, byteCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount) { - return EncodingForwarder.GetBytes(this, chars, charCount, bytes, byteCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetBytes(chars, charCount, bytes, byteCount, null); } // Returns the number of characters produced by decoding a range of bytes // in a byte array. - - public override int GetCharCount(byte[] bytes, int index, int count) + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetCharCount(byte[] bytes, int index, int count) { - return EncodingForwarder.GetCharCount(this, bytes, index, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (bytes.Length - index < count) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // If no input just return 0, fixed doesn't like 0 length arrays + if (count == 0) + return 0; + + // Just call pointer version + fixed (byte* pBytes = bytes) + return GetCharCount(pBytes + index, count, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public override unsafe int GetCharCount(byte* bytes, int count) { - return EncodingForwarder.GetCharCount(this, bytes, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (count < 0) + throw new ArgumentOutOfRangeException("count", + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetCharCount(bytes, count, null); } - public override int GetChars(byte[] bytes, int byteIndex, int byteCount, + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + + [System.Security.SecuritySafeCritical] // auto-generated + public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { - return EncodingForwarder.GetChars(this, bytes, byteIndex, byteCount, chars, charIndex); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (byteIndex < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((byteIndex<0 ? "byteIndex" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if ( bytes.Length - byteIndex < byteCount) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + + if (charIndex < 0 || charIndex > chars.Length) + throw new ArgumentOutOfRangeException("charIndex", + Environment.GetResourceString("ArgumentOutOfRange_Index")); + Contract.EndContractBlock(); + + // If no input, return 0 & avoid fixed problem + if (byteCount == 0) + return 0; + + // Just call pointer version + int charCount = chars.Length - charIndex; + + // Fixed doesn't like 0 length arrays. + if (chars.Length == 0) + chars = new char[1]; + + fixed (byte* pBytes = bytes) + fixed (char* pChars = chars) + // Remember that charCount is # to decode, not size of array + return GetChars(pBytes + byteIndex, byteCount, + pChars + charIndex, charCount, null); } + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + [System.Security.SecurityCritical] // auto-generated [CLSCompliant(false)] [System.Runtime.InteropServices.ComVisible(false)] public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount) { - return EncodingForwarder.GetChars(this, bytes, byteCount, chars, charCount); + // Validate Parameters + if (bytes == null || chars == null) + throw new ArgumentNullException(bytes == null ? "bytes" : "chars", + Environment.GetResourceString("ArgumentNull_Array")); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException((charCount<0 ? "charCount" : "byteCount"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + Contract.EndContractBlock(); + + return GetChars(bytes, byteCount, chars, charCount, null); } // Returns a string containing the decoded representation of a range of // bytes in a byte array. + // + // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) + // So if you fix this, fix the others. Currently those include: + // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding + // parent method is safe + [System.Security.SecuritySafeCritical] // auto-generated [System.Runtime.InteropServices.ComVisible(false)] - public override String GetString(byte[] bytes, int index, int count) + public override unsafe String GetString(byte[] bytes, int index, int count) { - return EncodingForwarder.GetString(this, bytes, index, count); + // Validate Parameters + if (bytes == null) + throw new ArgumentNullException("bytes", + Environment.GetResourceString("ArgumentNull_Array")); + + if (index < 0 || count < 0) + throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), + Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); + + if (bytes.Length - index < count) + throw new ArgumentOutOfRangeException("bytes", + Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer")); + Contract.EndContractBlock(); + + // Avoid problems with empty input buffer + if (count == 0) return String.Empty; + + fixed (byte* pBytes = bytes) + return String.CreateStringFromEncoding( + pBytes + index, count, this); } - - // End of overridden methods which use EncodingForwarder + + // + // End of standard methods copied from EncodingNLS.cs + // [System.Security.SecurityCritical] // auto-generated internal override unsafe int GetByteCount(char* chars, int count, EncoderNLS encoder)