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)
47 if ((flags & IsTight) == 0)
48 throw new NotImplementedException ();
58 int len = value.Length;
59 bool negative = false;
62 // Mimic broken .net behaviour
63 throw new ArgumentOutOfRangeException ("Empty string");
67 if (value [i] == '-') {
69 throw new ArgumentException ("String cannot contain a minus sign if the base is not 10.");
71 if ((flags & TreatAsUnsigned) != 0)
72 throw new OverflowException ("Negative number");
76 } else if (value [i] == '+') {
80 if (fromBase == 16 && i + 1 < len && value [i] =='0' && (value [i + 1] == 'x' || value [i + 1] == 'X')) {
85 if ((flags & TreatAsI1) != 0) {
86 max_value = Byte.MaxValue;
87 } else if ((flags & TreatAsI2) != 0) {
88 max_value = UInt16.MaxValue;
90 max_value = UInt32.MaxValue;
95 if (Char.IsNumber (c)) {
97 } else if (Char.IsLetter (c)) {
98 digitValue = Char.ToLowerInvariant (c) - 'a' + 10;
101 throw new FormatException ("Additional unparsable characters are at the end of the string.");
104 throw new FormatException ("Could not find any parsable digits.");
107 if (digitValue >= fromBase) {
109 throw new FormatException ("Additional unparsable characters are at the end of the string.");
112 throw new FormatException ("Could not find any parsable digits.");
115 var res = (uint) fromBase * result + (uint) digitValue;
116 if (res < result || res > max_value)
117 throw new OverflowException ();
124 throw new FormatException ("Could not find any parsable digits.");
126 return negative ? -(int)result : (int)result;
129 public static string LongToString (long value, int toBase, int width, char paddingChar, int flags)
134 return value.ToString ();
136 byte[] val = BitConverter.GetBytes (value);
140 return ConvertToBase2 (val);
142 return ConvertToBase8 (val);
144 return ConvertToBase16 (val);
146 throw new NotImplementedException ();
150 public static long StringToLong (string value, int fromBase, int flags)
152 if ((flags & IsTight) == 0)
153 throw new NotImplementedException ();
163 int len = value.Length;
164 bool negative = false;
167 // Mimic broken .net behaviour
168 throw new ArgumentOutOfRangeException ("Empty string");
172 if (value [i] == '-') {
174 throw new ArgumentException ("String cannot contain a minus sign if the base is not 10.");
176 if ((flags & TreatAsUnsigned) != 0)
177 throw new OverflowException ("Negative number");
181 } else if (value [i] == '+') {
185 if (fromBase == 16 && i + 1 < len && value [i] =='0' && (value [i + 1] == 'x' || value [i + 1] == 'X')) {
191 if (Char.IsNumber (c)) {
192 digitValue = c - '0';
193 } else if (Char.IsLetter (c)) {
194 digitValue = Char.ToLowerInvariant (c) - 'a' + 10;
197 throw new FormatException ("Additional unparsable "
198 + "characters are at the end of the string.");
200 throw new FormatException ("Could not find any parsable"
205 if (digitValue >= fromBase) {
207 throw new FormatException ("Additional unparsable "
208 + "characters are at the end of the string.");
210 throw new FormatException ("Could not find any parsable"
215 result = fromBase * result + digitValue;
220 throw new FormatException ("Could not find any parsable digits.");
222 return negative ? -result : result;
225 public static string IntToString (int value, int toBase, int width, char paddingChar, int flags)
231 return value.ToString ();
234 if ((flags & PrintAsI1) != 0) {
235 val = BitConverter.GetBytes ((byte) value);
236 } else if ((flags & PrintAsI2) != 0) {
237 val = BitConverter.GetBytes ((short) value);
239 val = BitConverter.GetBytes (value);
244 return ConvertToBase2 (val);
246 return ConvertToBase8 (val);
248 return ConvertToBase16 (val);
250 throw new NotImplementedException ();
254 static void EndianSwap (ref byte[] value)
256 byte[] buf = new byte[value.Length];
257 for (int i = 0; i < value.Length; i++)
258 buf[i] = value[value.Length-1-i];
262 static string ConvertToBase2 (byte[] value)
264 if (!BitConverter.IsLittleEndian)
265 EndianSwap (ref value);
266 StringBuilder sb = new StringBuilder ();
267 for (int i = value.Length - 1; i >= 0; i--) {
269 for (int j = 0; j < 8; j++) {
270 if ((b & 0x80) == 0x80) {
280 return sb.ToString ();
283 static string ConvertToBase8 (byte[] value)
286 switch (value.Length) {
288 l = (ulong) value [0];
291 l = (ulong) BitConverter.ToUInt16 (value, 0);
294 l = (ulong) BitConverter.ToUInt32 (value, 0);
297 l = BitConverter.ToUInt64 (value, 0);
300 throw new ArgumentException ("value");
303 StringBuilder sb = new StringBuilder ();
304 for (int i = 21; i >= 0; i--) {
305 // 3 bits at the time
306 char val = (char) ((l >> i * 3) & 0x7);
307 if ((val != 0) || (sb.Length > 0)) {
312 return sb.ToString ();
315 static string ConvertToBase16 (byte[] value)
317 if (!BitConverter.IsLittleEndian)
318 EndianSwap (ref value);
319 StringBuilder sb = new StringBuilder ();
320 for (int i = value.Length - 1; i >= 0; i--) {
321 char high = (char)((value[i] >> 4) & 0x0f);
322 if ((high != 0) || (sb.Length > 0)) {
332 char low = (char)(value[i] & 0x0f);
333 if ((low != 0) || (sb.Length > 0)) {
343 return sb.ToString ();