Merge pull request #12748 from helloguo/NUMASupportInitialize
[platform/upstream/coreclr.git] / src / mscorlib / shared / System / Text / DecoderNLS.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     // 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
17     // adjacent blocks.
18     //
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.
22
23     internal class DecoderNLS : Decoder
24     {
25         // Remember our encoding
26         private Encoding _encoding;
27         private bool _mustFlush;
28         internal bool _throwOnOverflow;
29         internal int _bytesUsed;
30
31         internal DecoderNLS(Encoding encoding)
32         {
33             _encoding = encoding;
34             _fallback = this._encoding.DecoderFallback;
35             this.Reset();
36         }
37
38         // This is used by our child deserializers
39         internal DecoderNLS()
40         {
41             _encoding = null;
42             this.Reset();
43         }
44
45         public override void Reset()
46         {
47             _fallbackBuffer?.Reset();
48         }
49
50         public override unsafe int GetCharCount(byte[] bytes, int index, int count)
51         {
52             return GetCharCount(bytes, index, count, false);
53         }
54
55         public override unsafe int GetCharCount(byte[] bytes, int index, int count, bool flush)
56         {
57             // Validate Parameters
58             if (bytes == null)
59                 throw new ArgumentNullException(nameof(bytes),
60                     SR.ArgumentNull_Array);
61
62             if (index < 0 || count < 0)
63                 throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)),
64                     SR.ArgumentOutOfRange_NeedNonNegNum);
65
66             if (bytes.Length - index < count)
67                 throw new ArgumentOutOfRangeException(nameof(bytes),
68                     SR.ArgumentOutOfRange_IndexCountBuffer);
69
70             Contract.EndContractBlock();
71
72             // Avoid null fixed problem
73             if (bytes.Length == 0)
74                 bytes = new byte[1];
75
76             // Just call pointer version
77             fixed (byte* pBytes = &bytes[0])
78                 return GetCharCount(pBytes + index, count, flush);
79         }
80
81         public unsafe override int GetCharCount(byte* bytes, int count, bool flush)
82         {
83             // Validate parameters
84             if (bytes == null)
85                 throw new ArgumentNullException(nameof(bytes),
86                       SR.ArgumentNull_Array);
87
88             if (count < 0)
89                 throw new ArgumentOutOfRangeException(nameof(count),
90                       SR.ArgumentOutOfRange_NeedNonNegNum);
91             Contract.EndContractBlock();
92
93             // Remember the flush
94             _mustFlush = flush;
95             _throwOnOverflow = true;
96
97             // By default just call the encoding version, no flush by default
98             return _encoding.GetCharCount(bytes, count, this);
99         }
100
101         public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
102                                              char[] chars, int charIndex)
103         {
104             return GetChars(bytes, byteIndex, byteCount, chars, charIndex, false);
105         }
106
107         public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
108                                              char[] chars, int charIndex, bool flush)
109         {
110             // Validate Parameters
111             if (bytes == null || chars == null)
112                 throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars),
113                     SR.ArgumentNull_Array);
114
115             if (byteIndex < 0 || byteCount < 0)
116                 throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)),
117                     SR.ArgumentOutOfRange_NeedNonNegNum);
118
119             if (bytes.Length - byteIndex < byteCount)
120                 throw new ArgumentOutOfRangeException(nameof(bytes),
121                     SR.ArgumentOutOfRange_IndexCountBuffer);
122
123             if (charIndex < 0 || charIndex > chars.Length)
124                 throw new ArgumentOutOfRangeException(nameof(charIndex),
125                     SR.ArgumentOutOfRange_Index);
126
127             Contract.EndContractBlock();
128
129             // Avoid empty input fixed problem
130             if (bytes.Length == 0)
131                 bytes = new byte[1];
132
133             int charCount = chars.Length - charIndex;
134             if (chars.Length == 0)
135                 chars = new char[1];
136
137             // Just call pointer version
138             fixed (byte* pBytes = &bytes[0])
139             fixed (char* pChars = &chars[0])
140                 // Remember that charCount is # to decode, not size of array
141                 return GetChars(pBytes + byteIndex, byteCount,
142                                 pChars + charIndex, charCount, flush);
143         }
144
145         public unsafe override int GetChars(byte* bytes, int byteCount,
146                                               char* chars, int charCount, bool flush)
147         {
148             // Validate parameters
149             if (chars == null || bytes == null)
150                 throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)),
151                       SR.ArgumentNull_Array);
152
153             if (byteCount < 0 || charCount < 0)
154                 throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
155                       SR.ArgumentOutOfRange_NeedNonNegNum);
156             Contract.EndContractBlock();
157
158             // Remember our flush
159             _mustFlush = flush;
160             _throwOnOverflow = true;
161
162             // By default just call the encodings version
163             return _encoding.GetChars(bytes, byteCount, chars, charCount, this);
164         }
165
166         // This method is used when the output buffer might not be big enough.
167         // Just call the pointer version.  (This gets chars)
168         public override unsafe void Convert(byte[] bytes, int byteIndex, int byteCount,
169                                               char[] chars, int charIndex, int charCount, bool flush,
170                                               out int bytesUsed, out int charsUsed, out bool completed)
171         {
172             // Validate parameters
173             if (bytes == null || chars == null)
174                 throw new ArgumentNullException((bytes == null ? nameof(bytes) : nameof(chars)),
175                       SR.ArgumentNull_Array);
176
177             if (byteIndex < 0 || byteCount < 0)
178                 throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)),
179                       SR.ArgumentOutOfRange_NeedNonNegNum);
180
181             if (charIndex < 0 || charCount < 0)
182                 throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)),
183                       SR.ArgumentOutOfRange_NeedNonNegNum);
184
185             if (bytes.Length - byteIndex < byteCount)
186                 throw new ArgumentOutOfRangeException(nameof(bytes),
187                       SR.ArgumentOutOfRange_IndexCountBuffer);
188
189             if (chars.Length - charIndex < charCount)
190                 throw new ArgumentOutOfRangeException(nameof(chars),
191                       SR.ArgumentOutOfRange_IndexCountBuffer);
192
193             Contract.EndContractBlock();
194
195             // Avoid empty input problem
196             if (bytes.Length == 0)
197                 bytes = new byte[1];
198             if (chars.Length == 0)
199                 chars = new char[1];
200
201             // Just call the pointer version (public overrides can't do this)
202             fixed (byte* pBytes = &bytes[0])
203             {
204                 fixed (char* pChars = &chars[0])
205                 {
206                     Convert(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, flush,
207                         out bytesUsed, out charsUsed, out completed);
208                 }
209             }
210         }
211
212         // This is the version that used pointers.  We call the base encoding worker function
213         // after setting our appropriate internal variables.  This is getting chars
214         public unsafe override void Convert(byte* bytes, int byteCount,
215                                               char* chars, int charCount, bool flush,
216                                               out int bytesUsed, out int charsUsed, out bool completed)
217         {
218             // Validate input parameters
219             if (chars == null || bytes == null)
220                 throw new ArgumentNullException(chars == null ? nameof(chars) : nameof(bytes),
221                     SR.ArgumentNull_Array);
222
223             if (byteCount < 0 || charCount < 0)
224                 throw new ArgumentOutOfRangeException((byteCount < 0 ? nameof(byteCount) : nameof(charCount)),
225                     SR.ArgumentOutOfRange_NeedNonNegNum);
226             Contract.EndContractBlock();
227
228             // We don't want to throw
229             _mustFlush = flush;
230             _throwOnOverflow = false;
231             _bytesUsed = 0;
232
233             // Do conversion
234             charsUsed = _encoding.GetChars(bytes, byteCount, chars, charCount, this);
235             bytesUsed = _bytesUsed;
236
237             // Its completed if they've used what they wanted AND if they didn't want flush or if we are flushed
238             completed = (bytesUsed == byteCount) && (!flush || !this.HasState) &&
239                                (_fallbackBuffer == null || _fallbackBuffer.Remaining == 0);
240
241             // Our data thingy are now full, we can return
242         }
243
244         public bool MustFlush
245         {
246             get
247             {
248                 return _mustFlush;
249             }
250         }
251
252         // Anything left in our decoder?
253         internal virtual bool HasState
254         {
255             get
256             {
257                 return false;
258             }
259         }
260
261         // Allow encoding to clear our must flush instead of throwing (in ThrowCharsOverflow)
262         internal void ClearMustFlush()
263         {
264             _mustFlush = false;
265         }
266     }
267 }