/// <summary>
        /// This constructor takes a Boolean expression in infix format.
        /// Some examples
        /// are shown below. Assume <b>T</b> is an instance of the
        /// <see cref="Tags"/>
        /// class.
        /// <list type="table">
        /// <item>
        /// T[CommonPropertyNames.title] contains "foo"
        /// <term>
        /// </term>
        /// <description>
        /// <see cref="MediaComparer.IsMatch"/> will return
        /// true on media objects that have <i>foo</i> in the title.
        /// </description>
        /// </item>
        ///
        /// <item>
        /// T[CommonPropertyNames.creator] doesNotContain "\"HappyBand\""
        /// <term>
        /// </term>
        /// <description>
        /// <see cref="MediaComparer.IsMatch"/> will return
        /// true on media objects that do not have <i>"HappyBand"</i> in the title.
        /// </description>
        /// </item>
        ///
        /// <item>
        /// (T[CommonPropertyNames.Class] = "object.item.audioItem.musicTrack" and Tags.PropertyAttributes.res_size > "40") or (T[CommonPropertyNames.author] exists true)
        /// <term>
        /// </term>
        /// <description>
        /// <see cref="MediaComparer.IsMatch"/> will return
        /// true on media objects that are music tracks with at least one resource greater than 40 bytes
        /// OR on media objects that have a value set for the author metadata.
        /// </description>
        /// </item>
        /// </list>
        /// </summary>
        /// <param name="infix">The boolean infix expression conforming to the syntax and semantics of ContentDirectory's boolean query language.</param>
        /// <exception cref="OpenSource.UPnP.AV.CdsMetadata.Error_MalformedSearchCriteria">
        /// Thrown if the infix expression has a syntax error.
        /// </exception>
        public MediaComparer(string infix)
        {
            string allstring = infix.Trim();

            if ((allstring == "") || (allstring == "*"))
            {
                this.m_AlwaysMatch = true;
                return;
            }

            //Initialize an empty stack and empty result string variable.
            //
            Stack stack = new Stack();

            m_Postfix = new Queue();

            RelExpStates state = RelExpStates.unknown;
            TokenResult  token;

            while (infix.Length > 0)
            {
                infix = infix.Trim();
                token = GetToken(ref infix, state);

                switch (state)
                {
                case RelExpStates.unknown:
                    if (token.TokenType == Tokens.PropertyName)
                    {
                        state = RelExpStates.expectOp;
                    }
                    break;

                case RelExpStates.expectOp:
                    if (token.TokenType != Tokens.Operator)
                    {
                        throw new UPnPCustomException(402, "Invalid Args: Invalid operator " + token.Data);
                    }
                    state = RelExpStates.expectValue;
                    break;

                case RelExpStates.expectValue:
                    if (token.TokenType != Tokens.PropertyValue)
                    {
                        throw new UPnPCustomException(402, "Invalid Args: Unexpected value " + token.Data);
                    }
                    state = RelExpStates.unknown;
                    break;
                }

                switch (token.TokenType)
                {
                case Tokens.Operator:
                    if (token.OpToken == OperatorTokens.LParen)
                    {
                        //left paren
                        //
                        stack.Push(token);
                    }
                    else if (token.OpToken == OperatorTokens.RParen)
                    {
                        //right paren
                        //
                        TokenResult tr = new TokenResult(false);
                        do
                        {
                            if (stack.Count > 0)
                            {
                                tr = (TokenResult)stack.Pop();
                                if (tr.OpToken != OperatorTokens.LParen)
                                {
                                    m_Postfix.Enqueue(tr);
                                }
                            }
                            else
                            {
                                throw new UPnPCustomException(402, "Invalid Args: Missing Left Parenthesis.");
                            }
                        }while (tr.OpToken != OperatorTokens.LParen);
                    }
                    else
                    {
                        //standard operator
                        //
                        if (token.OpToken == OperatorTokens.Invalid)
                        {
                            throw new Exception("bad code");
                        }

                        while
                        (
                            (stack.Count > 0) &&
                            (((TokenResult)stack.Peek()).Precedence >= token.Precedence) &&
                            (((TokenResult)stack.Peek()).OpToken != OperatorTokens.LParen)
                        )
                        {
                            // While stack is not empty &&
                            // top operator has higher or equal precedence...
                            // pop operator and stuff into queue
                            m_Postfix.Enqueue(stack.Pop());
                        }
                        stack.Push(token);
                    }
                    break;

                case Tokens.PropertyName:
                    m_Postfix.Enqueue(token);
                    TagExtractor te = new TagExtractor(token.Data);
                    this.m_PE[token.Data] = te;
                    break;

                case Tokens.PropertyValue:
                    m_Postfix.Enqueue(token);
                    break;
                }
            }

            // pop remaining items in stack and stuff into queue
            //

            while (stack.Count > 0)
            {
                TokenResult tr = (TokenResult)stack.Pop();
                if (tr.OpToken != OperatorTokens.LParen)
                {
                    m_Postfix.Enqueue(tr);
                }
            }
        }
        /// <summary>
        /// Evaluates a subexpression of a whole expression.
        /// </summary>
        /// <param name="media">the media object with the metadata</param>
        /// <param name="prop">the property/attribute metadata to examine</param>
        /// <param name="op">the operator to use for examination</param>
        /// <param name="val">the value to compare against in string form</param>
        /// <returns></returns>
        /// <exception cref="OpenSource.UPnP.AV.CdsMetadata.Error_MalformedSearchCriteria">
        /// Thrown when the expression provided at constructor time could not
        /// be used to evaluate the media because of syntax errors in
        /// the expression.
        /// </exception>
        private bool Evaluate(IUPnPMedia media, string prop, OperatorTokens op, string val)
        {
            bool result = false;

            TagExtractor te = (TagExtractor)this.m_PE[prop];

            IList values = te.Extract(media);


            if (op == OperatorTokens.Exists)
            {
                bool testVal = (string.Compare(val, "true", true) == 0);

                result = (
                    ((values.Count > 0) && (testVal)) ||
                    ((values.Count == 0) && (testVal == false))
                    );
            }
            else
            {
                foreach (object testVal in values)
                {
                    int opCode = (int)op;
                    if ((opCode >= (int)OperatorTokens.Equal) && (opCode <= (int)OperatorTokens.GreaterThanEqualTo))
                    {
                        // Compare using a relational operator
                        //
                        try
                        {
                            int relResult = MetadataValueComparer.CompareTagValues(testVal, val, this.IgnoreCase);

                            if (relResult == 0)
                            {
                                result = true;
                                break;
                            }
                        }
                        catch                         //(Exception e)
                        {
                            string opString = Enum.GetName(typeof(OperatorTokens), opCode);
                            throw new Error_MalformedSearchCriteria("(" + val + ") " + opString + " " + testVal.ToString() + ") could not occur.");
                        }
                    }
                    else if (op == OperatorTokens.Contains)
                    {
                        string tv  = testVal.ToString();
                        int    pos = tv.IndexOf(val);
                        result = (pos >= 0);
                    }
                    else if (op == OperatorTokens.DoesNotContain)
                    {
                        string tv  = testVal.ToString();
                        int    pos = tv.IndexOf(val);
                        result = (pos < 0);
                    }
                    else if (op == OperatorTokens.DerivedFrom)
                    {
                        string tv = testVal.ToString();

                        result = tv.StartsWith(val);
                    }
                }
            }

            return(result);
        }
