TimeSpanParse.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Globalization / TimeSpanParse.cs / 1602379 / TimeSpanParse.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
// [....]
// 
//////////////////////////////////////////////////////////////////////////// 
//
//  Class:    TimeSpan Parse 
//
//  Purpose:  This class is called by TimeSpan to parse a time interval string.
//
//  Standard Format: 
//  -=-=-=-=-=-=-=-
//  "c":  Constant format.  [-][d'.']hh':'mm':'ss['.'fffffff] 
//  Not culture sensitive.  Default format (and null/empty format string) map to this format. 
//
//  "g":  General format, short:  [-][d':']h':'mm':'ss'.'FFFFFFF 
//  Only print what's needed.  Localized (if you want Invariant, pass in Invariant).
//  The fractional seconds separator is localized, equal to the culture's DecimalSeparator.
//
//  "G":  General format, long:  [-]d':'hh':'mm':'ss'.'fffffff 
//  Always print days and 7 fractional digits.  Localized (if you want Invariant, pass in Invariant).
//  The fractional seconds separator is localized, equal to the culture's DecimalSeparator. 
// 
//
//  * "TryParseTimeSpan" is the main method for Parse/TryParse 
//
//  - TimeSpanTokenizer.GetNextToken() is used to split the input string into number and literal tokens.
//  - TimeSpanRawInfo.ProcessToken() adds the next token into the parsing intermediary state structure
//  - ProcessTerminalState() uses the fully initialized TimeSpanRawInfo to find a legal parse match. 
//    The terminal states are attempted as follows:
//    foreach (+InvariantPattern, -InvariantPattern, +LocalizedPattern, -LocalizedPattern) try 
//       1 number  => d 
//       2 numbers => h:m
//       3 numbers => h:m:s     | d.h:m   | h:m:.f 
//       4 numbers => h:m:s.f   | d.h:m:s | d.h:m:.f
//       5 numbers => d.h:m:s.f
//
// Custom Format: 
// -=-=-=-=-=-=-=
// 
// * "TryParseExactTimeSpan" is the main method for ParseExact/TryParseExact methods 
// * "TryParseExactMultipleTimeSpan" is the main method for ParseExact/TryparseExact
//    methods that take a String[] of formats 
//
// - For single-letter formats "TryParseTimeSpan" is called (see above)
// - For multi-letter formats "TryParseByFormat" is called
// - TryParseByFormat uses helper methods (ParseExactLiteral, ParseExactDigits, etc) 
//   which drive the underlying TimeSpanTokenizer.  However, unlike standard formatting which
//   operates on whole-tokens, ParseExact operates at the character-level.  As such, 
//   TimeSpanTokenizer.NextChar and TimeSpanTokenizer.BackOne() are called directly. 
//
//////////////////////////////////////////////////////////////////////////// 
namespace System.Globalization {
    using System.Text;
    using System;
    using System.Diagnostics.Contracts; 
    using System.Globalization;
 
    [Flags] 
    public enum TimeSpanStyles {
          None                  = 0x00000000, 
          AssumeNegative        = 0x00000001,
    }

 
    internal static class TimeSpanParse {
        // ---- SECTION:  members for internal support ---------* 
        internal static void ValidateStyles(TimeSpanStyles style, String parameterName) { 
            if (style != TimeSpanStyles.None && style != TimeSpanStyles.AssumeNegative)
                throw new ArgumentException(Environment.GetResourceString("Argument_InvalidTimeSpanStyles"), parameterName); 
        }

        internal const int unlimitedDigits = -1;
        internal const int maxFractionDigits = 7; 

        internal const int maxDays     = 10675199; 
        internal const int maxHours    = 23; 
        internal const int maxMinutes  = 59;
        internal const int maxSeconds  = 59; 
        internal const int maxFraction = 9999999;

        #region InternalSupport
        enum TimeSpanThrowStyle { 
            None    = 0,
            All     = 1, 
        } 

        private enum ParseFailureKind { 
            None                     = 0,
            ArgumentNull             = 1,
            Format                   = 2,
            FormatWithParameter      = 3, 
            Overflow                 = 4,
        } 
 
        [Flags]
        enum TimeSpanStandardStyles {     // Standard Format Styles 
            None                  = 0x00000000,
            Invariant             = 0x00000001, //Allow Invariant Culture
            Localized             = 0x00000002, //Allow Localized Culture
            RequireFull           = 0x00000004, //Require the input to be in DHMSF format 
            Any                   = Invariant | Localized,
        } 
 
        // TimeSpan Token Types
        private enum TTT { 
            None              = 0,    // None of the TimeSpanToken fields are set
            End               = 1,    // '\0'
            Num               = 2,    // Number
            Sep               = 3,    // literal 
            NumOverflow       = 4,    // Number that overflowed
        } 
 
        private static readonly TimeSpanToken zero = new TimeSpanToken(0);
        struct TimeSpanToken { 
            internal TTT ttt;
            internal int num;           // Store the number that we are parsing (if any)
            internal int zeroes;        // Store the number of leading zeroes (if any)
            internal String sep;        // Store the literal that we are parsing (if any) 

            public TimeSpanToken(int number) { 
                ttt = TTT.Num; 
                num = number;
                zeroes = 0; 
                sep = null;
            }

            public TimeSpanToken(int leadingZeroes, int number) { 
                ttt = TTT.Num;
                num = number; 
                zeroes = leadingZeroes; 
                sep = null;
            } 

            public bool IsInvalidNumber(int maxValue, int maxPrecision) {
                Contract.Assert(ttt == TTT.Num);
                Contract.Assert(num > -1); 
                Contract.Assert(maxValue > 0);
                Contract.Assert(maxPrecision == maxFractionDigits || maxPrecision == unlimitedDigits); 
 
                if (num > maxValue)
                    return true; 
                if (maxPrecision == unlimitedDigits)
                    return false; // all validation past this point applies only to fields with precision limits
                if (zeroes > maxPrecision)
                    return true; 
                if (num == 0 || zeroes == 0)
                    return false; 
 
                // num > 0 && zeroes > 0 && num <= maxValue && zeroes <= maxPrecision
                return (num >= (maxValue/(long)Math.Pow(10, zeroes-1))); 
           }
        }

        // 
        //  TimeSpanTokenizer
        // 
        //  Actions: TimeSpanTokenizer.GetNextToken() returns the next token in the input string. 
        //
        struct TimeSpanTokenizer { 
            private int m_pos;
            private String m_value;

