예제 #1
0
        private static StringSegment ReadToSemicolonOrEnd(StringSegment input, ref int offset, bool includeComma = true)
        {
            var end = input.IndexOf(';', offset);

            if (end < 0)
            {
                // Also valid end of cookie
                if (includeComma)
                {
                    end = input.IndexOf(',', offset);
                }
            }
            else if (includeComma)
            {
                var commaPosition = input.IndexOf(',', offset);
                if (commaPosition >= 0 && commaPosition < end)
                {
                    end = commaPosition;
                }
            }

            if (end < 0)
            {
                // Remainder of the string
                end = input.Length;
            }

            var itemLength = end - offset;
            var result     = input.Subsegment(offset, itemLength);

            offset += itemLength;
            return(result);
        }
예제 #2
0
        private int IndexOfNonQuotedSeparator(StringSegment chars)
        {
            var isQuoted = false;
            var isUri    = false;

            for (int i = 0; i < chars.Length; i++)
            {
                if (chars[i] == QuoteChar && !(i > 0 && chars[i - 1] == EscapeChar))
                {
                    isQuoted = !isQuoted && !isUri && chars.IndexOf(QuoteChar, i + 1) >= 0;
                }
                else if (chars[i] == UriStartChar && !isUri && !isQuoted && chars.IndexOf(UriEndChar, i + 1) >= 0)
                {
                    isUri = true;
                }
                else if (chars[i] == UriEndChar && isUri && !isQuoted)
                {
                    isUri = false;
                }
                else if (chars[i] == ValueSeparatorChar && !isUri && !isQuoted)
                {
                    return(i);
                }
            }

            return(-1);
        }
예제 #3
0
        public void TestIndexOfCh()
        {
            StringSegment seg = new StringSegment("hey you", 1, 5);

            Assert.AreEqual(-1, seg.IndexOf('h'));
            Assert.AreEqual(0, seg.IndexOf('e'));
            Assert.AreEqual(1, seg.IndexOf('y'));
            Assert.AreEqual(-1, seg.IndexOf('u'));
            Assert.AreEqual(-1, seg.IndexOf('x'));
        }
예제 #4
0
        public void TestIndexOfStr()
        {
            StringSegment seg = new StringSegment("hey you", 1, 5);

            Assert.AreEqual(-1, seg.IndexOf("he", StringComparison.Ordinal));
            Assert.AreEqual(0, seg.IndexOf("ey", StringComparison.Ordinal));
            Assert.AreEqual(1, seg.IndexOf("y", StringComparison.Ordinal));
            Assert.AreEqual(-1, seg.IndexOf("ou", StringComparison.Ordinal));
            Assert.AreEqual(-1, seg.IndexOf("ox", StringComparison.Ordinal));
        }
        public void IndexOfChar()
        {
            string source = "abcde";
            var    segBCD = new StringSegment(source, 1, 3);

            var pos = segBCD.IndexOf('a');

            Assert.AreEqual(-1, pos);

            pos = segBCD.IndexOf('b');
            Assert.AreEqual(0, pos);

            pos = segBCD.IndexOf('c');
            Assert.AreEqual(1, pos);

            pos = segBCD.IndexOf('d');
            Assert.AreEqual(2, pos);

            pos = segBCD.IndexOf('e');
            Assert.AreEqual(-1, pos);


            pos = segBCD.IndexOf('B');
            Assert.AreEqual(-1, pos);

            pos = segBCD.IndexOf('B', true);
            Assert.AreEqual(0, pos);

            pos = segBCD.IndexOf('C', true);
            Assert.AreEqual(1, pos);

            pos = segBCD.IndexOf('C');
            Assert.AreEqual(-1, pos);
        }
