(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / Microsoft.VisualBasic / Microsoft.VisualBasic / Conversion.cs
blob1d32ca56af3dd3a14c06e3cc05124ae9d6a6f043
1 //
2 // Conversion.cs
3 //
4 // Author:
5 // Chris J Breisch (cjbreisch@altavista.net)
6 //
7 // (C) 2002 Chris J Breisch
8 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System;
34 using System.Text.RegularExpressions;
35 using Microsoft.VisualBasic.CompilerServices;
37 namespace Microsoft.VisualBasic {
38 [StandardModule]
39 sealed public class Conversion {
40 ///
41 /// <summary>
42 /// Collection : The BASIC Collection Object
43 /// </summary>
44 ///
45 /// <remarks>
46 /// </remarks>
47 private Conversion ()
49 //Nothing to do, nobody should see this constructor
52 // Declarations
53 private static readonly char[] _HexDigits = {
54 '0', '1', '2', '3', '4', '5', '6', '7',
55 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
57 private static readonly char[] _OctDigits = {
58 '0', '1', '2', '3', '4', '5', '6', '7'
60 private static readonly long[] _Maxes = {
61 32767, 2147483647, 9223372036854775807
63 private enum SizeIndexes {
64 Int16 = 0,
65 Int32 = 1,
66 Int64 = 2
69 // Constructors
70 // Properties
71 // Methods
73 public static string ErrorToString () {
74 return Information.Err().Description;
77 public static string ErrorToString (System.Int32 ErrorNumber) {
78 if(ErrorNumber >= 65535)
79 throw new ArgumentException(VBUtils.GetResourceString("MaxErrNumber"));
80 if(ErrorNumber == 0)
81 return Information.Err().Description;
83 String errStr = VBUtils.GetResourceString(ErrorNumber);
85 if (errStr == null)
86 errStr = VBUtils.GetResourceString(95);
88 return errStr;
91 // Return whether d is +/- Could do this with a macro,
92 // but this is cleaner
93 private static int Sign(double d) { return d > 0 ? 1 : -1;}
95 // try to cast an Object to a string...used in several places
96 private static string CastToString (System.Object Expression) {
97 try {
98 return Expression.ToString();
100 catch {
101 throw new InvalidCastException();
105 // Fix on Integer types doesn't do anything
106 public static short Fix (short Number) { return Number; }
107 public static int Fix (int Number) { return Number; }
108 public static long Fix (long Number) { return Number; }
110 // Fix on other numberic types = Sign(Number) * Int(Abs(Number))
111 public static double Fix (double Number) {
112 return Sign(Number) * Int (Math.Abs (Number));
114 public static float Fix (float Number) {
115 return Sign(Number) * Int (Math.Abs (Number));
117 public static decimal Fix (decimal Number) {
118 return Sign((double)Number) * Int (Math.Abs (Number));
121 // Fix on an Object type is trickier
122 // first we have to cast it to the right type
123 public static System.Object Fix (System.Object Number)
125 // always start out by throwing an exception
126 // if Number is null
127 if (Number == null) {
128 throw new ArgumentNullException ("Number",
129 "Value cannot be null");
132 TypeCode TC = Type.GetTypeCode (Number.GetType ());
134 // switch on TypeCode and call appropriate Fix method
135 switch (TC) {
136 case TypeCode.Decimal:
137 return Fix (Convert.ToDecimal (Number));
138 case TypeCode.Double:
139 return Fix (Convert.ToDouble (Number));
140 case TypeCode.Single:
141 return Fix (Convert.ToSingle (Number));
142 case TypeCode.String:
143 return Fix (Double.Parse (
144 CastToString (Number)));
146 // for integer types, don't need to do anything
147 case TypeCode.Byte:
148 case TypeCode.Int16:
149 case TypeCode.Int32:
150 case TypeCode.Int64:
151 case TypeCode.SByte:
152 case TypeCode.UInt16:
153 case TypeCode.UInt32:
154 case TypeCode.UInt64:
155 return Number;
157 // spec defines Empty as returning 0
158 case TypeCode.Empty:
159 return 0;
161 // we can't convert these types
162 case TypeCode.Boolean:
163 case TypeCode.Char:
164 case TypeCode.DateTime:
165 case TypeCode.DBNull:
166 case TypeCode.Object:
167 default:
168 throw new ArgumentException (
169 "Type of argument 'Number' is '"
170 + Number.GetType().FullName +
171 "', which is not numeric.");
175 // Int on Integer types doesn't do anything
176 public static short Int (short Number) { return Number; }
177 public static int Int (int Number) { return Number; }
178 public static long Int (long Number) { return Number; }
180 // Int on other numberic types is same thing as "Floor"
181 public static double Int (double Number) {
182 return (double) Math.Floor(Number);
184 public static float Int (float Number) {
185 return (float) Math.Floor(Number);
187 public static decimal Int (decimal Number) {
188 return Decimal.Floor(Number);
191 // doing an Int on an Object is trickier
192 // first we have to cast to the correct type
193 public static System.Object Int (System.Object Number) {
194 // always start out by throwing an exception
195 // if Number is null
196 if (Number == null) {
197 throw new ArgumentNullException("Number",
198 "Value cannot be null");
201 TypeCode TC = Type.GetTypeCode (Number.GetType ());
203 // switch on TypeCode and call appropriate Int method
204 switch (TC) {
205 case TypeCode.Decimal:
206 return Int (Convert.ToDecimal (Number));
207 case TypeCode.Double:
208 return Int (Convert.ToDouble (Number));
209 case TypeCode.Single:
210 return Int (Convert.ToSingle (Number));
211 case TypeCode.String:
212 return Int (Double.Parse (
213 CastToString(Number)));
215 // Int on integer types does nothing
216 case TypeCode.Byte:
217 case TypeCode.Int16:
218 case TypeCode.Int32:
219 case TypeCode.Int64:
220 case TypeCode.SByte:
221 case TypeCode.UInt16:
222 case TypeCode.UInt32:
223 case TypeCode.UInt64:
224 return Number;
226 // Spec defines Empty as returning 0
227 case TypeCode.Empty:
228 return 0;
230 // otherwise, it's we can't cast to a numeric
231 case TypeCode.Boolean:
232 case TypeCode.Char:
233 case TypeCode.DateTime:
234 case TypeCode.DBNull:
235 case TypeCode.Object:
236 default:
237 throw new ArgumentException (
238 "Type of argument 'Number' is '" +
239 Number.GetType().FullName +
240 "', which is not numeric.");
244 // we use this internally to get a string
245 // representation of a number in a specific base
246 private static string ToBase (ulong Number, int Length,
247 char[] BaseDigits, uint Base) {
248 int i;
249 ulong r;
250 // we use a char array here for performance
251 char [] c = new Char[Length];
252 string s = null;
255 for (i = Length - 1; i >= 0; i--) {
256 r = Number % Base;
257 Number = Number / Base;
258 c[i] = BaseDigits[r];
259 if (Number == 0) {
260 s = new string (c, i, Length - i);
261 break;
264 if (s == null) {
265 return new string (c);
267 else {
268 return s;
273 // convert a number to Hex
274 // a little bit of magic goes on here with negative #'s
275 private static string ToHex(long Number, int Digits,
276 SizeIndexes Size) {
277 ulong UNumber;
279 if (Number < 0) {
280 // we add maxint of the Number's type
281 // twice and then 2 more...this has the
282 // effect of turning it into a ulong
283 // that has the same hex representation
284 UNumber = (ulong)((Number + 2) +
285 _Maxes[(int)Size]) +
286 (ulong)_Maxes[(int)Size];
288 else {
289 UNumber = (ulong)Number;
291 return ToBase(UNumber, Digits, _HexDigits, 16);
294 // call our private function,
295 // passing it the size of the item to convert
296 public static string Hex (short Number) {
297 return ToHex(Number, 4, SizeIndexes.Int16);
299 public static string Hex (byte Number) {
300 return ToHex(Number, 2, SizeIndexes.Int16);
302 public static string Hex (int Number) {
303 return ToHex(Number, 8, SizeIndexes.Int32);
305 public static string Hex (long Number) {
306 return ToHex(Number, 16, SizeIndexes.Int64);
309 // Objects are trickier
310 // first we have to cast to appropriate type
311 public static System.String Hex (System.Object Number) {
312 // always start out by throwing an exception
313 // if Number is null
314 long lval;
315 if (Number == null) {
316 throw new ArgumentNullException ("Number",
317 "Value cannot be null");
320 TypeCode TC = Type.GetTypeCode (Number.GetType ());
322 switch (TC) {
323 // try to parse the string as an Int32,
324 // then an Int64, if that fails
325 case TypeCode.String:
326 try {
327 return Hex (
328 Int32.Parse (
329 CastToString (Number)));
331 catch {
332 return Hex (
333 Int64.Parse (
334 CastToString (Number)));
337 // for the int types,
338 // just call the normal "Hex" for that type
339 case TypeCode.Byte:
340 return Hex ((byte)Number);
341 case TypeCode.Int16:
342 return Hex ((short)Number);
343 case TypeCode.Int32:
344 return Hex ((int)Number);
345 case TypeCode.Int64:
346 return Hex ((long)Number);
348 // empty is defined as returning 0
349 case TypeCode.Empty:
350 return "0";
351 case TypeCode.Single:
352 float fval = (float)Number;
353 lval = (long) Math.Round(fval);
354 if ((lval > Int32.MinValue) && (lval < Int32.MaxValue))
355 return Hex ((int)lval);
357 return Hex(lval);
358 case TypeCode.Double:
359 double dval = (double)Number;
360 if (dval > Int64.MaxValue || dval < Int64.MinValue)
361 throw new OverflowException(
362 VBUtils.GetResourceString("Overflow_Int64"));
363 lval = (long) Math.Round(dval);
364 if ((lval > Int32.MinValue) && (lval < Int32.MaxValue))
365 return Hex((int)lval);
367 return Hex(lval);
369 case TypeCode.Decimal:
370 Decimal big = new Decimal(Int64.MaxValue);
371 Decimal small = new Decimal(Int64.MinValue);
372 Decimal current = (Decimal)Number;
374 if (current.CompareTo(big) > 0 ||
375 current.CompareTo(small) < 0)
376 throw new OverflowException(
377 VBUtils.GetResourceString("Overflow_Int64"));
379 lval = Decimal.ToInt64(current);
380 if ((lval > Int32.MinValue) && (lval < Int32.MaxValue))
381 return Hex((int)lval);
383 return Hex(lval);
384 // we can't do any of these types
385 case TypeCode.Boolean:
386 case TypeCode.Char:
387 case TypeCode.DBNull:
388 case TypeCode.DateTime:
389 case TypeCode.Object:
390 case TypeCode.SByte:
391 case TypeCode.UInt16:
392 case TypeCode.UInt32:
393 case TypeCode.UInt64:
394 default:
395 throw new ArgumentException (
396 "Type of argument 'Number' is '" +
397 Number.GetType().FullName +
398 "', which is not numeric.");
402 // ToOct works just like ToHex, only in Octal.
403 private static string ToOct(long Number, int Digits,
404 SizeIndexes Size) {
405 ulong UNumber;
407 if (Number < 0) {
408 // for neg numbers add the maxint of
409 // the appropriate size twice, and then two more
410 // this has the effect of turning it
411 // into a ulong with the same oct representation
412 UNumber = (ulong)((Number + 2) +
413 _Maxes[(int)Size]) +
414 (ulong)(_Maxes[(int)Size]);
416 else {
417 UNumber = (ulong)Number;
419 return ToBase (UNumber, Digits, _OctDigits, 8);
422 // call ToOct with appropriate information
423 public static string Oct (short Number) {
424 return ToOct(Number, 6, SizeIndexes.Int16);
426 public static string Oct (byte Number) {
427 return ToOct(Number, 3, SizeIndexes.Int16);
429 public static string Oct (int Number) {
430 return ToOct(Number, 11, SizeIndexes.Int32);
432 public static string Oct (long Number) {
433 return ToOct(Number, 22, SizeIndexes.Int64);
436 // Objects are always trickier
437 // first need to cast to appropriate type
438 public static string Oct (System.Object Number) {
439 // first, always throw an exception if Number is null
440 if (Number == null) {
441 throw new ArgumentNullException("Number",
442 "Value cannot be null");
444 long lval;
445 TypeCode TC = Type.GetTypeCode (Number.GetType ());
447 switch (TC) {
448 // try to parse a string as an Int32
449 // and then an Int64
450 case TypeCode.String:
451 try {
452 return Oct (
453 Int32.Parse (
454 CastToString (Number)));
456 catch {
457 return Oct (
458 Int64.Parse (
459 CastToString (Number)));
462 // integer types just call the appropriate "Oct"
463 case TypeCode.Byte:
464 return Oct ((byte)Number);
465 case TypeCode.Int16:
466 return Oct ((short)Number);
467 case TypeCode.Int32:
468 return Oct ((int)Number);
469 case TypeCode.Int64:
470 return Oct ((long)Number);
471 case TypeCode.Single:
472 float fval = (float)Number;
473 lval = (long) Math.Round(fval);
474 if ((lval > Int32.MinValue) && (lval < Int32.MaxValue))
475 return Oct((int)lval);
477 return Oct(lval);
478 case TypeCode.Double:
479 double dval = (double)Number;
480 if (dval > Int64.MaxValue || dval < Int64.MinValue)
481 throw new OverflowException(
482 VBUtils.GetResourceString("Overflow_Int64"));
484 lval = (long) Math.Round(dval);
485 if ((lval > Int32.MinValue) && (lval < Int32.MaxValue))
486 return Oct((int)lval);
488 return Oct(lval);
489 case TypeCode.Decimal:
490 Decimal big = new Decimal(Int64.MaxValue);
491 Decimal small = new Decimal(Int64.MinValue);
492 Decimal current = (Decimal) Number;
494 if ((current.CompareTo(big) > 0) ||
495 (current.CompareTo(small) < 0))
496 throw new OverflowException(
497 VBUtils.GetResourceString("Overflow_Int64"));
499 lval = Decimal.ToInt64(current);
500 if ((lval > Int32.MinValue) && (lval < Int32.MaxValue))
501 return Oct((int)lval);
503 return Oct(lval);
504 // Empty is defined as returning 0
505 case TypeCode.Empty:
506 return "0";
508 // We can't convert these to Octal
509 case TypeCode.Boolean:
510 case TypeCode.Char:
511 case TypeCode.DBNull:
512 case TypeCode.DateTime:
513 case TypeCode.Object:
514 case TypeCode.SByte:
515 case TypeCode.UInt16:
516 case TypeCode.UInt32:
517 case TypeCode.UInt64:
518 default:
519 throw new ArgumentException (
520 "Type of argument 'Number' is '" +
521 Number.GetType().FullName +
522 "', which is not numeric.");
526 // Str is pretty easy now that we have a language
527 // with a ToString method()
528 public static string Str (System.Object Number) {
530 // check for null as always and throw an exception
531 if (Number == null) {
532 throw new ArgumentNullException("Number");
535 switch (Type.GetTypeCode (Number.GetType ())) {
536 // for unsigned types, just call ToString
537 case TypeCode.Byte:
538 case TypeCode.UInt16:
539 case TypeCode.UInt32:
540 case TypeCode.UInt64:
541 return Number.ToString();
543 // for signed types, we have to leave a
544 // space for the missing + sign
545 case TypeCode.Decimal:
546 return ((decimal)Number > 0 ? " " : "")
547 + Number.ToString();
548 case TypeCode.Double:
549 return ((double)Number > 0 ? " " : "")
550 + Number.ToString();
551 case TypeCode.Int16:
552 return ((short)Number > 0 ? " " : "")
553 + Number.ToString();
554 case TypeCode.Int32:
555 return ((int)Number > 0 ? " " : "")
556 + Number.ToString();
557 case TypeCode.Int64:
558 return ((long)Number > 0 ? " " : "")
559 + Number.ToString();
560 case TypeCode.SByte:
561 return ((sbyte)Number > 0 ? " " : "")
562 + Number.ToString();
563 case TypeCode.Single:
564 return ((float)Number > 0 ? " " : "")
565 + Number.ToString();
567 // can't cast anything else to a Number
568 default:
569 throw new InvalidCastException(
570 "Argument 'Number' cannot be converted to a numeric value.");
574 // The Val function is pretty bizarre
575 // Val ("&HFF") = 255
576 // Val ("&O377") = 255
577 // Val ("1234 Any Street") = 1234
578 // Val (" 12 45 . 90 7 E + 0 0 2 ") = 1245.907e+002 = 124590.7
579 public static double Val (string InputStr) {
580 int i;
581 int Base;
582 int NumChars = 0;
583 char c;
584 int Length = InputStr.Length;
585 char[] Number = new char[Length];
586 bool FoundRadixPrefix = false;
587 Regex NumberReg;
588 Match NumberMatch;
590 Base = 10;
591 Number[0] = '\0';
593 // go through string
594 for (i = 0; i < Length; i++) {
595 c = InputStr[i];
597 // look for Radix prefix "&"
598 if (i == 0 && c == '&') {
599 FoundRadixPrefix = true;
602 // look for an H or O following the prefix
603 else if (FoundRadixPrefix && i == 1 &&
604 (char.ToLower(c) == 'h' ||
605 char.ToLower(c) == 'o')) {
606 if (c == 'H') {
607 Base = 16;
609 else {
610 Base = 8;
614 // if we didn't find a radix prefix,
615 // ignore whitespace
616 else if (char.IsWhiteSpace(c) && (Base == 10)) {
617 continue;
620 // mash what's left together
621 else {
622 Number[NumChars++] = c;
626 // now we have a string to parse
627 switch (Base) {
628 // FIXME : for Octal and Hex,
629 // Regex is probably overkill
630 // Even for base 10, it might be faster
631 // to write our own parser
632 case 8:
633 NumberReg = new Regex ("^[0-7]*");
634 NumberMatch = NumberReg.Match (
635 new string(Number, 0, NumChars));
636 break;
637 case 16:
638 NumberReg = new Regex ("^[0-9a-f]*",
639 RegexOptions.IgnoreCase);
640 NumberMatch = NumberReg.Match (
641 new string(Number, 0, NumChars));
642 break;
643 case 10:
644 default:
645 NumberReg = new Regex (
646 "^[+-]?\\d*\\.?\\d*(e[+-]?\\d*)?",
647 RegexOptions.IgnoreCase);
648 NumberMatch = NumberReg.Match (
649 new string(Number, 0, NumChars));
650 break;
655 // we found a match, try to convert it
656 if (NumberMatch.Success) {
657 try {
658 if(NumberMatch.Length == 0)
659 return (double)0;
661 switch (Base) {
662 case 10:
663 return
664 Convert.ToDouble (
665 NumberMatch.Value);
666 case 8:
667 case 16:
668 return (double)
669 Convert.ToInt64 (
670 NumberMatch.Value,
671 Base);
672 default:
673 return (double)0;
676 catch {
677 throw new OverflowException();
680 else {
681 return (double)0;
685 // Val on a char type is pretty simple '9' = 9, 'a' = exception
686 public static int Val (char Expression) {
687 if (char.IsDigit(Expression)) {
688 return Expression - '0';
690 else {
691 throw new ArgumentException();
695 // if it's an object, and we can't convert
696 // it to a string, it's an exception
697 public static double Val (System.Object Expression) {
698 // always check for null first
699 if (Expression == null) {
700 throw new ArgumentNullException ("Expression",
701 "Value cannot be null");
704 try {
705 return Val (CastToString (Expression));
707 catch {
709 throw new ArgumentException(
710 "Type of argument 'Expression' is '" +
711 Expression.GetType().FullName +
712 "', which can nt be converted to numeric.");
715 // Events