            internal void Init(String input) { 
                Init(input, 0);
            } 
            internal void Init(String input, int startPosition) { 
                m_pos = startPosition;
                m_value = input; 
            }
            // used by the parsing routines that operate on standard-formats
            internal TimeSpanToken GetNextToken() {
                Contract.Assert(m_pos > -1); 

                TimeSpanToken tok = new TimeSpanToken(); 
                char ch = CurrentChar; 

                if (ch == (char)0) { 
                    tok.ttt = TTT.End;
                    return tok;
                }
 
                if (ch >= '0' && ch <= '9') {
                    tok.ttt = TTT.Num; 
                    tok.num = 0; 
                    tok.zeroes = 0;
                    do { 
                        if ((tok.num & 0xF0000000) != 0) {
                            tok.ttt = TTT.NumOverflow;
                            return tok;
                        } 
                        tok.num = tok.num * 10 + ch - '0';
                        if (tok.num == 0) tok.zeroes++; 
                        if (tok.num < 0) { 
                            tok.ttt = TTT.NumOverflow;
                            return tok; 
                        }
                        ch = NextChar;
                    } while (ch >= '0' && ch <= '9');
                    return tok; 
                }
                else { 
                    tok.ttt = TTT.Sep; 
                    int startIndex = m_pos;
                    int length = 0; 

                    while (ch != (char)0 && (ch < '0' || '9' < ch)) {
                        ch = NextChar;
                        length++; 
                    }
                    tok.sep = m_value.Substring(startIndex, length); 
                    return tok; 
                }
            } 

            internal Boolean EOL {
                get {
                    return m_pos >= (m_value.Length-1); 
                }
            } 
            // BackOne, NextChar, CurrentChar - used by ParseExact (ParseByFormat) to operate 
            // on custom-formats where exact character-by-character control is allowed
            internal void BackOne() { 
                if (m_pos > 0) --m_pos;
            }

            internal char NextChar { 
                get {
                    m_pos++; 
                    return CurrentChar; 
                }
            } 
            internal char CurrentChar {
                get {
                    if (m_pos > -1 && m_pos < m_value.Length) {
                        return m_value[m_pos]; 
                    }
                    else { 
                        return (char) 0; 
                    }
                } 
            }
        }

 

        // This stores intermediary parsing state for the standard formats 
        struct TimeSpanRawInfo { 
            internal TimeSpanFormat.FormatLiterals PositiveInvariant {
                get { 
                    return TimeSpanFormat.PositiveInvariantFormatLiterals;
                }
            }
            internal TimeSpanFormat.FormatLiterals NegativeInvariant { 
                get {
                    return TimeSpanFormat.NegativeInvariantFormatLiterals; 
                } 
            }
 
            internal TimeSpanFormat.FormatLiterals PositiveLocalized {
                get {
                    if (!m_posLocInit) {
                        m_posLoc = new TimeSpanFormat.FormatLiterals(); 
                        m_posLoc.Init(m_fullPosPattern, false);
                        m_posLocInit = true; 
                    } 
                    return m_posLoc;
                } 
            }
            internal TimeSpanFormat.FormatLiterals NegativeLocalized {
                get {
                    if (!m_negLocInit) { 
                        m_negLoc = new TimeSpanFormat.FormatLiterals();
                        m_negLoc.Init(m_fullNegPattern, false); 
                        m_negLocInit = true; 
                    }
                    return m_negLoc; 
                }
            }
            //
            internal Boolean FullAppCompatMatch(TimeSpanFormat.FormatLiterals pattern) { 
                return SepCount                  == 5
                    && NumCount                  == 4 
                    && pattern.Start             == literals[0] 
                    && pattern.DayHourSep        == literals[1]
                    && pattern.HourMinuteSep     == literals[2] 
                    && pattern.AppCompatLiteral  == literals[3]
                    && pattern.End               == literals[4];
            }
            // 
            internal Boolean PartialAppCompatMatch(TimeSpanFormat.FormatLiterals pattern) {
                return SepCount                  == 4 
                    && NumCount                  == 3 
                    && pattern.Start             == literals[0]
                    && pattern.HourMinuteSep     == literals[1] 
                    && pattern.AppCompatLiteral  == literals[2]
                    && pattern.End               == literals[3];
            }
            // DHMSF (all values matched) 
            internal Boolean FullMatch(TimeSpanFormat.FormatLiterals pattern) {
                return SepCount                  == MaxLiteralTokens 
                    && NumCount                  == MaxNumericTokens 
                    && pattern.Start             == literals[0]
                    && pattern.DayHourSep        == literals[1] 
                    && pattern.HourMinuteSep     == literals[2]
                    && pattern.MinuteSecondSep   == literals[3]
                    && pattern.SecondFractionSep == literals[4]
                    && pattern.End               == literals[5]; 
            }
            // D (no hours, minutes, seconds, or fractions) 
            internal Boolean FullDMatch(TimeSpanFormat.FormatLiterals pattern) { 
                return SepCount                  == 2
                    && NumCount                  == 1 
                    && pattern.Start             == literals[0]
                    && pattern.End               == literals[1];
            }
            // HM (no days, seconds, or fractions) 
            internal Boolean FullHMMatch(TimeSpanFormat.FormatLiterals pattern) {
                return SepCount                  == 3 
                    && NumCount                  == 2 
                    && pattern.Start             == literals[0]
                    && pattern.HourMinuteSep     == literals[1] 
                    && pattern.End               == literals[2];
            }
            // DHM (no seconds or fraction)
            internal Boolean FullDHMMatch(TimeSpanFormat.FormatLiterals pattern) { 
                return SepCount                  == 4
                    && NumCount                  == 3 
                    && pattern.Start             == literals[0] 
                    && pattern.DayHourSep        == literals[1]
                    && pattern.HourMinuteSep     == literals[2] 
                    && pattern.End               == literals[3];

            }
            // HMS (no days or fraction) 
            internal Boolean FullHMSMatch(TimeSpanFormat.FormatLiterals pattern) {
                return SepCount                  == 4 
                    && NumCount                  == 3 
                    && pattern.Start             == literals[0]
                    && pattern.HourMinuteSep     == literals[1] 
                    && pattern.MinuteSecondSep   == literals[2]
                    && pattern.End               == literals[3];
            }
            // DHMS (no fraction) 
            internal Boolean FullDHMSMatch(TimeSpanFormat.FormatLiterals pattern) {
                return SepCount                  == 5 
                    && NumCount                  == 4 
                    && pattern.Start             == literals[0]
                    && pattern.DayHourSep        == literals[1] 
                    && pattern.HourMinuteSep     == literals[2]
                    && pattern.MinuteSecondSep   == literals[3]
                    && pattern.End               == literals[4];
            } 
            // HMSF (no days)
            internal Boolean FullHMSFMatch(TimeSpanFormat.FormatLiterals pattern) { 
                return SepCount                  == 5 
                    && NumCount                  == 4
                    && pattern.Start             == literals[0] 
                    && pattern.HourMinuteSep     == literals[1]
                    && pattern.MinuteSecondSep   == literals[2]
                    && pattern.SecondFractionSep == literals[3]
                    && pattern.End               == literals[4]; 
            }
 
