/// <summary>
        /// Converts a string to a byte[] value.
        /// </summary>
        /// <param name="text">String text to convert.</param>
        /// <param name="targetValue">After invocation, converted value.</param>
        /// <returns>true if the value was converted; false otherwise.</returns>
        /// <remarks>Copy of WebConvert.TryKeyStringToByteArray.</remarks>
        private static bool TryUriStringToByteArray(string text, out byte[] targetValue)
        {
            Debug.Assert(text != null, "text != null");

            if (!UriParserHelper.TryRemoveLiteralPrefix(ExpressionConstants.LiteralPrefixBinary, ref text))
            {
                targetValue = null;
                return(false);
            }

            if (!UriParserHelper.TryRemoveQuotes(ref text))
            {
                targetValue = null;
                return(false);
            }

            try
            {
                targetValue = Convert.FromBase64String(text);
            }
            catch (FormatException)
            {
                targetValue = null;
                return(false);
            }

            return(true);
        }
Beispiel #2
0
        /// <summary>
        /// Parse the level option in the expand option text.
        /// </summary>
        /// <returns>The level option for expand in long type</returns>
        private long?ParseInnerLevel()
        {
            long?levelsOption = null;

            // advance to the equal sign
            this.lexer.NextToken();
            string levelsText = UriParserHelper.ReadQueryOption(this.lexer);
            long   level;

            if (string.Equals(
                    ExpressionConstants.KeywordMax,
                    levelsText,
                    this.enableCaseInsensitiveBuiltinIdentifier ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal))
            {
                levelsOption = long.MinValue;
            }
            else if (!long.TryParse(levelsText, NumberStyles.None, CultureInfo.InvariantCulture, out level) || level < 0)
            {
                throw new ODataException(ODataErrorStrings.UriSelectParser_InvalidLevelsOption(levelsText));
            }
            else
            {
                levelsOption = level;
            }

            return(levelsOption);
        }
Beispiel #3
0
        /// <summary>
        /// Parse the expand option in the select/expand option text.
        /// </summary>
        /// <param name="pathToken">The path segment token</param>
        /// <returns>The expand option for select/expand</returns>
        private ExpandToken ParseInnerExpand(PathSegmentToken pathToken)
        {
            // advance to the equal sign
            this.lexer.NextToken();

            string expandText = UriParserHelper.ReadQueryOption(this.lexer);

            IEdmStructuredType targetStructuredType = null;

            if (this.resolver != null && this.parentStructuredType != null)
            {
                var parentProperty = this.resolver.ResolveProperty(parentStructuredType, pathToken.Identifier);

                // it is a property, need to find the type.
                // Like $expand=Friends($expand=Trips($expand=*)), when expandText becomes "Trips($expand=*)",
                // find navigation property Trips of Friends, then get Entity type of Trips.
                // or for select query like: $select=Address($expand=City)
                if (parentProperty != null)
                {
                    targetStructuredType = parentProperty.Type.ToStructuredType();
                }
            }

            SelectExpandParser innerExpandParser = new SelectExpandParser(
                resolver,
                expandText,
                targetStructuredType,
                this.maxRecursionDepth - 1,
                this.enableCaseInsensitiveBuiltinIdentifier,
                this.enableNoDollarQueryOptions);

            return(innerExpandParser.ParseExpand());
        }
Beispiel #4
0
            /// <summary>
            /// Tries to remove formatting specific to this parser's expected type.
            /// </summary>
            /// <param name="text">The text to remove formatting from.</param>
            /// <returns>Whether or not the expected formatting was found and successfully removed.</returns>
            internal virtual bool TryRemoveFormatting(ref string text)
            {
                if (this.prefix != null)
                {
                    if (!UriParserHelper.TryRemovePrefix(this.prefix, ref text))
                    {
                        return(false);
                    }
                }

                bool shouldBeQuoted = this.prefix != null || ValueOfTypeCanContainQuotes(this.expectedType);

                if (shouldBeQuoted && !UriParserHelper.TryRemoveQuotes(ref text))
                {
                    return(false);
                }

                if (this.suffix != null)
                {
                    // we need to try to remove the literal even if it isn't required.
                    if (!TryRemoveLiteralSuffix(this.suffix, ref text) && this.suffixRequired)
                    {
                        return(false);
                    }
                }

                return(true);
            }
