| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using System.Text;
- using System;
- using System.Runtime.InteropServices;
- namespace System.Text
- {
- // An Encoder is used to encode a sequence of blocks of characters into
- // a sequence of blocks of bytes. Following instantiation of an encoder,
- // sequential blocks of characters are converted into blocks of bytes through
- // calls to the GetBytes method. The encoder maintains state between the
- // conversions, allowing it to correctly encode character sequences that span
- // adjacent blocks.
- //
- // Instances of specific implementations of the Encoder abstract base
- // class are typically obtained through calls to the GetEncoder method
- // of Encoding objects.
- //
- internal class EncoderNLS : Encoder
- {
- // Need a place for the last left over character, most of our encodings use this
- internal char _charLeftOver;
- private Encoding _encoding;
- private bool _mustFlush;
- internal bool _throwOnOverflow;
- internal int _charsUsed;
- internal EncoderNLS(Encoding encoding)
- {
- _encoding = encoding;
- _fallback = _encoding.EncoderFallback;
- this.Reset();
- }
- internal EncoderNLS()
- {
- _encoding = null;
- this.Reset();
- }
- public override void Reset()
- {
- _charLeftOver = (char)0;
- if (_fallbackBuffer != null)
- _fallbackBuffer.Reset();
- }
- public override unsafe int GetByteCount(char[] chars, int index, int count, bool flush)
- {
- // Validate input parameters
- if (chars == null)
- throw new ArgumentNullException(nameof(chars),
- SR.ArgumentNull_Array);
- if (index < 0 || count < 0)
- throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)),
- SR.ArgumentOutOfRange_NeedNonNegNum);
- if (chars.Length - index < count)
- throw new ArgumentOutOfRangeException(nameof(chars),
- SR.ArgumentOutOfRange_IndexCountBuffer);
- // Just call the pointer version
- int result = -1;
- fixed (char* pChars = &MemoryMarshal.GetReference((Span<char>)chars))
- {
- result = GetByteCount(pChars + index, count, flush);
- }
- return result;
- }
- public unsafe override int GetByteCount(char* chars, int count, bool flush)
- {
- // Validate input parameters
- if (chars == null)
- throw new ArgumentNullException(nameof(chars),
- SR.ArgumentNull_Array);
- if (count < 0)
- throw new ArgumentOutOfRangeException(nameof(count),
- SR.ArgumentOutOfRange_NeedNonNegNum);
- _mustFlush = flush;
- _throwOnOverflow = true;
- return _encoding.GetByteCount(chars, count, this);
- }
- public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
- byte[] bytes, int byteIndex, bool flush)
- {
- // Validate parameters
- if (chars == null || bytes == null)
- throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
- SR.ArgumentNull_Array);
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
- SR.ArgumentOutOfRange_NeedNonNegNum);
- if (chars.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException(nameof(chars),
- SR.ArgumentOutOfRange_IndexCountBuffer);
- if (byteIndex < 0 || byteIndex > bytes.Length)
- throw new ArgumentOutOfRangeException(nameof(byteIndex),
- SR.ArgumentOutOfRange_Index);
- int byteCount = bytes.Length - byteIndex;
- // Just call pointer version
- fixed (char* pChars = &MemoryMarshal.GetReference((Span<char>)chars))
- fixed (byte* pBytes = &MemoryMarshal.GetReference((Span<byte>)bytes))
- // Remember that charCount is # to decode, not size of array.
- return GetBytes(pChars + charIndex, charCount,
- pBytes + byteIndex, byteCount, flush);
- }
- public unsafe override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount, bool flush)
- {
- // Validate parameters
- if (chars == null || bytes == null)
- throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
- SR.ArgumentNull_Array);
- if (byteCount < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
- SR.ArgumentOutOfRange_NeedNonNegNum);
- _mustFlush = flush;
- _throwOnOverflow = true;
- return _encoding.GetBytes(chars, charCount, bytes, byteCount, this);
- }
- // This method is used when your output buffer might not be large enough for the entire result.
- // Just call the pointer version. (This gets bytes)
- public override unsafe void Convert(char[] chars, int charIndex, int charCount,
- byte[] bytes, int byteIndex, int byteCount, bool flush,
- out int charsUsed, out int bytesUsed, out bool completed)
- {
- // Validate parameters
- if (chars == null || bytes == null)
- throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
- SR.ArgumentNull_Array);
- if (charIndex < 0 || charCount < 0)
- throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
- SR.ArgumentOutOfRange_NeedNonNegNum);
- if (byteIndex < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)),
- SR.ArgumentOutOfRange_NeedNonNegNum);
- if (chars.Length - charIndex < charCount)
- throw new ArgumentOutOfRangeException(nameof(chars),
- SR.ArgumentOutOfRange_IndexCountBuffer);
- if (bytes.Length - byteIndex < byteCount)
- throw new ArgumentOutOfRangeException(nameof(bytes),
- SR.ArgumentOutOfRange_IndexCountBuffer);
- // Just call the pointer version (can't do this for non-msft encoders)
- fixed (char* pChars = &MemoryMarshal.GetReference((Span<char>)chars))
- {
- fixed (byte* pBytes = &MemoryMarshal.GetReference((Span<byte>)bytes))
- {
- Convert(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, flush,
- out charsUsed, out bytesUsed, out completed);
- }
- }
- }
- // This is the version that uses pointers. We call the base encoding worker function
- // after setting our appropriate internal variables. This is getting bytes
- public override unsafe void Convert(char* chars, int charCount,
- byte* bytes, int byteCount, bool flush,
- out int charsUsed, out int bytesUsed, out bool completed)
- {
- // Validate input parameters
- if (bytes == null || chars == null)
- throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars),
- SR.ArgumentNull_Array);
- if (charCount < 0 || byteCount < 0)
- throw new ArgumentOutOfRangeException((charCount < 0 ? nameof(charCount) : nameof(byteCount)),
- SR.ArgumentOutOfRange_NeedNonNegNum);
- // We don't want to throw
- _mustFlush = flush;
- _throwOnOverflow = false;
- _charsUsed = 0;
- // Do conversion
- bytesUsed = _encoding.GetBytes(chars, charCount, bytes, byteCount, this);
- charsUsed = _charsUsed;
- // Its completed if they've used what they wanted AND if they didn't want flush or if we are flushed
- completed = (charsUsed == charCount) && (!flush || !this.HasState) &&
- (_fallbackBuffer == null || _fallbackBuffer.Remaining == 0);
- // Our data thingys are now full, we can return
- }
- public Encoding Encoding
- {
- get
- {
- return _encoding;
- }
- }
- public bool MustFlush
- {
- get
- {
- return _mustFlush;
- }
- }
- // Anything left in our encoder?
- internal virtual bool HasState
- {
- get
- {
- return (_charLeftOver != (char)0);
- }
- }
- // Allow encoding to clear our must flush instead of throwing (in ThrowBytesOverflow)
- internal void ClearMustFlush()
- {
- _mustFlush = false;
- }
- }
- }
|