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.Runtime.Serialization;
8 using System.Security.Permissions;
11 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.
25 internal class EncoderNLS : Encoder, ISerializable
27 // Need a place for the last left over character, most of our encodings use this
28 internal char charLeftOver;
30 protected Encoding m_encoding;
32 [NonSerialized] protected bool m_mustFlush;
33 [NonSerialized] internal bool m_throwOnOverflow;
34 [NonSerialized] internal int m_charsUsed;
38 // Constructor called by serialization. called during deserialization.
39 internal EncoderNLS(SerializationInfo info, StreamingContext context)
41 throw new NotSupportedException(
43 System.Globalization.CultureInfo.CurrentCulture,
44 Environment.GetResourceString("NotSupported_TypeCannotDeserialized"), this.GetType()));
47 // ISerializable implementation. called during serialization.
48 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
50 SerializeEncoder(info);
51 info.AddValue("encoding", this.m_encoding);
52 info.AddValue("charLeftOver", this.charLeftOver);
53 info.SetType(typeof(Encoding.DefaultEncoder));
56 #endregion Serialization
58 internal EncoderNLS(Encoding encoding)
60 this.m_encoding = encoding;
61 this.m_fallback = this.m_encoding.EncoderFallback;
65 // This one is used when deserializing (like UTF7Encoding.Encoder)
68 this.m_encoding = null;
72 public override void Reset()
74 this.charLeftOver = (char)0;
75 if (m_fallbackBuffer != null)
76 m_fallbackBuffer.Reset();
79 public override unsafe int GetByteCount(char[] chars, int index, int count, bool flush)
81 // Validate input parameters
83 throw new ArgumentNullException(nameof(chars),
84 Environment.GetResourceString("ArgumentNull_Array"));
86 if (index < 0 || count < 0)
87 throw new ArgumentOutOfRangeException((index<0 ? nameof(index) : nameof(count)),
88 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
90 if (chars.Length - index < count)
91 throw new ArgumentOutOfRangeException(nameof(chars),
92 Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
93 Contract.EndContractBlock();
95 // Avoid empty input problem
96 if (chars.Length == 0)
99 // Just call the pointer version
101 fixed (char* pChars = chars)
103 result = GetByteCount(pChars + index, count, flush);
108 public unsafe override int GetByteCount(char* chars, int count, bool flush)
110 // Validate input parameters
112 throw new ArgumentNullException(nameof(chars),
113 Environment.GetResourceString("ArgumentNull_Array"));
116 throw new ArgumentOutOfRangeException(nameof(count),
117 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
118 Contract.EndContractBlock();
120 this.m_mustFlush = flush;
121 this.m_throwOnOverflow = true;
122 return m_encoding.GetByteCount(chars, count, this);
125 public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
126 byte[] bytes, int byteIndex, bool flush)
128 // Validate parameters
129 if (chars == null || bytes == null)
130 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
131 Environment.GetResourceString("ArgumentNull_Array"));
133 if (charIndex < 0 || charCount < 0)
134 throw new ArgumentOutOfRangeException((charIndex<0 ? nameof(charIndex) : nameof(charCount)),
135 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
137 if (chars.Length - charIndex < charCount)
138 throw new ArgumentOutOfRangeException(nameof(chars),
139 Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
141 if (byteIndex < 0 || byteIndex > bytes.Length)
142 throw new ArgumentOutOfRangeException(nameof(byteIndex),
143 Environment.GetResourceString("ArgumentOutOfRange_Index"));
144 Contract.EndContractBlock();
146 if (chars.Length == 0)
149 int byteCount = bytes.Length - byteIndex;
150 if (bytes.Length == 0)
153 // Just call pointer version
154 fixed (char* pChars = chars)
155 fixed (byte* pBytes = bytes)
157 // Remember that charCount is # to decode, not size of array.
158 return GetBytes(pChars + charIndex, charCount,
159 pBytes + byteIndex, byteCount, flush);
162 public unsafe override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount, bool flush)
164 // Validate parameters
165 if (chars == null || bytes == null)
166 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
167 Environment.GetResourceString("ArgumentNull_Array"));
169 if (byteCount < 0 || charCount < 0)
170 throw new ArgumentOutOfRangeException((byteCount<0 ? nameof(byteCount) : nameof(charCount)),
171 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
172 Contract.EndContractBlock();
174 this.m_mustFlush = flush;
175 this.m_throwOnOverflow = true;
176 return m_encoding.GetBytes(chars, charCount, bytes, byteCount, this);
179 // This method is used when your output buffer might not be large enough for the entire result.
180 // Just call the pointer version. (This gets bytes)
181 public override unsafe void Convert(char[] chars, int charIndex, int charCount,
182 byte[] bytes, int byteIndex, int byteCount, bool flush,
183 out int charsUsed, out int bytesUsed, out bool completed)
185 // Validate parameters
186 if (chars == null || bytes == null)
187 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
188 Environment.GetResourceString("ArgumentNull_Array"));
190 if (charIndex < 0 || charCount < 0)
191 throw new ArgumentOutOfRangeException((charIndex<0 ? nameof(charIndex) : nameof(charCount)),
192 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
194 if (byteIndex < 0 || byteCount < 0)
195 throw new ArgumentOutOfRangeException((byteIndex<0 ? nameof(byteIndex) : nameof(byteCount)),
196 Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
198 if (chars.Length - charIndex < charCount)
199 throw new ArgumentOutOfRangeException(nameof(chars),
200 Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
202 if (bytes.Length - byteIndex < byteCount)
203 throw new ArgumentOutOfRangeException(nameof(bytes),
204 Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
206 Contract.EndContractBlock();
208 // Avoid empty input problem
209 if (chars.Length == 0)
211 if (bytes.Length == 0)
214 // Just call the pointer version (can't do this for non-msft encoders)
215 fixed (char* pChars = chars)
217 fixed (byte* pBytes = bytes)
219 Convert(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, flush,
220 out charsUsed, out bytesUsed, out completed);
225 // This is the version that uses pointers. We call the base encoding worker function
226 // after setting our appropriate internal variables. This is getting bytes
227 public override unsafe void Convert(char* chars, int charCount,
228 byte* bytes, int byteCount, bool flush,
229 out int charsUsed, out int bytesUsed, out bool completed)
231 // Validate input parameters
232 if (bytes == null || chars == null)
233 throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars),
234 Environment.GetResourceString("ArgumentNull_Array"));
235 if (charCount < 0 || byteCount < 0)
236 throw new ArgumentOutOfRangeException((charCount<0 ? nameof(charCount) : nameof(byteCount)),
237 Environment.GetResourceString("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_charsUsed = 0;
246 bytesUsed = this.m_encoding.GetBytes(chars, charCount, bytes, byteCount, this);
247 charsUsed = this.m_charsUsed;
249 // Its completed if they've used what they wanted AND if they didn't want flush or if we are flushed
250 completed = (charsUsed == charCount) && (!flush || !this.HasState) &&
251 (m_fallbackBuffer == null || m_fallbackBuffer.Remaining == 0);
253 // Our data thingys are now full, we can return
256 public Encoding Encoding
264 public bool MustFlush
273 // Anything left in our encoder?
274 internal virtual bool HasState
278 return (this.charLeftOver != (char)0);
282 // Allow encoding to clear our must flush instead of throwing (in ThrowBytesOverflow)
283 internal void ClearMustFlush()