Beispiel #5
0
        /// <summary>
        /// Parse the select option in the select/expand option text.
        /// </summary>
        /// <param name="pathToken">The path segment token</param>
        /// <returns>The select option for select/expand</returns>
        private SelectToken ParseInnerSelect(PathSegmentToken pathToken)
        {
            // advance to the equal sign
            this.lexer.NextToken();
            string selectText = UriParserHelper.ReadQueryOption(this.lexer);

            IEdmStructuredType targetStructuredType = null;

            if (this.resolver != null && this.parentStructuredType != null)
            {
                var parentProperty = this.resolver.ResolveProperty(parentStructuredType, pathToken.Identifier);

                // It is a property, need to find the type.
                // or for select query like: $select=Address($expand=City)
                if (parentProperty != null)
                {
                    targetStructuredType = parentProperty.Type.ToStructuredType();
                }
            }

            SelectExpandParser innerSelectParser = new SelectExpandParser(
                resolver,
                selectText,
                targetStructuredType,
                this.maxRecursionDepth - 1,
                this.enableCaseInsensitiveBuiltinIdentifier,
                this.enableNoDollarQueryOptions);

            return(innerSelectParser.ParseSelect());
        }
        /// <summary>
        /// Try to parse the given text to a Geometry object.
        /// </summary>
        /// <param name="text">Text to parse.</param>
        /// <param name="targetValue">Geometry to return.</param>
        /// <param name="parsingFailureReasonException">The detailed reason of parsing error.</param>
        /// <returns>True if succeeds, false if not.</returns>
        private static bool TryUriStringToGeometry(string text, out Geometry targetValue, out UriLiteralParsingException parsingFailureReasonException)
        {
            parsingFailureReasonException = null;

            if (!UriParserHelper.TryRemoveLiteralPrefix(ExpressionConstants.LiteralPrefixGeometry, ref text))
            {
                targetValue = default(Geometry);
                return(false);
            }

            if (!UriParserHelper.TryRemoveQuotes(ref text))
            {
                targetValue = default(Geometry);
                return(false);
            }

            try
            {
                targetValue = LiteralUtils.ParseGeometry(text);
                return(true);
            }
            catch (ParseErrorException e)
            {
                targetValue = default(Geometry);

                parsingFailureReasonException =
                    new UriLiteralParsingException(e.Message);
                return(false);
            }
        }
        /// <summary>
        /// Converts a string to a Duration value.
        /// </summary>
        /// <param name="text">String text to convert.</param>
        /// <param name="targetValue">After invocation, converted value.</param>
        /// <returns>true if the value was converted; false otherwise.</returns>
        /// <remarks>Copy of WebConvert.TryKeyStringToTime.</remarks>
        private static bool TryUriStringToDuration(string text, out TimeSpan targetValue)
        {
            if (!UriParserHelper.TryRemoveLiteralPrefix(ExpressionConstants.LiteralPrefixDuration, ref text))
            {
                targetValue = default(TimeSpan);
                return(false);
            }

            if (!UriParserHelper.TryRemoveQuotes(ref text))
            {
                targetValue = default(TimeSpan);
                return(false);
            }

            try
            {
                targetValue = EdmValueParser.ParseDuration(text);
                return(true);
            }
            catch (FormatException)
            {
                targetValue = default(TimeSpan);
                return(false);
            }
        }
Beispiel #8
0
        /// <summary>
        /// Try to bind an identifier to a EnumNode
        /// </summary>
        /// <param name="identifier">the identifier to bind</param>
        /// <param name="typeReference">the enum typeReference</param>
        /// <param name="modelWhenNoTypeReference">the current model when no enum typeReference.</param>
        /// <param name="resolver">ODataUriResolver .</param>
        /// <param name="boundEnum">an enum node .</param>
        /// <returns>true if we bound an enum for this token.</returns>
        internal static bool TryBindIdentifier(string identifier, IEdmEnumTypeReference typeReference, IEdmModel modelWhenNoTypeReference, ODataUriResolver resolver, out QueryNode boundEnum)
        {
            boundEnum = null;
            string text = identifier;

            // parse the string, e.g., NS.Color'Green'
            // get type information, and also convert Green into an ODataEnumValue

            // find the first ', before that, it is namespace.type
            int indexOfSingleQuote = text.IndexOf('\'');

            if (indexOfSingleQuote < 0)
            {
                return(false);
            }

            string namespaceAndType = text.Substring(0, indexOfSingleQuote);

            Debug.Assert((typeReference == null) || (modelWhenNoTypeReference == null), "((typeReference == null) || (modelWhenNoTypeReference == null)");

            // validate typeReference but allow type name not found in model for delayed throwing.
            if ((typeReference != null) && !string.Equals(namespaceAndType, typeReference.FullName(), StringComparison.Ordinal))
            {
                return(false);
            }

            // get the type
            IEdmEnumType enumType = typeReference != null
                ?
                                    (IEdmEnumType)typeReference.Definition
                :
                                    UriEdmHelpers.FindEnumTypeFromModel(modelWhenNoTypeReference, namespaceAndType, resolver);

            if (enumType == null)
            {
                return(false);
            }

            // now, find out the value
            UriParserHelper.TryRemovePrefix(namespaceAndType, ref text);
            UriParserHelper.TryRemoveQuotes(ref text);

            // parse string or int value to edm enum value
            string         enumValueString = text;
            ODataEnumValue enumValue;

            if (!TryParseEnum(enumType, enumValueString, out enumValue))
            {
                return(false);
            }

            // create an enum node, enclosing an odata enum value
            IEdmEnumTypeReference enumTypeReference = typeReference ?? new EdmEnumTypeReference(enumType, false);

            boundEnum = new ConstantNode(enumValue, identifier, enumTypeReference);

            return(true);
        }
Beispiel #9
0
        /// <summary>
        /// Parse the compute option in the expand option text.
        /// </summary>
        /// <returns>The compute option for expand</returns>
        private ComputeToken ParseInnerCompute()
        {
            this.lexer.NextToken();
            string computeText = UriParserHelper.ReadQueryOption(this.lexer);

            UriQueryExpressionParser computeParser = new UriQueryExpressionParser(this.MaxOrderByDepth, enableCaseInsensitiveBuiltinIdentifier);

            return(computeParser.ParseCompute(computeText));
        }
Beispiel #10
0
        /// <summary>
        /// Parse the apply option in the expand option text.
        /// </summary>
        /// <returns>The apply option for expand</returns>
        private IEnumerable <QueryToken> ParseInnerApply()
        {
            this.lexer.NextToken();
            string applyText = UriParserHelper.ReadQueryOption(this.lexer);

            UriQueryExpressionParser applyParser = new UriQueryExpressionParser(this.MaxOrderByDepth, enableCaseInsensitiveBuiltinIdentifier);

            return(applyParser.ParseApply(applyText));
        }
