You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2005/10/09 15:40:50 UTC
svn commit: r307423 -
/directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/RDNParser.java
Author: elecharny
Date: Sun Oct 9 06:40:46 2005
New Revision: 307423
URL: http://svn.apache.org/viewcvs?rev=307423&view=rev
Log:
The RDNParser has been added to decouple the class which stores RDNs and the parsing
of a RDN.
Added:
directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/RDNParser.java
Added: directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/RDNParser.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/RDNParser.java?rev=307423&view=auto
==============================================================================
--- directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/RDNParser.java (added)
+++ directory/shared/ldap/trunk/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/RDNParser.java Sun Oct 9 06:40:46 2005
@@ -0,0 +1,485 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.asn1new.ldap.codec.primitives;
+
+import javax.naming.InvalidNameException;
+
+import org.apache.asn1new.ldap.codec.utils.DNUtils;
+import org.apache.asn1new.util.StringUtils;
+
+/**
+ * This class parse the name-component part or the following BNF grammar (as of RFC2253, par. 3,
+ * and RFC1779, fig. 1) : <br>
+ * - <name-component> ::= <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues> <br>
+ * - <attributeTypeAndValues> ::= <spaces> '+' <spaces> <attributeType> <spaces> '=' <spaces> <attributeValue> <attributeTypeAndValues> | e <br>
+ * - <attributeType> ::= [a-zA-Z] <keychars> | <oidPrefix> [0-9] <digits> <oids> | [0-9] <digits> <oids> <br>
+ * - <keychars> ::= [a-zA-Z] <keychars> | [0-9] <keychars> | '-' <keychars> | e <br>
+ * - <oidPrefix> ::= 'OID.' | 'oid.' | e <br>
+ * - <oids> ::= '.' [0-9] <digits> <oids> | e <br>
+ * - <attributeValue> ::= <pairs-or-strings> | '#' <hexstring> |'"' <quotechar-or-pairs> '"' <br>
+ * - <pairs-or-strings> ::= '\' <pairchar> <pairs-or-strings> | <stringchar> <pairs-or-strings> | e <br>
+ * - <quotechar-or-pairs> ::= <quotechar> <quotechar-or-pairs> | '\' <pairchar> <quotechar-or-pairs> | e <br>
+ * - <pairchar> ::= ',' | '=' | '+' | '<' | '>' | '#' | ';' | '\' | '"' | [0-9a-fA-F] [0-9a-fA-F] <br>
+ * - <hexstring> ::= [0-9a-fA-F] [0-9a-fA-F] <hexpairs> <br>
+ * - <hexpairs> ::= [0-9a-fA-F] [0-9a-fA-F] <hexpairs> | e <br>
+ * - <digits> ::= [0-9] <digits> | e <br>
+ * - <stringchar> ::= [0x00-0xFF] - [,=+<>#;\"\n\r] <br>
+ * - <quotechar> ::= [0x00-0xFF] - [\"] <br>
+ * - <separator> ::= ',' | ';' <br>
+ * - <spaces> ::= ' ' <spaces> | e <br>
+ *<br>
+ * A RDN is a part of a DN. It can be composed of many types, as in the RDN
+ * following RDN :<br>
+ * ou=value + cn=other value<br>
+ * <br>
+ * In this case, we have to store an 'ou' and a 'cn' in the RDN.<br>
+ * <br>
+ * The types are case insensitive. <br>
+ * Spaces before and after types and values are not stored.<br>
+ * Spaces before and after '+' are not stored.<br>
+ * <br>
+ * Thus, we can consider that the following RDNs are equals :<br>
+ * <br>
+ * 'ou=test 1'<br>
+ * ' ou=test 1'<br>
+ * 'ou =test 1'<br>
+ * 'ou= test 1'<br>
+ * 'ou=test 1 '<br>
+ * ' ou = test 1 '<br>
+ * <br>
+ * So are the following :<br>
+ * <br>
+ * 'ou=test 1+cn=test 2'<br>
+ * 'ou = test 1 + cn = test 2'<br>
+ * ' ou =test 1+ cn =test 2 ' <br>
+ * 'cn = test 2 +ou = test 1'<br>
+ * <br>
+ * but the following are not equal :<br>
+ * 'ou=test 1' <br>
+ * 'ou=test 1'<br>
+ * because we have more than one spaces inside the value.<br>
+ * <br>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class RDNParser
+{
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <oidValue> ::= [0-9] <digits> <oids>
+ * </p>
+ *
+ * @param chars The char array to parse
+ * @param pos The current position in the byte buffer
+ * @return The new position in the char array, or PARSING_ERROR if the rule does not apply to the char array
+ */
+ private static int parseOidValue(char[] chars, int pos)
+ {
+ // <attributType> ::= [0-9] <digits> <oids>
+ if ( StringUtils.isDigit( chars, pos ) == false )
+ {
+ // Nope... An error
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ // Let's process an oid
+ pos++;
+
+ while ( StringUtils.isDigit( chars, pos ) )
+ {
+ pos++;
+ }
+
+ // <oids> ::= '.' [0-9] <digits> <oids> | e
+ if ( StringUtils.isCharASCII( chars, pos, '.' ) == false )
+ {
+ return pos;
+ }
+ else
+ {
+ do
+ {
+ pos++;
+
+ if ( StringUtils.isDigit( chars, pos ) == false )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ pos++;
+
+ while ( StringUtils.isDigit( chars, pos ) )
+ {
+ pos++;
+ }
+ }
+ }
+ while ( StringUtils.isCharASCII( chars, pos, '.' ) );
+
+ return pos;
+ }
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <oidPrefix> ::= 'OID.' | 'oid.' | e
+ * </p>
+ *
+ * @param bytes The buffer to parse
+ * @param pos The current position in the char array
+ * @return The new position in the char array, or PARSING_ERROR if the rule does not apply to the char array
+ */
+ private static int parseOidPrefix( char[] chars, int pos )
+ {
+ if ( ( StringUtils.areEquals( chars, pos, DNUtils.OID_LOWER ) == DNUtils.PARSING_ERROR ) &&
+ ( StringUtils.areEquals( chars, pos, DNUtils.OID_UPPER ) == DNUtils.PARSING_ERROR ) )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ pos += DNUtils.OID_LOWER.length;
+
+ return pos;
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <attributType> ::= [a-zA-Z] <keychars> |
+ * <oidPrefix> [0-9] <digits> <oids> |
+ * [0-9] <digits> <oids>
+ * </p>
+ *
+ * The string *MUST* be an ASCII string, not an unicode string.
+ *
+ * @param chars The char array to parse
+ * @param pos The current position in the char array
+ * @return The new position in the char array, or PARSING_ERROR if the rule does not apply to the char array
+ */
+ private static int parseAttributeType( char[] chars, int pos )
+ {
+ // <attributType> ::= [a-zA-Z] <keychars> | <oidPrefix> [0-9] <digits> <oids> | [0-9] <digits> <oids>
+
+ if ( StringUtils.isAlphaASCII( chars, pos ))
+ {
+ // <attributType> ::= [a-zA-Z] <keychars> | <oidPrefix> [0-9] <digits> <oids>
+
+ // We have got an Alpha char, it may be the begining of an OID ?
+ int oldPos = pos;
+
+ if ( ( pos = parseOidPrefix( chars, oldPos ) ) != DNUtils.PARSING_ERROR )
+ {
+ return parseOidValue(chars, pos);
+ }
+ else
+ {
+ // It's not an oid, it's a String (ASCII)
+ // <attributType> ::= [a-zA-Z] <keychars>
+ // <keychars> ::= [a-zA-Z] <keychar> | [0-9] <keychar> | '-' <keychar> | e
+ pos = oldPos + 1;
+
+ while ( StringUtils.isAlphaDigitMinus( chars, pos ) )
+ {
+ pos++;
+ }
+
+ return pos;
+ }
+ }
+ else
+ {
+
+ // An oid
+ // <attributType> ::= [0-9] <digits> <oids>
+ return parseOidValue(chars, pos);
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <attributeValue> ::= <pairs-or-strings> | '#' <hexstring> |'"' <quotechar-or-pairs> '"' <br>
+ * <pairs-or-strings> ::= '\' <pairchar> <pairs-or-strings> | <stringchar> <pairs-or-strings> | | e <br>
+ * <quotechar-or-pairs> ::= <quotechar> <quotechar-or-pairs> | '\' <pairchar> <quotechar-or-pairs> | e <br>
+ * </p>
+ *
+ * @param chars The char array to parse
+ * @param pos The current position in the char array
+ * @return The new position in the char array, or PARSING_ERROR if the rule does not apply to the char array
+ */
+ private static int parseAttributeValue( char[] chars, int pos )
+ {
+ if ( StringUtils.isCharASCII( chars, pos, '#' ) )
+ {
+ pos++;
+
+ // <attributeValue> ::= '#' <hexstring>
+ if ( ( pos = DNUtils.parseHexString( chars, pos ) ) == DNUtils.PARSING_ERROR )
+ {
+
+ return DNUtils.PARSING_ERROR;
+ }
+
+ return StringUtils.trimLeft( chars, pos );
+ }
+ else if ( StringUtils.isCharASCII( chars, pos, '"' ) )
+ {
+ pos++;
+ int nbBytes = 0;
+
+ // <attributeValue> ::= '"' <quotechar-or-pair> '"'
+ // <quotechar-or-pairs> ::= <quotechar> <quotechar-or-pairs> | '\' <pairchar> <quotechar-or-pairs> | e
+ while ( true )
+ {
+ if ( StringUtils.isCharASCII( chars, pos, '\\' ) )
+ {
+ pos++;
+
+ if ( DNUtils.isPairChar( chars, pos ) )
+ {
+ pos++;
+ }
+ else
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ }
+ else if ( (nbBytes = DNUtils.isQuoteChar( chars, pos ) ) != DNUtils.PARSING_ERROR )
+ {
+ pos += nbBytes;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if ( StringUtils.isCharASCII( chars, pos, '"' ) )
+ {
+ pos++;
+
+ return StringUtils.trimLeft( chars, pos );
+ }
+ else
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ }
+ else
+ {
+ while ( true )
+ {
+ if ( StringUtils.isCharASCII( chars, pos, '\\' ) )
+ {
+ // '\' <pairchar> <pairs-or-strings>
+ pos++;
+
+ if ( DNUtils.isPairChar( chars, pos ) == false )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ pos++;
+ }
+ }
+ else
+ {
+ int nbChars = 0;
+
+ // <stringchar> <pairs-or-strings>
+ if ( ( nbChars = DNUtils.isStringChar( chars, pos )) != DNUtils.PARSING_ERROR )
+ {
+ // A special case : if we have some spaces before the '+' character,
+ // we MUST skip them.
+ if ( StringUtils.isCharASCII( chars, pos, ' ') )
+ {
+ pos = StringUtils.trimLeft( chars, pos );
+
+ if ( ( DNUtils.isStringChar( chars, pos ) == DNUtils.PARSING_ERROR ) &&
+ ( StringUtils.isCharASCII( chars, pos, '\\' ) == false ) )
+ {
+ // Ok, we are done with the stringchar.
+ return pos;
+ }
+ }
+ else
+ {
+ // An unicode char could be more than one byte long
+ pos += nbChars;
+ }
+ }
+ else
+ {
+ return pos;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Parse this rule : <br>
+ * <p>
+ * <nameComponents> ::= <spaces> '+' <spaces> <attributeType> <spaces> '=' <spaces> <attributeValue> <nameComponents> | e
+ * </p>
+ *
+ * @param chars The char buffer to parse
+ * @param pos The current position in the byte buffer
+ * @return The new position in the char buffer, or PARSING_ERROR if the rule does not apply to the char buffer
+ */
+ private static int parseNameComponents( char[] chars, int pos, LdapRDN rdn ) throws InvalidNameException
+ {
+ int newPos = 0;
+ String type = null;
+ String value = null;
+
+ while ( true )
+ {
+ pos = StringUtils.trimLeft( chars, pos );
+
+ if ( StringUtils.isCharASCII( chars, pos, '+' ) )
+ {
+ pos++;
+ }
+ else
+ {
+ // <attributeTypeAndValues> ::= e
+ return pos;
+ }
+
+ pos = StringUtils.trimLeft( chars, pos );
+
+ if ( ( newPos = parseAttributeType( chars, pos ) ) == DNUtils.PARSING_ERROR )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+
+ if ( rdn != null )
+ {
+ type = new String( chars, pos, newPos - pos );
+ }
+
+ pos = StringUtils.trimLeft( chars, newPos );
+
+ if ( StringUtils.isCharASCII( chars, pos, '=' ) )
+ {
+ pos++;
+ }
+ else
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+
+ pos = StringUtils.trimLeft( chars, pos );
+
+ newPos = parseAttributeValue( chars, pos );
+
+ if ( newPos != DNUtils.PARSING_ERROR )
+ {
+ if ( rdn != null )
+ {
+ newPos = StringUtils.trimRight( chars, newPos );
+ value = new String( chars, pos, newPos - pos );
+
+ rdn.addAttributeTypeAndValue( type, value );
+ }
+ }
+
+ pos = newPos;
+ }
+ }
+
+ /**
+ * Parse a NameComponent : <br>
+ * <p>
+ * <name-component> ::= <attributeType> <spaces> '=' <spaces> <attributeValue> <nameComponents>
+ * </p>
+ *
+ * @param bytes The buffer to parse
+ * @param pos The current position in the buffer
+ * @return The new position in the char array, or PARSING_ERROR if the rule does not apply to the char array
+ */
+ public static int parse( char[] chars, int pos, LdapRDN rdn ) throws InvalidNameException
+ {
+ int newPos = 0;
+ String type = null;
+ String value = null;
+
+ pos = StringUtils.trimLeft( chars, pos );
+
+ if ( ( newPos = parseAttributeType( chars, pos ) ) == DNUtils.PARSING_ERROR )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+
+ if ( rdn != null )
+ {
+ type = new String( chars, pos, newPos - pos );
+ }
+
+ pos = StringUtils.trimLeft( chars, newPos );
+
+ if ( StringUtils.isCharASCII( chars, pos, '=' ) == false )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+ else
+ {
+ pos++;
+ }
+
+ pos = StringUtils.trimLeft( chars, pos );
+
+ if ( ( newPos = parseAttributeValue( chars, pos ) ) == DNUtils.PARSING_ERROR )
+ {
+ return DNUtils.PARSING_ERROR;
+ }
+
+ if ( rdn != null )
+ {
+ newPos = StringUtils.trimRight( chars, newPos );
+ value = new String( chars, pos, newPos - pos );
+
+ rdn.addAttributeTypeAndValue( type, value );
+ }
+
+ int end = parseNameComponents( chars, newPos, rdn );
+ return end;
+ }
+
+ /**
+ * Parse a NameComponent : <br>
+ * <p>
+ * <name-component> ::= <attributeType> <spaces> '=' <spaces> <attributeValue> <nameComponents>
+ * </p>
+ *
+ * @param string The buffer to parse
+ * @param rdn The RDN to fill. Beware that if the RDN is not empty, the new AttributeTypeAndValue will be added.
+ */
+ public static void parse( String string, LdapRDN rdn ) throws InvalidNameException
+ {
+ parse( string.toCharArray(), 0, rdn );
+ }
+}