예제 #6
0
        public static StringSegment ParseJsCallExpression(this StringSegment literal, out JsCallExpression expression, bool filterExpression = false)
        {
            literal = literal.ParseIdentifier(out var token);

            if (!(token is JsIdentifier identifier))
            {
                throw new SyntaxErrorException($"Expected identifier but instead found '{token}'");
            }

            literal = literal.AdvancePastWhitespace();

            if (literal.IsNullOrEmpty() || literal.GetChar(0) != '(')
            {
                var isWhitespaceSyntax = filterExpression && literal.GetChar(0) == ':';
                if (isWhitespaceSyntax)
                {
                    literal = literal.Advance(1);

                    // replace everything after ':' up till new line and rewrite as single string to method
                    var endStringPos    = literal.IndexOf("\n");
                    var endStatementPos = literal.IndexOf("}}");

                    if (endStringPos == -1 || (endStatementPos != -1 && endStatementPos < endStringPos))
                    {
                        endStringPos = endStatementPos;
                    }

                    if (endStringPos == -1)
                    {
                        throw new SyntaxErrorException($"Whitespace sensitive syntax did not find a '\\n' new line to mark the end of the statement, near '{literal.SubstringWithElipsis(0,50)}'");
                    }

                    var originalArg   = literal.Subsegment(0, endStringPos).Trim().ToString();
                    var rewrittenArgs = originalArg.Replace("{", "{{").Replace("}", "}}");
                    var strArg        = new JsLiteral(rewrittenArgs);

                    expression = new JsCallExpression(identifier, strArg);
                    return(literal.Subsegment(endStringPos));
                }

                expression = new JsCallExpression(identifier);
                return(literal);
            }

            literal.Advance(1);

            literal = literal.ParseArguments(out var args, termination: ')');

            expression = new JsCallExpression(identifier, args.ToArray());
            return(literal);
        }
예제 #7
0
        // {{#name}}  {{else if a=b}}  {{else}}  {{/name}}
        //          ^
        // returns    ^                         ^
        static StringSegment ParseStatementBody(this StringSegment literal, StringSegment blockName, out List <PageFragment> body)
        {
            var inStatements = 0;
            var pos          = 0;

            while (true)
            {
                pos = literal.IndexOf("{{", pos);
                if (pos == -1)
                {
                    throw new SyntaxErrorException($"End block for '{blockName}' not found.");
                }

                var c = literal.SafeGetChar(pos + 2);

                if (c == '#')
                {
                    inStatements++;
                    pos = literal.IndexOf("}}", pos) + 2; //end of expression
                    continue;
                }

                if (c == '/')
                {
                    if (inStatements == 0)
                    {
                        literal.Subsegment(pos + 2 + 1).ParseVarName(out var name);
                        if (name == blockName)
                        {
                            body = ParseTemplatePage(literal.Subsegment(0, pos).TrimFirstNewLine());
                            return(literal.Subsegment(pos));
                        }
                    }

                    inStatements--;
                }
                else if (literal.Subsegment(pos + 2).StartsWith("else"))
                {
                    if (inStatements == 0)
                    {
                        body = ParseTemplatePage(literal.Subsegment(0, pos).TrimFirstNewLine());
                        return(literal.Subsegment(pos));
                    }
                }

                pos += 2;
            }
        }