Beispiel #11
0
        /// <summary>
        /// Parse the search option in the select/expand option text.
        /// </summary>
        /// <returns>The search option for select/expand</returns>
        private QueryToken ParseInnerSearch()
        {
            // advance to the equal sign
            this.lexer.NextToken();
            string searchText = UriParserHelper.ReadQueryOption(this.lexer);

            SearchParser searchParser = new SearchParser(this.MaxSearchDepth);

            return(searchParser.ParseSearch(searchText));
        }
Beispiel #12
0
        /// <summary>
        /// Parse the filter option in the $count segment.
        /// </summary>
        /// <returns>The filter option for the $count segment.</returns>
        private QueryToken ParseInnerFilter()
        {
            // advance to the equal sign
            this.lexer.NextToken();
            string filterText = UriParserHelper.ReadQueryOption(this.lexer);

            UriQueryExpressionParser filterParser = new UriQueryExpressionParser(ODataUriParserSettings.DefaultFilterLimit, this.UriQueryExpressionParser.EnableCaseInsensitiveBuiltinIdentifier);

            return(filterParser.ParseFilter(filterText));
        }
Beispiel #13
0
        /// <summary>
        /// Parse the filter option in the select/expand option text.
        /// </summary>
        /// <returns>The filter option for select/expand</returns>
        private QueryToken ParseInnerFilter()
        {
            // advance to the equal sign
            this.lexer.NextToken();
            string filterText = UriParserHelper.ReadQueryOption(this.lexer);

            UriQueryExpressionParser filterParser = new UriQueryExpressionParser(this.MaxFilterDepth, enableCaseInsensitiveBuiltinIdentifier);

            return(filterParser.ParseFilter(filterText));
        }
Beispiel #14
0
        /// <summary>
        /// Parse the orderby option in the select/expand option text.
        /// </summary>
        /// <returns>The orderby option for select/expand</returns>
        private IEnumerable <OrderByToken> ParseInnerOrderBy()
        {
            // advance to the equal sign
            this.lexer.NextToken();
            string orderByText = UriParserHelper.ReadQueryOption(this.lexer);

            UriQueryExpressionParser orderbyParser = new UriQueryExpressionParser(this.MaxOrderByDepth, enableCaseInsensitiveBuiltinIdentifier);

            return(orderbyParser.ParseOrderBy(orderByText));
        }
Beispiel #15
0
        /// <summary>
        /// Parse the search option in the $count segment.
        /// </summary>
        /// <returns>The search option for the $count segment.</returns>
        private QueryToken ParseInnerSearch()
        {
            // advance to the equal sign
            this.lexer.NextToken();
            string searchText = UriParserHelper.ReadQueryOption(this.lexer);

            SearchParser searchParser = new SearchParser(ODataUriParserSettings.DefaultSearchLimit);

            return(searchParser.ParseSearch(searchText));
        }
        /// <summary>
        /// Build a segment from a token.
        /// </summary>
        /// <param name="tokenIn">the token to bind</param>
        /// <param name="model">The model.</param>
        /// <param name="edmType">the type of the current scope based on type segments.</param>
        /// <param name="resolver">Resolver for uri parser.</param>
        /// <returns>The segment created from the token.</returns>
        public static ODataPathSegment ConvertNonTypeTokenToSegment(PathSegmentToken tokenIn, IEdmModel model, IEdmStructuredType edmType, ODataUriResolver resolver)
        {
            ExceptionUtils.CheckArgumentNotNull(resolver, "resolver");

            ODataPathSegment nextSegment;

            if (UriParserHelper.IsAnnotation(tokenIn.Identifier))
            {
                if (TryBindAsDeclaredTerm(tokenIn, model, resolver, out nextSegment))
                {
                    return(nextSegment);
                }

                string qualifiedTermName = tokenIn.Identifier.Remove(0, 1);
                int    separator         = qualifiedTermName.LastIndexOf(".", StringComparison.Ordinal);
                string namespaceName     = qualifiedTermName.Substring(0, separator);
                string termName          = qualifiedTermName.Substring(separator == 0 ? 0 : separator + 1);

                // Don't allow selecting odata control information
                if (String.Compare(namespaceName, ODataConstants.ODataPrefix, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    throw new ODataException(ODataErrorStrings.UriSelectParser_TermIsNotValid(tokenIn.Identifier));
                }

                return(new AnnotationSegment(new EdmTerm(namespaceName, termName, EdmCoreModel.Instance.GetUntyped())));
            }

            if (TryBindAsDeclaredProperty(tokenIn, edmType, resolver, out nextSegment))
            {
                return(nextSegment);
            }

            // Operations must be container-qualified, and because the token type indicates it was not a .-seperated identifier, we should not try to look up operations.
            if (tokenIn.IsNamespaceOrContainerQualified())
            {
                if (TryBindAsOperation(tokenIn, model, edmType, out nextSegment))
                {
                    return(nextSegment);
                }

                // If an action or function is requested in a selectItem using a qualifiedActionName or a qualifiedFunctionName
                // and that operation cannot be bound to the entities requested, the service MUST ignore the selectItem.
                if (!edmType.IsOpen)
                {
                    return(null);
                }
            }

            if (edmType.IsOpen)
            {
                return(new DynamicPathSegment(tokenIn.Identifier));
            }

            throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(edmType.FullTypeName(), tokenIn.Identifier));
        }
