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.
5 using System.Runtime.Serialization;
8 using System.Diagnostics.Contracts;
12 // A Decoder is used to decode a sequence of blocks of bytes into a
13 // sequence of blocks of characters. Following instantiation of a decoder,
14 // sequential blocks of bytes are converted into blocks of characters through
15 // calls to the GetChars method. The decoder maintains state between the
16 // conversions, allowing it to correctly decode byte sequences that span
19 // Instances of specific implementations of the Decoder abstract base
20 // class are typically obtained through calls to the GetDecoder method
21 // of Encoding objects.
23 internal class DecoderNLS : Decoder
25 // Remember our encoding
26 private Encoding _encoding;
27 private bool _mustFlush;
28 internal bool _throwOnOverflow;
29 internal int _bytesUsed;
31 internal DecoderNLS(Encoding encoding)
34 _fallback = this._encoding.DecoderFallback;
38 // This is used by our child deserializers
45 public override void Reset()
47 _fallbackBuffer?.Reset();
50 public override unsafe int GetCharCount(byte[] bytes, int index, int count)
52 return GetCharCount(bytes, index, count, false);
55 public override unsafe int GetCharCount(byte[] bytes, int index, int count, bool flush)
57 // Validate Parameters
59 throw new ArgumentNullException(nameof(bytes),
60 SR.ArgumentNull_Array);
62 if (index < 0 || count < 0)
63 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)),
64 SR.ArgumentOutOfRange_NeedNonNegNum);
66 if (bytes.Length - index < count)
67 throw new ArgumentOutOfRangeException(nameof(bytes),
68 SR.ArgumentOutOfRange_IndexCountBuffer);
70 Contract.EndContractBlock();
72 // Avoid null fixed problem
73 if (bytes.Length == 0)
76 // Just call pointer version
77 fixed (byte* pBytes = &bytes[0])
78 return GetCharCount(pBytes + index, count, flush);
81 public unsafe override int GetCharCount(byte* bytes, int count, bool flush)
83 // Validate parameters
85 throw new ArgumentNullException(nameof(bytes),
86 SR.ArgumentNull_Array);
89 throw new ArgumentOutOfRangeException(nameof(count),
90 SR.ArgumentOutOfRange_NeedNonNegNum);
91 Contract.EndContractBlock();
95 _throwOnOverflow = true;
97 // By default just call the encoding version, no flush by default
98 return _encoding.GetCharCount(bytes, count, this);
101 public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
102 char[] chars, int charIndex)
104 return GetChars(bytes, byteIndex, byteCount, chars, charIndex, false);
107 public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
108 char[] chars, int charIndex, bool flush)
110 // Validate Parameters
111 if (bytes == null || chars == null)
112 throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars),
113 SR.ArgumentNull_Array);
115 if (byteIndex < 0 || byteCount < 0)
116 throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)),
117 SR.ArgumentOutOfRange_NeedNonNegNum);
119 if (bytes.Length - byteIndex < byteCount)
120 throw new ArgumentOutOfRangeException(nameof(bytes),
121 SR.ArgumentOutOfRange_IndexCountBuffer);
123 if (charIndex < 0 || charIndex > chars.Length)
124 throw new ArgumentOutOfRangeException(nameof(charIndex),
125 SR.ArgumentOutOfRange_Index);
127 Contract.EndContractBlock();
129 // Avoid empty input fixed problem
130 if (bytes.Length == 0)
133 int charCount = chars.Length - charIndex;
134 if (chars.Length == 0)
137 // Just call pointer version
138 fixed (byte* pBytes = &bytes[0])
139 fixed (char* pChars = &chars[0])
140 // Remember that charCount is # to decode, not size of array
141 return GetChars(pBytes + byteIndex, byteCount,
142 pChars + charIndex, charCount, flush);
145 public unsafe override int GetChars(byte* bytes, int byteCount,
146 char* chars, int charCount, bool flush)
148 // Validate parameters
149 if (chars == null || bytes == null)
150 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
151 SR.ArgumentNull_Array);
153 if (byteCount < 0 || charCount < 0)
154 throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
155 SR.ArgumentOutOfRange_NeedNonNegNum);
156 Contract.EndContractBlock();
158 // Remember our flush
160 _throwOnOverflow = true;
162 // By default just call the encodings version
163 return _encoding.GetChars(bytes, byteCount, chars, charCount, this);
166 // This method is used when the output buffer might not be big enough.
167 // Just call the pointer version. (This gets chars)
168 public override unsafe void Convert(byte[] bytes, int byteIndex, int byteCount,
169 char[] chars, int charIndex, int charCount, bool flush,
170 out int bytesUsed, out int charsUsed, out bool completed)
172 // Validate parameters
173 if (bytes == null || chars == null)
174 throw new ArgumentNullException((bytes == null ? nameof(bytes) : nameof(chars)),
175 SR.ArgumentNull_Array);
177 if (byteIndex < 0 || byteCount < 0)
178 throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)),
179 SR.ArgumentOutOfRange_NeedNonNegNum);
181 if (charIndex < 0 || charCount < 0)
182 throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
183 SR.ArgumentOutOfRange_NeedNonNegNum);
185 if (bytes.Length - byteIndex < byteCount)
186 throw new ArgumentOutOfRangeException(nameof(bytes),
187 SR.ArgumentOutOfRange_IndexCountBuffer);
189 if (chars.Length - charIndex < charCount)
190 throw new ArgumentOutOfRangeException(nameof(chars),
191 SR.ArgumentOutOfRange_IndexCountBuffer);
193 Contract.EndContractBlock();
195 // Avoid empty input problem
196 if (bytes.Length == 0)
198 if (chars.Length == 0)
201 // Just call the pointer version (public overrides can't do this)
202 fixed (byte* pBytes = &bytes[0])
204 fixed (char* pChars = &chars[0])
206 Convert(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, flush,
207 out bytesUsed, out charsUsed, out completed);
212 // This is the version that used pointers. We call the base encoding worker function
213 // after setting our appropriate internal variables. This is getting chars
214 public unsafe override void Convert(byte* bytes, int byteCount,
215 char* chars, int charCount, bool flush,
216 out int bytesUsed, out int charsUsed, out bool completed)
218 // Validate input parameters
219 if (chars == null || bytes == null)
220 throw new ArgumentNullException(chars == null ? nameof(chars) : nameof(bytes),
221 SR.ArgumentNull_Array);
223 if (byteCount < 0 || charCount < 0)
224 throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
225 SR.ArgumentOutOfRange_NeedNonNegNum);
226 Contract.EndContractBlock();
228 // We don't want to throw
230 _throwOnOverflow = false;
234 charsUsed = _encoding.GetChars(bytes, byteCount, chars, charCount, this);
235 bytesUsed = _bytesUsed;
237 // Its completed if they've used what they wanted AND if they didn't want flush or if we are flushed
238 completed = (bytesUsed == byteCount) && (!flush || !this.HasState) &&
239 (_fallbackBuffer == null || _fallbackBuffer.Remaining == 0);
241 // Our data thingy are now full, we can return
244 public bool MustFlush
252 // Anything left in our decoder?
253 internal virtual bool HasState
261 // Allow encoding to clear our must flush instead of throwing (in ThrowCharsOverflow)
262 internal void ClearMustFlush()