예제 #8
0
        // This does not duplicate format validations that are expected to be performed by the host.
        private bool ValidateHost(HttpContext context)
        {
            StringSegment host = context.Request.Headers[HeaderNames.Host].ToString().Trim();

            if (StringSegment.IsNullOrEmpty(host))
            {
                // Http/1.0 does not require the Host header.
                // Http/1.1 requires the header but the value may be empty.
                return(true);
            }

            // Drop the port
            int colonIndex = host.LastIndexOf(':');

            // IPv6 special case
            if (host.StartsWith("[", StringComparison.Ordinal))
            {
                int endBracketIndex = host.IndexOf(']');
                if (endBracketIndex < 0)
                {
                    // Invalid format
                    return(false);
                }

                if (colonIndex < endBracketIndex)
                {
                    {
                        // No port, just the IPv6 Host
                        colonIndex = -1;
                    }
                }

                if (colonIndex > 0)
                {
                    host = host.Subsegment(0, colonIndex);
                }

                foreach (string allowedHost in _hosts)
                {
                    if (StringSegment.Equals(allowedHost, host, StringComparison.OrdinalIgnoreCase))
                    {
                        return(true);
                    }

                    // Sub-domain wildcards: *.example.com
                    if (allowedHost.StartsWith("*.", StringComparison.Ordinal) && host.Length >=
                        allowedHost.Length)
                    {
                        // .example.com
                        StringSegment allowedRoot = new StringSegment(allowedHost, 1, allowedHost.Length - 1);
                        StringSegment hostRoot    = host.Subsegment(host.Length - allowedRoot.Length, allowedRoot.Length);
                        if (hostRoot.Equals(allowedRoot, StringComparison.OrdinalIgnoreCase))
                        {
                            return(true);
                        }
                    }
                }
            }
            return(true);
        }
예제 #9
0
        public MessageEntityEx(Message message, MessageEntity messageEntity)
        {
            Message = message;
            Type    = messageEntity.Type;
            Offset  = messageEntity.Offset;
            Length  = messageEntity.Length;
            Url     = messageEntity.Url;
            User    = messageEntity.User;

            Value      = new StringSegment(Message.Text, Offset, Length);
            AfterValue = new StringSegment(Message.Text, Offset + Length, Message.Text !.Length - Offset - Length);

            if (Type == MessageEntityType.BotCommand && Value.IndexOf('@') is var atOffset)
            {
                if (atOffset >= 0)
                {
                    Command    = Value.Subsegment(0, atOffset);
                    CommandBot = Value.Subsegment(atOffset + 1);
                }
                else
                {
                    Command = Value;
                }
            }
        }
예제 #10
0
        public void StringSegment_IndexOfString_ReturnsCorrectValueForExistingCharacter()
        {
            var segment = new StringSegment("Hello, world!");
            var result  = segment.IndexOf("world");

            TheResultingValue(result).ShouldBe(7);
        }
예제 #11
0
        public void StringSegment_IndexOfString_ReturnsNegativeOneForNonExistingCharacter()
        {
            var segment = new StringSegment("Hello, world!");
            var result  = segment.IndexOf("zorld");

            TheResultingValue(result).ShouldBe(-1);
        }
예제 #12
0
        public void StringSegment_IndexOfString_ReturnsNegativeOneForNonExistingCharacter()
        {
            var segment = new StringSegment("Hello, world!");
            var result = segment.IndexOf("zorld");

            TheResultingValue(result).ShouldBe(-1);
        }
예제 #13
0
        public void StringSegment_IndexOfString_ReturnsCorrectValueForExistingCharacter()
        {
            var segment = new StringSegment("Hello, world!");
            var result = segment.IndexOf("world");

            TheResultingValue(result).ShouldBe(7);
        }
예제 #14
0
        private static StringSegment ReadUri(StringSegment chars)
        {
            var uriStartIndex = chars.IndexOf(UriStartChar);
            var uriEndIndex   = chars.IndexOf(UriEndChar);

            if (uriStartIndex == 0 && uriEndIndex > 0)
            {
                return(chars.Subsegment(0, uriEndIndex + 1));
            }

            var parametersStartIndex = chars.IndexOf(ParameterSeparatorChar);

            if (parametersStartIndex > 0)
            {
                return(chars.Subsegment(0, parametersStartIndex));
            }

            return(chars);
        }
예제 #15
0
    public void IndexOf_ReturnsMinusOne_IfElementNotInSegment()
    {
        // Arrange
        var segment = new StringSegment("Hello, World!", 1, 3);

        // Act
        var result = segment.IndexOf(',');

        // Assert
        Assert.Equal(-1, result);
    }