예제 #3
0
		/// <summary>
		/// This constructor takes a Boolean expression in infix format.
		/// Some examples
		/// are shown below. Assume <b>T</b> is an instance of the 
		/// <see cref="Tags"/>
		/// class.
		/// <list type="table">
		/// <item>
		/// T[CommonPropertyNames.title] contains "foo"
		/// <term>
		/// </term>
		/// <description>
		/// <see cref="MediaComparer.IsMatch"/> will return
		/// true on media objects that have <i>foo</i> in the title.
		/// </description>
		/// </item>
		/// 
		/// <item>
		/// T[CommonPropertyNames.creator] doesNotContain "\"HappyBand\""
		/// <term>
		/// </term>
		/// <description>
		/// <see cref="MediaComparer.IsMatch"/> will return
		/// true on media objects that do not have <i>"HappyBand"</i> in the title.
		/// </description>
		/// </item>
		/// 
		/// <item>
		/// (T[CommonPropertyNames.Class] = "object.item.audioItem.musicTrack" and Tags.PropertyAttributes.res_size > "40") or (T[CommonPropertyNames.author] exists true)
		/// <term>
		/// </term>
		/// <description>
		/// <see cref="MediaComparer.IsMatch"/> will return
		/// true on media objects that are music tracks with at least one resource greater than 40 bytes
		/// OR on media objects that have a value set for the author metadata.
		/// </description>
		/// </item>
		/// </list>
		/// </summary>
		/// <param name="infix">The boolean infix expression conforming to the syntax and semantics of ContentDirectory's boolean query language.</param>
		/// <exception cref="OpenSource.UPnP.AV.CdsMetadata.Error_MalformedSearchCriteria">
		/// Thrown if the infix expression has a syntax error.
		/// </exception>
		public MediaComparer (string infix)
		{

			string allstring = infix.Trim();
			if ((allstring == "") || (allstring == "*"))
			{
				this.m_AlwaysMatch = true;
				return;
			}

			//Initialize an empty stack and empty result string variable.
			//
			Stack stack = new Stack();
			m_Postfix = new Queue();

			RelExpStates state = RelExpStates.unknown;
			TokenResult token;
			while (infix.Length > 0)
			{
				infix = infix.Trim();
				token = GetToken(ref infix, state);

				switch (state)
				{
					case RelExpStates.unknown:
						if (token.TokenType == Tokens.PropertyName)
						{
							state = RelExpStates.expectOp;
						} 
						break;
					case RelExpStates.expectOp:
						if (token.TokenType != Tokens.Operator)
						{
							throw new UPnPCustomException(402, "Invalid Args: Invalid operator " + token.Data);
						}
						state = RelExpStates.expectValue;
						break;
					case RelExpStates.expectValue:
						if (token.TokenType != Tokens.PropertyValue)
						{
							throw new UPnPCustomException(402, "Invalid Args: Unexpected value " + token.Data);
						}
						state = RelExpStates.unknown;
						break;
				}

				switch (token.TokenType)
				{
					case Tokens.Operator:
						if (token.OpToken == OperatorTokens.LParen)
						{
							//left paren
							//
							stack.Push(token);
						}
						else if (token.OpToken == OperatorTokens.RParen)
						{
							//right paren
							//
							TokenResult tr = new TokenResult(false);
							do
							{
								if (stack.Count > 0)
								{
									tr = (TokenResult) stack.Pop();
									if (tr.OpToken != OperatorTokens.LParen)
									{
										m_Postfix.Enqueue(tr);
									}
								}
								else
								{
									throw new UPnPCustomException(402, "Invalid Args: Missing Left Parenthesis.");
								}
							}
							while (tr.OpToken != OperatorTokens.LParen);
						}
						else
						{
							//standard operator
							//
							if (token.OpToken == OperatorTokens.Invalid)
							{
								throw new Exception("bad code");
							}

							while
								(
								(stack.Count > 0) && 
								( ((TokenResult) stack.Peek()).Precedence >= token.Precedence) && 
								( ((TokenResult) stack.Peek()).OpToken != OperatorTokens.LParen) 
								)
							{
								// While stack is not empty &&
								// top operator has higher or equal precedence...
								// pop operator and stuff into queue
								m_Postfix.Enqueue( stack.Pop() );
							}
							stack.Push(token);
						}
						break;

					case Tokens.PropertyName:
						m_Postfix.Enqueue(token);
						TagExtractor te = new TagExtractor(token.Data);
						this.m_PE[token.Data] = te;
						break;

					case Tokens.PropertyValue:
						m_Postfix.Enqueue(token);
						break;
				}
			}

			// pop remaining items in stack and stuff into queue
			// 

			while (stack.Count > 0)
			{
				TokenResult tr = (TokenResult) stack.Pop();
				if (tr.OpToken != OperatorTokens.LParen) 
				{
					m_Postfix.Enqueue( tr );
				}
			}
		}