internal static TimeSpan ParseExactMultiple(string input, string[] formats, IFormatProvider formatProvider, TimeSpanStyles styles) { TimeSpanResult result = new TimeSpanResult(); result.Init(TimeSpanThrowStyle.All); if (!TryParseExactMultipleTimeSpan(input, formats, formatProvider, styles, ref result)) { throw result.GetTimeSpanParseException(); } return result.parsedTimeSpan; }
internal static TimeSpan Parse(string input, IFormatProvider formatProvider) { TimeSpanResult result = new TimeSpanResult(); result.Init(TimeSpanThrowStyle.All); if (!TryParseTimeSpan(input, TimeSpanStandardStyles.Any, formatProvider, ref result)) { throw result.GetTimeSpanParseException(); } return result.parsedTimeSpan; }
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 static bool TryParse(string input, IFormatProvider formatProvider, out TimeSpan result) { TimeSpanResult result2 = new TimeSpanResult(); result2.Init(TimeSpanThrowStyle.None); if (TryParseTimeSpan(input, TimeSpanStandardStyles.Any, formatProvider, ref result2)) { result = result2.parsedTimeSpan; return true; } result = new TimeSpan(); 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; } }
// ---- 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, nameof(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; }
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(); } }
// ---- 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(); } }
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 static bool TryParseTimeSpanConstant(string input, ref TimeSpanResult result) { StringParser parser2 = new StringParser(); return parser2.TryParse(input, ref result); }
private static bool 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)); for (TimeSpanToken token = tokenizer.GetNextToken(); token.ttt != TTT.End; token = tokenizer.GetNextToken()) { if (!raw.ProcessToken(ref token, ref result)) { result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); return false; } } if (!tokenizer.EOL) { 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; }
private static bool 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) { return TryParseByFormat(input, format, styles, ref result); } TimeSpanStandardStyles none = TimeSpanStandardStyles.None; if (((format[0] == 'c') || (format[0] == 't')) || (format[0] == 'T')) { return TryParseTimeSpanConstant(input, ref result); } if (format[0] == 'g') { none = TimeSpanStandardStyles.Localized; } else if (format[0] == 'G') { none = TimeSpanStandardStyles.RequireFull | TimeSpanStandardStyles.Localized; } else { result.SetFailure(ParseFailureKind.Format, "Format_BadFormatSpecifier"); return false; } return TryParseTimeSpan(input, none, formatProvider, ref result); }
private static bool 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; } for (int i = 0; i < formats.Length; i++) { if ((formats[i] == null) || (formats[i].Length == 0)) { result.SetFailure(ParseFailureKind.Format, "Format_BadFormatSpecifier"); return false; } TimeSpanResult result2 = new TimeSpanResult(); result2.Init(TimeSpanThrowStyle.None); if (TryParseExactTimeSpan(input, formats[i], formatProvider, styles, ref result2)) { result.parsedTimeSpan = result2.parsedTimeSpan; return true; } } result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); return false; }
internal static bool TryParseExactMultiple(string input, string[] formats, IFormatProvider formatProvider, TimeSpanStyles styles, out TimeSpan result) { TimeSpanResult result2 = new TimeSpanResult(); result2.Init(TimeSpanThrowStyle.None); if (TryParseExactMultipleTimeSpan(input, formats, formatProvider, styles, ref result2)) { result = result2.parsedTimeSpan; return true; } result = new TimeSpan(); return false; }
private static bool TryParseByFormat(string input, string format, TimeSpanStyles styles, ref TimeSpanResult result) { bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = false; bool flag5 = false; int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int zeroes = 0; int num6 = 0; int pos = 0; int returnValue = 0; TimeSpanTokenizer tokenizer = new TimeSpanTokenizer(); tokenizer.Init(input, -1); while (pos < format.Length) { int num9; char failureMessageFormatArgument = format[pos]; switch (failureMessageFormatArgument) { case '%': num9 = DateTimeFormat.ParseNextChar(format, pos); if ((num9 < 0) || (num9 == 0x25)) { goto Label_0280; } returnValue = 1; goto Label_02CA; case '\'': case '"': { StringBuilder builder = new StringBuilder(); if (!DateTimeParse.TryParseQuoteString(format, pos, builder, out returnValue)) { result.SetFailure(ParseFailureKind.FormatWithParameter, "Format_BadQuote", failureMessageFormatArgument); return false; } if (ParseExactLiteral(ref tokenizer, builder)) { goto Label_02CA; } result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); return false; } case 'F': returnValue = DateTimeFormat.ParseRepeatPattern(format, pos, failureMessageFormatArgument); if ((returnValue > 7) || flag5) { result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); return false; } ParseExactDigits(ref tokenizer, returnValue, returnValue, out zeroes, out num6); flag5 = true; goto Label_02CA; case 'm': returnValue = DateTimeFormat.ParseRepeatPattern(format, pos, failureMessageFormatArgument); if (((returnValue > 2) || flag3) || !ParseExactDigits(ref tokenizer, returnValue, out num3)) { result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); return false; } flag3 = true; goto Label_02CA; case 's': returnValue = DateTimeFormat.ParseRepeatPattern(format, pos, failureMessageFormatArgument); if (((returnValue > 2) || flag4) || !ParseExactDigits(ref tokenizer, returnValue, out num4)) { result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); return false; } flag4 = true; goto Label_02CA; case 'd': { returnValue = DateTimeFormat.ParseRepeatPattern(format, pos, failureMessageFormatArgument); int num10 = 0; if (((returnValue > 8) || flag) || !ParseExactDigits(ref tokenizer, (returnValue < 2) ? 1 : returnValue, (returnValue < 2) ? 8 : returnValue, out num10, out num)) { result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); return false; } flag = true; goto Label_02CA; } case 'f': returnValue = DateTimeFormat.ParseRepeatPattern(format, pos, failureMessageFormatArgument); if (((returnValue <= 7) && !flag5) && ParseExactDigits(ref tokenizer, returnValue, returnValue, out zeroes, out num6)) { goto Label_0193; } result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); return false; case 'h': returnValue = DateTimeFormat.ParseRepeatPattern(format, pos, failureMessageFormatArgument); if (((returnValue <= 2) && !flag2) && ParseExactDigits(ref tokenizer, returnValue, out num2)) { break; } result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); return false; case '\\': num9 = DateTimeFormat.ParseNextChar(format, pos); if ((num9 >= 0) && (tokenizer.NextChar == ((char) num9))) { returnValue = 2; goto Label_02CA; } result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); return false; default: result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); return false; } flag2 = true; goto Label_02CA; Label_0193: flag5 = true; goto Label_02CA; Label_0280: result.SetFailure(ParseFailureKind.Format, "Format_InvalidString"); return false; Label_02CA: pos += returnValue; } if (!tokenizer.EOL) { result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); return false; } long num11 = 0L; bool positive = (styles & TimeSpanStyles.AssumeNegative) == TimeSpanStyles.None; if (TryTimeToTicks(positive, new TimeSpanToken(num), new TimeSpanToken(num2), new TimeSpanToken(num3), new TimeSpanToken(num4), new TimeSpanToken(zeroes, num6), out num11)) { if (!positive) { num11 = -num11; } result.parsedTimeSpan._ticks = num11; return true; } result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); return false; }
// // 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, nameof(input)); return false; } if (formats == null) { result.SetFailure(ParseFailureKind.ArgumentNull, "ArgumentNull_String", null, nameof(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); }
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; Debug.Assert(tokenCount == (SepCount + NumCount), "tokenCount == (SepCount + NumCount)"); return true; }
private static bool ProcessTerminal_D(ref TimeSpanRawInfo raw, TimeSpanStandardStyles style, ref TimeSpanResult result) { if (((raw.SepCount != 2) || (raw.NumCount != 1)) || ((style & TimeSpanStandardStyles.RequireFull) != TimeSpanStandardStyles.None)) { result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); return false; } bool flag = (style & TimeSpanStandardStyles.Invariant) != TimeSpanStandardStyles.None; bool flag2 = (style & TimeSpanStandardStyles.Localized) != TimeSpanStandardStyles.None; bool positive = false; bool flag4 = false; if (flag) { if (raw.FullDMatch(raw.PositiveInvariant)) { flag4 = true; positive = true; } if (!flag4 && raw.FullDMatch(raw.NegativeInvariant)) { flag4 = true; positive = false; } } if (flag2) { if (!flag4 && raw.FullDMatch(raw.PositiveLocalized)) { flag4 = true; positive = true; } if (!flag4 && raw.FullDMatch(raw.NegativeLocalized)) { flag4 = true; positive = false; } } long num = 0L; if (flag4) { if (!TryTimeToTicks(positive, raw.numbers[0], zero, zero, zero, zero, out num)) { result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); return false; } if (!positive) { num = -num; if (num > 0L) { result.SetFailure(ParseFailureKind.Overflow, "Overflow_TimeSpanElementTooLarge"); return false; } } result.parsedTimeSpan._ticks = num; return true; } result.SetFailure(ParseFailureKind.Format, "Format_BadTimeSpan"); return false; }
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; }
// // 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, nameof(input)); return false; } if (format == null) { result.SetFailure(ParseFailureKind.ArgumentNull, "ArgumentNull_String", null, nameof(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); }
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; } }
// // 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) { Debug.Assert(input != null, "input != null"); Debug.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; } }
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; } }
// // 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)); }
// // 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; } }
internal bool TryParse(String input, ref TimeSpanResult result) { result.parsedTimeSpan._ticks = 0; if (input == null) { result.SetFailure(ParseFailureKind.ArgumentNull, "ArgumentNull_String", null, nameof(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; }
// // 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; }
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; }