Ejemplo n.º 1
0
        /// <summary>
        /// Converts the IRC statement into an IRC string containing all of its bytes,
        /// including the ending CR+LF, and additionally returns whether the string was truncated.
        /// </summary>
        /// <param name="truncated"><c>true</c> if the string was too long and had to be truncated.</param>
        /// <returns>An IRC string.</returns>
        public IrcString ToIrcString(out bool truncated)
        {
            string errorMessage;

            if (!IrcValidation.ValidateStatement(this, out errorMessage))
            {
                throw new InvalidOperationException(errorMessage);
            }

            // Convert to an IrcString first.
            truncated = false; var @string = IrcString.Empty;

            if (Source != null)
            {
                @string += ":" + Source.ToIrcString() + " ";
            }

            @string += Command;

            for (int i = 0; i < Parameters.Count; i++)
            {
                var parameter = Parameters[i];

                @string += " ";
                if (i == Parameters.Count - 1 && parameter.Contains((byte)' '))
                {
                    @string += ":";
                }
                @string += parameter;
            }

            // Now convert to a byte array, truncate if need be, and add CR+LF.
            if (@string.Length > IrcConstants.MaxStatementLength - 2)
            {
                @string   = @string.Substring(0, IrcConstants.MaxStatementLength - 2);
                truncated = true;
            }

            @string += "\r\n";
            return(@string);
        }
Ejemplo n.º 2
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);
        }