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.
24 internal class DecoderNLS : Decoder, ISerializable
26 // Remember our encoding
27 protected Encoding m_encoding;
28 [NonSerialized] protected bool m_mustFlush;
29 [NonSerialized] internal bool m_throwOnOverflow;
30 [NonSerialized] internal int m_bytesUsed;
34 // ISerializable implementation.
35 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
37 throw new PlatformNotSupportedException();
40 #endregion Serialization
42 internal DecoderNLS(Encoding encoding)
44 this.m_encoding = encoding;
45 this.m_fallback = this.m_encoding.DecoderFallback;
49 // This is used by our child deserializers
52 this.m_encoding = null;
56 public override void Reset()
58 if (m_fallbackBuffer != null)
59 m_fallbackBuffer.Reset();
62 public override unsafe int GetCharCount(byte[] bytes, int index, int count)
64 return GetCharCount(bytes, index, count, false);
67 public override unsafe int GetCharCount(byte[] bytes, int index, int count, bool flush)
69 // Validate Parameters
71 throw new ArgumentNullException(nameof(bytes),
72 SR.ArgumentNull_Array);
74 if (index < 0 || count < 0)
75 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)),
76 SR.ArgumentOutOfRange_NeedNonNegNum);
78 if (bytes.Length - index < count)
79 throw new ArgumentOutOfRangeException(nameof(bytes),
80 SR.ArgumentOutOfRange_IndexCountBuffer);
82 Contract.EndContractBlock();
84 // Avoid null fixed problem
85 if (bytes.Length == 0)
88 // Just call pointer version
89 fixed (byte* pBytes = &bytes[0])
90 return GetCharCount(pBytes + index, count, flush);
93 public unsafe override int GetCharCount(byte* bytes, int count, bool flush)
95 // Validate parameters
97 throw new ArgumentNullException(nameof(bytes),
98 SR.ArgumentNull_Array);
101 throw new ArgumentOutOfRangeException(nameof(count),
102 SR.ArgumentOutOfRange_NeedNonNegNum);
103 Contract.EndContractBlock();
105 // Remember the flush
106 this.m_mustFlush = flush;
107 this.m_throwOnOverflow = true;
109 // By default just call the encoding version, no flush by default
110 return m_encoding.GetCharCount(bytes, count, this);
113 public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
114 char[] chars, int charIndex)
116 return GetChars(bytes, byteIndex, byteCount, chars, charIndex, false);
119 public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
120 char[] chars, int charIndex, bool flush)
122 // Validate Parameters
123 if (bytes == null || chars == null)
124 throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars),
125 SR.ArgumentNull_Array);
127 if (byteIndex < 0 || byteCount < 0)
128 throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)),
129 SR.ArgumentOutOfRange_NeedNonNegNum);
131 if (bytes.Length - byteIndex < byteCount)
132 throw new ArgumentOutOfRangeException(nameof(bytes),
133 SR.ArgumentOutOfRange_IndexCountBuffer);
135 if (charIndex < 0 || charIndex > chars.Length)
136 throw new ArgumentOutOfRangeException(nameof(charIndex),
137 SR.ArgumentOutOfRange_Index);
139 Contract.EndContractBlock();
141 // Avoid empty input fixed problem
142 if (bytes.Length == 0)
145 int charCount = chars.Length - charIndex;
146 if (chars.Length == 0)
149 // Just call pointer version
150 fixed (byte* pBytes = &bytes[0])
151 fixed (char* pChars = &chars[0])
152 // Remember that charCount is # to decode, not size of array
153 return GetChars(pBytes + byteIndex, byteCount,
154 pChars + charIndex, charCount, flush);
157 public unsafe override int GetChars(byte* bytes, int byteCount,
158 char* chars, int charCount, bool flush)
160 // Validate parameters
161 if (chars == null || bytes == null)
162 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
163 SR.ArgumentNull_Array);
165 if (byteCount < 0 || charCount < 0)
166 throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
167 SR.ArgumentOutOfRange_NeedNonNegNum);
168 Contract.EndContractBlock();
170 // Remember our flush
172 m_throwOnOverflow = true;
174 // By default just call the encoding's version
175 return m_encoding.GetChars(bytes, byteCount, chars, charCount, this);
178 // This method is used when the output buffer might not be big enough.
179 // Just call the pointer version. (This gets chars)
180 public override unsafe void Convert(byte[] bytes, int byteIndex, int byteCount,
181 char[] chars, int charIndex, int charCount, bool flush,
182 out int bytesUsed, out int charsUsed, out bool completed)
184 // Validate parameters
185 if (bytes == null || chars == null)
186 throw new ArgumentNullException((bytes == null ? nameof(bytes) : nameof(chars)),
187 SR.ArgumentNull_Array);
189 if (byteIndex < 0 || byteCount < 0)
190 throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)),
191 SR.ArgumentOutOfRange_NeedNonNegNum);
193 if (charIndex < 0 || charCount < 0)
194 throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
195 SR.ArgumentOutOfRange_NeedNonNegNum);
197 if (bytes.Length - byteIndex < byteCount)
198 throw new ArgumentOutOfRangeException(nameof(bytes),
199 SR.ArgumentOutOfRange_IndexCountBuffer);
201 if (chars.Length - charIndex < charCount)
202 throw new ArgumentOutOfRangeException(nameof(chars),
203 SR.ArgumentOutOfRange_IndexCountBuffer);
205 Contract.EndContractBlock();
207 // Avoid empty input problem
208 if (bytes.Length == 0)
210 if (chars.Length == 0)
213 // Just call the pointer version (public overrides can't do this)
214 fixed (byte* pBytes = &bytes[0])
216 fixed (char* pChars = &chars[0])
218 Convert(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, flush,
219 out bytesUsed, out charsUsed, out completed);
224 // This is the version that used pointers. We call the base encoding worker function
225 // after setting our appropriate internal variables. This is getting chars
226 public unsafe override void Convert(byte* bytes, int byteCount,
227 char* chars, int charCount, bool flush,
228 out int bytesUsed, out int charsUsed, out bool completed)
230 // Validate input parameters
231 if (chars == null || bytes == null)
232 throw new ArgumentNullException(chars == null ? nameof(chars) : nameof(bytes),
233 SR.ArgumentNull_Array);
235 if (byteCount < 0 || charCount < 0)
236 throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
237 SR.ArgumentOutOfRange_NeedNonNegNum);
238 Contract.EndContractBlock();
240 // We don't want to throw
241 this.m_mustFlush = flush;
242 this.m_throwOnOverflow = false;
243 this.m_bytesUsed = 0;
246 charsUsed = this.m_encoding.GetChars(bytes, byteCount, chars, charCount, this);
247 bytesUsed = this.m_bytesUsed;
249 // Its completed if they've used what they wanted AND if they didn't want flush or if we are flushed
250 completed = (bytesUsed == byteCount) && (!flush || !this.HasState) &&
251 (m_fallbackBuffer == null || m_fallbackBuffer.Remaining == 0);
253 // Our data thingys are now full, we can return
256 public bool MustFlush
264 // Anything left in our decoder?
265 internal virtual bool HasState
273 // Allow encoding to clear our must flush instead of throwing (in ThrowCharsOverflow)
274 internal void ClearMustFlush()