예제 #16
0
    public void IndexOf_ComputesIndex_RelativeToTheCurrentSegment()
    {
        // Arrange
        var segment = new StringSegment("Hello, World!", 1, 10);

        // Act
        var result = segment.IndexOf(',');

        // Assert
        Assert.Equal(4, result);
    }
예제 #17
0
        private static StringSegment SplitAtWhitespace(StringSegment segment)
        {
            var idx = segment.IndexOf(' ');

            if (idx == -1)
            {
                return(StringSegment.Empty);
            }

            return(segment.Subsegment(idx + 1).TrimStart());
        }
        /// <summary>
        /// Strips an existing structured syntax suffix from a media type.
        /// </summary>
        protected static StringSegment StripSuffix(StringSegment subType)
        {
            var suffixSeparatorIndex = subType.IndexOf('+');

            if (suffixSeparatorIndex >= 0)
            {
                return(subType.Subsegment(0, suffixSeparatorIndex));
            }

            return(subType);
        }
예제 #19
0
        /// <summary>
        /// Parses the current value. IPv6 addresses will have brackets added if they are missing.
        /// </summary>
        private static void GetParts(StringSegment value, out StringSegment host, out StringSegment port)
        {
            int index;

            port = null;
            host = null;

            if (StringSegment.IsNullOrEmpty(value))
            {
                return;
            }
            else if ((index = value.IndexOf(']')) >= 0)
            {
                // IPv6 in brackets [::1], maybe with port
                host = value.Subsegment(0, index + 1);
                // Is there a colon and at least one character?
                if (index + 2 < value.Length && value[index + 1] == ':')
                {
                    port = value.Subsegment(index + 2);
                }
            }
            else if ((index = value.IndexOf(':')) >= 0 &&
                     index < value.Length - 1 &&
                     value.IndexOf(':', index + 1) >= 0)
            {
                // IPv6 without brackets ::1 is the only type of host with 2 or more colons
                host = $"[{value}]";
                port = null;
            }
            else if (index >= 0)
            {
                // Has a port
                host = value.Subsegment(0, index);
                port = value.Subsegment(index + 1);
            }
            else
            {
                host = value;
                port = null;
            }
        }
예제 #20
0
    public void IndexOf_SkipsANumberOfCaracters_IfStartIsProvided()
    {
        // Arrange
        const string buffer  = "Hello, World!, Hello people!";
        var          segment = new StringSegment(buffer, 3, buffer.Length - 3);

        // Act
        var result = segment.IndexOf('!', 15);

        // Assert
        Assert.Equal(buffer.Length - 4, result);
    }
예제 #21
0
    public void IndexOf_SearchOnlyInsideTheRange_IfStartAndCountAreProvided()
    {
        // Arrange
        const string buffer  = "Hello, World!, Hello people!";
        var          segment = new StringSegment(buffer, 3, buffer.Length - 3);

        // Act
        var result = segment.IndexOf('!', 15, 5);

        // Assert
        Assert.Equal(-1, result);
    }
예제 #22
0
        private StringSegment RemoveGenericContent(StringSegment typeName)
        {
            var genericSeparatorStart = typeName.IndexOf('<');

            if (genericSeparatorStart > 0)
            {
                var ungenericTypeName = typeName.Subsegment(0, genericSeparatorStart);
                return(ungenericTypeName);
            }

            return(typeName);
        }
예제 #23
0
        private StringSegment ReadValue()
        {
            var hasQuoted        = TryReadQuotedValue(out var startIndex, out var length);
            var skipQuotedOffset = hasQuoted ? startIndex + length : 0;
            var separatorIndex   = remainingChars.IndexOf(ParameterSeparatorChar, skipQuotedOffset);

            if (separatorIndex < 0)
            {
                return(remainingChars);
            }

            return(remainingChars.Subsegment(0, separatorIndex));
        }
