EncoderNLS.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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.Text;
  5. using System;
  6. using System.Runtime.InteropServices;
  7. namespace System.Text
  8. {
  9. // An Encoder is used to encode a sequence of blocks of characters into
  10. // a sequence of blocks of bytes. Following instantiation of an encoder,
  11. // sequential blocks of characters are converted into blocks of bytes through
  12. // calls to the GetBytes method. The encoder maintains state between the
  13. // conversions, allowing it to correctly encode character sequences that span
  14. // adjacent blocks.
  15. //
  16. // Instances of specific implementations of the Encoder abstract base
  17. // class are typically obtained through calls to the GetEncoder method
  18. // of Encoding objects.
  19. //
  20. internal class EncoderNLS : Encoder
  21. {
  22. // Need a place for the last left over character, most of our encodings use this
  23. internal char _charLeftOver;
  24. private Encoding _encoding;
  25. private bool _mustFlush;
  26. internal bool _throwOnOverflow;
  27. internal int _charsUsed;
  28. internal EncoderNLS(Encoding encoding)
  29. {
  30. _encoding = encoding;
  31. _fallback = _encoding.EncoderFallback;
  32. this.Reset();
  33. }
  34. internal EncoderNLS()
  35. {
  36. _encoding = null;
  37. this.Reset();
  38. }
  39. public override void Reset()
  40. {
  41. _charLeftOver = (char)0;
  42. if (_fallbackBuffer != null)
  43. _fallbackBuffer.Reset();
  44. }
  45. public override unsafe int GetByteCount(char[] chars, int index, int count, bool flush)
  46. {
  47. // Validate input parameters
  48. if (chars == null)
  49. throw new ArgumentNullException(nameof(chars),
  50. SR.ArgumentNull_Array);
  51. if (index < 0 || count < 0)
  52. throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)),
  53. SR.ArgumentOutOfRange_NeedNonNegNum);
  54. if (chars.Length - index < count)
  55. throw new ArgumentOutOfRangeException(nameof(chars),
  56. SR.ArgumentOutOfRange_IndexCountBuffer);
  57. // Just call the pointer version
  58. int result = -1;
  59. fixed (char* pChars = &MemoryMarshal.GetReference((Span<char>)chars))
  60. {
  61. result = GetByteCount(pChars + index, count, flush);
  62. }
  63. return result;
  64. }
  65. public unsafe override int GetByteCount(char* chars, int count, bool flush)
  66. {
  67. // Validate input parameters
  68. if (chars == null)
  69. throw new ArgumentNullException(nameof(chars),
  70. SR.ArgumentNull_Array);
  71. if (count < 0)
  72. throw new ArgumentOutOfRangeException(nameof(count),
  73. SR.ArgumentOutOfRange_NeedNonNegNum);
  74. _mustFlush = flush;
  75. _throwOnOverflow = true;
  76. return _encoding.GetByteCount(chars, count, this);
  77. }
  78. public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
  79. byte[] bytes, int byteIndex, bool flush)
  80. {
  81. // Validate parameters
  82. if (chars == null || bytes == null)
  83. throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
  84. SR.ArgumentNull_Array);
  85. if (charIndex < 0 || charCount < 0)
  86. throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
  87. SR.ArgumentOutOfRange_NeedNonNegNum);
  88. if (chars.Length - charIndex < charCount)
  89. throw new ArgumentOutOfRangeException(nameof(chars),
  90. SR.ArgumentOutOfRange_IndexCountBuffer);
  91. if (byteIndex < 0 || byteIndex > bytes.Length)
  92. throw new ArgumentOutOfRangeException(nameof(byteIndex),
  93. SR.ArgumentOutOfRange_Index);
  94. int byteCount = bytes.Length - byteIndex;
  95. // Just call pointer version
  96. fixed (char* pChars = &MemoryMarshal.GetReference((Span<char>)chars))
  97. fixed (byte* pBytes = &MemoryMarshal.GetReference((Span<byte>)bytes))
  98. // Remember that charCount is # to decode, not size of array.
  99. return GetBytes(pChars + charIndex, charCount,
  100. pBytes + byteIndex, byteCount, flush);
  101. }
  102. public unsafe override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount, bool flush)
  103. {
  104. // Validate parameters
  105. if (chars == null || bytes == null)
  106. throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
  107. SR.ArgumentNull_Array);
  108. if (byteCount < 0 || charCount < 0)
  109. throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
  110. SR.ArgumentOutOfRange_NeedNonNegNum);
  111. _mustFlush = flush;
  112. _throwOnOverflow = true;
  113. return _encoding.GetBytes(chars, charCount, bytes, byteCount, this);
  114. }
  115. // This method is used when your output buffer might not be large enough for the entire result.
  116. // Just call the pointer version. (This gets bytes)
  117. public override unsafe void Convert(char[] chars, int charIndex, int charCount,
  118. byte[] bytes, int byteIndex, int byteCount, bool flush,
  119. out int charsUsed, out int bytesUsed, out bool completed)
  120. {
  121. // Validate parameters
  122. if (chars == null || bytes == null)
  123. throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
  124. SR.ArgumentNull_Array);
  125. if (charIndex < 0 || charCount < 0)
  126. throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
  127. SR.ArgumentOutOfRange_NeedNonNegNum);
  128. if (byteIndex < 0 || byteCount < 0)
  129. throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)),
  130. SR.ArgumentOutOfRange_NeedNonNegNum);
  131. if (chars.Length - charIndex < charCount)
  132. throw new ArgumentOutOfRangeException(nameof(chars),
  133. SR.ArgumentOutOfRange_IndexCountBuffer);
  134. if (bytes.Length - byteIndex < byteCount)
  135. throw new ArgumentOutOfRangeException(nameof(bytes),
  136. SR.ArgumentOutOfRange_IndexCountBuffer);
  137. // Just call the pointer version (can't do this for non-msft encoders)
  138. fixed (char* pChars = &MemoryMarshal.GetReference((Span<char>)chars))
  139. {
  140. fixed (byte* pBytes = &MemoryMarshal.GetReference((Span<byte>)bytes))
  141. {
  142. Convert(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, flush,
  143. out charsUsed, out bytesUsed, out completed);
  144. }
  145. }
  146. }
  147. // This is the version that uses pointers. We call the base encoding worker function
  148. // after setting our appropriate internal variables. This is getting bytes
  149. public override unsafe void Convert(char* chars, int charCount,
  150. byte* bytes, int byteCount, bool flush,
  151. out int charsUsed, out int bytesUsed, out bool completed)
  152. {
  153. // Validate input parameters
  154. if (bytes == null || chars == null)
  155. throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars),
  156. SR.ArgumentNull_Array);
  157. if (charCount < 0 || byteCount < 0)
  158. throw new ArgumentOutOfRangeException((charCount < 0 ? nameof(charCount) : nameof(byteCount)),
  159. SR.ArgumentOutOfRange_NeedNonNegNum);
  160. // We don't want to throw
  161. _mustFlush = flush;
  162. _throwOnOverflow = false;
  163. _charsUsed = 0;
  164. // Do conversion
  165. bytesUsed = _encoding.GetBytes(chars, charCount, bytes, byteCount, this);
  166. charsUsed = _charsUsed;
  167. // Its completed if they've used what they wanted AND if they didn't want flush or if we are flushed
  168. completed = (charsUsed == charCount) && (!flush || !this.HasState) &&
  169. (_fallbackBuffer == null || _fallbackBuffer.Remaining == 0);
  170. // Our data thingys are now full, we can return
  171. }
  172. public Encoding Encoding
  173. {
  174. get
  175. {
  176. return _encoding;
  177. }
  178. }
  179. public bool MustFlush
  180. {
  181. get
  182. {
  183. return _mustFlush;
  184. }
  185. }
  186. // Anything left in our encoder?
  187. internal virtual bool HasState
  188. {
  189. get
  190. {
  191. return (_charLeftOver != (char)0);
  192. }
  193. }
  194. // Allow encoding to clear our must flush instead of throwing (in ThrowBytesOverflow)
  195. internal void ClearMustFlush()
  196. {
  197. _mustFlush = false;
  198. }
  199. }
  200. }