EncodingNLS.cs 14 KB

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