EncodingNLS.cs 15 KB

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