示例#1
0
        /// <summary>
        /// Tries to read a buffer and parse out an IRC statement.
        /// </summary>
        /// <param name="buffer">The buffer to read from.</param>
        /// <param name="offset">The offset to begin reading. The parser may advance this, even if parsing fails.</param>
        /// <param name="count">The maximum number of bytes to read.</param>
        /// <param name="statement">The statement, if parsing succeeds, or <c>null</c>.</param>
        /// <returns><c>true</c> if parsing succeeded.</returns>
        public static bool TryParse(byte[] buffer, ref int offset, int count,
                                    out IrcStatement statement)
        {
            IrcStatementParseResult parseResult;

            return(TryParse(buffer, ref offset, count, out statement, out parseResult));
        }
示例#2
0
        bool TryReceiveFromBuffer(out IrcStatement statement, out IrcStatementParseResult parseResult)
        {
            int  offset       = 0;
            bool gotStatement = IrcStatement.TryParse(_buffer, ref offset, _count, out statement, out parseResult);

            Debug.Assert(offset <= _count);

            if (offset != 0)
            {
                Array.Copy(_buffer, offset, _buffer, 0, _count - offset); _count -= offset;
            }
            return(gotStatement);
        }
示例#3
0
        internal static bool ValidateStatement(IrcStatement statement, out string errorMessage)
        {
            errorMessage = null;

            if (statement.Source != null && !ValidateIdentity(statement.Source, out errorMessage))
            {
                return(false);
            }

            if (statement.Command == null)
            {
                errorMessage = "Command is not set."; return(false);
            }

            if (statement.Command.Length == 3 && statement.Command.All(x => x >= (byte)'0' && x <= (byte)'9'))
            {
                // Command is a number.
            }
            else if (statement.Command.Length > 0 && statement.Command.All(x => x >= (byte)'A' && x <= (byte)'Z'))
            {
                // Command is letters.
            }
            else
            {
                errorMessage = "Command is invalid."; return(false);
            }

            if (statement.Parameters.Count > IrcConstants.MaxParameters)
            {
                errorMessage = string.Format("IRC only allows up to {0} parameters.", IrcConstants.MaxParameters);
                return(false);
            }

            for (int i = 0; i < statement.Parameters.Count; i++)
            {
                var parameter = statement.Parameters[i];
                if (parameter == null)
                {
                    errorMessage = "No parameters may be null."; return(false);
                }
                if (!ValidateParameter(parameter, i == statement.Parameters.Count - 1, out errorMessage))
                {
                    return(false);
                }
            }

            return(true);
        }
示例#4
0
        /// <summary>
        /// Tries to receive an IRC statement.
        ///
        /// A blocking read is used.
        /// If you have a timeout set, <paramref name="parseResult"/> may be <see cref="IrcStatementParseResult.TimedOut"/>.
        /// </summary>
        /// <param name="statement">The statement.</param>
        /// <param name="parseResult">The parse result.</param>
        /// <returns><c>true</c> if a complete IRC statement was received.</returns>
        public bool TryReceive(out IrcStatement statement, out IrcStatementParseResult parseResult)
        {
            if (TryReceiveFromBuffer(out statement, out parseResult))
            {
                return(true);
            }

            var receiveResult = TryReceiveFromStream();

            if (receiveResult != IrcStatementParseResult.OK)
            {
                statement = null; parseResult = receiveResult;
                return(false);
            }

            return(TryReceiveFromBuffer(out statement, out parseResult));
        }
示例#5
0
        /// <summary>
        /// Tries to read a buffer and parse out an IRC statement.
        /// Additionally, on failure, the reason for failure is returned.
        /// </summary>
        /// <param name="buffer">The buffer to read from.</param>
        /// <param name="offset">The offset to begin reading. The parser may advance this, even if parsing fails.</param>
        /// <param name="count">The maximum number of bytes to read.</param>
        /// <param name="statement">The statement, if parsing succeeds, or <c>null</c>.</param>
        /// <param name="parseResult">The result of parsing. On failure, this is the reason for the failure.</param>
        /// <returns><c>true</c> if parsing succeeded.</returns>
        public static bool TryParse(byte[] buffer, ref int offset, int count,
                                    out IrcStatement statement, out IrcStatementParseResult parseResult)
        {
            Throw.If.Null(buffer, "buffer");
            string errorMessage = null;

            IrcString[] parts;
            statement = null; parseResult = IrcStatementParseResult.NothingToParse;

            // First, skip all initial CR/LF.
            SkipCrlf(buffer, ref offset, ref count);

            // See if we've got a CR or LF anywhere.
            int crlfIndex = IrcString.IndexOf(buffer, @byte => @byte == 13 || @byte == 10, offset, count);

            if (crlfIndex == -1)
            {
                if (count >= IrcConstants.MaxStatementLength)
                {
                    parseResult = IrcStatementParseResult.StatementTooLong;
                }

                return(false);
            }

            // OK, let's get our string.
            var @string = new IrcString(buffer, offset, crlfIndex - offset);

#if DEBUG
            var debugString = @string;
#endif
            offset += @string.Length + 1; count -= @string.Length + 1;
            SkipCrlf(buffer, ref offset, ref count);

            if (crlfIndex >= IrcConstants.MaxStatementLength)
            {
                parseResult = IrcStatementParseResult.StatementTooLong; return(false);
            }

            // Do we have a prefix?
            statement = new IrcStatement();

            if (@string.Length >= 1 && @string[0] == (byte)':')
            {
                parts = @string.Split((byte)' ', 2);

                var sourceString = parts[0].Substring(1); IrcIdentity source;
                if (!IrcIdentity.TryParse(sourceString, out source))
                {
                    goto invalid;
                }
                statement.Source = source;

                @string = parts.Length >= 2 ? parts[1] : IrcString.Empty;
            }

            // Now get the command.
            parts             = @string.Split((byte)' ', 2);
            statement.Command = parts[0];
            @string           = parts.Length >= 2 ? parts[1] : IrcString.Empty;

            // Parameters, now...
            while (@string.Length > 0)
            {
                if (@string[0] == (byte)':')
                {
                    statement.Parameters.Add(@string.Substring(1));
                    break;
                }
                else
                {
                    parts = @string.Split((byte)' ', 2);
                    statement.Parameters.Add(parts[0]);
                    if (parts.Length == 1)
                    {
                        break;
                    }
                    @string = parts[1];
                }
            }

            // We're done. If everything's kosher, we'll return true.
            if (!IrcValidation.ValidateStatement(statement, out errorMessage))
            {
                goto invalid;
            }

            parseResult = IrcStatementParseResult.OK;
            return(true);

invalid:
#if DEBUG
            Console.WriteLine("Invalid statement '{0}' (error '{1}').", debugString, errorMessage);
#endif
            statement = null; parseResult = IrcStatementParseResult.InvalidStatement;
            return(false);
        }