EncodingNLS.cs 14 KB

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