FileDocCategorySizeDatePackage
Lexer.javaAPI DocphoneME MR2 API (J2ME)24351Wed May 02 18:00:42 BST 2007gov.nist.siplite.parser

Lexer

public class Lexer extends LexerCore
Lexer class for the parser.
version
JAIN-SIP-1.1 This code is in the public domain.

Fields Summary
Constructors Summary
public Lexer(String lexerName, String buffer)
Constructor with initial lecername and buffer to process.

param
lexerName lexer for processing
param
buffer data to be parsed

        super(lexerName, buffer);
        this.selectLexer(lexerName);
    
Methods Summary
public static java.lang.StringgetHeaderName(java.lang.String line)
Gets the header name of the line.

param
line the text to be parsed
return
the header name

        if (line == null) {
            return null;
        }
        String headerName = null;
        try {
            int begin = line.indexOf(":");
            headerName = null;
            if (begin >= 1) {
                headerName = line.substring(0, begin);
            }
        } catch (IndexOutOfBoundsException e) {
            return null;
        }
        return headerName;
    
public static java.lang.StringgetHeaderValue(java.lang.String line)
Gets the header value of the line.

param
line the text to be parsed
return
the header value

        if (line == null) {
            return null;
        }
        String headerValue = null;
        try {
            int begin = line.indexOf(":");
            headerValue = line.substring(begin + 1);
        } catch (IndexOutOfBoundsException e) {
            return null;
        }
        return headerValue;
    
public static booleanisValidDisplayName(java.lang.String displayName)
Checks if the given string is valid display name.

