internal static Exception TryParse(string s, DurationType durationType, out XsdDuration result) {
string errorCode;
int length;
int value, pos, numDigits;
Parts parts = Parts.HasNone;
result = new XsdDuration();
s = s.Trim();
length = s.Length;
pos = 0;
numDigits = 0;
if (pos >= length) goto InvalidFormat;
if (s[pos] == '-') {
pos++;
result.nanoseconds = NegativeBit;
}
else {
result.nanoseconds = 0;
}
if (pos >= length) goto InvalidFormat;
if (s[pos++] != 'P') goto InvalidFormat;
errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
if (errorCode != null) goto Error;
if (pos >= length) goto InvalidFormat;
if (s[pos] == 'Y') {
if (numDigits == 0) goto InvalidFormat;
parts |= Parts.HasYears;
result.years = value;
if (++pos == length) goto Done;
errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
if (errorCode != null) goto Error;
if (pos >= length) goto InvalidFormat;
}
if (s[pos] == 'M') {
if (numDigits == 0) goto InvalidFormat;
parts |= Parts.HasMonths;
result.months = value;
if (++pos == length) goto Done;
errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
if (errorCode != null) goto Error;
if (pos >= length) goto InvalidFormat;
}
if (s[pos] == 'D') {
if (numDigits == 0) goto InvalidFormat;
parts |= Parts.HasDays;
result.days = value;
if (++pos == length) goto Done;
errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
if (errorCode != null) goto Error;
if (pos >= length) goto InvalidFormat;
}
if (s[pos] == 'T') {
if (numDigits != 0) goto InvalidFormat;
pos++;
errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
if (errorCode != null) goto Error;
if (pos >= length) goto InvalidFormat;
if (s[pos] == 'H') {
if (numDigits == 0) goto InvalidFormat;
parts |= Parts.HasHours;
result.hours = value;
if (++pos == length) goto Done;
errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
if (errorCode != null) goto Error;
if (pos >= length) goto InvalidFormat;
}
if (s[pos] == 'M') {
if (numDigits == 0) goto InvalidFormat;
parts |= Parts.HasMinutes;
result.minutes = value;
if (++pos == length) goto Done;
errorCode = TryParseDigits(s, ref pos, false, out value, out numDigits);
if (errorCode != null) goto Error;
if (pos >= length) goto InvalidFormat;
}
if (s[pos] == '.') {
pos++;
parts |= Parts.HasSeconds;
result.seconds = value;
errorCode = TryParseDigits(s, ref pos, true, out value, out numDigits);
if (errorCode != null) goto Error;
if (numDigits == 0) { //If there are no digits after the decimal point, assume 0
value = 0;
}
// Normalize to nanosecond intervals
for (; numDigits > 9; numDigits--)
value /= 10;
for (; numDigits < 9; numDigits++)
value *= 10;
result.nanoseconds |= (uint) value;
if (pos >= length) goto InvalidFormat;
if (s[pos] != 'S') goto InvalidFormat;
if (++pos == length) goto Done;
}
else if (s[pos] == 'S') {
if (numDigits == 0) goto InvalidFormat;
parts |= Parts.HasSeconds;
result.seconds = value;
if (++pos == length) goto Done;
}
}
// Duration cannot end with digits
if (numDigits != 0) goto InvalidFormat;
// No further characters are allowed
if (pos != length) goto InvalidFormat;
Done:
// At least one part must be defined
if (parts == Parts.HasNone) goto InvalidFormat;
if (durationType == DurationType.DayTimeDuration) {
if ((parts & (Parts.HasYears | Parts.HasMonths)) != 0)
goto InvalidFormat;
}
else if (durationType == DurationType.YearMonthDuration) {
if ((parts & ~(XsdDuration.Parts.HasYears | XsdDuration.Parts.HasMonths)) != 0)
goto InvalidFormat;
}
return null;
InvalidFormat:
return new FormatException(Res.GetString(Res.XmlConvert_BadFormat, s, durationType));
Error:
return new OverflowException(Res.GetString(Res.XmlConvert_Overflow, s, durationType));
}