Revert "Fast-path for ASCII & UTF8 Encoding ASCII data"
[platform/upstream/coreclr.git] / src / mscorlib / src / System / Text / EncoderNLS.cs
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.
4
5 namespace System.Text
6 {
7     using System.Runtime.Serialization;
8     using System.Security.Permissions;
9     using System.Text;
10     using System;
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
17     // adjacent blocks.
18     //
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.
22     //
23
24     [Serializable]
25     internal class EncoderNLS : Encoder, ISerializable
26     {
27         // Need a place for the last left over character, most of our encodings use this
28         internal char   charLeftOver;
29         
30         protected Encoding m_encoding;
31         
32         [NonSerialized] protected   bool     m_mustFlush;
33         [NonSerialized] internal    bool     m_throwOnOverflow;
34         [NonSerialized] internal    int      m_charsUsed;
35
36 #region Serialization
37
38         // Constructor called by serialization. called during deserialization.
39         internal EncoderNLS(SerializationInfo info, StreamingContext context)
40         {
41             throw new NotSupportedException(
42                         String.Format(
43                             System.Globalization.CultureInfo.CurrentCulture, 
44                             Environment.GetResourceString("NotSupported_TypeCannotDeserialized"), this.GetType()));
45         }
46
47         // ISerializable implementation. called during serialization.
48         void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
49         {
50             SerializeEncoder(info);
51             info.AddValue("encoding", this.m_encoding);
52             info.AddValue("charLeftOver", this.charLeftOver);
53             info.SetType(typeof(Encoding.DefaultEncoder));
54         }
55
56 #endregion Serialization 
57
58         internal EncoderNLS(Encoding encoding)
59         {
60             this.m_encoding = encoding;
61             this.m_fallback = this.m_encoding.EncoderFallback;
62             this.Reset();
63         }
64
65         // This one is used when deserializing (like UTF7Encoding.Encoder)
66         internal EncoderNLS()
67         {
68             this.m_encoding = null;
69             this.Reset();
70         }
71
72         public override void Reset()
73         {
74             this.charLeftOver = (char)0;
75             if (m_fallbackBuffer != null)
76                 m_fallbackBuffer.Reset();
77         }
78
79         public override unsafe int GetByteCount(char[] chars, int index, int count, bool flush)
80         {
81             // Validate input parameters
82             if (chars == null)
83                 throw new ArgumentNullException(nameof(chars),
84                       Environment.GetResourceString("ArgumentNull_Array"));
85
86             if (index < 0 || count < 0)
87                 throw new ArgumentOutOfRangeException((index<0 ? nameof(index) : nameof(count)),
88                       Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
89
90             if (chars.Length - index < count)
91                 throw new ArgumentOutOfRangeException(nameof(chars),
92                       Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
93             Contract.EndContractBlock();
94
95             // Avoid empty input problem
96             if (chars.Length == 0)
97                 chars = new char[1];
98
99             // Just call the pointer version
100             int result = -1;
101             fixed (char* pChars = chars)
102             {
103                 result = GetByteCount(pChars + index, count, flush);
104             }
105             return result;
106         }
107
108         public unsafe override int GetByteCount(char* chars, int count, bool flush)
109         {
110             // Validate input parameters
111             if (chars == null)
112                 throw new ArgumentNullException(nameof(chars),
113                       Environment.GetResourceString("ArgumentNull_Array"));
114
115             if (count < 0)
116                 throw new ArgumentOutOfRangeException(nameof(count),
117                       Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
118             Contract.EndContractBlock();
119
120             this.m_mustFlush = flush;
121             this.m_throwOnOverflow = true;
122             return m_encoding.GetByteCount(chars, count, this);
123         }
124
125         public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
126                                               byte[] bytes, int byteIndex, bool flush)
127         {
128             // Validate parameters
129             if (chars == null || bytes == null)
130                 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
131                       Environment.GetResourceString("ArgumentNull_Array"));
132
133             if (charIndex < 0 || charCount < 0)
134                 throw new ArgumentOutOfRangeException((charIndex<0 ? nameof(charIndex) : nameof(charCount)),
135                       Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
136
137             if (chars.Length - charIndex < charCount)
138                 throw new ArgumentOutOfRangeException(nameof(chars),
139                       Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
140
141             if (byteIndex < 0 || byteIndex > bytes.Length)
142                 throw new ArgumentOutOfRangeException(nameof(byteIndex),
143                      Environment.GetResourceString("ArgumentOutOfRange_Index"));
144             Contract.EndContractBlock();
145
146             if (chars.Length == 0)
147                 chars = new char[1];
148
149             int byteCount = bytes.Length - byteIndex;
150             if (bytes.Length == 0)
151                 bytes = new byte[1];
152
153             // Just call pointer version
154             fixed (char* pChars = chars)
155                 fixed (byte* pBytes = bytes)
156
157                     // Remember that charCount is # to decode, not size of array.
158                     return GetBytes(pChars + charIndex, charCount,
159                                     pBytes + byteIndex, byteCount, flush);
160         }
161
162         public unsafe override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount, bool flush)
163         {
164             // Validate parameters
165             if (chars == null || bytes == null)
166                 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
167                       Environment.GetResourceString("ArgumentNull_Array"));
168
169             if (byteCount < 0 || charCount < 0)
170                 throw new ArgumentOutOfRangeException((byteCount<0 ? nameof(byteCount) : nameof(charCount)),
171                       Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
172             Contract.EndContractBlock();
173
174             this.m_mustFlush = flush;
175             this.m_throwOnOverflow = true;
176             return m_encoding.GetBytes(chars, charCount, bytes, byteCount, this);
177         }
178
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)
184         {
185             // Validate parameters
186             if (chars == null || bytes == null)
187                 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
188                       Environment.GetResourceString("ArgumentNull_Array"));
189
190             if (charIndex < 0 || charCount < 0)
191                 throw new ArgumentOutOfRangeException((charIndex<0 ? nameof(charIndex) : nameof(charCount)),
192                       Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
193
194             if (byteIndex < 0 || byteCount < 0)
195                 throw new ArgumentOutOfRangeException((byteIndex<0 ? nameof(byteIndex) : nameof(byteCount)),
196                       Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
197
198             if (chars.Length - charIndex < charCount)
199                 throw new ArgumentOutOfRangeException(nameof(chars),
200                       Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
201
202             if (bytes.Length - byteIndex < byteCount)
203                 throw new ArgumentOutOfRangeException(nameof(bytes),
204                       Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
205
206             Contract.EndContractBlock();
207
208             // Avoid empty input problem
209             if (chars.Length == 0)
210                 chars = new char[1];
211             if (bytes.Length == 0)
212                 bytes = new byte[1];
213
214             // Just call the pointer version (can't do this for non-msft encoders)
215             fixed (char* pChars = chars)
216             {
217                 fixed (byte* pBytes = bytes)
218                 {
219                     Convert(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, flush,
220                         out charsUsed, out bytesUsed, out completed);
221                 }
222             }
223         }
224
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)
230         {
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();
239
240             // We don't want to throw
241             this.m_mustFlush = flush;
242             this.m_throwOnOverflow = false;
243             this.m_charsUsed = 0;
244
245             // Do conversion
246             bytesUsed = this.m_encoding.GetBytes(chars, charCount, bytes, byteCount, this);
247             charsUsed = this.m_charsUsed;
248
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);
252
253             // Our data thingys are now full, we can return
254         }
255
256         public Encoding Encoding
257         {
258             get
259             {
260                 return m_encoding;
261             }
262         }
263
264         public bool MustFlush
265         {
266             get
267             {
268                 return m_mustFlush;
269             }
270         }
271
272
273         // Anything left in our encoder?
274         internal virtual bool HasState
275         {
276             get
277             {
278                 return (this.charLeftOver != (char)0);
279             }
280         }
281
282         // Allow encoding to clear our must flush instead of throwing (in ThrowBytesOverflow)
283         internal void ClearMustFlush()
284         {
285             m_mustFlush = false;
286         }
287
288     }
289 }