Beispiel #17
0
        internal IEdmTypeReference GetLiteralEdmTypeReference()
        {
            Debug.Assert(this.Kind != ExpressionTokenKind.CustomTypeLiteral || this.LiteralEdmType != null, "ExpressionTokenKind is marked as CustomTypeLiteral but not EdmType was set");

            if (this.LiteralEdmType == null && this.Kind != ExpressionTokenKind.CustomTypeLiteral)
            {
                this.LiteralEdmType = UriParserHelper.GetLiteralEdmTypeReference(this.Kind);
            }

            return(this.LiteralEdmType);
        }
        /// <summary>
        /// Remove the given literal prefix
        /// </summary>
        /// <param name="literalPrefix">The custom name of the literal prefix</param>
        /// <returns>'true' if the literal prefix is successfully found and removed; otherwise, 'false'.</returns>
        /// <exception cref="ArgumentNullException">Argument is null or empty</exception>
        public static bool RemoveCustomLiteralPrefix(string literalPrefix)
        {
            // Arguments validation
            ExceptionUtils.CheckArgumentStringNotNullOrEmpty(literalPrefix, "literalPrefix");

            UriParserHelper.ValidatePrefixLiteral(literalPrefix);

            // Try to remove the custom uri literal prefix from cache
            lock (Locker)
            {
                return(CustomLiteralPrefixesOfEdmTypes.Remove(literalPrefix));
            }
        }
Beispiel #19
0
            /// <summary>
            /// Tries to remove formatting specific to this parser's expected type.
            /// </summary>
            /// <param name="text">The text to remove formatting from.</param>
            /// <returns>
            /// Whether or not the expected formatting was found and succesfully removed.
            /// </returns>
            internal override bool TryRemoveFormatting(ref string text)
            {
                if (!UriParserHelper.TryRemovePrefix(ExpressionConstants.LiteralPrefixBinary, ref text))
                {
                    return(false);
                }

                if (!UriParserHelper.TryRemoveQuotes(ref text))
                {
                    return(false);
                }

                return(true);
            }
Beispiel #20
0
        /// <summary>
        /// Parse the skip option in the select/expand option text.
        /// </summary>
        /// <returns>The skip option for select/expand</returns>
        private long?ParseInnerSkip()
        {
            // advance to the equal sign
            this.lexer.NextToken();
            string skipText = UriParserHelper.ReadQueryOption(this.lexer);

            // TryParse requires a non-nullable non-negative long.
            long skip;

            if (!long.TryParse(skipText, out skip) || skip < 0)
            {
                throw new ODataException(ODataErrorStrings.UriSelectParser_InvalidSkipOption(skipText));
            }

            return(skip);
        }
Beispiel #21
0
        /// <summary>
        /// Parse the count option in the select/expand option text.
        /// </summary>
        /// <returns>The count option for select/expand</returns>
        private bool?ParseInnerCount()
        {
            // advance to the equal sign
            this.lexer.NextToken();
            string countText = UriParserHelper.ReadQueryOption(this.lexer);

            switch (countText)
            {
            case ExpressionConstants.KeywordTrue:
                return(true);

            case ExpressionConstants.KeywordFalse:
                return(false);

            default:
                throw new ODataException(ODataErrorStrings.UriSelectParser_InvalidCountOption(countText));
            }
        }
Beispiel #22
0
        /// <summary>
        /// Tries to bind a given token as a declared annotation term.
        /// </summary>
        /// <param name="tokenIn">Token to bind.</param>
        /// <param name="model">The model to search for this term</param>
        /// <param name="resolver">Resolver for uri parser.</param>
        /// <param name="segment">Bound segment if the token was bound to a declared term successfully, or null.</param>
        /// <returns>True if the token was bound successfully, or false otherwise.</returns>
        private static bool TryBindAsDeclaredTerm(PathSegmentToken tokenIn, IEdmModel model, ODataUriResolver resolver, out ODataPathSegment segment)
        {
            if (!UriParserHelper.IsAnnotation(tokenIn.Identifier))
            {
                segment = null;
                return(false);
            }

            IEdmTerm term = resolver.ResolveTerm(model, tokenIn.Identifier.Remove(0, 1));

            if (term == null)
            {
                segment = null;
                return(false);
            }

            segment = new AnnotationSegment(term);
            return(true);
        }
        /// <summary>
        /// Add a literal prefix for the given EdmType.
        /// </summary>
        /// <example>filter=MyProperty eq MyCustomLiteral'VALUE'.
        /// "MyCustomLiteral" is the literal prefix and the <paramref name="literalEdmTypeReference"/> is the type of the "VALUE".</example>
        /// <param name="literalPrefix">The custom name of the literal prefix</param>
        /// <param name="literalEdmTypeReference">The edm type of the custom literal</param>
        /// <exception cref="ArgumentNullException">Arguments are null or empty</exception>
        /// <exception cref="ArgumentException">The given literal prefix is not valid</exception>
        /// <exception cref="ODataException">The given literal prefix already exists</exception>
        public static void AddCustomLiteralPrefix(string literalPrefix, IEdmTypeReference literalEdmTypeReference)
        {
            // Arguments validation
            ExceptionUtils.CheckArgumentNotNull(literalEdmTypeReference, "literalEdmTypeReference");

            ExceptionUtils.CheckArgumentStringNotNullOrEmpty(literalPrefix, "literalPrefix");

            UriParserHelper.ValidatePrefixLiteral(literalPrefix);

            // Try to add the custom uri literal to cache
            lock (Locker)
            {
                // Check if literal does already exists
                if (CustomLiteralPrefixesOfEdmTypes.ContainsKey(literalPrefix))
                {
                    throw new ODataException(ODataErrorStrings.CustomUriTypePrefixLiterals_AddCustomUriTypePrefixLiteralAlreadyExists(literalPrefix));
                }

                CustomLiteralPrefixesOfEdmTypes.Add(literalPrefix, literalEdmTypeReference);
            }
        }
