Merge pull request #12748 from helloguo/NUMASupportInitialize
[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 using System.Runtime.Serialization;
6 using System.Text;
7 using System;
8 using System.Diagnostics.Contracts;
9
10 namespace System.Text
11 {
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     internal class EncoderNLS : Encoder, ISerializable
25     {
26         // Need a place for the last left over character, most of our encodings use this
27         internal char charLeftOver;
28
29         protected Encoding m_encoding;
30
31         [NonSerialized] protected bool m_mustFlush;
32         [NonSerialized] internal bool m_throwOnOverflow;
33         [NonSerialized] internal int m_charsUsed;
34
35         #region Serialization
36
37         // ISerializable implementation.
38         void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
39         {
40             throw new PlatformNotSupportedException();
41         }
42
43         #endregion Serialization 
44
45         internal EncoderNLS(Encoding encoding)
46         {
47             this.m_encoding = encoding;
48             this.m_fallback = this.m_encoding.EncoderFallback;
49             this.Reset();
50         }
51
52         // This one is used when deserializing (like UTF7Encoding.Encoder)
53         internal EncoderNLS()
54         {
55             this.m_encoding = null;
56             this.Reset();
57         }
58
59         public override void Reset()
60         {
61             this.charLeftOver = (char)0;
62             if (m_fallbackBuffer != null)
63                 m_fallbackBuffer.Reset();
64         }
65
66         public override unsafe int GetByteCount(char[] chars, int index, int count, bool flush)
67         {
68             // Validate input parameters
69             if (chars == null)
70                 throw new ArgumentNullException(nameof(chars),
71                       SR.ArgumentNull_Array);
72
73             if (index < 0 || count < 0)
74                 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)),
75                       SR.ArgumentOutOfRange_NeedNonNegNum);
76
77             if (chars.Length - index < count)
78                 throw new ArgumentOutOfRangeException(nameof(chars),
79                       SR.ArgumentOutOfRange_IndexCountBuffer);
80             Contract.EndContractBlock();
81
82             // Avoid empty input problem
83             if (chars.Length == 0)
84                 chars = new char[1];
85
86             // Just call the pointer version
87             int result = -1;
88             fixed (char* pChars = &chars[0])
89             {
90                 result = GetByteCount(pChars + index, count, flush);
91             }
92             return result;
93         }
94
95         public unsafe override int GetByteCount(char* chars, int count, bool flush)
96         {
97             // Validate input parameters
98             if (chars == null)
99                 throw new ArgumentNullException(nameof(chars),
100                       SR.ArgumentNull_Array);
101
102             if (count < 0)
103                 throw new ArgumentOutOfRangeException(nameof(count),
104                       SR.ArgumentOutOfRange_NeedNonNegNum);
105             Contract.EndContractBlock();
106
107             this.m_mustFlush = flush;
108             this.m_throwOnOverflow = true;
109             return m_encoding.GetByteCount(chars, count, this);
110         }
111
112         public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
113                                               byte[] bytes, int byteIndex, bool flush)
114         {
115             // Validate parameters
116             if (chars == null || bytes == null)
117                 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
118                       SR.ArgumentNull_Array);
119
120             if (charIndex < 0 || charCount < 0)
121                 throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
122                       SR.ArgumentOutOfRange_NeedNonNegNum);
123
124             if (chars.Length - charIndex < charCount)
125                 throw new ArgumentOutOfRangeException(nameof(chars),
126                       SR.ArgumentOutOfRange_IndexCountBuffer);
127
128             if (byteIndex < 0 || byteIndex > bytes.Length)
129                 throw new ArgumentOutOfRangeException(nameof(byteIndex),
130                      SR.ArgumentOutOfRange_Index);
131             Contract.EndContractBlock();
132
133             if (chars.Length == 0)
134                 chars = new char[1];
135
136             int byteCount = bytes.Length - byteIndex;
137             if (bytes.Length == 0)
138                 bytes = new byte[1];
139
140             // Just call pointer version
141             fixed (char* pChars = &chars[0])
142             fixed (byte* pBytes = &bytes[0])
143
144                 // Remember that charCount is # to decode, not size of array.
145                 return GetBytes(pChars + charIndex, charCount,
146                                 pBytes + byteIndex, byteCount, flush);
147         }
148
149         public unsafe override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount, bool flush)
150         {
151             // Validate parameters
152             if (chars == null || bytes == null)
153                 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
154                       SR.ArgumentNull_Array);
155
156             if (byteCount < 0 || charCount < 0)
157                 throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
158                       SR.ArgumentOutOfRange_NeedNonNegNum);
159             Contract.EndContractBlock();
160
161             this.m_mustFlush = flush;
162             this.m_throwOnOverflow = true;
163             return m_encoding.GetBytes(chars, charCount, bytes, byteCount, this);
164         }
165
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)
171         {
172             // Validate parameters
173             if (chars == null || bytes == null)
174                 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
175                       SR.ArgumentNull_Array);
176
177             if (charIndex < 0 || charCount < 0)
178                 throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
179                       SR.ArgumentOutOfRange_NeedNonNegNum);
180
181             if (byteIndex < 0 || byteCount < 0)
182                 throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)),
183                       SR.ArgumentOutOfRange_NeedNonNegNum);
184
185             if (chars.Length - charIndex < charCount)
186                 throw new ArgumentOutOfRangeException(nameof(chars),
187                       SR.ArgumentOutOfRange_IndexCountBuffer);
188
189             if (bytes.Length - byteIndex < byteCount)
190                 throw new ArgumentOutOfRangeException(nameof(bytes),
191                       SR.ArgumentOutOfRange_IndexCountBuffer);
192
193             Contract.EndContractBlock();
194
195             // Avoid empty input problem
196             if (chars.Length == 0)
197                 chars = new char[1];
198             if (bytes.Length == 0)
199                 bytes = new byte[1];
200
201             // Just call the pointer version (can't do this for non-msft encoders)
202             fixed (char* pChars = &chars[0])
203             {
204                 fixed (byte* pBytes = &bytes[0])
205                 {
206                     Convert(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, flush,
207                         out charsUsed, out bytesUsed, out completed);
208                 }
209             }
210         }
211
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)
217         {
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();
226
227             // We don't want to throw
228             this.m_mustFlush = flush;
229             this.m_throwOnOverflow = false;
230             this.m_charsUsed = 0;
231
232             // Do conversion
233             bytesUsed = this.m_encoding.GetBytes(chars, charCount, bytes, byteCount, this);
234             charsUsed = this.m_charsUsed;
235
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);
239
240             // Our data thingys are now full, we can return
241         }
242
243         public Encoding Encoding
244         {
245             get
246             {
247                 return m_encoding;
248             }
249         }
250
251         public bool MustFlush
252         {
253             get
254             {
255                 return m_mustFlush;
256             }
257         }
258
259
260         // Anything left in our encoder?
261         internal virtual bool HasState
262         {
263             get
264             {
265                 return (this.charLeftOver != (char)0);
266             }
267         }
268
269         // Allow encoding to clear our must flush instead of throwing (in ThrowBytesOverflow)
270         internal void ClearMustFlush()
271         {
272             m_mustFlush = false;
273         }
274     }
275 }