[System] Process.WaitForExit now triggers event Exited.
[mono.git] / mcs / class / corlib / ReferenceSources / ParseNumbers.cs
1 //
2 // ParseNumbers.cs
3 //
4 // Authors:
5 //      Marek Safar  <marek.safar@gmail.com>
6 //
7 // Copyright (C) 2015 Xamarin Inc (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System.Globalization;
30 using System.Text;
31
32 namespace System {
33    
34     static class ParseNumbers
35     {
36         internal const int PrintAsI1=0x40;
37         internal const int PrintAsI2=0x80;
38 //        internal const int PrintAsI4=0x100;
39         internal const int TreatAsUnsigned=0x200;
40         internal const int TreatAsI1=0x400;
41         internal const int TreatAsI2=0x800;
42         internal const int IsTight=0x1000;
43         internal const int NoSpace=0x2000;
44
45                 public static int StringToInt (string value, int fromBase, int flags)
46                 {
47                         unsafe {
48                                 return StringToInt (value, fromBase, flags, null);
49                         }
50                 }
51
52                 public unsafe static int StringToInt (string value, int fromBase, int flags, int* parsePos)
53                 {
54                         if ((flags & (IsTight | NoSpace)) == 0)
55                                 throw new NotImplementedException (flags.ToString ());
56                         
57                         if (value == null)
58                                 return 0;
59
60                         int chars = 0;
61                         uint result = 0;
62                         int digitValue;
63
64                         int len = value.Length;
65                         bool negative = false;
66
67                         if (len == 0) {
68                                 // Mimic broken .net behaviour
69                                 throw new ArgumentOutOfRangeException ("Empty string");
70                         }
71
72                         int i = parsePos == null ? 0 : *parsePos;
73
74                         //Check for a sign
75                         if (value [i] == '-') {
76                                 if (fromBase != 10)
77                                         throw new ArgumentException ("String cannot contain a minus sign if the base is not 10.");
78
79                                 if ((flags & TreatAsUnsigned) != 0)
80                                         throw new OverflowException ("Negative number");
81
82                                 negative = true;
83                                 i++;
84                         } else if (value [i] == '+') {
85                                 i++;
86                         }
87
88                         if (fromBase == 16 && i + 1 < len && value [i] =='0' && (value [i + 1] == 'x' || value [i + 1] == 'X')) {
89                                 i += 2;
90                         }
91
92                         uint max_value;
93                         if ((flags & TreatAsI1) != 0) {
94                                 max_value = Byte.MaxValue;
95                         } else if ((flags & TreatAsI2) != 0) {
96                                 max_value = UInt16.MaxValue;
97                         } else {
98                                 max_value = UInt32.MaxValue;
99                         }
100
101                         while (i < len) {
102                                 char c = value [i];
103                                 if (Char.IsNumber (c)) {
104                                         digitValue = c - '0';
105                                 } else if (Char.IsLetter (c)) {
106                                         digitValue = Char.ToLowerInvariant (c) - 'a' + 10;
107                                 } else {
108                                         if (i == 0)
109                                                 throw new FormatException ("Could not find any parsable digits.");
110                                         
111                                         if ((flags & IsTight) != 0)
112                                                 throw new FormatException ("Additional unparsable characters are at the end of the string.");
113                                         
114                                         break;
115                                 }
116
117                                 if (digitValue >= fromBase) {
118                                         if (chars > 0) {
119                                                 throw new FormatException ("Additional unparsable characters are at the end of the string.");
120                                         }
121
122                                         throw new FormatException ("Could not find any parsable digits.");
123                                 }
124
125                                 var res = (uint) fromBase * result + (uint) digitValue;
126                                 if (res < result || res > max_value)
127                                         throw new OverflowException ();
128                                         
129                                 result = res;
130                                 chars++;
131                                 ++i;
132                         }
133
134                         if (chars == 0)
135                                 throw new FormatException ("Could not find any parsable digits.");
136
137                         if (parsePos != null)
138                                 *parsePos = i;
139
140                         return negative ? -(int)result : (int)result;
141                 }        
142
143                 public static string LongToString (long value, int toBase, int width, char paddingChar, int flags)
144         {
145                         if (value == 0)
146                                 return "0";
147                         if (toBase == 10)
148                                 return value.ToString ();
149
150                         byte[] val = BitConverter.GetBytes (value);
151
152                         switch (toBase) {
153                         case 2:
154                                 return ConvertToBase2 (val).ToString ();
155                         case 8:
156                                 return ConvertToBase8 (val).ToString ();
157                         case 16:
158                                 return ConvertToBase16 (val).ToString ();
159                         default:
160                                 throw new NotImplementedException ();
161                         }
162         }
163
164                 public static long StringToLong (string value, int fromBase, int flags)
165                 {
166                         unsafe {
167                                 return StringToLong (value, fromBase, flags, null);
168                         }
169                 }
170
171                 public unsafe static long StringToLong (string value, int fromBase, int flags, int* parsePos)
172                 {
173                         if ((flags & (IsTight | NoSpace)) == 0)
174                                 throw new NotImplementedException (flags.ToString ());
175
176                         if (value == null)
177                                 return 0;
178
179                         int chars = 0;
180                         int digitValue = -1;
181                         long result = 0;
182
183                         int len = value.Length;
184                         bool negative = false;
185
186                         if (len == 0) {
187                                 // Mimic broken .net behaviour
188                                 throw new ArgumentOutOfRangeException ("Empty string");
189                         }
190
191                         int i = parsePos == null ? 0 : *parsePos;
192
193                         //Check for a sign
194                         if (value [i] == '-') {
195                                 if (fromBase != 10)
196                                         throw new ArgumentException ("String cannot contain a minus sign if the base is not 10.");
197
198                                 if ((flags & TreatAsUnsigned) != 0)
199                                         throw new OverflowException ("Negative number");
200
201                                 negative = true;
202                                 i++;
203                         } else if (value [i] == '+') {
204                                 i++;
205                         }
206
207                         if (fromBase == 16 && i + 1 < len && value [i] =='0' && (value [i + 1] == 'x' || value [i + 1] == 'X')) {
208                                 i += 2;
209                         }
210
211                         while (i < len) {
212                                 char c = value[i];
213                                 if (Char.IsNumber (c)) {
214                                         digitValue = c - '0';
215                                 } else if (Char.IsLetter (c)) {
216                                         digitValue = Char.ToLowerInvariant (c) - 'a' + 10;
217                                 } else {
218                                         if (i == 0)
219                                                 throw new FormatException ("Could not find any parsable digits.");
220
221                                         if ((flags & IsTight) != 0)
222                                                 throw new FormatException ("Additional unparsable characters are at the end of the string.");
223
224                                         break;
225                                 }
226
227                                 if (digitValue >= fromBase) {
228                                         if (chars > 0) {
229                                                 throw new FormatException ("Additional unparsable "
230                                                         + "characters are at the end of the string.");
231                                         } else {
232                                                 throw new FormatException ("Could not find any parsable"
233                                                         + " digits.");
234                                         }
235                                 }
236
237                                 result = fromBase * result + digitValue;
238                                 chars++;
239                                 ++i;
240                         }
241
242                         if (chars == 0)
243                                 throw new FormatException ("Could not find any parsable digits.");
244
245                         if (parsePos != null)
246                                 *parsePos = i;
247
248                         return negative ? -result : result;
249                 }
250
251                 public static string IntToString (int value, int toBase, int width, char paddingChar, int flags)
252                 {
253                         StringBuilder sb;
254
255                         if (value == 0) {
256                                 if (width <= 0)
257                                         return "0";
258
259                                 sb = new StringBuilder ("0", width);
260                         } else if (toBase == 10)
261                                 sb = new StringBuilder (value.ToString ());
262                         else {
263                                 byte[] val;
264                                 if ((flags & PrintAsI1) != 0) {
265                                         val = BitConverter.GetBytes ((byte) value);
266                                 } else if ((flags & PrintAsI2) != 0) {
267                                         val = BitConverter.GetBytes ((short) value);
268                                 } else {
269                                         val = BitConverter.GetBytes (value);
270                                 }
271
272                                 switch (toBase) {
273                                 case 2:
274                                         sb = ConvertToBase2 (val);
275                                         break;
276                                 case 8:
277                                         sb = ConvertToBase8 (val);
278                                         break;
279                                 case 16:
280                                         sb = ConvertToBase16 (val);
281                                         break;
282                                 default:
283                                         throw new NotImplementedException ();
284                                 }
285                         }
286
287                         var padding = width - sb.Length;
288                         while (padding > 0) {
289                                 sb.Insert (0, paddingChar);
290                                 --padding;
291                         }
292
293                         return sb.ToString ();
294                 }
295
296                 static void EndianSwap (ref byte[] value)
297                 {
298                         byte[] buf = new byte[value.Length];
299                         for (int i = 0; i < value.Length; i++)
300                                 buf[i] = value[value.Length-1-i];
301                         value = buf;
302                 }
303
304                 static StringBuilder ConvertToBase2 (byte[] value)
305                 {
306                         if (!BitConverter.IsLittleEndian)
307                                 EndianSwap (ref value);
308                         StringBuilder sb = new StringBuilder ();
309                         for (int i = value.Length - 1; i >= 0; i--) {
310                                 byte b = value [i];
311                                 for (int j = 0; j < 8; j++) {
312                                         if ((b & 0x80) == 0x80) {
313                                                 sb.Append ('1');
314                                         }
315                                         else {
316                                                 if (sb.Length > 0)
317                                                         sb.Append ('0');
318                                         }
319                                         b <<= 1;
320                                 }
321                         }
322                         return sb;
323                 }
324
325                 static StringBuilder ConvertToBase8 (byte[] value)
326                 {
327                         ulong l = 0;
328                         switch (value.Length) {
329                         case 1:
330                                 l = (ulong) value [0];
331                                 break;
332                         case 2:
333                                 l = (ulong) BitConverter.ToUInt16 (value, 0);
334                                 break;
335                         case 4:
336                                 l = (ulong) BitConverter.ToUInt32 (value, 0);
337                                 break;
338                         case 8:
339                                 l = BitConverter.ToUInt64 (value, 0);
340                                 break;
341                         default:
342                                 throw new ArgumentException ("value");
343                         }
344
345                         StringBuilder sb = new StringBuilder ();
346                         for (int i = 21; i >= 0; i--) {
347                                 // 3 bits at the time
348                                 char val = (char) ((l >> i * 3) & 0x7);
349                                 if ((val != 0) || (sb.Length > 0)) {
350                                         val += '0';
351                                         sb.Append (val);
352                                 }
353                         }
354                         return sb;
355                 }
356
357                 static StringBuilder ConvertToBase16 (byte[] value)
358                 {
359                         if (!BitConverter.IsLittleEndian)
360                                 EndianSwap (ref value);
361                         StringBuilder sb = new StringBuilder ();
362                         for (int i = value.Length - 1; i >= 0; i--) {
363                                 char high = (char)((value[i] >> 4) & 0x0f);
364                                 if ((high != 0) || (sb.Length > 0)) {
365                                         if (high < 10) 
366                                                 high += '0';
367                                         else {
368                                                 high -= (char) 10;
369                                                 high += 'a';
370                                         }
371                                         sb.Append (high);
372                                 }
373
374                                 char low = (char)(value[i] & 0x0f);
375                                 if ((low != 0) || (sb.Length > 0)) {
376                                         if (low < 10)
377                                                 low += '0';
378                                         else {
379                                                 low -= (char) 10;
380                                                 low += 'a';
381                                         }
382                                         sb.Append (low);
383                                 }
384                         }
385                         return sb;
386                 }
387
388     }
389 }