Beispiel #24
0
        /// <summary>Parses a token that starts with a digit.</summary>
        /// <returns>The kind of token recognized.</returns>
        private ExpressionTokenKind ParseFromDigit()
        {
            Debug.Assert(this.IsValidDigit || ('-' == this.ch), "this.IsValidDigit || ('-' == this.ch)");
            ExpressionTokenKind result;
            int  tokenPos  = this.textPos;
            char startChar = this.ch.Value;

            this.NextChar();
            if (startChar == '0' && (this.ch == 'x' || this.ch == 'X'))
            {
                result = ExpressionTokenKind.BinaryLiteral;
                do
                {
                    this.NextChar();
                }while (this.ch.HasValue && UriParserHelper.IsCharHexDigit(this.ch.Value));
            }
            else
            {
                result = ExpressionTokenKind.IntegerLiteral;
                while (this.IsValidDigit)
                {
                    this.NextChar();
                }

                // DateTimeOffset, Date and Guids will have '-' in them
                if (this.ch == '-')
                {
                    if (this.TryParseDate(tokenPos))
                    {
                        return(ExpressionTokenKind.DateLiteral);
                    }
                    else if (this.TryParseDateTimeoffset(tokenPos))
                    {
                        return(ExpressionTokenKind.DateTimeOffsetLiteral);
                    }
                    else if (this.TryParseGuid(tokenPos))
                    {
                        return(ExpressionTokenKind.GuidLiteral);
                    }
                }

                // TimeOfDay will have ":" in them
                if (this.ch == ':')
                {
                    if (this.TryParseTimeOfDay(tokenPos))
                    {
                        return(ExpressionTokenKind.TimeOfDayLiteral);
                    }
                }

                // Guids will have alpha-numeric characters along with '-', so if a letter is encountered
                // try to see if this is Guid or not.
                if (this.ch.HasValue && Char.IsLetter(this.ch.Value))
                {
                    if (this.TryParseGuid(tokenPos))
                    {
                        return(ExpressionTokenKind.GuidLiteral);
                    }
                }

                if (this.ch == '.')
                {
                    result = ExpressionTokenKind.DoubleLiteral;
                    this.NextChar();
                    this.ValidateDigit();

                    do
                    {
                        this.NextChar();
                    }while (this.IsValidDigit);
                }

                if (this.ch == 'E' || this.ch == 'e')
                {
                    result = ExpressionTokenKind.DoubleLiteral;
                    this.NextChar();
                    if (this.ch == '+' || this.ch == '-')
                    {
                        this.NextChar();
                    }

                    this.ValidateDigit();
                    do
                    {
                        this.NextChar();
                    }while (this.IsValidDigit);
                }

                if (this.ch == 'M' || this.ch == 'm')
                {
                    result = ExpressionTokenKind.DecimalLiteral;
                    this.NextChar();
                }
                else if (this.ch == 'd' || this.ch == 'D')
                {
                    result = ExpressionTokenKind.DoubleLiteral;
                    this.NextChar();
                }
                else if (this.ch == 'L' || this.ch == 'l')
                {
                    result = ExpressionTokenKind.Int64Literal;
                    this.NextChar();
                }
                else if (this.ch == 'f' || this.ch == 'F')
                {
                    result = ExpressionTokenKind.SingleLiteral;
                    this.NextChar();
                }
                else
                {
                    string valueStr = this.Text.Substring(tokenPos, this.textPos - tokenPos);
                    result = MakeBestGuessOnNoSuffixStr(valueStr, result);
                }
            }

            return(result);
        }