            internal TTT lastSeenTTT; 
            internal int tokenCount;
            internal int SepCount; 
            internal int NumCount;
            internal String[] literals;
            internal TimeSpanToken[] numbers;  // raw numbers
 
            private TimeSpanFormat.FormatLiterals m_posLoc;
            private TimeSpanFormat.FormatLiterals m_negLoc; 
            private Boolean m_posLocInit; 
            private Boolean m_negLocInit;
            private String m_fullPosPattern; 
            private String m_fullNegPattern;

            private const int MaxTokens = 11;
            private const int MaxLiteralTokens = 6; 
            private const int MaxNumericTokens = 5;
 
            internal void Init(DateTimeFormatInfo dtfi) { 
                Contract.Assert(dtfi != null);
 
                lastSeenTTT = TTT.None;
                tokenCount = 0;
                SepCount = 0;
                NumCount = 0; 

                literals = new String[MaxLiteralTokens]; 
                numbers  = new TimeSpanToken[MaxNumericTokens]; 

                m_fullPosPattern = dtfi.FullTimeSpanPositivePattern; 
                m_fullNegPattern = dtfi.FullTimeSpanNegativePattern;
                m_posLocInit = false;
                m_negLocInit = false;
            } 

            internal Boolean ProcessToken(ref TimeSpanToken tok, ref TimeSpanResult result) { 
                if (tok.ttt == TTT.NumOverflow) { 
                    result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge", null);
                    return false; 
                }
                if (tok.ttt != TTT.Sep && tok.ttt != TTT.Num) {
                    // Some unknown token or a repeat token type in the input
                    result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan", null); 
                    return false;
                } 
 
                switch (tok.ttt) {
                    case TTT.Sep: 
                        if (!AddSep(tok.sep, ref result)) return false;
                        break;
                    case TTT.Num:
                        if (tokenCount == 0) { 
                            if (!AddSep(String.Empty, ref result)) return false;
                        } 
                        if (!AddNum(tok, ref result)) return false; 
                        break;
                    default: 
                        break;
                }

                lastSeenTTT = tok.ttt; 
                Contract.Assert(tokenCount == (SepCount + NumCount), "tokenCount == (SepCount + NumCount)");
                return true; 
            } 

            private bool AddSep(String sep, ref TimeSpanResult result) { 
                if (SepCount >= MaxLiteralTokens || tokenCount >= MaxTokens) {
                    result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan", null);
                    return false;
                } 
                literals[SepCount++] = sep;
                tokenCount++; 
                return true; 
            }
            private bool AddNum(TimeSpanToken num, ref TimeSpanResult result) { 
                if (NumCount >= MaxNumericTokens || tokenCount >= MaxTokens) {
                    result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan", null);
                    return false;
                } 
                numbers[NumCount++] = num;
                tokenCount++; 
                return true; 
            }
        } 

        // This will store the result of the parsing.  And it will eventually be used to construct a TimeSpan instance.
        struct TimeSpanResult {
            internal TimeSpan parsedTimeSpan; 
            internal TimeSpanThrowStyle throwStyle;
 
            internal ParseFailureKind m_failure; 
            internal string m_failureMessageID;
            internal object m_failureMessageFormatArgument; 
            internal string m_failureArgumentName;

            internal void Init(TimeSpanThrowStyle canThrow) {
                parsedTimeSpan = default(TimeSpan); 
                throwStyle = canThrow;
            } 
            internal void SetFailure(ParseFailureKind failure, string failureMessageID) { 
                SetFailure(failure, failureMessageID, null, null);
            } 
            internal void SetFailure(ParseFailureKind failure, string failureMessageID, object failureMessageFormatArgument) {
                SetFailure(failure, failureMessageID, failureMessageFormatArgument, null);
            }
            internal void SetFailure(ParseFailureKind failure, string failureMessageID, object failureMessageFormatArgument, 
                                     string failureArgumentName) {
                m_failure = failure; 
                m_failureMessageID = failureMessageID; 
                m_failureMessageFormatArgument = failureMessageFormatArgument;
                m_failureArgumentName = failureArgumentName; 
                if (throwStyle != TimeSpanThrowStyle.None) {
                    throw GetTimeSpanParseException();
                }
            } 

            internal Exception GetTimeSpanParseException() { 
                switch (m_failure) { 
                case ParseFailureKind.ArgumentNull:
                    return new ArgumentNullException(m_failureArgumentName, Environment.GetResourceString(m_failureMessageID)); 

                case ParseFailureKind.FormatWithParameter:
                    return new FormatException(Environment.GetResourceString(m_failureMessageID, m_failureMessageFormatArgument));
 
                case ParseFailureKind.Format:
                    return new FormatException(Environment.GetResourceString(m_failureMessageID)); 
 
                case ParseFailureKind.Overflow:
                    return new OverflowException(Environment.GetResourceString(m_failureMessageID)); 

                default:
                    Contract.Assert(false, "Unknown TimeSpanParseFailure: " + m_failure);
                    return new FormatException(Environment.GetResourceString("Format_InvalidString")); 
                }
            } 
        } 

        static bool TryTimeToTicks(bool positive, TimeSpanToken days, TimeSpanToken hours, TimeSpanToken minutes, TimeSpanToken seconds, TimeSpanToken fraction, out long result) { 
            if (days.IsInvalidNumber(maxDays, unlimitedDigits)
             || hours.IsInvalidNumber(maxHours, unlimitedDigits)
             || minutes.IsInvalidNumber(maxMinutes, unlimitedDigits)
             || seconds.IsInvalidNumber(maxSeconds, unlimitedDigits) 
             || fraction.IsInvalidNumber(maxFraction, maxFractionDigits)) {
                result = 0; 
                return false; 
            }
 
            Int64 ticks = ((Int64)days.num * 3600 * 24 + (Int64)hours.num * 3600 + (Int64)minutes.num * 60 + seconds.num) * 1000;
            if (ticks > TimeSpan.MaxMilliSeconds || ticks < TimeSpan.MinMilliSeconds) {
                result = 0;
                return false; 
            }
 
            // Normalize the fraction component 
            //
            // string representation => (zeroes,num) => resultant fraction ticks 
            // ---------------------    ------------    ------------------------
            // ".9999999"            => (0,9999999)  => 9,999,999 ticks (same as constant maxFraction)
            // ".1"                  => (0,1)        => 1,000,000 ticks
            // ".01"                 => (1,1)        =>   100,000 ticks 
            // ".001"                => (2,1)        =>    10,000 ticks
            long f = fraction.num; 
            if (f != 0) { 
                long lowerLimit = TimeSpan.TicksPerTenthSecond;
                if (fraction.zeroes > 0) { 
                    long divisor = (long)Math.Pow(10, fraction.zeroes);
                    lowerLimit = lowerLimit / divisor;
                }
                while (f < lowerLimit) { 
                    f *= 10;
                } 
            } 
            result = ((long)ticks * TimeSpan.TicksPerMillisecond) + f;
            if (positive && result < 0) { 
                result = 0;
                return false;
            }
            return true; 
        }
        #endregion 
 

