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.
7 using System.Diagnostics.Contracts;
11 // An Encoder is used to encode a sequence of blocks of characters into
12 // a sequence of blocks of bytes. Following instantiation of an encoder,
13 // sequential blocks of characters are converted into blocks of bytes through
14 // calls to the GetBytes method. The encoder maintains state between the
15 // conversions, allowing it to correctly encode character sequences that span
18 // Instances of specific implementations of the Encoder abstract base
19 // class are typically obtained through calls to the GetEncoder method
20 // of Encoding objects.
23 internal class EncoderNLS : Encoder
25 // Need a place for the last left over character, most of our encodings use this
26 internal char _charLeftOver;
27 private Encoding _encoding;
28 private bool _mustFlush;
29 internal bool _throwOnOverflow;
30 internal int _charsUsed;
32 internal EncoderNLS(Encoding encoding)
35 _fallback = _encoding.EncoderFallback;
45 public override void Reset()
47 _charLeftOver = (char)0;
48 if (_fallbackBuffer != null)
49 _fallbackBuffer.Reset();
52 public override unsafe int GetByteCount(char[] chars, int index, int count, bool flush)
54 // Validate input parameters
56 throw new ArgumentNullException(nameof(chars),
57 SR.ArgumentNull_Array);
59 if (index < 0 || count < 0)
60 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)),
61 SR.ArgumentOutOfRange_NeedNonNegNum);
63 if (chars.Length - index < count)
64 throw new ArgumentOutOfRangeException(nameof(chars),
65 SR.ArgumentOutOfRange_IndexCountBuffer);
66 Contract.EndContractBlock();
68 // Avoid empty input problem
69 if (chars.Length == 0)
72 // Just call the pointer version
74 fixed (char* pChars = &chars[0])
76 result = GetByteCount(pChars + index, count, flush);
81 public unsafe override int GetByteCount(char* chars, int count, bool flush)
83 // Validate input parameters
85 throw new ArgumentNullException(nameof(chars),
86 SR.ArgumentNull_Array);
89 throw new ArgumentOutOfRangeException(nameof(count),
90 SR.ArgumentOutOfRange_NeedNonNegNum);
91 Contract.EndContractBlock();
94 _throwOnOverflow = true;
95 return _encoding.GetByteCount(chars, count, this);
98 public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
99 byte[] bytes, int byteIndex, bool flush)
101 // Validate parameters
102 if (chars == null || bytes == null)
103 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
104 SR.ArgumentNull_Array);
106 if (charIndex < 0 || charCount < 0)
107 throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
108 SR.ArgumentOutOfRange_NeedNonNegNum);
110 if (chars.Length - charIndex < charCount)
111 throw new ArgumentOutOfRangeException(nameof(chars),
112 SR.ArgumentOutOfRange_IndexCountBuffer);
114 if (byteIndex < 0 || byteIndex > bytes.Length)
115 throw new ArgumentOutOfRangeException(nameof(byteIndex),
116 SR.ArgumentOutOfRange_Index);
117 Contract.EndContractBlock();
119 if (chars.Length == 0)
122 int byteCount = bytes.Length - byteIndex;
123 if (bytes.Length == 0)
126 // Just call pointer version
127 fixed (char* pChars = &chars[0])
128 fixed (byte* pBytes = &bytes[0])
130 // Remember that charCount is # to decode, not size of array.
131 return GetBytes(pChars + charIndex, charCount,
132 pBytes + byteIndex, byteCount, flush);
135 public unsafe override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount, bool flush)
137 // Validate parameters
138 if (chars == null || bytes == null)
139 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
140 SR.ArgumentNull_Array);
142 if (byteCount < 0 || charCount < 0)
143 throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
144 SR.ArgumentOutOfRange_NeedNonNegNum);
145 Contract.EndContractBlock();
148 _throwOnOverflow = true;
149 return _encoding.GetBytes(chars, charCount, bytes, byteCount, this);
152 // This method is used when your output buffer might not be large enough for the entire result.
153 // Just call the pointer version. (This gets bytes)
154 public override unsafe void Convert(char[] chars, int charIndex, int charCount,
155 byte[] bytes, int byteIndex, int byteCount, bool flush,
156 out int charsUsed, out int bytesUsed, out bool completed)
158 // Validate parameters
159 if (chars == null || bytes == null)
160 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
161 SR.ArgumentNull_Array);
163 if (charIndex < 0 || charCount < 0)
164 throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
165 SR.ArgumentOutOfRange_NeedNonNegNum);
167 if (byteIndex < 0 || byteCount < 0)
168 throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)),
169 SR.ArgumentOutOfRange_NeedNonNegNum);
171 if (chars.Length - charIndex < charCount)
172 throw new ArgumentOutOfRangeException(nameof(chars),
173 SR.ArgumentOutOfRange_IndexCountBuffer);
175 if (bytes.Length - byteIndex < byteCount)
176 throw new ArgumentOutOfRangeException(nameof(bytes),
177 SR.ArgumentOutOfRange_IndexCountBuffer);
179 Contract.EndContractBlock();
181 // Avoid empty input problem
182 if (chars.Length == 0)
184 if (bytes.Length == 0)
187 // Just call the pointer version (can't do this for non-msft encoders)
188 fixed (char* pChars = &chars[0])
190 fixed (byte* pBytes = &bytes[0])
192 Convert(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, flush,
193 out charsUsed, out bytesUsed, out completed);
198 // This is the version that uses pointers. We call the base encoding worker function
199 // after setting our appropriate internal variables. This is getting bytes
200 public override unsafe void Convert(char* chars, int charCount,
201 byte* bytes, int byteCount, bool flush,
202 out int charsUsed, out int bytesUsed, out bool completed)
204 // Validate input parameters
205 if (bytes == null || chars == null)
206 throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars),
207 SR.ArgumentNull_Array);
208 if (charCount < 0 || byteCount < 0)
209 throw new ArgumentOutOfRangeException((charCount < 0 ? nameof(charCount) : nameof(byteCount)),
210 SR.ArgumentOutOfRange_NeedNonNegNum);
211 Contract.EndContractBlock();
213 // We don't want to throw
215 _throwOnOverflow = false;
219 bytesUsed = _encoding.GetBytes(chars, charCount, bytes, byteCount, this);
220 charsUsed = _charsUsed;
222 // Its completed if they've used what they wanted AND if they didn't want flush or if we are flushed
223 completed = (charsUsed == charCount) && (!flush || !this.HasState) &&
224 (_fallbackBuffer == null || _fallbackBuffer.Remaining == 0);
226 // Our data thingys are now full, we can return
229 public Encoding Encoding
237 public bool MustFlush
246 // Anything left in our encoder?
247 internal virtual bool HasState
251 return (_charLeftOver != (char)0);
255 // Allow encoding to clear our must flush instead of throwing (in ThrowBytesOverflow)
256 internal void ClearMustFlush()