Beispiel #25
0
        /// <summary>
        /// Process a <see cref="PathSegmentToken"/> following any type segments if necessary.
        /// </summary>
        /// <param name="tokenIn">the path token to process.</param>
        private List <ODataPathSegment> ProcessSelectTokenPath(PathSegmentToken tokenIn)
        {
            Debug.Assert(tokenIn != null, "tokenIn != null");

            List <ODataPathSegment> pathSoFar        = new List <ODataPathSegment>();
            IEdmStructuredType      currentLevelType = this.edmType;

            // first, walk through all type segments in a row, converting them from tokens into segments.
            if (tokenIn.IsNamespaceOrContainerQualified() && !UriParserHelper.IsAnnotation(tokenIn.Identifier))
            {
                PathSegmentToken firstNonTypeToken;
                pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(tokenIn, this.Model, this.Settings.SelectExpandLimit, this.configuration.Resolver, ref currentLevelType, out firstNonTypeToken));
                Debug.Assert(firstNonTypeToken != null, "Did not get last token.");
                tokenIn = firstNonTypeToken as NonSystemToken;
                if (tokenIn == null)
                {
                    throw new ODataException(ODataErrorStrings.SelectExpandBinder_SystemTokenInSelect(firstNonTypeToken.Identifier));
                }
            }

            // next, create a segment for the first non-type segment in the path.
            ODataPathSegment lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(tokenIn, this.Model, currentLevelType, this.configuration.Resolver, this.state);

            // next, create an ODataPath and add the segments to it.
            if (lastSegment != null)
            {
                pathSoFar.Add(lastSegment);

                // try create a complex type property path.
                while (true)
                {
                    // no need to go on if the current property is not of complex type or collection of complex type,
                    // unless the segment is a primitive type cast or a property on an open complex property.
                    currentLevelType = lastSegment.EdmType as IEdmStructuredType;
                    IEdmCollectionType collectionType = lastSegment.EdmType as IEdmCollectionType;
                    IEdmPrimitiveType  primitiveType  = lastSegment.EdmType as IEdmPrimitiveType;
                    DynamicPathSegment dynamicPath    = lastSegment as DynamicPathSegment;
                    if ((currentLevelType == null || currentLevelType.TypeKind != EdmTypeKind.Complex) &&
                        (collectionType == null || collectionType.ElementType.TypeKind() != EdmTypeKind.Complex) &&
                        (primitiveType == null || primitiveType.TypeKind != EdmTypeKind.Primitive) &&
                        (dynamicPath == null || tokenIn.NextToken == null))
                    {
                        break;
                    }

                    NonSystemToken nextToken = tokenIn.NextToken as NonSystemToken;
                    if (nextToken == null)
                    {
                        break;
                    }

                    if (UriParserHelper.IsAnnotation(nextToken.Identifier))
                    {
                        lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(nextToken, this.Model,
                                                                                                currentLevelType, this.configuration.Resolver, null);
                    }
                    else if (primitiveType == null && dynamicPath == null)
                    {
                        // This means last segment a collection of complex type,
                        // current segment can only be type cast and cannot be property name.
                        if (currentLevelType == null)
                        {
                            currentLevelType = collectionType.ElementType.Definition as IEdmStructuredType;
                        }

                        // If there is no collection type in the path yet, will try to bind property for the next token
                        // first try bind the segment as property.
                        lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(nextToken, this.Model,
                                                                                                currentLevelType, this.configuration.Resolver, null);
                    }
                    else
                    {
                        // determine whether we are looking at a type cast or a dynamic path segment.
                        EdmPrimitiveTypeKind nextTypeKind = EdmCoreModel.Instance.GetPrimitiveTypeKind(nextToken.Identifier);
                        IEdmPrimitiveType    castType     = EdmCoreModel.Instance.GetPrimitiveType(nextTypeKind);
                        if (castType != null)
                        {
                            lastSegment = new TypeSegment(castType, castType, null);
                        }
                        else if (dynamicPath != null)
                        {
                            lastSegment = new DynamicPathSegment(nextToken.Identifier);
                        }
                        else
                        {
                            throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect);
                        }
                    }

                    // then try bind the segment as type cast.
                    if (lastSegment == null)
                    {
                        IEdmStructuredType typeFromNextToken =
                            UriEdmHelpers.FindTypeFromModel(this.Model, nextToken.Identifier, this.configuration.Resolver) as
                            IEdmStructuredType;

                        if (typeFromNextToken.IsOrInheritsFrom(currentLevelType))
                        {
                            lastSegment = new TypeSegment(typeFromNextToken, /*entitySet*/ null);
                        }
                    }

                    // type cast failed too.
                    if (lastSegment == null)
                    {
                        break;
                    }

                    // try move to and add next path segment.
                    tokenIn = nextToken;
                    pathSoFar.Add(lastSegment);
                }
            }

            // non-navigation cases do not allow further segments in $select.
            if (tokenIn.NextToken != null)
            {
                throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect);
            }

            // Later, we can consider to create a "DynamicOperationSegment" to handle this.
            // But now, Let's throw exception.
            if (lastSegment == null)
            {
                throw new ODataException(ODataErrorStrings.MetadataBinder_InvalidIdentifierInQueryOption(tokenIn.Identifier));
            }

            // navigation property is not allowed to append sub path in the selection.
            NavigationPropertySegment navPropSegment = pathSoFar.LastOrDefault() as NavigationPropertySegment;

            if (navPropSegment != null && tokenIn.NextToken != null)
            {
                throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect);
            }

            return(pathSoFar);
        }
