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 // An Encoder is used to encode a sequence of blocks of characters into
13 // a sequence of blocks of bytes. Following instantiation of an encoder,
14 // sequential blocks of characters are converted into blocks of bytes through
15 // calls to the GetBytes method. The encoder maintains state between the
16 // conversions, allowing it to correctly encode character sequences that span
19 // Instances of specific implementations of the Encoder abstract base
20 // class are typically obtained through calls to the GetEncoder method
21 // of Encoding objects.
24 internal class EncoderNLS : Encoder, ISerializable
26 // Need a place for the last left over character, most of our encodings use this
27 internal char charLeftOver;
29 protected Encoding m_encoding;
31 [NonSerialized] protected bool m_mustFlush;
32 [NonSerialized] internal bool m_throwOnOverflow;
33 [NonSerialized] internal int m_charsUsed;
37 // ISerializable implementation.
38 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
40 throw new PlatformNotSupportedException();
43 #endregion Serialization
45 internal EncoderNLS(Encoding encoding)
47 this.m_encoding = encoding;
48 this.m_fallback = this.m_encoding.EncoderFallback;
52 // This one is used when deserializing (like UTF7Encoding.Encoder)
55 this.m_encoding = null;
59 public override void Reset()
61 this.charLeftOver = (char)0;
62 if (m_fallbackBuffer != null)
63 m_fallbackBuffer.Reset();
66 public override unsafe int GetByteCount(char[] chars, int index, int count, bool flush)
68 // Validate input parameters
70 throw new ArgumentNullException(nameof(chars),
71 SR.ArgumentNull_Array);
73 if (index < 0 || count < 0)
74 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)),
75 SR.ArgumentOutOfRange_NeedNonNegNum);
77 if (chars.Length - index < count)
78 throw new ArgumentOutOfRangeException(nameof(chars),
79 SR.ArgumentOutOfRange_IndexCountBuffer);
80 Contract.EndContractBlock();
82 // Avoid empty input problem
83 if (chars.Length == 0)
86 // Just call the pointer version
88 fixed (char* pChars = &chars[0])
90 result = GetByteCount(pChars + index, count, flush);
95 public unsafe override int GetByteCount(char* chars, int count, bool flush)
97 // Validate input parameters
99 throw new ArgumentNullException(nameof(chars),
100 SR.ArgumentNull_Array);
103 throw new ArgumentOutOfRangeException(nameof(count),
104 SR.ArgumentOutOfRange_NeedNonNegNum);
105 Contract.EndContractBlock();
107 this.m_mustFlush = flush;
108 this.m_throwOnOverflow = true;
109 return m_encoding.GetByteCount(chars, count, this);
112 public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
113 byte[] bytes, int byteIndex, bool flush)
115 // Validate parameters
116 if (chars == null || bytes == null)
117 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
118 SR.ArgumentNull_Array);
120 if (charIndex < 0 || charCount < 0)
121 throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
122 SR.ArgumentOutOfRange_NeedNonNegNum);
124 if (chars.Length - charIndex < charCount)
125 throw new ArgumentOutOfRangeException(nameof(chars),
126 SR.ArgumentOutOfRange_IndexCountBuffer);
128 if (byteIndex < 0 || byteIndex > bytes.Length)
129 throw new ArgumentOutOfRangeException(nameof(byteIndex),
130 SR.ArgumentOutOfRange_Index);
131 Contract.EndContractBlock();
133 if (chars.Length == 0)
136 int byteCount = bytes.Length - byteIndex;
137 if (bytes.Length == 0)
140 // Just call pointer version
141 fixed (char* pChars = &chars[0])
142 fixed (byte* pBytes = &bytes[0])
144 // Remember that charCount is # to decode, not size of array.
145 return GetBytes(pChars + charIndex, charCount,
146 pBytes + byteIndex, byteCount, flush);
149 public unsafe override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount, bool flush)
151 // Validate parameters
152 if (chars == null || bytes == null)
153 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
154 SR.ArgumentNull_Array);
156 if (byteCount < 0 || charCount < 0)
157 throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
158 SR.ArgumentOutOfRange_NeedNonNegNum);
159 Contract.EndContractBlock();
161 this.m_mustFlush = flush;
162 this.m_throwOnOverflow = true;
163 return m_encoding.GetBytes(chars, charCount, bytes, byteCount, this);
166 // This method is used when your output buffer might not be large enough for the entire result.
167 // Just call the pointer version. (This gets bytes)
168 public override unsafe void Convert(char[] chars, int charIndex, int charCount,
169 byte[] bytes, int byteIndex, int byteCount, bool flush,
170 out int charsUsed, out int bytesUsed, out bool completed)
172 // Validate parameters
173 if (chars == null || bytes == null)
174 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
175 SR.ArgumentNull_Array);
177 if (charIndex < 0 || charCount < 0)
178 throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
179 SR.ArgumentOutOfRange_NeedNonNegNum);
181 if (byteIndex < 0 || byteCount < 0)
182 throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)),
183 SR.ArgumentOutOfRange_NeedNonNegNum);
185 if (chars.Length - charIndex < charCount)
186 throw new ArgumentOutOfRangeException(nameof(chars),
187 SR.ArgumentOutOfRange_IndexCountBuffer);
189 if (bytes.Length - byteIndex < byteCount)
190 throw new ArgumentOutOfRangeException(nameof(bytes),
191 SR.ArgumentOutOfRange_IndexCountBuffer);
193 Contract.EndContractBlock();
195 // Avoid empty input problem
196 if (chars.Length == 0)
198 if (bytes.Length == 0)
201 // Just call the pointer version (can't do this for non-msft encoders)
202 fixed (char* pChars = &chars[0])
204 fixed (byte* pBytes = &bytes[0])
206 Convert(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, flush,
207 out charsUsed, out bytesUsed, out completed);
212 // This is the version that uses pointers. We call the base encoding worker function
213 // after setting our appropriate internal variables. This is getting bytes
214 public override unsafe void Convert(char* chars, int charCount,
215 byte* bytes, int byteCount, bool flush,
216 out int charsUsed, out int bytesUsed, out bool completed)
218 // Validate input parameters
219 if (bytes == null || chars == null)
220 throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars),
221 SR.ArgumentNull_Array);
222 if (charCount < 0 || byteCount < 0)
223 throw new ArgumentOutOfRangeException((charCount < 0 ? nameof(charCount) : nameof(byteCount)),
224 SR.ArgumentOutOfRange_NeedNonNegNum);
225 Contract.EndContractBlock();
227 // We don't want to throw
228 this.m_mustFlush = flush;
229 this.m_throwOnOverflow = false;
230 this.m_charsUsed = 0;
233 bytesUsed = this.m_encoding.GetBytes(chars, charCount, bytes, byteCount, this);
234 charsUsed = this.m_charsUsed;
236 // Its completed if they've used what they wanted AND if they didn't want flush or if we are flushed
237 completed = (charsUsed == charCount) && (!flush || !this.HasState) &&
238 (m_fallbackBuffer == null || m_fallbackBuffer.Remaining == 0);
240 // Our data thingys are now full, we can return
243 public Encoding Encoding
251 public bool MustFlush
260 // Anything left in our encoder?
261 internal virtual bool HasState
265 return (this.charLeftOver != (char)0);
269 // Allow encoding to clear our must flush instead of throwing (in ThrowBytesOverflow)
270 internal void ClearMustFlush()