예제 #24
0
        private string GetHostAndPrefix(StringSegment host, StringSegment path)
        {
            // The request path starts with a leading '/'
            var firstSegmentIndex = path.Length > 0 ? path.IndexOf('/', 1) : -1;

            if (firstSegmentIndex > -1)
            {
                return(host + path.Subsegment(0, firstSegmentIndex).Value);
            }
            else
            {
                return(host + path.Value);
            }
        }
예제 #25
0
        internal static StringSegment ParseWhitespaceArgument(this StringSegment literal, out JsToken argument)
        {
            // replace everything after ':' up till new line and rewrite as single string to method
            var endStringPos    = literal.IndexOf("\n");
            var endStatementPos = literal.IndexOf("}}");

            if (endStringPos == -1 || (endStatementPos != -1 && endStatementPos < endStringPos))
            {
                endStringPos = endStatementPos;
            }

            if (endStringPos == -1)
            {
                throw new SyntaxErrorException($"Whitespace sensitive syntax did not find a '\\n' new line to mark the end of the statement, near {literal.DebugLiteral()}");
            }

            var originalArg   = literal.Subsegment(0, endStringPos).Trim().ToString();
            var rewrittenArgs = originalArg.Replace("{", "{{").Replace("}", "}}");
            var strArg        = new JsLiteral(rewrittenArgs);

            argument = strArg;
            return(literal.Subsegment(endStringPos));
        }
        private static StringSegment ReadToSemicolonOrEnd(StringSegment input, ref int offset)
        {
            var end = input.IndexOf(';', offset);

            if (end < 0)
            {
                // Remainder of the string
                end = input.Length;
            }
            var itemLength = end - offset;
            var result     = input.Subsegment(offset, itemLength);

            offset += itemLength;
            return(result);
        }
예제 #27
0
        // Length is the number of characters required to reach semicolon separating one parameter from another
        // or end of the given segment.
        private static (int Length, StringSegment Value, string Error) GetParameterValue(
            StringSegment segment,
            int initialIndex)
        {
            if (initialIndex >= segment.Length)
            {
                return(Length : 0, StringSegment.Empty, Error : null);
            }

            var firstChar = segment[initialIndex];

            if (firstChar == '\'' || firstChar == '"')
            {
                var quoteIndex = segment.IndexOf(firstChar, initialIndex + 1);
                if (quoteIndex == -1)
                {
                    var error = string.Format(
                        CultureInfo.CurrentCulture,
                        Resources.Command_ContainsUnmatchedQuote,
                        firstChar,
                        initialIndex);
                    return(Length : 0, StringSegment.Empty, error);
                }

                var index = quoteIndex + 1;
                index += GetWhitespaceLength(segment, index);

                if (index < segment.Length && segment[index] != ';')
                {
                    // Found something other than whitespace before the next semicolon or the end of the segment.
                    var error = string.Format(
                        CultureInfo.CurrentCulture,
                        Resources.Command_ValueInvalid,
                        segment[index],
                        index);
                    return(Length : 0, StringSegment.Empty, error);
                }

                var value = segment.Subsegment(initialIndex + 1, length: quoteIndex - initialIndex - 1);
                return(index - initialIndex, value, Error : null);
            }

            var(length, unquotedValue) = GetUnquotedValue(segment, initialIndex);
            return(length, unquotedValue, Error : null);
        }
 private string GetHostAndPrefix(StringSegment host, StringSegment path)
 {
     if (path.get_Length() > 0)
     {
         stackVariable6 = path.IndexOf('/', 1);
     }
     else
     {
         stackVariable6 = -1;
     }
     V_0 = stackVariable6;
     if (V_0 <= -1)
     {
         return(string.Concat(host.ToString(), path.get_Value()));
     }
     stackVariable15 = host.ToString();
     V_1             = path.Subsegment(0, V_0);
     return(string.Concat(stackVariable15, V_1.get_Value()));
 }