Beispiel #26
0
 /// <summary>
 /// Tries to remove formatting specific to this parser's expected type.
 /// </summary>
 /// <param name="text">The text to remove formatting from.</param>
 /// <returns>
 /// Whether or not the expected formatting was found and succesfully removed.
 /// </returns>
 internal override bool TryRemoveFormatting(ref string text)
 {
     return(UriParserHelper.TryRemoveQuotes(ref text));
 }
        private bool TryUriStringToPrimitive(string text, IEdmTypeReference targetType, out object targetValue, out UriLiteralParsingException exception)
        {
            Debug.Assert(text != null, "text != null");
            Debug.Assert(targetType != null, "targetType != null");
            exception = null;

            try
            {
                if (targetType.IsNullable)
                {
                    // COMPAT 38: Product does not support "null" literals in service operation arguments
                    // check for the 'null' constant for nullable types
                    if (text == ExpressionConstants.KeywordNull)
                    {
                        targetValue = null;
                        return(true);
                    }
                }

                IEdmPrimitiveTypeReference primitiveTargetType = targetType.AsPrimitiveOrNull();
                if (primitiveTargetType == null)
                {
                    targetValue = null;
                    return(false);
                }

                EdmPrimitiveTypeKind targetTypeKind = primitiveTargetType.PrimitiveKind();

                byte[] byteArrayValue;
                bool   binaryResult = TryUriStringToByteArray(text, out byteArrayValue);
                if (targetTypeKind == EdmPrimitiveTypeKind.Binary)
                {
                    targetValue = (object)byteArrayValue;
                    return(binaryResult);
                }
                else if (binaryResult)
                {
                    string keyValue = Encoding.UTF8.GetString(byteArrayValue, 0, byteArrayValue.Length);
                    return(this.TryUriStringToPrimitive(keyValue, targetType, out targetValue));
                }
                else if (targetTypeKind == EdmPrimitiveTypeKind.Guid)
                {
                    Guid guidValue;
                    bool result = UriUtils.TryUriStringToGuid(text, out guidValue);
                    targetValue = guidValue;
                    return(result);
                }
                else if (targetTypeKind == EdmPrimitiveTypeKind.Date)
                {
                    Date dateValue;
                    bool result = UriUtils.TryUriStringToDate(text, out dateValue);
                    targetValue = dateValue;
                    return(result);
                }
                else if (targetTypeKind == EdmPrimitiveTypeKind.DateTimeOffset)
                {
                    DateTimeOffset dateTimeOffsetValue;
                    bool           result = UriUtils.ConvertUriStringToDateTimeOffset(text, out dateTimeOffsetValue);
                    targetValue = dateTimeOffsetValue;
                    return(result);
                }
                else if (targetTypeKind == EdmPrimitiveTypeKind.Duration)
                {
                    TimeSpan timespanValue;
                    bool     result = TryUriStringToDuration(text, out timespanValue);
                    targetValue = timespanValue;
                    return(result);
                }
                else if (targetTypeKind == EdmPrimitiveTypeKind.Geography)
                {
                    Geography geographyValue;
                    bool      result = TryUriStringToGeography(text, out geographyValue, out exception);
                    targetValue = geographyValue;
                    return(result);
                }
                else if (targetTypeKind == EdmPrimitiveTypeKind.Geometry)
                {
                    Geometry geometryValue;
                    bool     result = TryUriStringToGeometry(text, out geometryValue, out exception);
                    targetValue = geometryValue;
                    return(result);
                }
                else if (targetTypeKind == EdmPrimitiveTypeKind.TimeOfDay)
                {
                    TimeOfDay timeOfDayValue;
                    bool      result = UriUtils.TryUriStringToTimeOfDay(text, out timeOfDayValue);
                    targetValue = timeOfDayValue;
                    return(result);
                }

                bool quoted = targetTypeKind == EdmPrimitiveTypeKind.String;
                if (quoted != UriParserHelper.IsUriValueQuoted(text))
                {
                    targetValue = null;
                    return(false);
                }

                if (quoted)
                {
                    text = UriParserHelper.RemoveQuotes(text);
                }

                try
                {
                    switch (targetTypeKind)
                    {
                    case EdmPrimitiveTypeKind.String:
                        targetValue = text;
                        break;

                    case EdmPrimitiveTypeKind.Boolean:
                        targetValue = XmlConvert.ToBoolean(text);
                        break;

                    case EdmPrimitiveTypeKind.Byte:
                        targetValue = XmlConvert.ToByte(text);
                        break;

                    case EdmPrimitiveTypeKind.SByte:
                        targetValue = XmlConvert.ToSByte(text);
                        break;

                    case EdmPrimitiveTypeKind.Int16:
                        targetValue = XmlConvert.ToInt16(text);
                        break;

                    case EdmPrimitiveTypeKind.Int32:
                        targetValue = XmlConvert.ToInt32(text);
                        break;

                    case EdmPrimitiveTypeKind.Int64:
                        UriParserHelper.TryRemoveLiteralSuffix(ExpressionConstants.LiteralSuffixInt64, ref text);
                        targetValue = XmlConvert.ToInt64(text);
                        break;

                    case EdmPrimitiveTypeKind.Single:
                        UriParserHelper.TryRemoveLiteralSuffix(ExpressionConstants.LiteralSuffixSingle, ref text);
                        targetValue = XmlConvert.ToSingle(text);
                        break;

                    case EdmPrimitiveTypeKind.Double:
                        UriParserHelper.TryRemoveLiteralSuffix(ExpressionConstants.LiteralSuffixDouble, ref text);
                        targetValue = XmlConvert.ToDouble(text);
                        break;

                    case EdmPrimitiveTypeKind.Decimal:
                        UriParserHelper.TryRemoveLiteralSuffix(ExpressionConstants.LiteralSuffixDecimal, ref text);
                        try
                        {
                            targetValue = XmlConvert.ToDecimal(text);
                        }
                        catch (FormatException)
                        {
                            // we need to support exponential format for decimals since we used to support them in V1
                            decimal result;
                            if (Decimal.TryParse(text, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out result))
                            {
                                targetValue = result;
                            }
                            else
                            {
                                targetValue = default(Decimal);
                                return(false);
                            }
                        }

                        break;

                    default:
                        throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.UriPrimitiveTypeParser_TryUriStringToPrimitive));
                    }

                    return(true);
                }
                catch (FormatException)
                {
                    targetValue = null;
                    return(false);
                }
                catch (OverflowException)
                {
                    targetValue = null;
                    return(false);
                }
            }
            catch (Exception primitiveParserException)
            {
                exception = new UriLiteralParsingException(
                    string.Format(CultureInfo.InvariantCulture, ODataErrorStrings.UriPrimitiveTypeParsers_FailedToParseTextToPrimitiveValue(text, targetType),
                                  primitiveParserException));
                targetValue = null;
                return(false);
            }
        }
Beispiel #28
0
        /// <summary>
        /// Function to normalize quoted string, ensuring single quotes are escaped properly.
        /// If the string is double-quoted, no op since single quote doesn't need to be escaped.
        /// </summary>
        /// <param name="str">The quoted string item to be normalized.</param>
        /// <returns>The double-quoted string with single quotes properly escaped.</returns>
        private static string NormalizeStringItem(string str)
        {
            // Validate the string item is quoted properly.
            if (!((str[0] == '\'' && str[str.Length - 1] == '\'') || (str[0] == '"' && str[str.Length - 1] == '"')))
            {
                throw new ODataException(ODataErrorStrings.StringItemShouldBeQuoted(str));
            }

            // Skip conversion if the items are already in double-quote format (for backward compatibility).
            // Note that per ABNF, query option strings should use single quotes.
            string convertedString = str;

            if (str[0] == '\'')
            {
                convertedString = String.Format(CultureInfo.InvariantCulture, "\"{0}\"", UriParserHelper.RemoveQuotes(str));
            }

            return(convertedString);
        }
