Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / XmlUtils / System / Xml / Xsl / Runtime / XslNumber.cs / 1 / XslNumber.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Xml.XPath; namespace System.Xml.Xsl.Runtime { internal class TokenInfo { public char startChar; // First element of numbering sequence for format token public int startIdx; // Start index of separator token public string formatString; // Format string for separator token public int length; // Length of separator token, or minimum length of decimal numbers for format token // Instances of this internal class must be created via CreateFormat and CreateSeparator private TokenInfo() { } [Conditional("DEBUG")] public void AssertSeparator(bool isSeparator) { Debug.Assert(isSeparator == (formatString != null), "AssertSeparator"); } // Creates a TokenInfo for a separator token. public static TokenInfo CreateSeparator(string formatString, int startIdx, int tokLen) { Debug.Assert(startIdx >= 0 && tokLen > 0); TokenInfo token = new TokenInfo(); { token.startIdx = startIdx; token.formatString = formatString; token.length = tokLen; } return token; } // Maps a token of alphanumeric characters to a numbering format ID and a // minimum length bound. Tokens specify the character(s) that begins a Unicode // numbering sequence. For example, "i" specifies lower case roman numeral // numbering. Leading "zeros" specify a minimum length to be maintained by // padding, if necessary. public static TokenInfo CreateFormat(string formatString, int startIdx, int tokLen) { Debug.Assert(startIdx >= 0 && tokLen > 0); TokenInfo token = new TokenInfo(); token.formatString = null; token.length = 1; bool useDefault = false; char ch = formatString[startIdx]; switch (ch) { case '1': case 'A': case 'I': case 'a': case 'i': break; default: // NOTE: We do not support Tamil and Ethiopic numbering systems having no zeros if (CharUtil.IsDecimalDigitOne(ch)) { break; } if (CharUtil.IsDecimalDigitOne((char)(ch + 1))) { // Leading zeros request padding. Track how much. int idx = startIdx; do { token.length++; } while (--tokLen > 0 && ch == formatString[++idx]); // Recognize the token only if the next character is "one" if (formatString[idx] == ++ch) { break; } } useDefault = true; break; } if (tokLen != 1) { // If remaining token length is not 1, do not recognize the token useDefault = true; } if (useDefault) { // Default to Arabic numbering with no zero padding token.startChar = NumberFormatter.DefaultStartChar; token.length = 1; } else { token.startChar = ch; } return token; } } internal class NumberFormatter : NumberFormatterBase { private string formatString; private int lang; private string letterValue; private string groupingSeparator; private int groupingSize; private Listtokens; public const char DefaultStartChar = '1'; private static readonly TokenInfo DefaultFormat = TokenInfo.CreateFormat ("0", 0, 1); private static readonly TokenInfo DefaultSeparator = TokenInfo.CreateSeparator(".", 0, 1); // Creates a Format object parsing format string into format tokens (alphanumeric) and separators (non-alphanumeric). public NumberFormatter(string formatString, int lang, string letterValue, string groupingSeparator, int groupingSize) { Debug.Assert(groupingSeparator.Length <= 1); this.formatString = formatString; this.lang = lang; this.letterValue = letterValue; this.groupingSeparator = groupingSeparator; this.groupingSize = groupingSeparator.Length > 0 ? groupingSize : 0; if (formatString == "1" || formatString.Length == 0) { // Special case of the default format return; } this.tokens = new List (); int idxStart = 0; bool isAlphaNumeric = CharUtil.IsAlphaNumeric(formatString[idxStart]); if (isAlphaNumeric) { // If the first one is alpha num add empty separator as a prefix tokens.Add(null); } for (int idx = 0; idx <= formatString.Length; idx++) { // Loop until a switch from formatString token to separator is detected (or vice-versa) if (idx == formatString.Length || isAlphaNumeric != CharUtil.IsAlphaNumeric(formatString[idx])) { if (isAlphaNumeric) { // Just finished a format token tokens.Add(TokenInfo.CreateFormat(formatString, idxStart, idx - idxStart)); } else { // Just finished a separator token tokens.Add(TokenInfo.CreateSeparator(formatString, idxStart, idx - idxStart)); } // Begin parsing the next format token or separator idxStart = idx; // Flip flag from format token to separator or vice-versa isAlphaNumeric = !isAlphaNumeric; } } } /// /// Format the given xsl:number place marker /// /// Place marker - either a sequence of ints, or a double singleton ///Formatted string public string FormatSequence(IListval) { StringBuilder sb = new StringBuilder(); // If the value was supplied directly, in the 'value' attribute, check its validity if (val.Count == 1 && val[0].ValueType == typeof(double)) { double dblVal = val[0].ValueAsDouble; if (!(0.5 <= dblVal && dblVal < double.PositiveInfinity)) { // Errata E24: It is an error if the number is NaN, infinite or less than 0.5; an XSLT processor may signal // the error; if it does not signal the error, it must recover by converting the number to a string as if // by a call to the 'string' function and inserting the resulting string into the result tree. return XPathConvert.DoubleToString(dblVal); } } if (tokens == null) { // Special case of the default format for (int idx = 0; idx < val.Count; idx++) { if (idx > 0) { sb.Append('.'); } FormatItem(sb, val[idx], DefaultStartChar, 1); } } else { int cFormats = tokens.Count; TokenInfo prefix = tokens[0], suffix; if (cFormats % 2 == 0) { suffix = null; } else { suffix = tokens[--cFormats]; } TokenInfo periodicSeparator = 2 < cFormats ? tokens[cFormats - 2] : DefaultSeparator; TokenInfo periodicFormat = 0 < cFormats ? tokens[cFormats - 1] : DefaultFormat; if (prefix != null) { prefix.AssertSeparator(true); sb.Append(prefix.formatString, prefix.startIdx, prefix.length); } int valCount = val.Count; for (int i = 0; i < valCount; i++ ) { int formatIndex = i * 2; bool haveFormat = formatIndex < cFormats; if (i > 0) { TokenInfo thisSeparator = haveFormat ? tokens[formatIndex + 0] : periodicSeparator; thisSeparator.AssertSeparator(true); sb.Append(thisSeparator.formatString, thisSeparator.startIdx, thisSeparator.length); } TokenInfo thisFormat = haveFormat ? tokens[formatIndex + 1] : periodicFormat; thisFormat.AssertSeparator(false); FormatItem(sb, val[i], thisFormat.startChar, thisFormat.length); } if (suffix != null) { suffix.AssertSeparator(true); sb.Append(suffix.formatString, suffix.startIdx, suffix.length); } } return sb.ToString(); } private void FormatItem(StringBuilder sb, XPathItem item, char startChar, int length) { double dblVal; if (item.ValueType == typeof(int)) { dblVal = (double)item.ValueAsInt; } else { Debug.Assert(item.ValueType == typeof(double), "Item must be either of type int, or double"); dblVal = XsltFunctions.Round(item.ValueAsDouble); } Debug.Assert(1 <= dblVal && dblVal < double.PositiveInfinity); char zero = '0'; switch (startChar) { case '1': break; case 'A': case 'a': if (dblVal <= MaxAlphabeticValue) { ConvertToAlphabetic(sb, dblVal, startChar, 26); return; } break; case 'I': case 'i': if (dblVal <= MaxRomanValue) { ConvertToRoman(sb, dblVal, /*upperCase:*/ startChar == 'I'); return; } break; default: Debug.Assert(CharUtil.IsDecimalDigitOne(startChar), "Unexpected startChar: " + startChar); zero = (char)(startChar - 1); break; } sb.Append(ConvertToDecimal(dblVal, length, zero, groupingSeparator, groupingSize)); } private static string ConvertToDecimal(double val, int minLen, char zero, string groupSeparator, int groupSize) { Debug.Assert(val >= 0 && val == Math.Round(val), "ConvertToArabic operates on non-negative integer numbers only"); string str = XPathConvert.DoubleToString(val); int shift = zero - '0'; // Figure out new string length without separators int oldLen = str.Length; int newLen = Math.Max(oldLen, minLen); // Calculate length of string with separators if (groupSize != 0) { Debug.Assert(groupSeparator.Length == 1); checked { newLen += (newLen - 1) / groupSize; } } // If the new number of characters equals the old one, no changes need to be made if (newLen == oldLen && shift == 0) { return str; } // If grouping is not needed, add zero padding only if (groupSize == 0 && shift == 0) { return str.PadLeft(newLen, zero); } // Add both grouping separators and zero padding to the string representation of a number #if true unsafe { char *result = stackalloc char[newLen]; char separator = (groupSeparator.Length > 0) ? groupSeparator[0] : ' '; fixed (char *pin = str) { char *pOldEnd = pin + oldLen - 1; char *pNewEnd = result + newLen - 1; int cnt = groupSize; while (true) { // Move digit to its new location (zero if we've run out of digits) *pNewEnd-- = (pOldEnd >= pin) ? (char)(*pOldEnd-- + shift) : zero; if (pNewEnd < result) { break; } if (/*groupSize > 0 && */--cnt == 0) { // Every groupSize digits insert the separator *pNewEnd-- = separator; cnt = groupSize; Debug.Assert(pNewEnd >= result, "Separator cannot be the first character"); } } } return new string(result, 0, newLen); } #else // Safe version is about 20% slower after NGEN char[] result = new char[newLen]; char separator = (groupSeparator.Length > 0) ? groupSeparator[0] : ' '; int oldEnd = oldLen - 1; int newEnd = newLen - 1; int cnt = groupSize; while (true) { // Move digit to its new location (zero if we've run out of digits) result[newEnd--] = (oldEnd >= 0) ? (char)(str[oldEnd--] + shift) : zero; if (newEnd < 0) { break; } if (/*groupSize > 0 && */--cnt == 0) { // Every groupSize digits insert the separator result[newEnd--] = separator; cnt = groupSize; Debug.Assert(newEnd >= 0, "Separator cannot be the first character"); } } return new string(result, 0, newLen); #endif } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Xml.XPath; namespace System.Xml.Xsl.Runtime { internal class TokenInfo { public char startChar; // First element of numbering sequence for format token public int startIdx; // Start index of separator token public string formatString; // Format string for separator token public int length; // Length of separator token, or minimum length of decimal numbers for format token // Instances of this internal class must be created via CreateFormat and CreateSeparator private TokenInfo() { } [Conditional("DEBUG")] public void AssertSeparator(bool isSeparator) { Debug.Assert(isSeparator == (formatString != null), "AssertSeparator"); } // Creates a TokenInfo for a separator token. public static TokenInfo CreateSeparator(string formatString, int startIdx, int tokLen) { Debug.Assert(startIdx >= 0 && tokLen > 0); TokenInfo token = new TokenInfo(); { token.startIdx = startIdx; token.formatString = formatString; token.length = tokLen; } return token; } // Maps a token of alphanumeric characters to a numbering format ID and a // minimum length bound. Tokens specify the character(s) that begins a Unicode // numbering sequence. For example, "i" specifies lower case roman numeral // numbering. Leading "zeros" specify a minimum length to be maintained by // padding, if necessary. public static TokenInfo CreateFormat(string formatString, int startIdx, int tokLen) { Debug.Assert(startIdx >= 0 && tokLen > 0); TokenInfo token = new TokenInfo(); token.formatString = null; token.length = 1; bool useDefault = false; char ch = formatString[startIdx]; switch (ch) { case '1': case 'A': case 'I': case 'a': case 'i': break; default: // NOTE: We do not support Tamil and Ethiopic numbering systems having no zeros if (CharUtil.IsDecimalDigitOne(ch)) { break; } if (CharUtil.IsDecimalDigitOne((char)(ch + 1))) { // Leading zeros request padding. Track how much. int idx = startIdx; do { token.length++; } while (--tokLen > 0 && ch == formatString[++idx]); // Recognize the token only if the next character is "one" if (formatString[idx] == ++ch) { break; } } useDefault = true; break; } if (tokLen != 1) { // If remaining token length is not 1, do not recognize the token useDefault = true; } if (useDefault) { // Default to Arabic numbering with no zero padding token.startChar = NumberFormatter.DefaultStartChar; token.length = 1; } else { token.startChar = ch; } return token; } } internal class NumberFormatter : NumberFormatterBase { private string formatString; private int lang; private string letterValue; private string groupingSeparator; private int groupingSize; private Listtokens; public const char DefaultStartChar = '1'; private static readonly TokenInfo DefaultFormat = TokenInfo.CreateFormat ("0", 0, 1); private static readonly TokenInfo DefaultSeparator = TokenInfo.CreateSeparator(".", 0, 1); // Creates a Format object parsing format string into format tokens (alphanumeric) and separators (non-alphanumeric). public NumberFormatter(string formatString, int lang, string letterValue, string groupingSeparator, int groupingSize) { Debug.Assert(groupingSeparator.Length <= 1); this.formatString = formatString; this.lang = lang; this.letterValue = letterValue; this.groupingSeparator = groupingSeparator; this.groupingSize = groupingSeparator.Length > 0 ? groupingSize : 0; if (formatString == "1" || formatString.Length == 0) { // Special case of the default format return; } this.tokens = new List (); int idxStart = 0; bool isAlphaNumeric = CharUtil.IsAlphaNumeric(formatString[idxStart]); if (isAlphaNumeric) { // If the first one is alpha num add empty separator as a prefix tokens.Add(null); } for (int idx = 0; idx <= formatString.Length; idx++) { // Loop until a switch from formatString token to separator is detected (or vice-versa) if (idx == formatString.Length || isAlphaNumeric != CharUtil.IsAlphaNumeric(formatString[idx])) { if (isAlphaNumeric) { // Just finished a format token tokens.Add(TokenInfo.CreateFormat(formatString, idxStart, idx - idxStart)); } else { // Just finished a separator token tokens.Add(TokenInfo.CreateSeparator(formatString, idxStart, idx - idxStart)); } // Begin parsing the next format token or separator idxStart = idx; // Flip flag from format token to separator or vice-versa isAlphaNumeric = !isAlphaNumeric; } } } /// /// Format the given xsl:number place marker /// /// Place marker - either a sequence of ints, or a double singleton ///Formatted string public string FormatSequence(IListval) { StringBuilder sb = new StringBuilder(); // If the value was supplied directly, in the 'value' attribute, check its validity if (val.Count == 1 && val[0].ValueType == typeof(double)) { double dblVal = val[0].ValueAsDouble; if (!(0.5 <= dblVal && dblVal < double.PositiveInfinity)) { // Errata E24: It is an error if the number is NaN, infinite or less than 0.5; an XSLT processor may signal // the error; if it does not signal the error, it must recover by converting the number to a string as if // by a call to the 'string' function and inserting the resulting string into the result tree. return XPathConvert.DoubleToString(dblVal); } } if (tokens == null) { // Special case of the default format for (int idx = 0; idx < val.Count; idx++) { if (idx > 0) { sb.Append('.'); } FormatItem(sb, val[idx], DefaultStartChar, 1); } } else { int cFormats = tokens.Count; TokenInfo prefix = tokens[0], suffix; if (cFormats % 2 == 0) { suffix = null; } else { suffix = tokens[--cFormats]; } TokenInfo periodicSeparator = 2 < cFormats ? tokens[cFormats - 2] : DefaultSeparator; TokenInfo periodicFormat = 0 < cFormats ? tokens[cFormats - 1] : DefaultFormat; if (prefix != null) { prefix.AssertSeparator(true); sb.Append(prefix.formatString, prefix.startIdx, prefix.length); } int valCount = val.Count; for (int i = 0; i < valCount; i++ ) { int formatIndex = i * 2; bool haveFormat = formatIndex < cFormats; if (i > 0) { TokenInfo thisSeparator = haveFormat ? tokens[formatIndex + 0] : periodicSeparator; thisSeparator.AssertSeparator(true); sb.Append(thisSeparator.formatString, thisSeparator.startIdx, thisSeparator.length); } TokenInfo thisFormat = haveFormat ? tokens[formatIndex + 1] : periodicFormat; thisFormat.AssertSeparator(false); FormatItem(sb, val[i], thisFormat.startChar, thisFormat.length); } if (suffix != null) { suffix.AssertSeparator(true); sb.Append(suffix.formatString, suffix.startIdx, suffix.length); } } return sb.ToString(); } private void FormatItem(StringBuilder sb, XPathItem item, char startChar, int length) { double dblVal; if (item.ValueType == typeof(int)) { dblVal = (double)item.ValueAsInt; } else { Debug.Assert(item.ValueType == typeof(double), "Item must be either of type int, or double"); dblVal = XsltFunctions.Round(item.ValueAsDouble); } Debug.Assert(1 <= dblVal && dblVal < double.PositiveInfinity); char zero = '0'; switch (startChar) { case '1': break; case 'A': case 'a': if (dblVal <= MaxAlphabeticValue) { ConvertToAlphabetic(sb, dblVal, startChar, 26); return; } break; case 'I': case 'i': if (dblVal <= MaxRomanValue) { ConvertToRoman(sb, dblVal, /*upperCase:*/ startChar == 'I'); return; } break; default: Debug.Assert(CharUtil.IsDecimalDigitOne(startChar), "Unexpected startChar: " + startChar); zero = (char)(startChar - 1); break; } sb.Append(ConvertToDecimal(dblVal, length, zero, groupingSeparator, groupingSize)); } private static string ConvertToDecimal(double val, int minLen, char zero, string groupSeparator, int groupSize) { Debug.Assert(val >= 0 && val == Math.Round(val), "ConvertToArabic operates on non-negative integer numbers only"); string str = XPathConvert.DoubleToString(val); int shift = zero - '0'; // Figure out new string length without separators int oldLen = str.Length; int newLen = Math.Max(oldLen, minLen); // Calculate length of string with separators if (groupSize != 0) { Debug.Assert(groupSeparator.Length == 1); checked { newLen += (newLen - 1) / groupSize; } } // If the new number of characters equals the old one, no changes need to be made if (newLen == oldLen && shift == 0) { return str; } // If grouping is not needed, add zero padding only if (groupSize == 0 && shift == 0) { return str.PadLeft(newLen, zero); } // Add both grouping separators and zero padding to the string representation of a number #if true unsafe { char *result = stackalloc char[newLen]; char separator = (groupSeparator.Length > 0) ? groupSeparator[0] : ' '; fixed (char *pin = str) { char *pOldEnd = pin + oldLen - 1; char *pNewEnd = result + newLen - 1; int cnt = groupSize; while (true) { // Move digit to its new location (zero if we've run out of digits) *pNewEnd-- = (pOldEnd >= pin) ? (char)(*pOldEnd-- + shift) : zero; if (pNewEnd < result) { break; } if (/*groupSize > 0 && */--cnt == 0) { // Every groupSize digits insert the separator *pNewEnd-- = separator; cnt = groupSize; Debug.Assert(pNewEnd >= result, "Separator cannot be the first character"); } } } return new string(result, 0, newLen); } #else // Safe version is about 20% slower after NGEN char[] result = new char[newLen]; char separator = (groupSeparator.Length > 0) ? groupSeparator[0] : ' '; int oldEnd = oldLen - 1; int newEnd = newLen - 1; int cnt = groupSize; while (true) { // Move digit to its new location (zero if we've run out of digits) result[newEnd--] = (oldEnd >= 0) ? (char)(str[oldEnd--] + shift) : zero; if (newEnd < 0) { break; } if (/*groupSize > 0 && */--cnt == 0) { // Every groupSize digits insert the separator result[newEnd--] = separator; cnt = groupSize; Debug.Assert(newEnd >= 0, "Separator cannot be the first character"); } } return new string(result, 0, newLen); #endif } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- BindingMAnagerBase.cs
- TextTreeRootNode.cs
- FormsAuthentication.cs
- EventProxy.cs
- AttachedPropertyBrowsableForTypeAttribute.cs
- WebBrowserNavigatedEventHandler.cs
- QueryStack.cs
- ConvertEvent.cs
- NotifyInputEventArgs.cs
- Compiler.cs
- OutKeywords.cs
- DefaultHttpHandler.cs
- EventListenerClientSide.cs
- LineGeometry.cs
- QilInvoke.cs
- TcpTransportManager.cs
- MemberCollection.cs
- SafePointer.cs
- XPathException.cs
- GraphicsPathIterator.cs
- OperationSelectorBehavior.cs
- ReachFixedDocumentSerializerAsync.cs
- ParentQuery.cs
- FieldBuilder.cs
- ResetableIterator.cs
- FlagsAttribute.cs
- XmlSubtreeReader.cs
- IisTraceListener.cs
- MessageDirection.cs
- ConnectionStringsExpressionBuilder.cs
- hwndwrapper.cs
- PtsHost.cs
- XsltConvert.cs
- ColumnHeaderConverter.cs
- DictionaryBase.cs
- SessionStateContainer.cs
- WSSecurityOneDotOneReceiveSecurityHeader.cs
- KeyValueConfigurationCollection.cs
- ListViewEditEventArgs.cs
- CheckedListBox.cs
- XPathNodeIterator.cs
- ReservationNotFoundException.cs
- ReflectionPermission.cs
- SHA384.cs
- ResourceReferenceExpressionConverter.cs
- SpellerInterop.cs
- CollectionBuilder.cs
- PropertyPath.cs
- TimeoutTimer.cs
- EndpointReference.cs
- VisualStyleRenderer.cs
- XmlQueryContext.cs
- ApplicationProxyInternal.cs
- EventData.cs
- StorageTypeMapping.cs
- EmptyElement.cs
- MenuAdapter.cs
- DataPagerField.cs
- TableLayout.cs
- DbConnectionPoolGroup.cs
- Label.cs
- PropertyRecord.cs
- CodeTypeMember.cs
- shaperfactoryquerycachekey.cs
- RemoveFromCollection.cs
- SoapTypeAttribute.cs
- DeferredElementTreeState.cs
- WebProxyScriptElement.cs
- Deflater.cs
- BindableTemplateBuilder.cs
- HostingEnvironmentSection.cs
- CopyOnWriteList.cs
- ServiceDesigner.cs
- SqlCaseSimplifier.cs
- FillErrorEventArgs.cs
- XPathNavigatorKeyComparer.cs
- ScrollChrome.cs
- Freezable.cs
- KnownTypeAttribute.cs
- TextProperties.cs
- FontCollection.cs
- DictionaryGlobals.cs
- HtmlTextArea.cs
- VirtualDirectoryMappingCollection.cs
- TableCell.cs
- ExpressionBuilder.cs
- KerberosRequestorSecurityToken.cs
- ComponentResourceKeyConverter.cs
- Privilege.cs
- DataGridCell.cs
- TextContainerChangedEventArgs.cs
- EntityDataSourceEntityTypeFilterItem.cs
- HtmlInputImage.cs
- BinHexEncoder.cs
- COM2DataTypeToManagedDataTypeConverter.cs
- ContractAdapter.cs
- AssociationEndMember.cs
- StreamGeometry.cs
- LocatorPart.cs
- DiscardableAttribute.cs