예제 #29
0
        public void General()
        {
            var seg = new StringSegment(string.Empty);

            XAssert.AreEqual(0, seg.Length);
            XAssert.IsTrue(seg.IndexOf("AB") < 0);

            seg = new StringSegment("A");
            XAssert.AreEqual(1, seg.Length);
            XAssert.AreEqual('A', seg[0]);
            XAssert.IsTrue(seg.IndexOf("AB") < 0);

            var stable = new StringSegment("AB");

            seg = new StringSegment("AB");
            XAssert.AreEqual(2, seg.Length);
            XAssert.AreEqual('A', seg[0]);
            XAssert.AreEqual('B', seg[1]);
            XAssert.AreEqual(stable, seg);
            XAssert.IsTrue(seg.IndexOf("AB") == 0);

            seg = new StringSegment("XABY", 1, 2);
            XAssert.AreEqual(2, seg.Length);
            XAssert.AreEqual('A', seg[0]);
            XAssert.AreEqual('B', seg[1]);
            XAssert.AreEqual(stable, seg);
            XAssert.IsTrue(seg.IndexOf("AB") == 0);

            seg = new StringSegment("ABY", 0, 2);
            XAssert.AreEqual(2, seg.Length);
            XAssert.AreEqual('A', seg[0]);
            XAssert.AreEqual('B', seg[1]);
            XAssert.AreEqual(stable, seg);
            XAssert.IsTrue(seg.IndexOf("AB") == 0);

            seg = new StringSegment("XAB", 1, 2);
            XAssert.AreEqual(2, seg.Length);
            XAssert.AreEqual('A', seg[0]);
            XAssert.AreEqual('B', seg[1]);
            XAssert.AreEqual(stable, seg);
            XAssert.IsTrue(seg.IndexOf("AB") == 0);
        }
 private bool TryMatchStarMapping(StringSegment host, StringSegment hostOnly, StringSegment path, out ShellSettings result)
 {
     if (this.TryMatchInternal(StringSegment.op_Implicit(string.Concat("*.", host.ToString())), StringSegment.op_Implicit(string.Concat("*.", hostOnly.ToString())), path, out result))
     {
         return(true);
     }
     V_0 = -1;
     do
     {
         stackVariable21 = host.IndexOf('.', V_0 + 1);
         V_0             = stackVariable21;
         if (-1 != stackVariable21)
         {
             continue;
         }
         result = null;
         return(false);
     }while (!this.TryMatchInternal(StringSegment.op_Implicit(string.Concat("*", host.Subsegment(V_0).ToString())), StringSegment.op_Implicit(string.Concat("*", hostOnly.Subsegment(V_0).ToString())), path, out result));
     return(true);
 }
        private static bool TryGetFacetVersion(StringSegment subType, out int version)
        {
            var facetSeparatorIndex = subType.IndexOf('.');

            if (facetSeparatorIndex >= 0)
            {
                var facets = subType.Split(DotSeparator).Reverse();

                foreach (var facet in facets)
                {
                    if (ParsingUtility.TryParseVersion(facet, out version))
                    {
                        return(true);
                    }
                }
            }

            version = 0;
            return(false);
        }
예제 #32
0
        // TODO: optimize ExtractType
        public static Type ExtractType(StringSegment strType)
        {
            if (!strType.HasValue || strType.Length <= 1)
            {
                return(null);
            }

            var hasWhitespace = Json.JsonUtils.WhiteSpaceChars.Contains(strType.GetChar(1));

            if (hasWhitespace)
            {
                var pos = strType.IndexOf('"');
                if (pos >= 0)
                {
                    strType = new StringSegment($"{{{strType.Substring(pos, strType.Length - pos)}");
                }
            }

            var typeAttrInObject = Serializer.TypeAttrInObject;

            if (strType.Length > typeAttrInObject.Length &&
                strType.Substring(0, typeAttrInObject.Length) == typeAttrInObject)
            {
                var propIndex = typeAttrInObject.Length;
                var typeName  = Serializer.UnescapeSafeString(Serializer.EatValue(strType, ref propIndex)).Value;

                var type = JsConfig.TypeFinder(typeName);

                JsWriter.AssertAllowedRuntimeType(type);

                if (type == null)
                {
                    Tracer.Instance.WriteWarning($"Could not find type: {typeName}");
                    return(null);
                }

                return(PclExport.Instance.UseType(type));
            }

            return(null);
        }