Beispiel #29
0
        private void ProcessTokenAsPath(NonSystemToken tokenIn)
        {
            Debug.Assert(tokenIn != null, "tokenIn != null");

            List <ODataPathSegment> pathSoFar        = new List <ODataPathSegment>();
            IEdmStructuredType      currentLevelType = this.edmType;

            // first, walk through all type segments in a row, converting them from tokens into segments.
            if (tokenIn.IsNamespaceOrContainerQualified() && !UriParserHelper.IsAnnotation(tokenIn.Identifier))
            {
                PathSegmentToken firstNonTypeToken;
                pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(tokenIn, this.model, this.maxDepth, this.resolver, ref currentLevelType, out firstNonTypeToken));
                Debug.Assert(firstNonTypeToken != null, "Did not get last token.");
                tokenIn = firstNonTypeToken as NonSystemToken;
                if (tokenIn == null)
                {
                    throw new ODataException(ODataErrorStrings.SelectPropertyVisitor_SystemTokenInSelect(firstNonTypeToken.Identifier));
                }
            }

            // next, create a segment for the first non-type segment in the path.
            ODataPathSegment lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(tokenIn, this.model, currentLevelType, resolver, this.state);

            // next, create an ODataPath and add the segments to it.
            if (lastSegment != null)
            {
                pathSoFar.Add(lastSegment);

                // try create a complex type property path.
                while (true)
                {
                    // no need to go on if the current property is not of complex type or collection of complex type,
                    // unless the segment is a primitive type cast or a property on an open complex property.
                    currentLevelType = lastSegment.EdmType as IEdmStructuredType;
                    IEdmCollectionType collectionType = lastSegment.EdmType as IEdmCollectionType;
                    IEdmPrimitiveType  primitiveType  = lastSegment.EdmType as IEdmPrimitiveType;
                    DynamicPathSegment dynamicPath    = lastSegment as DynamicPathSegment;
                    if ((currentLevelType == null || currentLevelType.TypeKind != EdmTypeKind.Complex) &&
                        (collectionType == null || collectionType.ElementType.TypeKind() != EdmTypeKind.Complex) &&
                        (primitiveType == null || primitiveType.TypeKind != EdmTypeKind.Primitive) &&
                        (dynamicPath == null || tokenIn.NextToken == null))
                    {
                        break;
                    }

                    NonSystemToken nextToken = tokenIn.NextToken as NonSystemToken;
                    if (nextToken == null)
                    {
                        break;
                    }

                    if (UriParserHelper.IsAnnotation(nextToken.Identifier))
                    {
                        lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(nextToken, this.model,
                                                                                                currentLevelType, resolver, null);
                    }
                    else if (primitiveType == null && dynamicPath == null)
                    {
                        // This means last segment a collection of complex type,
                        // current segment can only be type cast and cannot be property name.
                        if (currentLevelType == null)
                        {
                            currentLevelType = collectionType.ElementType.Definition as IEdmStructuredType;
                        }

                        // If there is no collection type in the path yet, will try to bind property for the next token
                        // first try bind the segment as property.
                        lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(nextToken, this.model,
                                                                                                currentLevelType, resolver, null);
                    }
                    else
                    {
                        // determine whether we are looking at a type cast or a dynamic path segment.
                        EdmPrimitiveTypeKind nextTypeKind = EdmCoreModel.Instance.GetPrimitiveTypeKind(nextToken.Identifier);
                        IEdmPrimitiveType    castType     = EdmCoreModel.Instance.GetPrimitiveType(nextTypeKind);
                        if (castType != null)
                        {
                            lastSegment = new TypeSegment(castType, castType, null);
                        }
                        else if (dynamicPath != null)
                        {
                            lastSegment = new DynamicPathSegment(nextToken.Identifier);
                        }
                        else
                        {
                            throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect);
                        }
                    }

                    // then try bind the segment as type cast.
                    if (lastSegment == null)
                    {
                        IEdmStructuredType typeFromNextToken =
                            UriEdmHelpers.FindTypeFromModel(this.model, nextToken.Identifier, this.resolver) as
                            IEdmStructuredType;

                        if (typeFromNextToken.IsOrInheritsFrom(currentLevelType))
                        {
                            lastSegment = new TypeSegment(typeFromNextToken, /*entitySet*/ null);
                        }
                    }

                    // type cast failed too.
                    if (lastSegment == null)
                    {
                        break;
                    }

                    // try move to and add next path segment.
                    tokenIn = nextToken;
                    pathSoFar.Add(lastSegment);
                }
            }

            ODataSelectPath selectedPath = new ODataSelectPath(pathSoFar);

            var selectionItem = new PathSelectItem(selectedPath);

            // non-navigation cases do not allow further segments in $select.
            if (tokenIn.NextToken != null)
            {
                throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect);
            }

            // if the selected item is a nav prop, then see if its already there before we add it.
            NavigationPropertySegment trailingNavPropSegment = selectionItem.SelectedPath.LastSegment as NavigationPropertySegment;

            if (trailingNavPropSegment != null)
            {
                if (this.expandClauseToDecorate.SelectedItems.Any(x => x is PathSelectItem &&
                                                                  ((PathSelectItem)x).SelectedPath.Equals(selectedPath)))
                {
                    return;
                }
            }

            this.expandClauseToDecorate.AddToSelectedItems(selectionItem);
        }