Merge pull request #948 from ermshiperete/bug-xamarin-2394
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Metadata.W3cXsd2001 / SoapDuration.cs
index f4a07d5aaa48500669e83b71d0f28a9c61f719d3..21c28a345b869b237749978e0d4e1f10ed9b50a0 100644 (file)
@@ -1,5 +1,5 @@
 //
-// System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDuration
+// System.Runtime.Remoting.Metadata.W3cXsd2001.SoapDuration.cs
 //
 // Authors:
 //      Martin Willemoes Hansen (mwh@sysrq.dk)
 
 using System;
 using System.Text;
+using System.Globalization;
 
 namespace System.Runtime.Remoting.Metadata.W3cXsd2001 
 {
+       [System.Runtime.InteropServices.ComVisible (true)]
        public sealed class SoapDuration
        {
                public SoapDuration()
@@ -46,17 +48,17 @@ namespace System.Runtime.Remoting.Metadata.W3cXsd2001
                        get { return "duration"; }
                }
 
-               public static TimeSpan Parse (string s)
+               public static TimeSpan Parse (string value)
                {
-                       if (s.Length == 0)
+                       if (value.Length == 0)
                                throw new ArgumentException ("Invalid format string for duration schema datatype.");
 
                        int start = 0;
-                       if (s [0] == '-')
+                       if (value [0] == '-')
                                start = 1;
                        bool minusValue = (start == 1);
 
-                       if (s [start] != 'P')
+                       if (value [start] != 'P')
                                throw new ArgumentException ("Invalid format string for duration schema datatype.");
                        start++;
 
@@ -65,59 +67,87 @@ namespace System.Runtime.Remoting.Metadata.W3cXsd2001
                        bool isTime = false;
                        int hours = 0;
                        int minutes = 0;
-                       int seconds = 0;
+                       double seconds = 0;
 
                        bool error = false;
 
                        int i = start;
-                       while (i < s.Length) {
-                               if (s [i] == 'T') {
+                       while (i < value.Length) {
+                               if (value [i] == 'T') {
                                        isTime = true;
                                        parseStep = 4;
                                        i++;
                                        start = i;
                                        continue;
                                }
-                               for (; i < s.Length; i++) {
-                                       if (!Char.IsDigit (s [i]))
-                                               break;
+                               bool isIntegerValue = true;
+                               int dotOccurence = 0;
+                               for (; i < value.Length; i++) 
+                               {
+                                       if (!Char.IsDigit (value [i]))
+                                       {
+                                               //check if it is a non integer value.
+                                               if (value[i] == '.') 
+                                               {
+                                                       isIntegerValue = false;
+                                                       dotOccurence++;
+                                                       //if there is more than one dot in the number 
+                                                       //than its an error
+                                                       if (dotOccurence > 1 )
+                                                       {
+                                                               error = true;
+                                                               break;
+                                                       }
+                                               }
+                                               else
+                                                       break;
+                                       }
                                }
-                               int value = int.Parse (s.Substring (start, i - start));
-                               switch (s [i]) {
+
+                               int intValue = -1;
+                               double doubleValue = -1;
+                               if (isIntegerValue)
+                                       intValue = int.Parse (value.Substring (start, i - start));
+                               else
+                                       doubleValue = double.Parse (value.Substring (start, i - start), CultureInfo.InvariantCulture);
+                               switch (value [i]) {
                                case 'Y':
-                                       days += value * 365;
-                                       if (parseStep > 0)
+                                       days += intValue * 365;
+                                       if (parseStep > 0 || !isIntegerValue)
                                                error = true;
                                        else
                                                parseStep = 1;
                                        break;
                                case 'M':
-                                       if (parseStep < 2) {
-                                               days += 365 * (value / 12) + 30 * (value % 12);
+                                       if (parseStep < 2 && isIntegerValue) {
+                                               days += 365 * (intValue / 12) + 30 * (intValue % 12);
                                                parseStep = 2;
-                                       } else if (isTime && parseStep < 6) {
-                                               minutes = value;
+                                       } else if (isTime && parseStep < 6 && isIntegerValue) {
+                                               minutes = intValue;
                                                parseStep = 6;
                                        }
                                        else
                                                error = true;
                                        break;
                                case 'D':
-                                       days += value;
-                                       if (parseStep > 2)
+                                       days += intValue;
+                                       if (parseStep > 2 || !isIntegerValue)
                                                error = true;
                                        else
                                                parseStep = 3;
                                        break;
                                case 'H':
-                                       hours = value;
-                                       if (!isTime || parseStep > 4)
+                                       hours = intValue;
+                                       if (!isTime || parseStep > 4 || !isIntegerValue)
                                                error = true;
                                        else
                                                parseStep = 5;
                                        break;
                                case 'S':
-                                       seconds = value;
+                                       if (isIntegerValue)
+                                               seconds = intValue;
+                                       else
+                                               seconds = doubleValue;
                                        if (!isTime || parseStep > 6)
                                                error = true;
                                        else
@@ -134,26 +164,28 @@ namespace System.Runtime.Remoting.Metadata.W3cXsd2001
                        }
                        if (error)
                                throw new ArgumentException ("Invalid format string for duration schema datatype.");
-                       TimeSpan ts = new TimeSpan (days, hours, minutes, seconds);
+                       TimeSpan ts = new TimeSpan (days, hours, minutes, 0) + TimeSpan.FromSeconds (seconds);
                        return minusValue ? -ts : ts;
                }
 
-               public static string ToString (TimeSpan value)
+               public static string ToString (TimeSpan timeSpan)
                {
                        StringBuilder builder = new StringBuilder();
-                       if (value.Ticks < 0) {
+                       if (timeSpan.Ticks < 0) {
                                builder.Append('-');
-                               value = value.Negate();
+                               timeSpan = timeSpan.Negate();
                        }
                        builder.Append('P');
-                       if (value.Days > 0) builder.Append(value.Days).Append('D');
-                       if (value.Days > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0) {
+                       if (timeSpan.Days > 0) builder.Append(timeSpan.Days).Append('D');
+                       if (timeSpan.Days > 0 || timeSpan.Minutes > 0 || timeSpan.Seconds > 0 || timeSpan.Milliseconds > 0) {
                                builder.Append('T');
-                               if (value.Hours > 0) builder.Append(value.Hours).Append('D');
-                               if (value.Minutes > 0) builder.Append(value.Minutes).Append('M');
-                               if (value.Seconds > 0 || value.Milliseconds > 0) {
-                                       builder.Append(value.Seconds);
-                                       if (value.Milliseconds > 0) builder.Append('.').Append(String.Format("{0:000}", value.Milliseconds));
+                               if (timeSpan.Hours > 0) builder.Append(timeSpan.Hours).Append('H');
+                               if (timeSpan.Minutes > 0) builder.Append(timeSpan.Minutes).Append('M');
+                               if (timeSpan.Seconds > 0 || timeSpan.Milliseconds > 0) {
+                                       double secs = (double) timeSpan.Seconds;
+                                       if (timeSpan.Milliseconds > 0)
+                                               secs += ((double)timeSpan.Milliseconds) / 1000.0;
+                                       builder.Append(String.Format(CultureInfo.InvariantCulture, "{0:0.0000000}", secs));
                                        builder.Append('S');
                                }
                        }