        // ---- SECTION:  internal static methods called by System.TimeSpan ---------* 
        //
        //  [Try]Parse, [Try]ParseExact, and [Try]ParseExactMultiple
        //
        //  Actions: Main methods called from TimeSpan.Parse 
        #region ParseMethods
        internal static TimeSpan Parse(String input, IFormatProvider formatProvider) { 
            TimeSpanResult parseResult = new TimeSpanResult(); 
            parseResult.Init(TimeSpanThrowStyle.All);
 
            if (TryParseTimeSpan(input, TimeSpanStandardStyles.Any, formatProvider, ref parseResult)) {
                return parseResult.parsedTimeSpan;
            }
            else { 
                throw parseResult.GetTimeSpanParseException();
            } 
        } 
        internal static Boolean TryParse(String input, IFormatProvider formatProvider, out TimeSpan result) {
            TimeSpanResult parseResult = new TimeSpanResult(); 
            parseResult.Init(TimeSpanThrowStyle.None);

            if (TryParseTimeSpan(input, TimeSpanStandardStyles.Any, formatProvider, ref parseResult)) {
                result = parseResult.parsedTimeSpan; 
                return true;
            } 
            else { 
                result = default(TimeSpan);
                return false; 
            }
        }
        internal static TimeSpan ParseExact(String input, String format, IFormatProvider formatProvider, TimeSpanStyles styles) {
            TimeSpanResult parseResult = new TimeSpanResult(); 
            parseResult.Init(TimeSpanThrowStyle.All);
 
            if (TryParseExactTimeSpan(input, format, formatProvider, styles, ref parseResult)) { 
                return parseResult.parsedTimeSpan;
            } 
            else {
                throw parseResult.GetTimeSpanParseException();
            }
        } 
        internal static Boolean TryParseExact(String input, String format, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result) {
            TimeSpanResult parseResult = new TimeSpanResult(); 
            parseResult.Init(TimeSpanThrowStyle.None); 

            if (TryParseExactTimeSpan(input, format, formatProvider, styles, ref parseResult)) { 
                result = parseResult.parsedTimeSpan;
                return true;
            }
            else { 
                result = default(TimeSpan);
                return false; 
            } 
        }
        internal static TimeSpan ParseExactMultiple(String input, String[] formats, IFormatProvider formatProvider, TimeSpanStyles styles) { 
            TimeSpanResult parseResult = new TimeSpanResult();
            parseResult.Init(TimeSpanThrowStyle.All);

            if (TryParseExactMultipleTimeSpan(input, formats, formatProvider, styles, ref parseResult)) { 
                return parseResult.parsedTimeSpan;
            } 
            else { 
                throw parseResult.GetTimeSpanParseException();
            } 
        }
        internal static Boolean TryParseExactMultiple(String input, String[] formats, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result) {
            TimeSpanResult parseResult = new TimeSpanResult();
            parseResult.Init(TimeSpanThrowStyle.None); 

            if (TryParseExactMultipleTimeSpan(input, formats, formatProvider, styles, ref parseResult)) { 
                result = parseResult.parsedTimeSpan; 
                return true;
            } 
            else {
                result = default(TimeSpan);
                return false;
            } 
        }
        #endregion 
 

        // ---- SECTION:  private static methods that do the actual work ---------* 
        #region TryParseTimeSpan
        //
        //  TryParseTimeSpan
        // 
        //  Actions: Common private Parse method called by both Parse and TryParse
        // 
        private static Boolean TryParseTimeSpan(String input, TimeSpanStandardStyles style, IFormatProvider formatProvider, ref TimeSpanResult result) { 
            if (input == null) {
                result.SetFailure(ParseFailureKind.ArgumentNull, "ArgumentNull_String", null, "input"); 
                return false;
            }

            input = input.Trim(); 
            if (input == String.Empty) {
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); 
                return false; 
            }
 
            TimeSpanTokenizer tokenizer = new TimeSpanTokenizer();
            tokenizer.Init(input);

            TimeSpanRawInfo raw = new TimeSpanRawInfo(); 
            raw.Init(DateTimeFormatInfo.GetInstance(formatProvider));
 
            TimeSpanToken tok = tokenizer.GetNextToken(); 