예제 #33
0
        public void IndexOf_ComputesIndex_RelativeToTheCurrentSegment()
        {
            // Arrange
            var segment = new StringSegment("Hello, World!", 1, 10);

            // Act
            var result = segment.IndexOf(',');

            // Assert
            Assert.Equal(4, result);
        }
예제 #34
0
        public void IndexOf_SkipsANumberOfCaracters_IfStartIsProvided()
        {
            // Arrange
            const string buffer = "Hello, World!, Hello people!";
            var segment = new StringSegment(buffer, 3, buffer.Length - 3);

            // Act
            var result = segment.IndexOf('!', 15);

            // Assert
            Assert.Equal(buffer.Length - 4, result);
        }
예제 #35
0
 public void IndexOf(string content, string search, int expected)
 {
     var segment = new StringSegment(content);
     Assert.Equal(expected, segment.IndexOf(search));
 }
예제 #36
0
        public void IndexOf_SearchOnlyInsideTheRange_IfStartAndCountAreProvided()
        {
            // Arrange
            const string buffer = "Hello, World!, Hello people!";
            var segment = new StringSegment(buffer, 3, buffer.Length - 3);

            // Act
            var result = segment.IndexOf('!', 15, 5);

            // Assert
            Assert.Equal(-1, result);
        }
예제 #37
0
        public void IndexOf_ReturnsMinusOne_IfElementNotInSegment()
        {
            // Arrange
            var segment = new StringSegment("Hello, World!", 1, 3);

            // Act
            var result = segment.IndexOf(',');

            // Assert
            Assert.Equal(-1, result);
        }
예제 #38
0
        /// <summary>
        /// Handles text entry validation for the updown's text editor.
        /// </summary>
        private static void HandleTextEntryValidation(DependencyObject element, StringSegment text, Int32 offset, Char character, ref Boolean valid, ref RoutedEventData data)
        {
            var numericUpDown = (NumericUpDown)element;
            if (numericUpDown.PART_Input != data.OriginalSource)
                return;

            data.Handled = true;

            // Negative sign must be inserted at the beginning of the text.
            // Negative sign is only allowed if Minimum is less than zero.
            if (character == '-')
            {
                if (offset > 0 || numericUpDown.Minimum >= 0)
                    valid = false;

                return;
            }

            // Nothing can be inserted before the negative sign, if there is one.
            var negativeSignPos = text.IndexOf('-');
            if (negativeSignPos >= 0 && offset < 1)
            {
                valid = false;
                return;
            }
            
            // Decimal separator can only be inserted if we allow decimal points.
            // Decimal separator can only be inserted if it doesn't introduce more than the allowed number of decimals.
            var decimalSeparatorPos = text.IndexOf('.');
            if (character == '.')
            {
                if (decimalSeparatorPos >= 0 || numericUpDown.DecimalPlaces == 0)
                {
                    valid = false;
                    return;
                }

                var decimalsIntroduced = text.Length - offset;
                if (decimalsIntroduced > numericUpDown.DecimalPlaces)
                    valid = false;

                return;
            }

            // Non-digit characters cannot be inserted.
            if (!Char.IsDigit(character))
            {
                valid = false;
                return;
            }

            // Post-decimal digits can only be inserted if we have fewer than DecimalPlaces digits there already.
            var decimalCount = (decimalSeparatorPos < 0) ? 0 : text.Length - (decimalSeparatorPos + 1);
            if (decimalSeparatorPos >= 0 && decimalSeparatorPos < offset && decimalCount >= numericUpDown.DecimalPlaces)
            {
                valid = false;
                return;
            }
        }