DecoderNLS.cs 9.7 KB

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