            /* The following loop will break out when we reach the end of the str or 
             * when we can determine that the input is invalid. */
            while (tok.ttt != TTT.End) {
                if (!raw.ProcessToken(ref tok, ref result)) {
                    result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); 
                    return false;
                } 
                tok = tokenizer.GetNextToken(); 
            }
            if (!tokenizer.EOL) { 
                // embedded nulls in the input string
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
                return false;
            } 
            if (!ProcessTerminalState(ref raw, style, ref result)) {
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); 
                return false; 
            }
            return true; 
        }


 
        //
        //  ProcessTerminalState 
        // 
        //  Actions: Validate the terminal state of a standard format parse.
        //           Sets result.parsedTimeSpan on success. 
        //
        // Calculates the resultant TimeSpan from the TimeSpanRawInfo
        //
        // try => +InvariantPattern, -InvariantPattern, +LocalizedPattern, -LocalizedPattern 
        // 1) Verify Start matches
        // 2) Verify End matches 
        // 3) 1 number  => d 
        //    2 numbers => h:m
        //    3 numbers => h:m:s | d.h:m | h:m:.f 
        //    4 numbers => h:m:s.f | d.h:m:s | d.h:m:.f
        //    5 numbers => d.h:m:s.f
        private static Boolean ProcessTerminalState(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) {
            if (raw.lastSeenTTT == TTT.Num) { 
                TimeSpanToken tok = new TimeSpanToken();
                tok.ttt = TTT.Sep; 
                tok.sep = String.Empty; 
                if (!raw.ProcessToken(ref tok, ref result)) {
                    result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); 
                    return false;
                }
            }
 
            switch (raw.NumCount) {
                case 1: 
                    return ProcessTerminal_D(ref raw, style, ref result); 
                case 2:
                    return ProcessTerminal_HM(ref raw, style, ref result); 
                case 3:
                    return ProcessTerminal_HM_S_D(ref raw, style, ref result);
                case 4:
                    return ProcessTerminal_HMS_F_D(ref raw, style, ref result); 
                case 5:
                    return ProcessTerminal_DHMSF(ref raw, style, ref result); 
                default: 
                    result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
                    return false; 
            }
        }

        // 
        //  ProcessTerminal_DHMSF
        // 
        //  Actions: Validate the 5-number "Days.Hours:Minutes:Seconds.Fraction" terminal case. 
        //           Sets result.parsedTimeSpan on success.
        // 
        private static Boolean ProcessTerminal_DHMSF(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) {
            if (raw.SepCount != 6 || raw.NumCount != 5) {
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
                return false; 
            }
 
            bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0); 
            bool loc = ((style & TimeSpanStandardStyles.Localized) != 0);
 
            bool positive = false;
            bool match = false;

            if (inv) { 
                if (raw.FullMatch(raw.PositiveInvariant)) {
                    match = true; 
                    positive = true; 
                }
                if (!match && raw.FullMatch(raw.NegativeInvariant)) { 
                    match = true;
                    positive = false;
                }
            } 
            if (loc) {
                if (!match && raw.FullMatch(raw.PositiveLocalized)) { 
                    match = true; 
                    positive = true;
                } 
                if (!match && raw.FullMatch(raw.NegativeLocalized)) {
                    match = true;
                    positive = false;
                } 
            }
            long ticks; 
            if (match) { 
                if (!TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], raw.numbers[3], raw.numbers[4], out ticks)) {
                    result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); 
                    return false;
                }
                if (!positive) {
                    ticks = -ticks; 
                    if (ticks > 0) {
                        result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); 
                        return false; 
                    }
                } 
                result.parsedTimeSpan._ticks = ticks;
                return true;
            }
 
            result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
            return false; 
        } 

        // 
        //  ProcessTerminal_HMS_F_D
        //
        //  Actions: Validate the ambiguous 4-number "Hours:Minutes:Seconds.Fraction", "Days.Hours:Minutes:Seconds", or "Days.Hours:Minutes:.Fraction" terminal case.
        //           Sets result.parsedTimeSpan on success. 
        //
        private static Boolean ProcessTerminal_HMS_F_D(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) { 
            if (raw.SepCount != 5 || raw.NumCount != 4 || (style & TimeSpanStandardStyles.RequireFull) != 0) { 
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
                return false; 
            }

            bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0);
            bool loc = ((style & TimeSpanStandardStyles.Localized) != 0); 

            long ticks = 0; 
            bool positive = false; 
            bool match = false;
            bool overflow = false; 

            if (inv) {
                if (raw.FullHMSFMatch(raw.PositiveInvariant)) {
                    positive = true; 
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], raw.numbers[2], raw.numbers[3], out ticks);
                    overflow = overflow || !match; 
                } 
                if (!match && raw.FullDHMSMatch(raw.PositiveInvariant)) {
                    positive = true; 
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], raw.numbers[3], zero, out ticks);
                    overflow = overflow || !match;
                }
                if (!match && raw.FullAppCompatMatch(raw.PositiveInvariant)) { 
                    positive = true;
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, raw.numbers[3], out ticks); 
                    overflow = overflow || !match; 
                }
                if (!match && raw.FullHMSFMatch(raw.NegativeInvariant)) { 
                    positive = false;
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], raw.numbers[2], raw.numbers[3], out ticks);
                    overflow = overflow || !match;
                } 
                if (!match && raw.FullDHMSMatch(raw.NegativeInvariant)) {
                    positive = false; 
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], raw.numbers[3], zero, out ticks); 
                    overflow = overflow || !match;
                } 
                if (!match && raw.FullAppCompatMatch(raw.NegativeInvariant)) {
                    positive = false;
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, raw.numbers[3], out ticks);
                    overflow = overflow || !match; 
                }
            } 
            if (loc) { 
                if (!match && raw.FullHMSFMatch(raw.PositiveLocalized)) {
                    positive = true; 
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], raw.numbers[2], raw.numbers[3], out ticks);
                    overflow = overflow || !match;
                }
                if (!match && raw.FullDHMSMatch(raw.PositiveLocalized)) { 
                    positive = true;
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], raw.numbers[3], zero, out ticks); 
                    overflow = overflow || !match; 
                }
                if (!match && raw.FullAppCompatMatch(raw.PositiveLocalized)) { 
                    positive = true;
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, raw.numbers[3], out ticks);
                    overflow = overflow || !match;
                } 
                if (!match && raw.FullHMSFMatch(raw.NegativeLocalized)) {
                    positive = false; 
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], raw.numbers[2], raw.numbers[3], out ticks); 
                    overflow = overflow || !match;
                } 
                if (!match && raw.FullDHMSMatch(raw.NegativeLocalized)) {
                    positive = false;
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], raw.numbers[3], zero, out ticks);
                    overflow = overflow || !match; 
                }
                if (!match && raw.FullAppCompatMatch(raw.NegativeLocalized)) { 
                    positive = false; 
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, raw.numbers[3], out ticks);
                    overflow = overflow || !match; 
                }
            }

            if (match) { 
                if (!positive) {
                    ticks = -ticks; 
                    if (ticks > 0) { 
                        result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge");
                        return false; 
                    }
                }
                result.parsedTimeSpan._ticks = ticks;
                return true; 
            }
 
            if (overflow) { 
                // we found at least one literal pattern match but the numbers just didn't fit
                result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); 
                return false;
            }
            else {
                // we couldn't find a thing 
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
                return false; 
            } 
        }
 
        //
        //  ProcessTerminal_HM_S_D
        //
        //  Actions: Validate the ambiguous 3-number "Hours:Minutes:Seconds", "Days.Hours:Minutes", or "Hours:Minutes:.Fraction" terminal case 
        //
        private static Boolean ProcessTerminal_HM_S_D(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) { 
            if (raw.SepCount != 4 || raw.NumCount != 3 || (style & TimeSpanStandardStyles.RequireFull) != 0) { 
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
                return false; 
            }

            bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0);
            bool loc = ((style & TimeSpanStandardStyles.Localized) != 0); 

            bool positive = false; 
            bool match = false; 
            bool overflow = false;
 
            long ticks = 0;

            if (inv) {
                if (raw.FullHMSMatch(raw.PositiveInvariant)) { 
                    positive = true;
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, out ticks); 
                    overflow = overflow || !match; 
                }
                if (!match && raw.FullDHMMatch(raw.PositiveInvariant)) { 
                    positive = true;
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, zero, out ticks);
                    overflow = overflow || !match;
                } 
                if (!match && raw.PartialAppCompatMatch(raw.PositiveInvariant)) {
                    positive = true; 
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], zero, raw.numbers[2], out ticks); 
                    overflow = overflow || !match;
                } 
                if (!match && raw.FullHMSMatch(raw.NegativeInvariant)) {
                    positive = false;
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, out ticks);
                    overflow = overflow || !match; 
                }
                if (!match && raw.FullDHMMatch(raw.NegativeInvariant)) { 
                    positive = false; 
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, zero, out ticks);
                    overflow = overflow || !match; 
                }
                if (!match && raw.PartialAppCompatMatch(raw.NegativeInvariant)) {
                    positive = false;
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], zero, raw.numbers[2], out ticks); 
                    overflow = overflow || !match;
                } 
            } 
            if (loc) {
                if (!match && raw.FullHMSMatch(raw.PositiveLocalized)) { 
                    positive = true;
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, out ticks);
                    overflow = overflow || !match;
                } 
                if (!match && raw.FullDHMMatch(raw.PositiveLocalized)) {
                    positive = true; 
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, zero, out ticks); 
                    overflow = overflow || !match;
                } 
                if (!match && raw.PartialAppCompatMatch(raw.PositiveLocalized)) {
                    positive = true;
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], zero, raw.numbers[2], out ticks);
                    overflow = overflow || !match; 
                }
                if (!match && raw.FullHMSMatch(raw.NegativeLocalized)) { 
                    positive = false; 
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, out ticks);
                    overflow = overflow || !match; 
                }
                if (!match && raw.FullDHMMatch(raw.NegativeLocalized)) {
                    positive = false;
                    match = TryTimeToTicks(positive, raw.numbers[0], raw.numbers[1], raw.numbers[2], zero, zero, out ticks); 
                    overflow = overflow || !match;
                } 
                if (!match && raw.PartialAppCompatMatch(raw.NegativeLocalized)) { 
                    positive = false;
                    match = TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], zero, raw.numbers[2], out ticks); 
                    overflow = overflow || !match;
                }
            }
 
            if (match) {
                if (!positive) { 
                    ticks = -ticks; 
                    if (ticks > 0) {
                        result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); 
                        return false;
                    }
                }
                result.parsedTimeSpan._ticks = ticks; 
                return true;
            } 
 
            if (overflow) {
                // we found at least one literal pattern match but the numbers just didn't fit 
                result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge");
                return false;
            }
            else { 
                // we couldn't find a thing
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); 
                return false; 
            }
        } 

        //
        //  ProcessTerminal_HM
        // 
        //  Actions: Validate the 2-number "Hours:Minutes" terminal case
        // 
        private static Boolean ProcessTerminal_HM(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) { 
            if (raw.SepCount != 3 || raw.NumCount != 2 || (style & TimeSpanStandardStyles.RequireFull) != 0) {
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); 
                return false;
            }

            bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0); 
            bool loc = ((style & TimeSpanStandardStyles.Localized) != 0);
 
            bool positive = false; 
            bool match = false;
 
            if (inv) {
                if (raw.FullHMMatch(raw.PositiveInvariant)) {
                    match = true;
                    positive = true; 
                }
                if (!match && raw.FullHMMatch(raw.NegativeInvariant)) { 
                    match = true; 
                    positive = false;
                } 
            }
            if (loc) {
                if (!match && raw.FullHMMatch(raw.PositiveLocalized)) {
                    match = true; 
                    positive = true;
                } 
                if (!match && raw.FullHMMatch(raw.NegativeLocalized)) { 
                    match = true;
                    positive = false; 
                }
            }

            long ticks = 0; 
            if (match) {
                if (!TryTimeToTicks(positive, zero, raw.numbers[0], raw.numbers[1], zero, zero, out ticks)) { 
                    result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); 
                    return false;
                } 
                if (!positive) {
                    ticks = -ticks;
                    if (ticks > 0) {
                        result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); 
                        return false;
                    } 
                } 
                result.parsedTimeSpan._ticks = ticks;
                return true; 
            }

            result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
            return false; 
        }
 
 
        //
        //  ProcessTerminal_D 
        //
        //  Actions: Validate the 1-number "Days" terminal case
        //
        private static Boolean ProcessTerminal_D(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) { 
            if (raw.SepCount != 2 || raw.NumCount != 1 || (style & TimeSpanStandardStyles.RequireFull) != 0) {
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); 
                return false; 
            }
 
            bool inv = ((style & TimeSpanStandardStyles.Invariant) != 0);
            bool loc = ((style & TimeSpanStandardStyles.Localized) != 0);

            bool positive = false; 
            bool match = false;
 
            if (inv) { 
                if (raw.FullDMatch(raw.PositiveInvariant)) {
                    match = true; 
                    positive = true;
                }
                if (!match && raw.FullDMatch(raw.NegativeInvariant)) {
                    match = true; 
                    positive = false;
                } 
            } 
            if (loc) {
                if (!match && raw.FullDMatch(raw.PositiveLocalized)) { 
                    match = true;
                    positive = true;
                }
                if (!match && raw.FullDMatch(raw.NegativeLocalized)) { 
                    match = true;
                    positive = false; 
                } 
            }
 
            long ticks = 0;
            if (match) {
                if (!TryTimeToTicks(positive, raw.numbers[0], zero, zero, zero, zero, out ticks)) {
                    result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); 
                    return false;
                } 
                if (!positive) { 
                    ticks = -ticks;
                    if (ticks > 0) { 
                        result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge");
                        return false;
                    }
                } 
                result.parsedTimeSpan._ticks = ticks;
                return true; 
            } 

            result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); 
            return false;
        }
        #endregion
 
        #region TryParseExactTimeSpan
        // 
        //  TryParseExactTimeSpan 
        //
        //  Actions: Common private ParseExact method called by both ParseExact and TryParseExact 
        //
        private static Boolean TryParseExactTimeSpan(String input, String format, IFormatProvider formatProvider, TimeSpanStyles styles, ref TimeSpanResult result) {
            if (input == null) {
                result.SetFailure(ParseFailureKind.ArgumentNull, "ArgumentNull_String", null, "input"); 
                return false;
            } 
            if (format == null) { 
                result.SetFailure(ParseFailureKind.ArgumentNull, "ArgumentNull_String", null, "format");
                return false; 
            }
            if (format.Length == 0) {
                result.SetFailure(ParseFailureKind.Format, "Format_BadFormatSpecifier");
                return false; 
            }
 
            if (format.Length == 1) { 
                TimeSpanStandardStyles style = TimeSpanStandardStyles.None;
 
                if (format[0] == 'c' || format[0] == 't' || format[0] == 'T') {
                    // fast path for legacy style TimeSpan formats.
                    return TryParseTimeSpanConstant(input, ref result);
                } 
                else if (format[0] == 'g') {
                    style = TimeSpanStandardStyles.Localized; 
                } 
                else if (format[0] == 'G') {
                    style = TimeSpanStandardStyles.Localized | TimeSpanStandardStyles.RequireFull; 
                }
                else {
                    result.SetFailure(ParseFailureKind.Format, "Format_BadFormatSpecifier");
                    return false; 
                }
                return TryParseTimeSpan(input, style, formatProvider, ref result); 
            } 

            return TryParseByFormat(input, format, styles, ref result); 
        }

        //
        //  TryParseByFormat 
        //
        //  Actions: Parse the TimeSpan instance using the specified format.  Used by TryParseExactTimeSpan. 
        // 
        private static Boolean TryParseByFormat(String input, String format, TimeSpanStyles styles, ref TimeSpanResult result) {
            Contract.Assert(input != null, "input != null"); 
            Contract.Assert(format != null, "format != null");

            bool seenDD = false;      // already processed days?
            bool seenHH = false;      // already processed hours? 
            bool seenMM = false;      // already processed minutes?
            bool seenSS = false;      // already processed seconds? 
            bool seenFF = false;      // already processed fraction? 
            int dd = 0;               // parsed days
            int hh = 0;               // parsed hours 
            int mm = 0;               // parsed minutes
            int ss = 0;               // parsed seconds
            int leadingZeroes = 0;    // number of leading zeroes in the parsed fraction
            int ff = 0;               // parsed fraction 
            int i = 0;                // format string position
            int tokenLen = 0;         // length of current format token, used to update index 'i' 
 
            TimeSpanTokenizer tokenizer = new TimeSpanTokenizer();
            tokenizer.Init(input, -1); 

            while (i < format.Length) {
                char ch = format[i];
                int nextFormatChar; 
                switch (ch) {
                    case 'h': 
                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); 
                        if (tokenLen > 2 || seenHH || !ParseExactDigits(ref tokenizer, tokenLen, out hh)) {
                            result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); 
                            return false;
                        }
                        seenHH = true;
                        break; 
                    case 'm':
                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); 
                        if (tokenLen > 2 || seenMM || !ParseExactDigits(ref tokenizer, tokenLen, out mm)) { 
                            result.SetFailure(ParseFailureKind.Format, "Format_InvalidString");
                            return false; 
                        }
                        seenMM = true;
                        break;
                    case 's': 
                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
                        if (tokenLen > 2 || seenSS || !ParseExactDigits(ref tokenizer, tokenLen, out ss)) { 
                            result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); 
                            return false;
                        } 
                        seenSS = true;
                        break;
                    case 'f':
                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch); 
                        if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits || seenFF || !ParseExactDigits(ref tokenizer, tokenLen, tokenLen, out leadingZeroes, out ff)) {
                            result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); 
                            return false; 
                        }
                        seenFF = true; 
                        break;
                    case 'F':
                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
                        if (tokenLen > DateTimeFormat.MaxSecondsFractionDigits || seenFF) { 
                            result.SetFailure(ParseFailureKind.Format, "Format_InvalidString");
                            return false; 
                        } 
                        ParseExactDigits(ref tokenizer, tokenLen, tokenLen, out leadingZeroes, out ff);
                        seenFF = true; 
                        break;
                    case 'd':
                        tokenLen = DateTimeFormat.ParseRepeatPattern(format, i, ch);
                        int tmp = 0; 
                        if (tokenLen > 8 || seenDD || !ParseExactDigits(ref tokenizer, (tokenLen<2) ? 1 : tokenLen, (tokenLen<2) ? 8 : tokenLen, out tmp, out dd)) {
                            result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); 
                            return false; 
                        }
                        seenDD = true; 
                        break;
                    case '\'':
                    case '\"':
                        StringBuilder enquotedString = new StringBuilder(); 
                        if (!DateTimeParse.TryParseQuoteString(format, i, enquotedString, out tokenLen)) {
                            result.SetFailure(ParseFailureKind.FormatWithParameter, "Format_BadQuote", ch); 
                            return false; 
                        }
                        if (!ParseExactLiteral(ref tokenizer, enquotedString)) { 
                            result.SetFailure(ParseFailureKind.Format, "Format_InvalidString");
                            return false;
                        }
                        break; 
                    case '%':
                        // Optional format character. 
                        // For example, format string "%d" will print day 
                        // Most of the cases, "%" can be ignored.
                        nextFormatChar = DateTimeFormat.ParseNextChar(format, i); 
                        // nextFormatChar will be -1 if we already reach the end of the format string.
                        // Besides, we will not allow "%%" appear in the pattern.
                        if (nextFormatChar >= 0 && nextFormatChar != (int)'%') {
                            tokenLen = 1; // skip the '%' and process the format character 
                            break;
                        } 
                        else { 
                            // This means that '%' is at the end of the format string or
                            // "%%" appears in the format string. 
                            result.SetFailure(ParseFailureKind.Format, "Format_InvalidString");
                            return false;
                        }
                    case '\\': 
                        // Escaped character.  Can be used to insert character into the format string.
                        // For example, "\d" will insert the character 'd' into the string. 
                        // 
                        nextFormatChar = DateTimeFormat.ParseNextChar(format, i);
                        if (nextFormatChar >= 0 && tokenizer.NextChar == (char)nextFormatChar) { 
                            tokenLen = 2;
                        }
                        else {
                            // This means that '\' is at the end of the format string or the literal match failed. 
                            result.SetFailure(ParseFailureKind.Format, "Format_InvalidString");
                            return false; 
                        } 
                        break;
                    default: 
                        result.SetFailure(ParseFailureKind.Format, "Format_InvalidString");
                        return false;
                }
                i += tokenLen; 
            }
 
 
            if (!tokenizer.EOL) {
                // the custom format didn't consume the entire input 
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
                return false;
            }
 
            long ticks = 0;
            bool positive = (styles & TimeSpanStyles.AssumeNegative) == 0; 
            if (TryTimeToTicks(positive, new TimeSpanToken(dd), 
                                         new TimeSpanToken(hh),
                                         new TimeSpanToken(mm), 
                                         new TimeSpanToken(ss),
                                         new TimeSpanToken(leadingZeroes, ff),
                                         out ticks)) {
                if (!positive) ticks = -ticks; 
                result.parsedTimeSpan._ticks = ticks;
                return true; 
            } 
            else {
                result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); 
                return false;

            }
        } 

        private static Boolean ParseExactDigits(ref TimeSpanTokenizer tokenizer, int minDigitLength, out int result) { 
            result = 0; 
            int zeroes = 0;
            int maxDigitLength = (minDigitLength == 1) ? 2 : minDigitLength; 
            return ParseExactDigits(ref tokenizer, minDigitLength, maxDigitLength, out zeroes, out result);
        }
        private static Boolean ParseExactDigits(ref TimeSpanTokenizer tokenizer, int minDigitLength, int maxDigitLength, out int zeroes, out int result) {
            result = 0; 
            zeroes = 0;
 
            int tokenLength = 0; 
            while (tokenLength < maxDigitLength) {
                char ch = tokenizer.NextChar; 
                if (ch < '0' || ch > '9') {
                    tokenizer.BackOne();
                    break;
                } 
                result = result * 10 + (ch - '0');
                if (result == 0) zeroes++; 
                tokenLength++; 
            }
            return (tokenLength >= minDigitLength); 
        }
        private static Boolean ParseExactLiteral(ref TimeSpanTokenizer tokenizer, StringBuilder enquotedString) {
            for (int i = 0; i < enquotedString.Length; i++) {
                if (enquotedString[i] != tokenizer.NextChar) 
                    return false;
            } 
            return true; 
        }
        #endregion 

        #region TryParseTimeSpanConstant
        //
        // TryParseTimeSpanConstant 
        //
        // Actions: Parses the "c" (constant) format.  This code is 100% identical to the non-globalized v1.0-v3.5 TimeSpan.Parse() routine 
        //          and exists for performance/appcompat with legacy callers who cannot move onto the globalized Parse overloads. 
        //
        private static Boolean TryParseTimeSpanConstant(String input, ref TimeSpanResult result) { 
            return (new StringParser().TryParse(input, ref result));
        }

        private struct StringParser { 
            private String str;
            private char ch; 
            private int pos; 
            private int len;
 
            internal void NextChar() {
                if (pos < len) pos++;
                ch = pos < len? str[pos]: (char) 0;
            } 

            internal char NextNonDigit() { 
                int i = pos; 
                while (i < len) {
                    char ch = str[i]; 
                    if (ch < '0' || ch > '9') return ch;
                    i++;
                }
                return (char) 0; 
            }
 
            internal bool TryParse(String input, ref TimeSpanResult result) { 
                result.parsedTimeSpan._ticks = 0;
 
                if (input == null) {
                    result.SetFailure(ParseFailureKind.ArgumentNull, "ArgumentNull_String", null, "input");
                    return false;
                } 
                str = input;
                len = input.Length; 
                pos = -1; 
                NextChar();
                SkipBlanks(); 
                bool negative = false;
                if (ch == '-') {
                    negative = true;
                    NextChar(); 
                }
                long time; 
                if (NextNonDigit() == ':') { 
                    if (!ParseTime(out time, ref result)) {
                        return false; 
                    };
                }
                else {
                    int days; 
                    if (!ParseInt((int)(0x7FFFFFFFFFFFFFFFL / TimeSpan.TicksPerDay), out days, ref result)) {
                        return false; 
                    } 
                    time = days * TimeSpan.TicksPerDay;
                    if (ch == '.') { 
                        NextChar();
                        long remainingTime;
                        if (!ParseTime(out remainingTime, ref result)) {
                            return false; 
                        };
                        time += remainingTime; 
                    } 
                }
                if (negative) { 
                    time = -time;
                    // Allow -0 as well
                    if (time > 0) {
                        result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); 
                        return false;
                    } 
                } 
                else {
                    if (time < 0) { 
                        result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge");
                        return false;
                    }
                } 
                SkipBlanks();
                if (pos < len) { 
                    result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); 
                    return false;
                } 
                result.parsedTimeSpan._ticks = time;
                return true;
            }
 
            internal bool ParseInt(int max, out int i, ref TimeSpanResult result) {
                i = 0; 
                int p = pos; 
                while (ch >= '0' && ch <= '9') {
                    if ((i & 0xF0000000) != 0) { 
                        result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge");
                        return false;
                    }
                    i = i * 10 + ch - '0'; 
                    if (i < 0) {
                        result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); 
                        return false; 
                    }
                    NextChar(); 
                }
                if (p == pos) {
                    result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
                    return false; 
                }
                if (i > max) { 
                    result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); 
                    return false;
                } 
                return true;
            }

            internal bool ParseTime(out long time, ref TimeSpanResult result) { 
                time = 0;
                int unit; 
                if (!ParseInt(23, out unit, ref result)) { 
                    return false;
                } 
                time = unit * TimeSpan.TicksPerHour;
                if (ch != ':') {
                    result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
                    return false; 
                }
                NextChar(); 
                if (!ParseInt(59, out unit, ref result)) { 
                    return false;
                } 
                time += unit * TimeSpan.TicksPerMinute;
                if (ch == ':') {
                    NextChar();
                    // allow seconds with the leading zero 
                    if (ch != '.') {
                        if (!ParseInt(59, out unit, ref result)) { 
                            return false; 
                        }
                        time += unit * TimeSpan.TicksPerSecond; 
                    }
                    if (ch == '.') {
                        NextChar();
                        int f = (int)TimeSpan.TicksPerSecond; 
                        while (f > 1 && ch >= '0' && ch <= '9') {
                            f /= 10; 
                            time += (ch - '0') * f; 
                            NextChar();
                        } 
                    }
                }
                return true;
            } 

            internal void SkipBlanks() { 
                while (ch == ' ' || ch == '\t') NextChar(); 
            }
        } 
        #endregion

        #region TryParseExactMultipleTimeSpan
        // 
        //  TryParseExactMultipleTimeSpan
        // 
        //  Actions: Common private ParseExactMultiple method called by both ParseExactMultiple and TryParseExactMultiple 
        //
        private static Boolean TryParseExactMultipleTimeSpan(String input, String[] formats, IFormatProvider formatProvider, TimeSpanStyles styles, ref TimeSpanResult result) { 
            if (input == null) {
                result.SetFailure(ParseFailureKind.ArgumentNull, "ArgumentNull_String", null, "input");
                return false;
            } 
            if (formats == null) {
                result.SetFailure(ParseFailureKind.ArgumentNull, "ArgumentNull_String", null, "formats"); 
                return false; 
            }
 
            if (input.Length == 0) {
                result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan");
                return false;
            } 

            if (formats.Length == 0) { 
                result.SetFailure(ParseFailureKind.Format, "Format_BadFormatSpecifier"); 
                return false;
            } 

            //
            // Do a loop through the provided formats and see if we can parse succesfully in
            // one of the formats. 
            //
            for (int i = 0; i < formats.Length; i++) { 
                if (formats[i] == null || formats[i].Length == 0) { 
                    result.SetFailure(ParseFailureKind.Format, "Format_BadFormatSpecifier");
                    return false; 
                }

                // Create a new non-throwing result each time to ensure the runs are independent.
                TimeSpanResult innerResult = new TimeSpanResult(); 
                innerResult.Init(TimeSpanThrowStyle.None);
 
                if(TryParseExactTimeSpan(input, formats[i], formatProvider, styles, ref innerResult)) { 
                    result.parsedTimeSpan = innerResult.parsedTimeSpan;
                    return true; 
                }
            }

            result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); 
            return (false);
        } 
        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK