1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections; 7 using System.Globalization; 8 using System.Runtime.InteropServices; 9 using System.Threading; 10 11 namespace System.Text 12 { 13 // This class overrides Encoding with the things we need for our NLS Encodings 14 // 15 // All of the GetBytes/Chars GetByte/CharCount methods are just wrappers for the pointer 16 // plus decoder/encoder method that is our real workhorse. Note that this is an internal 17 // class, so our public classes cannot derive from this class. Because of this, all of the 18 // GetBytes/Chars GetByte/CharCount wrapper methods are duplicated in all of our public 19 // encodings, which currently include: 20 // 21 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, & UnicodeEncoding 22 // 23 // So if you change the wrappers in this class, you must change the wrappers in the other classes 24 // as well because they should have the same behavior. 25 26 internal abstract class EncodingNLS : Encoding 27 { EncodingNLS(int codePage)28 protected EncodingNLS(int codePage) : base(codePage) 29 { 30 } 31 32 // Returns the number of bytes required to encode a range of characters in 33 // a character array. 34 // 35 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) 36 // So if you fix this, fix the others. Currently those include: 37 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding 38 // parent method is safe GetByteCount(char[] chars, int index, int count)39 public override unsafe int GetByteCount(char[] chars, int index, int count) 40 { 41 // Validate input parameters 42 if (chars == null) 43 throw new ArgumentNullException("chars", SR.ArgumentNull_Array); 44 45 if (index < 0 || count < 0) 46 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum); 47 48 if (chars.Length - index < count) 49 throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCountBuffer); 50 51 // If no input, return 0, avoid fixed empty array problem 52 if (count == 0) 53 return 0; 54 55 // Just call the pointer version 56 fixed (char* pChars = chars) 57 return GetByteCount(pChars + index, count, null); 58 } 59 60 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) 61 // So if you fix this, fix the others. Currently those include: 62 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding 63 // parent method is safe GetByteCount(String s)64 public override unsafe int GetByteCount(String s) 65 { 66 // Validate input 67 if (s==null) 68 throw new ArgumentNullException("s"); 69 70 fixed (char* pChars = s) 71 return GetByteCount(pChars, s.Length, null); 72 } 73 74 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) 75 // So if you fix this, fix the others. Currently those include: 76 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding GetByteCount(char* chars, int count)77 public override unsafe int GetByteCount(char* chars, int count) 78 { 79 // Validate Parameters 80 if (chars == null) 81 throw new ArgumentNullException("chars", SR.ArgumentNull_Array); 82 83 if (count < 0) 84 throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum); 85 86 // Call it with empty encoder 87 return GetByteCount(chars, count, null); 88 } 89 90 // Parent method is safe. 91 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) 92 // So if you fix this, fix the others. Currently those include: 93 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding GetBytes(String s, int charIndex, int charCount, byte[] bytes, int byteIndex)94 public override unsafe int GetBytes(String s, int charIndex, int charCount, 95 byte[] bytes, int byteIndex) 96 { 97 if (s == null || bytes == null) 98 throw new ArgumentNullException((s == null ? "s" : "bytes"), SR.ArgumentNull_Array); 99 100 if (charIndex < 0 || charCount < 0) 101 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), SR.ArgumentOutOfRange_NeedNonNegNum); 102 103 if (s.Length - charIndex < charCount) 104 throw new ArgumentOutOfRangeException("s", SR.ArgumentOutOfRange_IndexCount); 105 106 if (byteIndex < 0 || byteIndex > bytes.Length) 107 throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index); 108 109 int byteCount = bytes.Length - byteIndex; 110 111 fixed (char* pChars = s) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span<byte>)bytes)) 112 return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); 113 } 114 115 // Encodes a range of characters in a character array into a range of bytes 116 // in a byte array. An exception occurs if the byte array is not large 117 // enough to hold the complete encoding of the characters. The 118 // GetByteCount method can be used to determine the exact number of 119 // bytes that will be produced for a given range of characters. 120 // Alternatively, the GetMaxByteCount method can be used to 121 // determine the maximum number of bytes that will be produced for a given 122 // number of characters, regardless of the actual character values. 123 // 124 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) 125 // So if you fix this, fix the others. Currently those include: 126 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding 127 // parent method is safe GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)128 public override unsafe int GetBytes(char[] chars, int charIndex, int charCount, 129 byte[] bytes, int byteIndex) 130 { 131 // Validate parameters 132 if (chars == null || bytes == null) 133 throw new ArgumentNullException((chars == null ? "chars" : "bytes"), SR.ArgumentNull_Array); 134 135 if (charIndex < 0 || charCount < 0) 136 throw new ArgumentOutOfRangeException((charIndex < 0 ? "charIndex" : "charCount"), SR.ArgumentOutOfRange_NeedNonNegNum); 137 138 if (chars.Length - charIndex < charCount) 139 throw new ArgumentOutOfRangeException("chars", SR.ArgumentOutOfRange_IndexCountBuffer); 140 141 if (byteIndex < 0 || byteIndex > bytes.Length) 142 throw new ArgumentOutOfRangeException("byteIndex", SR.ArgumentOutOfRange_Index); 143 144 // If nothing to encode return 0, avoid fixed problem 145 if (charCount == 0) 146 return 0; 147 148 // Just call pointer version 149 int byteCount = bytes.Length - byteIndex; 150 151 fixed (char* pChars = chars) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span<byte>)bytes)) 152 // Remember that byteCount is # to decode, not size of array. 153 return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null); 154 } 155 156 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) 157 // So if you fix this, fix the others. Currently those include: 158 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding GetBytes(char* chars, int charCount, byte* bytes, int byteCount)159 public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount) 160 { 161 // Validate Parameters 162 if (bytes == null || chars == null) 163 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array); 164 165 if (charCount < 0 || byteCount < 0) 166 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum); 167 168 return GetBytes(chars, charCount, bytes, byteCount, null); 169 } 170 171 // Returns the number of characters produced by decoding a range of bytes 172 // in a byte array. 173 // 174 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) 175 // So if you fix this, fix the others. Currently those include: 176 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding 177 // parent method is safe GetCharCount(byte[] bytes, int index, int count)178 public override unsafe int GetCharCount(byte[] bytes, int index, int count) 179 { 180 // Validate Parameters 181 if (bytes == null) 182 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array); 183 184 if (index < 0 || count < 0) 185 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum); 186 187 if (bytes.Length - index < count) 188 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer); 189 190 // If no input just return 0, fixed doesn't like 0 length arrays 191 if (count == 0) 192 return 0; 193 194 // Just call pointer version 195 fixed (byte* pBytes = bytes) 196 return GetCharCount(pBytes + index, count, null); 197 } 198 199 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) 200 // So if you fix this, fix the others. Currently those include: 201 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding GetCharCount(byte* bytes, int count)202 public override unsafe int GetCharCount(byte* bytes, int count) 203 { 204 // Validate Parameters 205 if (bytes == null) 206 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array); 207 208 if (count < 0) 209 throw new ArgumentOutOfRangeException("count", SR.ArgumentOutOfRange_NeedNonNegNum); 210 211 return GetCharCount(bytes, count, null); 212 } 213 214 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) 215 // So if you fix this, fix the others. Currently those include: 216 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding 217 // parent method is safe GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)218 public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount, 219 char[] chars, int charIndex) 220 { 221 // Validate Parameters 222 if (bytes == null || chars == null) 223 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array); 224 225 if (byteIndex < 0 || byteCount < 0) 226 throw new ArgumentOutOfRangeException((byteIndex < 0 ? "byteIndex" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum); 227 228 if ( bytes.Length - byteIndex < byteCount) 229 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer); 230 231 if (charIndex < 0 || charIndex > chars.Length) 232 throw new ArgumentOutOfRangeException("charIndex", SR.ArgumentOutOfRange_Index); 233 234 // If no input, return 0 & avoid fixed problem 235 if (byteCount == 0) 236 return 0; 237 238 // Just call pointer version 239 int charCount = chars.Length - charIndex; 240 241 fixed (byte* pBytes = bytes) fixed (char* pChars = &MemoryMarshal.GetReference((Span<char>)chars)) 242 // Remember that charCount is # to decode, not size of array 243 return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null); 244 } 245 246 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) 247 // So if you fix this, fix the others. Currently those include: 248 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding GetChars(byte* bytes, int byteCount, char* chars, int charCount)249 public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount) 250 { 251 // Validate Parameters 252 if (bytes == null || chars == null) 253 throw new ArgumentNullException(bytes == null ? "bytes" : "chars", SR.ArgumentNull_Array); 254 255 if (charCount < 0 || byteCount < 0) 256 throw new ArgumentOutOfRangeException((charCount < 0 ? "charCount" : "byteCount"), SR.ArgumentOutOfRange_NeedNonNegNum); 257 258 return GetChars(bytes, byteCount, chars, charCount, null); 259 } 260 261 // Returns a string containing the decoded representation of a range of 262 // bytes in a byte array. 263 // 264 // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS) 265 // So if you fix this, fix the others. Currently those include: 266 // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding 267 // parent method is safe GetString(byte[] bytes, int index, int count)268 public override unsafe String GetString(byte[] bytes, int index, int count) 269 { 270 // Validate Parameters 271 if (bytes == null) 272 throw new ArgumentNullException("bytes", SR.ArgumentNull_Array); 273 274 if (index < 0 || count < 0) 275 throw new ArgumentOutOfRangeException((index < 0 ? "index" : "count"), SR.ArgumentOutOfRange_NeedNonNegNum); 276 277 if (bytes.Length - index < count) 278 throw new ArgumentOutOfRangeException("bytes", SR.ArgumentOutOfRange_IndexCountBuffer); 279 280 // Avoid problems with empty input buffer 281 if (count == 0) return String.Empty; 282 283 fixed (byte* pBytes = bytes) 284 return String.CreateStringFromEncoding( 285 pBytes + index, count, this); 286 } 287 GetDecoder()288 public override Decoder GetDecoder() 289 { 290 return new DecoderNLS(this); 291 } 292 GetEncoder()293 public override Encoder GetEncoder() 294 { 295 return new EncoderNLS(this); 296 } 297 } 298 } 299