param
displayName the text to be parsed
return
true if the string is a valid display name, false otherwise

        // RFC 3261 p.228
        // display-name   =  *(token LWS)/ quoted-string
        // p.220
        // LWS  =  [*WSP CRLF] 1*WSP ; linear whitespace
        // UTF8-NONASCII   =  %xC0-DF 1UTF8-CONT
        //                 /  %xE0-EF 2UTF8-CONT
        //                 /  %xF0-F7 3UTF8-CONT
        //                 /  %xF8-Fb 4UTF8-CONT
        //                 /  %xFC-FD 5UTF8-CONT
        // UTF8-CONT       =  %x80-BF
        // p.221
        // token       =  1*(alphanum / "-" / "." / "!" / "%" / "*"
        //                      / "_" / "+" / "`" / "'" / "~" )
        // p.222
        // quoted-string  =  SWS DQUOTE *(qdtext / quoted-pair ) DQUOTE
        // qdtext         =  LWS / %x21 / %x23-5B / %x5D-7E
        //                   / UTF8-NONASCII
        // quoted-pair  =  "\" (%x00-09 / %x0B-0C
        //                 / %x0E-7F)
        if (null == displayName) {
            return false;
        }
        boolean quoted = false;
        displayName = StringTokenizer.convertNewLines(displayName);
        displayName = displayName.trim();
        int i = 0;
        if ('"" == displayName.charAt(0)) {
            quoted = true;
            i++;
        }
        while (i < displayName.length()) {
            char ch = displayName.charAt(i);
            if (!quoted) {
                if (!isValidChar(ch) && ch != ' " && ch != 0x09) {
                    return false;
                }
            } else {
                // left UTF8-NONASCII proper converting on i18n subsystem
                if (ch < 0x20 ||
                    (ch == '"" && i != displayName.length() - 1) ||
                    (ch > 0x7E && ch < 0xC0)) {
                    return false;
                }
                if (ch == '\\") {
                    if (isQuotedPair(displayName, i)) {
                        i++;
                    } else {
                        return false;
                    }
                }
            }
            i++;
        }
        return true;
    
public static booleanisValidHeaderValue(java.lang.String value)
Checks if the given string is a valid header value.

param
value the text to be parsed
return
true if the string is a valid value, false otherwise

        return isValidValue(value, false);
    
public static booleanisValidHostname(java.lang.String address)
Checks if the given string is valid hostname BNF(RFC3261 p.222) hostname = *( domainlabel "." ) toplabel [ "." ] domainlabel = alphanum / alphanum *( alphanum / "-" ) alphanum toplabel = ALPHA / ALPHA *( alphanum / "-" ) alphanum

param
address the text to be parsed
return
true if the string is a valid hostname, false otherwise

        if (address == null || 0 == address.length()) {
            return false;
        }
        int pCount = 0;
        boolean isHostname = false;
        for (int i = 0; i < address.length(); i++) {
            char c = address.charAt(i);
            if (c == '." ||
                isAlpha(c) ||
                c == '-" ||
                isDigit(c)) {
                continue;
            } else {
                return false;
            }
        }

        int lastPointPos = address.lastIndexOf('.");
        String toplabel;
        if (lastPointPos == address.length() - 1) {
            if (0 == lastPointPos) {
                // address is "."
                return false;
            }
            // get the previous point position
            // or -1
            lastPointPos  = address.lastIndexOf('.", lastPointPos - 1);
        }
        // if there is no previous point toplabel equals whole string
        toplabel = address.substring(lastPointPos + 1);
        if (!isAlpha(toplabel.charAt(0))) {
            return false;
        }
        return true;
    
public static booleanisValidIpv4Address(java.lang.String address)
Checks if the given string is valid IPv4Address. BNF (RFC3261, p. 223, 232): IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT

param
address the text to be parsed
return
true if the string is a valid IPv4Address, false otherwise

        char ch;
        if (address == null || 0 == address.length()) {
            return false;
        }
        int  len = address.length();
        int  pointCount = 0, digitCount = 0;
        int totalPoint = 0;
        for (int i = 0; i < len; i++) {
            ch = address.charAt(i);

            if (ch == '.") {
                if (i == len - 1) {
                    return false;
                }
                pointCount++;
                totalPoint++;
                digitCount = 0;
                continue;
            }

            if (digitCount > 3 || pointCount > 1) {
                return false;
            }

            pointCount = 0;

            if (!isDigit(ch)) {
                return false;
            } else {
                digitCount++;
            }
        } // end for

        if (totalPoint != 3) {
            return false;
        }
        return true;
    
public static booleanisValidIpv6Address(java.lang.String address)
Checks if the given string is valid IPv6Address. BNF (RFC3261, p. 223, 232): IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT IPv6address = hexpart [ ":" IPv4address ] hexpart = hexseq / hexseq "::" [ hexseq ] / "::" [ hexseq ] hexseq = hex4 *( ":" hex4) hex4 = 1*4HEXDIG

param
address the text to be parsed
return
true if the string is a valid IPv6Address, false otherwise

        char ch;
        if (address == null || 0 == address.length()) {
            return false;
        }
        int  len = address.length();
        int  colonCount = 0, hexdigCount = 0;

        for (int i = 0; i < len; i++) {
            ch = address.charAt(i);

            if (ch == ':") {
                colonCount++;
                continue;
            }

            if (ch == '.") {
                int colonPos = address.lastIndexOf(':", i);
                if (colonPos > 0) {
                    return isValidIpv4Address(address.substring(colonPos + 1));
                } else {
                    return false;
                }
            }

            if (hexdigCount > 4 || colonCount > 2) {
                return false;
            }

            colonCount = 0;

            // Check for IP v6:
            // hex digit?
            if (isHexDigit(ch)) {
                hexdigCount++;
                continue;
            }

            if (hexdigCount > 0) {
                // Hex part must be followed by ":", "::" or by the end
                // of address. '.' means IP v6 address.
                if ((i < len-1) && (ch != ':") && (ch != '.")) {
                    return false;
                }
            }

            hexdigCount = 0;

            // Check for IP v4.
            if (!(Character.isDigit(ch) || (ch == '."))) {
                return false;
            }
        } // end for

        // report about wrong address "::::::"
        //  and "::44444
        if (hexdigCount > 4 || colonCount > 2) {
            return false;
        }

        return true;
    
public static booleanisValidName(java.lang.String name)
Checks if the given string is a valid method/header/parameter name.

param
name the text to be parsed
return
true if the string is a valid name, false otherwise

        // RFC 3261, p.p. 225, 221:
        //
        // Method = INVITEm / ACKm / OPTIONSm / BYEm
        //          / CANCELm / REGISTERm
        //          / extension-method
        // extension-method = token
        // token = 1*(alphanum / "-" / "." / "!" / "%" / "*"
        //          / "_" / "+" / "`" / "'" / "~" )
        // alphanum = ALPHA / DIGIT
        //
        // p.227:
        // generic-param  =  token [ EQUAL gen-value ]
        //
        // p. 232:
        // extension-header = header-name HCOLON header-value
        // header-name      = token
        //
        if (name == null || name.length() == 0) {
            return false;
        }

        for (int i = 0; i < name.length(); i++) {
            char ch = name.charAt(i);

            if (!isValidChar(ch)) {
                return false;
            }
        }

        return true;
    
public static booleanisValidParameterValue(java.lang.String value)
Checks if the given string is a valid parameter value.

param
value the text to be parsed
return
true if the string is a valid value, false otherwise

        return isValidValue(value, true);
    
public static booleanisValidScheme(java.lang.String scheme)
Checks if the given string is valid scheme name.

param
scheme the text to be parsed
return
true if the string is a valid scheme name, false otherwise

        // RFC3261 p.224
        // scheme         =  ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
        if (null == scheme || 
            0 ==  scheme.length() || 
            !isAlpha(scheme.charAt(0))) {
            return false;
        }
        char ch;
        for (int i = 1; i < scheme.length(); i++) {
            ch = scheme.charAt(i);
            if (!Character.isDigit(ch)   &&
                !isAlpha(ch)             &&
                ch != '+"                &&
                ch != '-"                &&
                ch != '.") {
                return false;
            }
        }
        return true;
    
public static booleanisValidUserName(java.lang.String name)
Checks if the given string is valid as user part of a SIP(S)-URI.

param
name the text to be parsed
return
true if the string is a valid name, false otherwise

        // RFC3261 p.222
        // user             =  1*( unreserved / escaped / user-unreserved )
        // user-unreserved  =  "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
        // p.219
        // alphanum  =  ALPHA / DIGIT
        // p.220
        // unreserved  =  alphanum / mark
        // mark        =  "-" / "_" / "." / "!" / "~" / "*" / "'" / "(" / ")"
        // escaped     =  "%" HEXDIG HEXDIG
        //

        if (name == null) {
            return true;
        }
        if (name.length() == 0) {
            // Zerolength case causes wrong AT symbol appending,
            // the name has to be null or nonempty
            return false;
        }

        for (int i = 0; i < name.length(); i++) {
            char ch = name.charAt(i);

            if (URLParser.isUnreserved(ch) ||
                isEscaped(name, i) ||
                URLParser.isUserUnreserved(ch)) {
                continue;
            } else {
                return false;
            }
        }

        return true;
    
protected static booleanisValidValue(java.lang.String value, boolean isParameter)
Checks if the given string is a valid header/parameter value.

param
value the text to be parsed
param
isParameter true if the value to be checked is a parameter value, false otherwise
return
true if the string is a valid value, false otherwise


        // System.out.println(">>> value = " + value);

        if (value == null) {
            value = ""; // null is a valid parameter value
        }

        // Check that the value doesn't contain unescaped semicolons
        boolean isEscaped = false;
        boolean isQuoteOn = false;
        boolean isBracketOn = false;

        for (int i = 0; i < value.length(); i++) {
            char ch = value.charAt(i);

            // Ignore escaped (with preceding '\') characters
            if (isEscaped) {
                isEscaped = false;
                continue;
            }

            // Ignore characters that are a part of the string (inside qoutes)
            if (ch == '"") {
                isQuoteOn = !isQuoteOn;
                continue;
            }

            if (isQuoteOn) {
                continue;
            }

            if (ch == '\\") {
                isEscaped = true;
                continue;
            }

            // Ignore characters inside "<" and ">"
            if (isBracketOn) {
                if (ch == '>") {
                    isBracketOn = false;
                    continue;
                }
            } else {
                if (ch == '<") {
                    isBracketOn = true;
                    continue;
                }

                if (isParameter) {
                    // Restrictions on a parameter's value are more strict
                    // when header's value may be almost any text.
                    if (!isValidChar(ch)) {
                        return false;
                    }
                } else {
                    if (ch == ';") {
                        return false;
                    }
                }
            }
        }

        // System.out.println(">>> VALID");
        return true;
    
public voidselectLexer(java.lang.String lexerName)
Selects the lexer to used based on the current parsing context.

param
lexerName the lexer engine

        currentLexer = (Hashtable) lexerTables.get(lexerName);
        this.currentLexerName = lexerName;

        /*
         * 'SIP'/'SIPS' keywords are added to the keyword list
         * for all lexers except "command_keywordLexer" and
         * "method_keywordLexer" according to the RFC 3261:
         *
         * For "status_lineLexer" (p. 225):
         *
         *     Response  =  Status-Line
         *                  *( message-header )
         *                  CRLF
         *                  [ message-body ]
         *     Status-Line  =  SIP-Version SP Status-Code SP Reason-Phrase CRLF
         *
         * For "request_lineLexer" (p. 223):
         *
         *     Request  =  Request-Line
         *                 *( message-header )
         *                 CRLF
         *                 [ message-body ]
         * Request-Line  =  Method SP Request-URI SP SIP-Version CRLF
         *
         * For "sip_urlLexer" (p. 222):
         *
         *     SIP-URI  =  "sip:" [ userinfo ] hostport
         *                 uri-parameters [ headers ]
         */

        if (currentLexer == null) {
            addLexer(lexerName);
            if (lexerName.equals("method_keywordLexer")) {
                addKeyword(Request.REGISTER.toUpperCase(),
                           TokenTypes.REGISTER);
                addKeyword(Request.ACK.toUpperCase(),
                           TokenTypes.ACK);
                addKeyword(Request.OPTIONS.toUpperCase(),
                           TokenTypes.OPTIONS);
                addKeyword(Request.BYE.toUpperCase(),
                           TokenTypes.BYE);
                addKeyword(Request.INVITE.toUpperCase(),
                           TokenTypes.INVITE);
                addKeyword(Request.SUBSCRIBE.toUpperCase(),
                           TokenTypes.SUBSCRIBE);
                addKeyword(Request.NOTIFY.toUpperCase(),
                           TokenTypes.NOTIFY);
                addKeyword(Request.MESSAGE.toUpperCase(),
                           TokenTypes.MESSAGE);
                addKeyword(Request.PUBLISH.toUpperCase(),
                           TokenTypes.PUBLISH);
                addKeyword(Request.REFER.toUpperCase(),
                           TokenTypes.REFER);
                addKeyword(Request.INFO.toUpperCase(),
                           TokenTypes.INFO);
                addKeyword(Request.UPDATE.toUpperCase(),
                           TokenTypes.UPDATE);
            } else if (lexerName.equals("command_keywordLexer")) {
                addKeyword(Header.FROM.toUpperCase(),
                           TokenTypes.FROM); // 1
                addKeyword(Header.TO.toUpperCase(),
                           TokenTypes.TO); // 2
                addKeyword(Header.VIA.toUpperCase(),
                           TokenTypes.VIA); // 3
                addKeyword(Header.ROUTE.toUpperCase(),
                           TokenTypes.ROUTE); // 4
                addKeyword(Header.MAX_FORWARDS.toUpperCase(),
                           TokenTypes.MAX_FORWARDS); // 5
                addKeyword(Header.AUTHORIZATION.toUpperCase(),
                           TokenTypes.AUTHORIZATION); // 6
                addKeyword(Header.PROXY_AUTHORIZATION.toUpperCase(),
                           TokenTypes.PROXY_AUTHORIZATION); // 7
                addKeyword(Header.DATE.toUpperCase(),
                           TokenTypes.DATE); // 8
                addKeyword(Header.CONTENT_ENCODING.toUpperCase(),
                           TokenTypes.CONTENT_ENCODING); // 9
                addKeyword(Header.CONTENT_LENGTH.toUpperCase(),
                           TokenTypes.CONTENT_LENGTH); // 10
                addKeyword(Header.CONTENT_TYPE.toUpperCase(),
                           TokenTypes.CONTENT_TYPE); // 11
                addKeyword(Header.CONTACT.toUpperCase(),
                           TokenTypes.CONTACT); // 12
                addKeyword(Header.CALL_ID.toUpperCase(),
                           TokenTypes.CALL_ID); // 13
                addKeyword(Header.EXPIRES.toUpperCase(),
                           TokenTypes.EXPIRES); // 14
                addKeyword(Header.RECORD_ROUTE.toUpperCase(),
                           TokenTypes.RECORD_ROUTE); // 15
                addKeyword(Header.CSEQ.toUpperCase(),
                           TokenTypes.CSEQ); // 16
                addKeyword(Header.WWW_AUTHENTICATE.toUpperCase(),
                           TokenTypes.WWW_AUTHENTICATE); // 17
                addKeyword(Header.PROXY_AUTHENTICATE.toUpperCase(),
                           TokenTypes.PROXY_AUTHENTICATE); // 18
                addKeyword(Header.EVENT.toUpperCase(),
                           TokenTypes.EVENT); // 19
                addKeyword(Header.SUBJECT.toUpperCase(),
                           TokenTypes.SUBJECT); // 20
                addKeyword(Header.SUPPORTED.toUpperCase(),
                           TokenTypes.SUPPORTED); // 21
                addKeyword(Header.ALLOW_EVENTS.toUpperCase(),
                           TokenTypes.ALLOW_EVENTS); // 22
                addKeyword(Header.ACCEPT_CONTACT.toUpperCase(),
                           TokenTypes.ACCEPT_CONTACT); // 23
                //  And now the dreaded short forms....
                addKeyword(SIPConstants.TOKEN_LETTER_C.toUpperCase(),
                           TokenTypes.CONTENT_TYPE);
                //  CR fix 
                addKeyword(SIPConstants.TOKEN_LETTER_F.toUpperCase(),
                           TokenTypes.FROM);
                addKeyword(SIPConstants.TOKEN_LETTER_I.toUpperCase(),
                           TokenTypes.CALL_ID);
                addKeyword(SIPConstants.TOKEN_LETTER_M.toUpperCase(),
                           TokenTypes.CONTACT);
                addKeyword(SIPConstants.TOKEN_LETTER_E.toUpperCase(),
                           TokenTypes.CONTENT_ENCODING);
                addKeyword(SIPConstants.TOKEN_LETTER_L.toUpperCase(),
                           TokenTypes.CONTENT_LENGTH);
                addKeyword(SIPConstants.TOKEN_LETTER_C.toUpperCase(),
                           TokenTypes.CONTENT_TYPE);
                addKeyword(SIPConstants.TOKEN_LETTER_T.toUpperCase(),
                           TokenTypes.TO);
                addKeyword(SIPConstants.TOKEN_LETTER_V.toUpperCase(),
                           TokenTypes.VIA);
                addKeyword(SIPConstants.TOKEN_LETTER_O.toUpperCase(),
                           TokenTypes.EVENT);
                addKeyword(SIPConstants.TOKEN_LETTER_S.toUpperCase(),
                           TokenTypes.SUBJECT);
                addKeyword(SIPConstants.TOKEN_LETTER_K.toUpperCase(),
                           TokenTypes.SUPPORTED);
                addKeyword(SIPConstants.TOKEN_LETTER_U.toUpperCase(),
                           TokenTypes.ALLOW_EVENTS);
                addKeyword(SIPConstants.TOKEN_LETTER_A.toUpperCase(),
                           TokenTypes.ACCEPT_CONTACT);
            } else if (lexerName.equals("status_lineLexer") ||
                       lexerName.equals("request_lineLexer")) {
                addKeyword(SIPConstants.SCHEME_SIP.toUpperCase(),
                           TokenTypes.SIP);
                addKeyword(SIPConstants.SCHEME_SIPS.toUpperCase(),
                           TokenTypes.SIPS);
            } else if (lexerName.equals("sip_urlLexer")) {
                addKeyword(SIPConstants.SCHEME_TEL.toUpperCase(),
                           TokenTypes.TEL);
                addKeyword(SIPConstants.SCHEME_SIP.toUpperCase(),
                           TokenTypes.SIP);
                addKeyword(SIPConstants.SCHEME_SIPS.toUpperCase(),
                           TokenTypes.SIPS);
            }

        }