Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Base / MS / Internal / ContentType.cs / 1 / ContentType.cs
//------------------------------------------------------------------------------ // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // ContentType class parses and validates the content-type string. // It provides functionality to compare the type/subtype values. // // Details: // Grammar which this class follows - // // Content-type grammar MUST conform to media-type grammar as per // RFC 2616 (ABNF notation): // // media-type = type "/" subtype *( ";" parameter ) // type = token // subtype = token // parameter = attribute "=" value // attribute = token // value = token | quoted-string // quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) // qdtext => // quoted-pair = "\" CHAR // token = 1* // separators = "(" | ")" | "<" | ">" | "@" // | "," | ";" | ":" | "\" | <"> // | "/" | "[" | "]" | "?" | "=" // | "{" | "}" | SP | HT // TEXT = // OCTET = // CHAR = // CTL = // CR = // LF = // SP = // HT = // <"> = // LWS = [CRLF] 1*( SP | HT ) // CRLF = CR LF // Linear white space (LWS) MUST NOT be used between the type and subtype, nor // between an attribute and its value. Leading and trailing LWS are prohibited. // // // History: // 04/26/2004: [....]: Initial Creation //----------------------------------------------------------------------------- using System; using System.Collections.Generic; // For Dictionary using System.Text; // For StringBuilder using System.Windows; // For Exception strings - SRID using MS.Internal.WindowsBase; // For FriendAccessAllowed using System.Diagnostics; // For Debug.Assert namespace MS.Internal { /// /// Content Type class /// [FriendAccessAllowed] internal sealed class ContentType { //----------------------------------------------------- // // Internal Constructors // //----------------------------------------------------- #region Internal Constructors ////// This constructor creates a ContentType object that represents /// the content-type string. At construction time we validate the /// string as per the grammar specified in RFC 2616. /// Note: We allow empty strings as valid input. Empty string should /// we used more as an indication of an absent/unknown ContentType. /// /// content-type ///If the contentType parameter is null ///If the contentType string has leading or /// trailing Linear White Spaces(LWS) characters ///If the contentType string invalid CR-LF characters internal ContentType(string contentType) { if (contentType == null) throw new ArgumentNullException("contentType"); if (String.CompareOrdinal(contentType, String.Empty) == 0) { _contentType = String.Empty; } else { if (IsLinearWhiteSpaceChar(contentType[0]) || IsLinearWhiteSpaceChar(contentType[contentType.Length - 1])) throw new ArgumentException(SR.Get(SRID.ContentTypeCannotHaveLeadingTrailingLWS)); //Carriage return can be expressed as '\r\n' or '\n\r' //We need to make sure that a \r is accompanied by \n ValidateCarriageReturns(contentType); //Begin Parsing int semiColonIndex = contentType.IndexOf(_semicolonSeparator); if (semiColonIndex == -1) { // Parse content type similar to - type/subtype ParseTypeAndSubType(contentType); } else { // Parse content type similar to - type/subtype ; param1=value1 ; param2=value2 ; param3="value3" ParseTypeAndSubType(contentType.Substring(0, semiColonIndex)); ParseParameterAndValue(contentType.Substring(semiColonIndex)); } } // keep this untouched for return from OriginalString property _originalString = contentType; //This variable is used to print out the correct content type string representation //using the ToString method. This is mainly important while debugging and seeing the //value of the content type object in the debugger. _isInitialized = true; } #endregion Internal Constructors //------------------------------------------------------ // // Internal Methods // //----------------------------------------------------- #region Internal Properties ////// TypeComponent of the Content Type /// If the content type is "text/xml". This property will return "text" /// internal string TypeComponent { get { return _type; } } ////// SubType component /// If the content type is "text/xml". This property will return "xml" /// internal string SubTypeComponent { get { return _subType; } } ////// Enumerator which iterates over the Parameter and Value pairs which are stored /// in a dictionary. We hand out just the enumerator in order to make this property /// ReadOnly /// Consider following Content type - /// type/subtype ; param1=value1 ; param2=value2 ; param3="value3" /// This will return a enumerator over a dictionary of the parameter/value pairs. /// internal Dictionary.Enumerator ParameterValuePairs { get { EnsureParameterDictionary(); return _parameterDictionary.GetEnumerator(); } } /// /// Static property that represents a content type that is empty "" /// This is not a valid content type as per the grammar and should be used /// in places where the content type is missing or not available. /// internal static ContentType Empty { get { return _emptyContentType; } } ////// Original string provided to constructor /// internal string OriginalString { get { return _originalString; } } #endregion Internal Properties //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods ////// This method does a strong comparison of the content types, as parameters are not allowed. /// We only compare the type and subType values in an ASCII case-insensitive manner. /// Parameters are not allowed to be present on any of the content type operands. /// /// Content type to be compared with ///internal bool AreTypeAndSubTypeEqual(ContentType contentType) { return AreTypeAndSubTypeEqual(contentType, false); } /// /// This method does a weak comparison of the content types. We only compare the /// type and subType values in an ASCII case-insensitive manner. /// Parameter and value pairs are not used for the comparison. /// If you wish to compare the paramters too, then you must get the ParameterValuePairs from /// both the ContentType objects and compare each parameter entry. /// The allowParameterValuePairs parameter is used to indicate whether the /// comparison is tolerant to parameters being present or no. /// /// Content type to be compared with /// If true, allows the presence of parameter value pairs. /// If false, parameter/value pairs cannot be present in the content type string. /// In either case, the parameter value pair is not used for the comparison. ///internal bool AreTypeAndSubTypeEqual(ContentType contentType, bool allowParameterValuePairs) { bool result = false; if (contentType != null) { if (!allowParameterValuePairs) { //Return false if this content type object has parameters if (_parameterDictionary != null && _parameterDictionary.Count > 0) return false; //Return false if the content type object passed in has parameters Dictionary .Enumerator contentTypeEnumerator; contentTypeEnumerator = contentType.ParameterValuePairs; contentTypeEnumerator.MoveNext(); if (contentTypeEnumerator.Current.Key != null) return false; } // Perform a case-insensitive comparison on the type/subtype strings. This is a // safe comparison because the _type and _subType strings have been restricted to // ASCII characters, digits, and a small set of symbols. This is not a safe comparison // for the broader set of strings that have not been restricted in the same way. result = (String.Compare(_type, contentType.TypeComponent, StringComparison.OrdinalIgnoreCase) == 0 && String.Compare(_subType, contentType.SubTypeComponent, StringComparison.OrdinalIgnoreCase) == 0); } return result; } /// /// ToString - outputs a normalized form of the content type string /// ///public override string ToString() { if (_contentType == null) { //This is needed so that while debugging we get the correct //string if (!_isInitialized) return String.Empty; Debug.Assert(String.CompareOrdinal(_type, String.Empty) != 0 || String.CompareOrdinal(_subType, String.Empty) != 0); StringBuilder stringBuilder = new StringBuilder(_type); stringBuilder.Append(_forwardSlashSeparator[0]); stringBuilder.Append(_subType); if (_parameterDictionary != null && _parameterDictionary.Count > 0) { foreach (string paramterKey in _parameterDictionary.Keys) { stringBuilder.Append(_LinearWhiteSpaceChars[0]); stringBuilder.Append(_semicolonSeparator); stringBuilder.Append(_LinearWhiteSpaceChars[0]); stringBuilder.Append(paramterKey); stringBuilder.Append(_equalSeparator); stringBuilder.Append(_parameterDictionary[paramterKey]); } } _contentType = stringBuilder.ToString(); } return _contentType; } #endregion Internal Methods //----------------------------------------------------- // // Nested Classes // //------------------------------------------------------ #region Nested Classes /// /// Comparer class makes it easier to put ContentType objects in collections. /// Only compares type and subtype components of the ContentType. Could be /// expanded to optionally compare parameters as well. /// internal class StrongComparer : IEqualityComparer{ /// /// This method does a strong comparison of the content types. /// Only compares the ContentTypes' type and subtype components. /// public bool Equals(ContentType x, ContentType y) { if (x == null) { return (y == null); } else { return x.AreTypeAndSubTypeEqual(y); } } ////// We lower case the results of ToString() because it returns the original /// casing passed into the constructor. ContentTypes that are equal (which /// ignores casing) must have the same hash code. /// public int GetHashCode(ContentType obj) { return obj.ToString().ToUpperInvariant().GetHashCode(); } } internal class WeakComparer : IEqualityComparer{ /// /// This method does a weak comparison of the content types. /// Parameter and value pairs are not used for the comparison. /// public bool Equals(ContentType x, ContentType y) { if (x == null) { return (y == null); } else { return x.AreTypeAndSubTypeEqual(y, true); } } ////// We lower case the results of ToString() because it returns the original /// casing passed into the constructor. ContentTypes that are equal (which /// ignores casing) must have the same hash code. /// public int GetHashCode(ContentType obj) { return obj._type.ToUpperInvariant().GetHashCode() ^ obj._subType.ToUpperInvariant().GetHashCode(); } } #endregion Nested Classes //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- #region Private Methods ////// This method validates if the content type string has /// valid CR-LF characters. Specifically we test if '\r' is /// accompanied by a '\n' in the string, else its an error. /// /// private static void ValidateCarriageReturns(string contentType) { Debug.Assert(!IsLinearWhiteSpaceChar(contentType[0]) && !IsLinearWhiteSpaceChar(contentType[contentType.Length - 1])); //Prior to calling this method we have already checked that first and last //character of the content type are not Linear White Spaces. So its safe to //assume that the index will be greater than 0 and less that length-2. int index = contentType.IndexOf(_LinearWhiteSpaceChars[2]); while (index != -1) { if (contentType[index - 1] == _LinearWhiteSpaceChars[1] || contentType[index + 1] == _LinearWhiteSpaceChars[1]) { index = contentType.IndexOf(_LinearWhiteSpaceChars[2], ++index); } else throw new ArgumentException(SR.Get(SRID.InvalidLinearWhiteSpaceCharacter)); } } ////// Parses the type ans subType tokens from the string. /// Also verifies if the Tokens are valid as per the grammar. /// /// substring that has the type and subType of the content type ///If the typeAndSubType parameter does not have the "/" character private void ParseTypeAndSubType(string typeAndSubType) { //okay to trim at this point the end of the string as Linear White Spaces(LWS) chars are allowed here. typeAndSubType = typeAndSubType.TrimEnd(_LinearWhiteSpaceChars); string[] splitBasedOnForwardSlash = typeAndSubType.Split(_forwardSlashSeparator); if (splitBasedOnForwardSlash.Length != 2) throw new ArgumentException(SR.Get(SRID.InvalidTypeSubType)); _type = ValidateToken(splitBasedOnForwardSlash[0]); _subType = ValidateToken(splitBasedOnForwardSlash[1]); } ////// Parse the individual parameter=value strings /// /// This string has the parameter and value pair of the form /// parameter=value ///If the string does not have the required "=" private void ParseParameterAndValue(string parameterAndValue) { while (String.CompareOrdinal(parameterAndValue, String.Empty) != 0) { //At this point the first character MUST be a semi-colon //First time through this test is serving more as an assert. if (parameterAndValue[0] != _semicolonSeparator) throw new ArgumentException(SR.Get(SRID.ExpectingSemicolon)); //At this point if we have just one semicolon, then its an error. //Also, there can be no trailing LWS characters, as we already checked for that //in the constructor. if (parameterAndValue.Length == 1) throw new ArgumentException(SR.Get(SRID.ExpectingParameterValuePairs)); //Removing the leading ; from the string parameterAndValue = parameterAndValue.Substring(1); //okay to trim start as there can be spaces before the begining //of the parameter name. parameterAndValue = parameterAndValue.TrimStart(_LinearWhiteSpaceChars); int equalSignIndex = parameterAndValue.IndexOf(_equalSeparator); if (equalSignIndex <= 0 || equalSignIndex == (parameterAndValue.Length - 1)) throw new ArgumentException(SR.Get(SRID.InvalidParameterValuePair)); int parameterStartIndex = equalSignIndex + 1; //Get length of the parameter value int parameterValueLength = GetLengthOfParameterValue(parameterAndValue, parameterStartIndex); EnsureParameterDictionary(); _parameterDictionary.Add( ValidateToken(parameterAndValue.Substring(0, equalSignIndex)), ValidateQuotedStringOrToken(parameterAndValue.Substring(parameterStartIndex, parameterValueLength))); parameterAndValue = parameterAndValue.Substring(parameterStartIndex + parameterValueLength).TrimStart(_LinearWhiteSpaceChars); } } ////// This method returns the length of the first parameter value in the input string. /// /// /// Starting index for parsing ///private static int GetLengthOfParameterValue(string s, int startIndex) { Debug.Assert(s != null); int length = 0; //if the parameter value does not start with a '"' then, //we expect a valid token. So we look for Linear White Spaces or //a ';' as the terminator for the token value. if (s[startIndex] != '"') { int semicolonIndex = s.IndexOf(_semicolonSeparator, startIndex); if (semicolonIndex != -1) { int lwsIndex = s.IndexOfAny(_LinearWhiteSpaceChars, startIndex); if (lwsIndex != -1 && lwsIndex < semicolonIndex) length = lwsIndex; else length = semicolonIndex; } else length = semicolonIndex; //If there is no linear white space found we treat the entire remaining string as //parameter value. if (length == -1) length = s.Length; } else { //if the parameter value starts with a '"' then, we need to look for the //pairing '"' that is not preceded by a "\" ["\" is used to escape the '"'] bool found = false; length = startIndex; while (!found) { length = s.IndexOf('"', ++length); if (length == -1) throw new ArgumentException(SR.Get(SRID.InvalidParameterValue)); if (s[length - 1] != '\\') { found = true; length++; } } } return length - startIndex; } /// /// Validating the given token /// The following checks are being made - /// 1. If all the characters in the token are either ASCII letter or digit. /// 2. If all the characters in the token are either from the remaining allowed characeter set. /// /// string token ///validated string token ///If the token is Empty private static string ValidateToken(string token) { if (String.CompareOrdinal(token, String.Empty)==0) throw new ArgumentException(SR.Get(SRID.InvalidToken)); for (int i = 0; i < token.Length; i++) { if (IsAsciiLetterOrDigit(token[i])) continue; else if (IsAllowedCharacter(token[i])) continue; else throw new ArgumentException(SR.Get(SRID.InvalidToken)); } return token; } ////// Validating if the value of a parameter is either a valid token or a /// valid quoted string /// /// paramter value string ///validate parameter value string ///If the paramter value is empty private static string ValidateQuotedStringOrToken(string parameterValue) { if (String.CompareOrdinal(parameterValue, String.Empty) == 0) throw new ArgumentException(SR.Get(SRID.InvalidParameterValue)); if (parameterValue.Length >= 2 && parameterValue.StartsWith(_quote, StringComparison.Ordinal) && parameterValue.EndsWith(_quote, StringComparison.Ordinal)) ValidateQuotedText(parameterValue.Substring(1, parameterValue.Length-2)); else ValidateToken(parameterValue); return parameterValue; } ////// This method validates if the text in the quoted string /// /// private static void ValidateQuotedText(string quotedText) { //empty is okay for (int i = 0; i < quotedText.Length; i++) { if (IsLinearWhiteSpaceChar(quotedText[i])) continue; if (quotedText[i] <= ' ' || quotedText[i] >= 0xFF) throw new ArgumentException(SR.Get(SRID.InvalidParameterValue)); else if (quotedText[i] == '"' && (i==0 || quotedText[i-1] != '\\')) throw new ArgumentException(SR.Get(SRID.InvalidParameterValue)); } } ////// Returns true if the input character is an allowed character /// Returns false if the input characeter is not an allowed character /// /// input character ///private static bool IsAllowedCharacter(char character) { //We did not use any of the .Contains methods as //it will result in boxing costs. foreach (char c in _allowedCharacters) { if (c == character) return true; } return false; } /// /// Returns true if the input character is an ASCII digit or letter /// Returns false if the input character is not an ASCII digit or letter /// /// input character ///private static bool IsAsciiLetterOrDigit(char character) { if (IsAsciiLetter(character)) { return true; } if (character >= '0') { return (character <= '9'); } return false; } /// /// Returns true if the input character is an ASCII letter /// Returns false if the input character is not an ASCII letter /// /// input character ///private static bool IsAsciiLetter(char character) { if ((character >= 'a') && (character <= 'z')) { return true; } if (character >= 'A') { return (character <= 'Z'); } return false; } /// /// Returns true if the input character is one of the Linear White Space characters - /// ' ', '\t', '\n', '\r' /// Returns false if the input character is none of the above /// /// input character ///private static bool IsLinearWhiteSpaceChar(char ch) { if (ch > ' ') { return false; } foreach (char c in _LinearWhiteSpaceChars) { if (ch == c) return true; } return false; } /// /// Lazy initialization for the ParameterDictionary /// private void EnsureParameterDictionary() { if (_parameterDictionary == null) { _parameterDictionary = new Dictionary(); //initial size 0 } } #endregion Private Methods //----------------------------------------------------- // // Private Members // //------------------------------------------------------ #region Private Members private string _contentType = null; private string _type = String.Empty; private string _subType = String.Empty; private string _originalString; private Dictionary _parameterDictionary = null; private bool _isInitialized = false; private const string _quote = "\""; private const char _semicolonSeparator = ';'; private const char _equalSeparator = '='; //This array is sorted by the ascii value of these characters. private static readonly char[] _allowedCharacters = { '!' /*33*/, '#' /*35*/ , '$' /*36*/, '%' /*37*/, '&' /*38*/ , '\'' /*39*/, '*' /*42*/, '+' /*43*/ , '-' /*45*/, '.' /*46*/, '^' /*94*/ , '_' /*95*/, '`' /*96*/, '|' /*124*/, '~' /*126*/, }; private static readonly char[] _forwardSlashSeparator = { '/' }; //Linear White Space characters private static readonly char[] _LinearWhiteSpaceChars = { ' ', // space - \x20 '\n', // new line - \x0A '\r', // carriage return - \x0D '\t' // horizontal tab - \x09 }; private static readonly ContentType _emptyContentType = new ContentType(""); #endregion Private Members } } // 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
- MenuBase.cs
- TaskFormBase.cs
- DataMisalignedException.cs
- CustomTypeDescriptor.cs
- CharUnicodeInfo.cs
- ValidationHelper.cs
- ClickablePoint.cs
- IncrementalReadDecoders.cs
- WindowsStatusBar.cs
- RolePrincipal.cs
- SendActivityDesigner.cs
- MyContact.cs
- PropertyExpression.cs
- TransformedBitmap.cs
- Int32CollectionValueSerializer.cs
- TypeForwardedToAttribute.cs
- BevelBitmapEffect.cs
- SystemIPAddressInformation.cs
- XmlLoader.cs
- PropertiesTab.cs
- StrokeCollection.cs
- TextEffect.cs
- SerializableAttribute.cs
- ToolStripDropDownClosingEventArgs.cs
- SeekableReadStream.cs
- GenericWebPart.cs
- IncrementalReadDecoders.cs
- WrappedDispatcherException.cs
- CheckBoxFlatAdapter.cs
- EntryWrittenEventArgs.cs
- GridViewRow.cs
- QilGenerator.cs
- XmlUrlResolver.cs
- PowerModeChangedEventArgs.cs
- TreeBuilder.cs
- VectorCollectionConverter.cs
- Label.cs
- Normalizer.cs
- MatrixAnimationUsingKeyFrames.cs
- NavigationWindowAutomationPeer.cs
- DiagnosticTraceSchemas.cs
- CodeGeneratorOptions.cs
- LocationUpdates.cs
- SQLInt64Storage.cs
- RtfNavigator.cs
- TextAnchor.cs
- ConfigXmlAttribute.cs
- TypeReference.cs
- DBSchemaRow.cs
- DragDeltaEventArgs.cs
- PathSegment.cs
- FindSimilarActivitiesVerb.cs
- UserPreferenceChangedEventArgs.cs
- RSAOAEPKeyExchangeFormatter.cs
- ParallelTimeline.cs
- JumpPath.cs
- TextEndOfSegment.cs
- CommonGetThemePartSize.cs
- ToolboxComponentsCreatedEventArgs.cs
- FormatException.cs
- CryptoApi.cs
- DrawingAttributes.cs
- UnicastIPAddressInformationCollection.cs
- ProcessModule.cs
- SRGSCompiler.cs
- Serializer.cs
- Currency.cs
- XamlDesignerSerializationManager.cs
- StateMachineSubscription.cs
- DifferencingCollection.cs
- SqlConnectionString.cs
- KeyboardNavigation.cs
- XXXOnTypeBuilderInstantiation.cs
- Material.cs
- Message.cs
- Color.cs
- XmlnsDefinitionAttribute.cs
- TaskFileService.cs
- HtmlTableRowCollection.cs
- XmlSortKeyAccumulator.cs
- AlignmentYValidation.cs
- _ConnectionGroup.cs
- WebPartDescription.cs
- RuleSetCollection.cs
- TimeoutConverter.cs
- PassportPrincipal.cs
- SpellerError.cs
- SmtpFailedRecipientsException.cs
- Stopwatch.cs
- AppSecurityManager.cs
- HostingEnvironmentSection.cs
- Regex.cs
- SerializationHelper.cs
- uribuilder.cs
- OdbcDataReader.cs
- UndirectedGraph.cs
- NativeMethods.cs
- SystemWebSectionGroup.cs
- RuntimeConfig.cs
- Pen.cs