Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Xml / System / Xml / schema / XsdDuration.cs / 1 / XsdDuration.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- namespace System.Xml.Schema { using System; using System.Diagnostics; using System.Text; ////// This structure holds components of an Xsd Duration. It is used internally to support Xsd durations without loss /// of fidelity. XsdDuration structures are immutable once they've been created. /// internal struct XsdDuration { private int years; private int months; private int days; private int hours; private int minutes; private int seconds; private uint nanoseconds; // High bit is used to indicate whether duration is negative private const uint NegativeBit = 0x80000000; private enum Parts { HasNone = 0, HasYears = 1, HasMonths = 2, HasDays = 4, HasHours = 8, HasMinutes = 16, HasSeconds = 32, } internal enum DurationType { Duration, YearMonthDuration, DayTimeDuration, }; ////// Construct an XsdDuration from component parts. /// public XsdDuration(bool isNegative, int years, int months, int days, int hours, int minutes, int seconds, int nanoseconds) { if (years < 0) throw new ArgumentOutOfRangeException("years"); if (months < 0) throw new ArgumentOutOfRangeException("months"); if (days < 0) throw new ArgumentOutOfRangeException("days"); if (hours < 0) throw new ArgumentOutOfRangeException("hours"); if (minutes < 0) throw new ArgumentOutOfRangeException("minutes"); if (seconds < 0) throw new ArgumentOutOfRangeException("seconds"); if (nanoseconds < 0 || nanoseconds > 999999999) throw new ArgumentOutOfRangeException("nanoseconds"); this.years = years; this.months = months; this.days = days; this.hours = hours; this.minutes = minutes; this.seconds = seconds; this.nanoseconds = (uint) nanoseconds; if (isNegative) this.nanoseconds |= NegativeBit; } ////// Construct an XsdDuration from a TimeSpan value. /// public XsdDuration(TimeSpan timeSpan) : this(timeSpan, DurationType.Duration) { } ////// Construct an XsdDuration from a TimeSpan value that represents an xsd:duration, an xdt:dayTimeDuration, or /// an xdt:yearMonthDuration. /// internal XsdDuration(TimeSpan timeSpan, DurationType durationType) { long ticks = timeSpan.Ticks; ulong ticksPos; bool isNegative; if (ticks < 0) { // Note that (ulong) -Int64.MinValue = Int64.MaxValue + 1, which is what we want for that special case isNegative = true; ticksPos = (ulong) -ticks; } else { isNegative = false; ticksPos = (ulong) ticks; } if (durationType == DurationType.YearMonthDuration) { int years = (int) (ticksPos / ((ulong) TimeSpan.TicksPerDay * 365)); int months = (int) ((ticksPos % ((ulong) TimeSpan.TicksPerDay * 365)) / ((ulong) TimeSpan.TicksPerDay * 30)); if (months == 12) { // If remaining days >= 360 and < 365, then round off to year years++; months = 0; } this = new XsdDuration(isNegative, years, months, 0, 0, 0, 0, 0); } else { Debug.Assert(durationType == DurationType.Duration || durationType == DurationType.DayTimeDuration); // Tick count is expressed in 100 nanosecond intervals this.nanoseconds = (uint) (ticksPos % 10000000) * 100; if (isNegative) this.nanoseconds |= NegativeBit; this.years = 0; this.months = 0; this.days = (int) (ticksPos / (ulong) TimeSpan.TicksPerDay); this.hours = (int) ((ticksPos / (ulong) TimeSpan.TicksPerHour) % 24); this.minutes = (int) ((ticksPos / (ulong) TimeSpan.TicksPerMinute) % 60); this.seconds = (int) ((ticksPos / (ulong) TimeSpan.TicksPerSecond) % 60); } } ////// Constructs an XsdDuration from a string in the xsd:duration format. Components are stored with loss /// of fidelity (except in the case of overflow). /// public XsdDuration(string s) : this(s, DurationType.Duration) { } ////// Constructs an XsdDuration from a string in the xsd:duration format. Components are stored without loss /// of fidelity (except in the case of overflow). /// public XsdDuration(string s, DurationType durationType) { XsdDuration result; Exception exception = TryParse(s, durationType, out result); if (exception != null) { throw exception; } this.years = result.Years; this.months = result.Months; this.days = result.Days; this.hours = result.Hours; this.minutes = result.Minutes; this.seconds = result.Seconds; this.nanoseconds = (uint)result.Nanoseconds; if (result.IsNegative) { this.nanoseconds |= NegativeBit; } return; } ////// Return true if this duration is negative. /// public bool IsNegative { get { return (this.nanoseconds & NegativeBit) != 0; } } ////// Return number of years in this duration (stored in 31 bits). /// public int Years { get { return this.years; } } ////// Return number of months in this duration (stored in 31 bits). /// public int Months { get { return this.months; } } ////// Return number of days in this duration (stored in 31 bits). /// public int Days { get { return this.days; } } ////// Return number of hours in this duration (stored in 31 bits). /// public int Hours { get { return this.hours; } } ////// Return number of minutes in this duration (stored in 31 bits). /// public int Minutes { get { return this.minutes; } } ////// Return number of seconds in this duration (stored in 31 bits). /// public int Seconds { get { return this.seconds; } } ////// Return number of nanoseconds in this duration. /// public int Nanoseconds { get { return (int) (this.nanoseconds & ~NegativeBit); } } ////// Return number of microseconds in this duration. /// public int Microseconds { get { return Nanoseconds / 1000; } } ////// Return number of milliseconds in this duration. /// public int Milliseconds { get { return Nanoseconds / 1000000; } } ////// Normalize year-month part and day-time part so that month < 12, hour < 24, minute < 60, and second < 60. /// public XsdDuration Normalize() { int years = Years; int months = Months; int days = Days; int hours = Hours; int minutes = Minutes; int seconds = Seconds; try { checked { if (months >= 12) { years += months / 12; months %= 12; } if (seconds >= 60) { minutes += seconds / 60; seconds %= 60; } if (minutes >= 60) { hours += minutes / 60; minutes %= 60; } if (hours >= 24) { days += hours / 24; hours %= 24; } } } catch (OverflowException) { throw new OverflowException(Res.GetString(Res.XmlConvert_Overflow, ToString(), "Duration")); } return new XsdDuration(IsNegative, years, months, days, hours, minutes, seconds, Nanoseconds); } ////// Internal helper method that converts an Xsd duration to a TimeSpan value. This code uses the estimate /// that there are 365 days in the year and 30 days in a month. /// public TimeSpan ToTimeSpan() { return ToTimeSpan(DurationType.Duration); } ////// Internal helper method that converts an Xsd duration to a TimeSpan value. This code uses the estimate /// that there are 365 days in the year and 30 days in a month. /// internal TimeSpan ToTimeSpan(DurationType durationType) { TimeSpan result; Exception exception = TryToTimeSpan(durationType, out result); if (exception != null) { throw exception; } return result; } internal Exception TryToTimeSpan(out TimeSpan result) { return TryToTimeSpan(DurationType.Duration, out result); } internal Exception TryToTimeSpan(DurationType durationType, out TimeSpan result) { Exception exception = null; ulong ticks = 0; // Throw error if result cannot fit into a long try { checked { // Discard year and month parts if constructing TimeSpan for DayTimeDuration if (durationType != DurationType.DayTimeDuration) { ticks += ((ulong) this.years + (ulong) this.months / 12) * 365; ticks += ((ulong) this.months % 12) * 30; } // Discard day and time parts if constructing TimeSpan for YearMonthDuration if (durationType != DurationType.YearMonthDuration) { ticks += (ulong) this.days; ticks *= 24; ticks += (ulong) this.hours; ticks *= 60; ticks += (ulong) this.minutes; ticks *= 60; ticks += (ulong) this.seconds; // Tick count interval is in 100 nanosecond intervals (7 digits) ticks *= (ulong) TimeSpan.TicksPerSecond; ticks += (ulong) Nanoseconds / 100; } else { // Multiply YearMonth duration by number of ticks per day ticks *= (ulong) TimeSpan.TicksPerDay; } if (IsNegative) { // Handle special case of Int64.MaxValue + 1 before negation, since it would otherwise overflow if (ticks == (ulong) Int64.MaxValue + 1) { result = new TimeSpan(Int64.MinValue); } else { result = new TimeSpan(-((long) ticks)); } } else { result = new TimeSpan((long) ticks); } return null; } } catch (OverflowException) { result = TimeSpan.MinValue; exception = new OverflowException(Res.GetString(Res.XmlConvert_Overflow, durationType, "TimeSpan")); } return exception; } ////// Return the string representation of this Xsd duration. /// public override string ToString() { return ToString(DurationType.Duration); } ////// Return the string representation according to xsd:duration rules, xdt:dayTimeDuration rules, or /// xdt:yearMonthDuration rules. /// internal string ToString(DurationType durationType) { StringBuilder sb = new StringBuilder(20); int nanoseconds, digit, zeroIdx, len; if (IsNegative) sb.Append('-'); sb.Append('P'); if (durationType != DurationType.DayTimeDuration) { if (this.years != 0) { sb.Append(XmlConvert.ToString(this.years)); sb.Append('Y'); } if (this.months != 0) { sb.Append(XmlConvert.ToString(this.months)); sb.Append('M'); } } if (durationType != DurationType.YearMonthDuration) { if (this.days != 0) { sb.Append(XmlConvert.ToString(this.days)); sb.Append('D'); } if (this.hours != 0 || this.minutes != 0 || this.seconds != 0 || Nanoseconds != 0) { sb.Append('T'); if (this.hours != 0) { sb.Append(XmlConvert.ToString(this.hours)); sb.Append('H'); } if (this.minutes != 0) { sb.Append(XmlConvert.ToString(this.minutes)); sb.Append('M'); } nanoseconds = Nanoseconds; if (this.seconds != 0 || nanoseconds != 0) { sb.Append(XmlConvert.ToString(this.seconds)); if (nanoseconds != 0) { sb.Append('.'); len = sb.Length; sb.Length += 9; zeroIdx = sb.Length - 1; for (int idx = zeroIdx; idx >= len; idx--) { digit = nanoseconds % 10; sb[idx] = (char) (digit + '0'); if (zeroIdx == idx && digit == 0) zeroIdx--; nanoseconds /= 10; } sb.Length = zeroIdx + 1; } sb.Append('S'); } } // Zero is represented as "PT0S" if (sb[sb.Length - 1] == 'P') sb.Append("T0S"); } else { // Zero is represented as "T0M" if (sb[sb.Length - 1] == 'P') sb.Append("0M"); } return sb.ToString(); } internal static Exception TryParse(string s, out XsdDuration result) { return TryParse(s, DurationType.Duration, out result); } 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)); } /// Helper method that constructs an integer from leading digits starting at s[offset]. "offset" is /// updated to contain an offset just beyond the last digit. The number of digits consumed is returned in /// cntDigits. The integer is returned (0 if no digits). If the digits cannot fit into an Int32: /// 1. If eatDigits is true, then additional digits will be silently discarded (don't count towards numDigits) /// 2. If eatDigits is false, an overflow exception is thrown private static string TryParseDigits(string s, ref int offset, bool eatDigits, out int result, out int numDigits) { int offsetStart = offset; int offsetEnd = s.Length; int digit; result = 0; numDigits = 0; while (offset < offsetEnd && s[offset] >= '0' && s[offset] <= '9') { digit = s[offset] - '0'; if (result > (Int32.MaxValue - digit) / 10) { if (!eatDigits) { return Res.XmlConvert_Overflow; } // Skip past any remaining digits numDigits = offset - offsetStart; while (offset < offsetEnd && s[offset] >= '0' && s[offset] <= '9') { offset++; } return null; } result = result * 10 + digit; offset++; } numDigits = offset - offsetStart; return null; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SynchronizedDispatch.cs
- PerfCounterSection.cs
- EncoderReplacementFallback.cs
- TickBar.cs
- ConditionalExpression.cs
- Authorization.cs
- EventSinkHelperWriter.cs
- ZoneLinkButton.cs
- ListViewItem.cs
- TextEditorParagraphs.cs
- KernelTypeValidation.cs
- InvokeProviderWrapper.cs
- AdPostCacheSubstitution.cs
- ConditionedDesigner.cs
- ToolBarOverflowPanel.cs
- AffineTransform3D.cs
- ByteStream.cs
- CompositeDesignerAccessibleObject.cs
- Size3DValueSerializer.cs
- OleStrCAMarshaler.cs
- DoubleLinkListEnumerator.cs
- ValueUnavailableException.cs
- DeploymentExceptionMapper.cs
- BindingRestrictions.cs
- SurrogateSelector.cs
- VerticalAlignConverter.cs
- ReadOnlyHierarchicalDataSourceView.cs
- Function.cs
- CompilerWrapper.cs
- FixedBufferAttribute.cs
- SwitchAttribute.cs
- SafeUserTokenHandle.cs
- WorkflowViewService.cs
- DrawingImage.cs
- ReadonlyMessageFilter.cs
- datacache.cs
- ChangeTracker.cs
- ProvidersHelper.cs
- Header.cs
- Help.cs
- ListViewInsertionMark.cs
- ThrowHelper.cs
- SelectionEditingBehavior.cs
- JoinElimination.cs
- AstNode.cs
- DetailsViewModeEventArgs.cs
- SqlBooleanMismatchVisitor.cs
- isolationinterop.cs
- IntSumAggregationOperator.cs
- basenumberconverter.cs
- GroupBoxRenderer.cs
- MasterPageCodeDomTreeGenerator.cs
- ThreadAttributes.cs
- GraphicsPath.cs
- QueryTreeBuilder.cs
- BindingElementExtensionElement.cs
- Light.cs
- IgnoreSectionHandler.cs
- IntSecurity.cs
- CTreeGenerator.cs
- RuntimeConfigurationRecord.cs
- ContentDisposition.cs
- ObjectSpanRewriter.cs
- HtmlTableCellCollection.cs
- assemblycache.cs
- StyleConverter.cs
- StatusBar.cs
- DataPointer.cs
- RepeaterItemCollection.cs
- XPathPatternBuilder.cs
- UriSectionData.cs
- OleDbWrapper.cs
- WindowsGrip.cs
- DataRecordObjectView.cs
- ConfigXmlCDataSection.cs
- OneOfElement.cs
- TabPage.cs
- DataControlFieldsEditor.cs
- WebContext.cs
- Frame.cs
- ProfileServiceManager.cs
- ScrollViewer.cs
- NamedElement.cs
- AmbientValueAttribute.cs
- ConstNode.cs
- _KerberosClient.cs
- FacetEnabledSchemaElement.cs
- Control.cs
- StructuredTypeInfo.cs
- ResolveMatches11.cs
- ListMarkerSourceInfo.cs
- SystemIPv6InterfaceProperties.cs
- CallbackValidatorAttribute.cs
- TrackingSection.cs
- RegisteredScript.cs
- HtmlDocument.cs
- AssemblyInfo.cs
- SafeCertificateStore.cs
- EventLogPermissionEntry.cs
- Int32RectValueSerializer.cs