5 // Marek Safar <marek.safar@gmail.com>
7 // Copyright (C) 2015 Xamarin Inc (http://www.xamarin.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
29 using System.Globalization;
34 static class ParseNumbers
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;
45 public static int StringToInt (string value, int fromBase, int flags)
48 return StringToInt (value, fromBase, flags, null);
52 public unsafe static int StringToInt (string value, int fromBase, int flags, int* parsePos)
54 if ((flags & (IsTight | NoSpace)) == 0)
55 throw new NotImplementedException (flags.ToString ());
64 int len = value.Length;
65 bool negative = false;
68 // Mimic broken .net behaviour
69 throw new ArgumentOutOfRangeException ("Empty string");
72 int i = parsePos == null ? 0 : *parsePos;
75 if (value [i] == '-') {
77 throw new ArgumentException ("String cannot contain a minus sign if the base is not 10.");
79 if ((flags & TreatAsUnsigned) != 0)
80 throw new OverflowException ("Negative number");
84 } else if (value [i] == '+') {
88 if (fromBase == 16 && i + 1 < len && value [i] =='0' && (value [i + 1] == 'x' || value [i + 1] == 'X')) {
93 if ((flags & TreatAsI1) != 0) {
94 max_value = Byte.MaxValue;
95 } else if ((flags & TreatAsI2) != 0) {
96 max_value = UInt16.MaxValue;
98 max_value = UInt32.MaxValue;
103 if (Char.IsNumber (c)) {
104 digitValue = c - '0';
105 } else if (Char.IsLetter (c)) {
106 digitValue = Char.ToLowerInvariant (c) - 'a' + 10;
109 throw new FormatException ("Could not find any parsable digits.");
111 if ((flags & IsTight) != 0)
112 throw new FormatException ("Additional unparsable characters are at the end of the string.");
117 if (digitValue >= fromBase) {
119 throw new FormatException ("Additional unparsable characters are at the end of the string.");
122 throw new FormatException ("Could not find any parsable digits.");
125 var res = (uint) fromBase * result + (uint) digitValue;
126 if (res < result || res > max_value)
127 throw new OverflowException ();
135 throw new FormatException ("Could not find any parsable digits.");
137 if (parsePos != null)
140 return negative ? -(int)result : (int)result;
143 public static string LongToString (long value, int toBase, int width, char paddingChar, int flags)
148 return value.ToString ();
150 byte[] val = BitConverter.GetBytes (value);
154 return ConvertToBase2 (val).ToString ();
156 return ConvertToBase8 (val).ToString ();
158 return ConvertToBase16 (val).ToString ();
160 throw new NotImplementedException ();
164 public static long StringToLong (string value, int fromBase, int flags)
167 return StringToLong (value, fromBase, flags, null);
171 public unsafe static long StringToLong (string value, int fromBase, int flags, int* parsePos)
173 if ((flags & (IsTight | NoSpace)) == 0)
174 throw new NotImplementedException (flags.ToString ());
183 int len = value.Length;
184 bool negative = false;
187 // Mimic broken .net behaviour
188 throw new ArgumentOutOfRangeException ("Empty string");
191 int i = parsePos == null ? 0 : *parsePos;
194 if (value [i] == '-') {
196 throw new ArgumentException ("String cannot contain a minus sign if the base is not 10.");
198 if ((flags & TreatAsUnsigned) != 0)
199 throw new OverflowException ("Negative number");
203 } else if (value [i] == '+') {
207 if (fromBase == 16 && i + 1 < len && value [i] =='0' && (value [i + 1] == 'x' || value [i + 1] == 'X')) {
213 if (Char.IsNumber (c)) {
214 digitValue = c - '0';
215 } else if (Char.IsLetter (c)) {
216 digitValue = Char.ToLowerInvariant (c) - 'a' + 10;
219 throw new FormatException ("Could not find any parsable digits.");
221 if ((flags & IsTight) != 0)
222 throw new FormatException ("Additional unparsable characters are at the end of the string.");
227 if (digitValue >= fromBase) {
229 throw new FormatException ("Additional unparsable "
230 + "characters are at the end of the string.");
232 throw new FormatException ("Could not find any parsable"
237 result = fromBase * result + digitValue;
243 throw new FormatException ("Could not find any parsable digits.");
245 if (parsePos != null)
248 return negative ? -result : result;
251 public static string IntToString (int value, int toBase, int width, char paddingChar, int flags)
259 sb = new StringBuilder ("0", width);
260 } else if (toBase == 10)
261 sb = new StringBuilder (value.ToString ());
264 if ((flags & PrintAsI1) != 0) {
265 val = BitConverter.GetBytes ((byte) value);
266 } else if ((flags & PrintAsI2) != 0) {
267 val = BitConverter.GetBytes ((short) value);
269 val = BitConverter.GetBytes (value);
274 sb = ConvertToBase2 (val);
277 sb = ConvertToBase8 (val);
280 sb = ConvertToBase16 (val);
283 throw new NotImplementedException ();
287 var padding = width - sb.Length;
288 while (padding > 0) {
289 sb.Insert (0, paddingChar);
293 return sb.ToString ();
296 static void EndianSwap (ref byte[] value)
298 byte[] buf = new byte[value.Length];
299 for (int i = 0; i < value.Length; i++)
300 buf[i] = value[value.Length-1-i];
304 static StringBuilder ConvertToBase2 (byte[] value)
306 if (!BitConverter.IsLittleEndian)
307 EndianSwap (ref value);
308 StringBuilder sb = new StringBuilder ();
309 for (int i = value.Length - 1; i >= 0; i--) {
311 for (int j = 0; j < 8; j++) {
312 if ((b & 0x80) == 0x80) {
325 static StringBuilder ConvertToBase8 (byte[] value)
328 switch (value.Length) {
330 l = (ulong) value [0];
333 l = (ulong) BitConverter.ToUInt16 (value, 0);
336 l = (ulong) BitConverter.ToUInt32 (value, 0);
339 l = BitConverter.ToUInt64 (value, 0);
342 throw new ArgumentException ("value");
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)) {
357 static StringBuilder ConvertToBase16 (byte[] value)
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)) {
374 char low = (char)(value[i] & 0x0f);
375 if ((low != 0) || (sb.Length > 0)) {