directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From elecha...@apache.org
Subject svn commit: r234264 [7/11] - in /directory/shared/ldap/branches/new-codec-integration/apache2-provider/src: ./ java/ java/main/ java/main/org/ java/main/org/apache/ java/main/org/apache/asn1new/ java/main/org/apache/asn1new/ldap/ java/main/org/apache/a...
Date Sun, 21 Aug 2005 16:54:00 GMT
Added: directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/grammar/SearchResultReferenceGrammar.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/grammar/SearchResultReferenceGrammar.java?rev=234264&view=auto
==============================================================================
--- directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/grammar/SearchResultReferenceGrammar.java (added)
+++ directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/grammar/SearchResultReferenceGrammar.java Sun Aug 21 09:53:27 2005
@@ -0,0 +1,158 @@
+/*
+ *   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.grammar;
+
+import org.apache.asn1new.DecoderException;
+import org.apache.asn1new.ber.containers.IAsn1Container;
+import org.apache.asn1new.ber.grammar.AbstractGrammar;
+import org.apache.asn1new.ber.grammar.GrammarAction;
+import org.apache.asn1new.ber.grammar.GrammarTransition;
+import org.apache.asn1new.ber.grammar.IGrammar;
+import org.apache.asn1new.ber.tlv.TLV;
+import org.apache.asn1new.ber.tlv.UniversalTag;
+import org.apache.asn1new.ldap.codec.LdapConstants;
+import org.apache.asn1new.ldap.codec.LdapMessageContainer;
+import org.apache.asn1new.ldap.codec.primitives.LdapURL;
+import org.apache.asn1new.ldap.pojo.LdapMessage;
+import org.apache.asn1new.ldap.pojo.SearchResultReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the SearchResultReference LDAP message. All the actions are declared in this
+ * class. As it is a singleton, these declaration are only done once.
+ * 
+ * If an action is to be added or modified, this is where the work is to be done !
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SearchResultReferenceGrammar extends AbstractGrammar implements IGrammar
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** The logger */
+    private static final Logger log = LoggerFactory.getLogger( SearchResultReferenceGrammar.class );
+
+    /** Logging speed up  */
+    private static final boolean DEBUG = log.isDebugEnabled();
+
+    /** The instance of grammar. SearchResultReferenceGrammar is a singleton */
+    private static IGrammar instance = new SearchResultReferenceGrammar();
+
+    //~ Constructors -------------------------------------------------------------------------------
+
+    /**
+     * Creates a new SearchResultReferenceGrammar object.
+     */
+    private SearchResultReferenceGrammar()
+    {
+        name       = SearchResultReferenceGrammar.class.getName();
+        statesEnum = LdapStatesEnum.getInstance();
+
+        // Initialisation of the transitions table
+        super.transitions = new GrammarTransition[LdapStatesEnum.LAST_SEARCH_RESULT_REFERENCE_STATE_STATE][256];
+
+        //============================================================================================
+        // SearchResultReference Message
+        //============================================================================================
+        // SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL (Tag)
+        // Nothing to do
+        super.transitions[LdapStatesEnum.SEARCH_RESULT_REFERENCE_TAG][LdapConstants.SEARCH_RESULT_REFERENCE_TAG] = new GrammarTransition(
+                LdapStatesEnum.SEARCH_RESULT_REFERENCE_TAG, LdapStatesEnum.SEARCH_RESULT_REFERENCE_VALUE, null );
+
+        // SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL (Value)
+        // We won't have a value. The next Tag will be the LDAPUrl Tag (0x04)
+        super.transitions[LdapStatesEnum.SEARCH_RESULT_REFERENCE_VALUE][LdapConstants.SEARCH_RESULT_REFERENCE_TAG] = new GrammarTransition(
+                LdapStatesEnum.SEARCH_RESULT_REFERENCE_VALUE, LdapStatesEnum.SEARCH_RESULT_REFERENCE_LDAP_URL_TAG,
+                new GrammarAction( "Init SearchResultReference" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        LdapMessageContainer ldapMessageContainer = ( LdapMessageContainer )
+                            container;
+                        LdapMessage      ldapMessage          =
+                            ldapMessageContainer.getLdapMessage();
+
+                        // Now, we can allocate the BindRequest Object
+                        SearchResultReference searchResultReference = new SearchResultReference();
+
+                        // As this is a new Constructed object, we have to init its length
+                        searchResultReference.setParent( ldapMessage );
+
+                        // And we associate it to the ldapMessage Object
+                        ldapMessage.setProtocolOP( searchResultReference );
+                    }
+                }  );
+
+        // LDAPURL (Tag)
+        super.transitions[LdapStatesEnum.SEARCH_RESULT_REFERENCE_LDAP_URL_TAG][UniversalTag.OCTET_STRING_TAG] = new GrammarTransition(
+                LdapStatesEnum.SEARCH_RESULT_REFERENCE_LDAP_URL_TAG, LdapStatesEnum.SEARCH_RESULT_REFERENCE_LDAP_URL_VALUE,
+                null );
+
+        // LDAPURL loop (Tag)
+        super.transitions[LdapStatesEnum.SEARCH_RESULT_REFERENCE_LOOP_OR_END_TAG][UniversalTag.OCTET_STRING_TAG] = new GrammarTransition(
+                LdapStatesEnum.SEARCH_RESULT_REFERENCE_LOOP_OR_END_TAG, LdapStatesEnum.SEARCH_RESULT_REFERENCE_LDAP_URL_VALUE,
+                null );
+
+        // LDAPURL (Value)
+        super.transitions[LdapStatesEnum.SEARCH_RESULT_REFERENCE_LDAP_URL_VALUE][UniversalTag.OCTET_STRING_TAG] = new GrammarTransition(
+                LdapStatesEnum.SEARCH_RESULT_REFERENCE_LDAP_URL_VALUE,
+                LdapStatesEnum.SEARCH_RESULT_REFERENCE_LOOP_OR_END_TAG, 
+                new GrammarAction( "Store ldapUrl value" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        LdapMessageContainer ldapMessageContainer = ( LdapMessageContainer )
+                            container;
+
+                        SearchResultReference     searchResultReference =
+                            ldapMessageContainer.getLdapMessage().getSearchResultReference();
+
+                        // Get the Value and store it in the BindRequest
+                        TLV tlv = ldapMessageContainer.getCurrentTLV();
+
+                        // We have to handle the special case of a 0 length server sasl credentials
+                        if ( tlv.getLength().getLength() == 0 )
+                        {
+                            searchResultReference.addSearchResultReference( LdapURL.EMPTY_STRING );
+                        }
+                        else
+                        {
+                            searchResultReference.addSearchResultReference( new LdapURL( tlv.getValue().getData() ) );
+                        }
+                        
+                        return;
+                    }
+                } );
+
+    }
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Get the instance of this grammar
+     *
+     * @return An instance on the LdapMessage Grammar
+     */
+    public static IGrammar getInstance()
+    {
+        return instance;
+    }
+}

Added: directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/grammar/UnBindRequestGrammar.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/grammar/UnBindRequestGrammar.java?rev=234264&view=auto
==============================================================================
--- directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/grammar/UnBindRequestGrammar.java (added)
+++ directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/grammar/UnBindRequestGrammar.java Sun Aug 21 09:53:27 2005
@@ -0,0 +1,126 @@
+/*
+ *   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.grammar;
+
+import org.apache.asn1new.DecoderException;
+import org.apache.asn1new.ber.containers.IAsn1Container;
+import org.apache.asn1new.ber.grammar.AbstractGrammar;
+import org.apache.asn1new.ber.grammar.GrammarAction;
+import org.apache.asn1new.ber.grammar.GrammarTransition;
+import org.apache.asn1new.ber.grammar.IGrammar;
+import org.apache.asn1new.ber.tlv.TLV;
+import org.apache.asn1new.ldap.codec.LdapConstants;
+import org.apache.asn1new.ldap.codec.LdapMessageContainer;
+import org.apache.asn1new.ldap.pojo.LdapMessage;
+import org.apache.asn1new.ldap.pojo.UnBindRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * This class implements the UnBindRequest LDAP message. All the actions are declared in this
+ * class. As it is a singleton, these declaration are only done once.
+ * 
+ * If an action is to be added or modified, this is where the work is to be done !
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class UnBindRequestGrammar extends AbstractGrammar implements IGrammar
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** The logger */
+    private static final Logger log = LoggerFactory.getLogger( UnBindRequestGrammar.class );
+
+    /** Logging speed up  */
+    private static final boolean DEBUG = log.isDebugEnabled();
+
+    /** The instance of grammar. UnBindRequestGrammar is a singleton */
+    private static IGrammar instance = new UnBindRequestGrammar();
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Get the instance of this grammar
+     *
+     * @return An instance on the UnBindRequest Grammar
+     */
+    public static IGrammar getInstance()
+    {
+        return instance;
+    }
+
+    //~ Constructors -------------------------------------------------------------------------------
+
+    /**
+     * Creates a new UnBindRequestGrammar object.
+     */
+    private UnBindRequestGrammar()
+    {
+
+        name = UnBindRequestGrammar.class.getName();
+        
+        statesEnum = LdapStatesEnum.getInstance();
+
+        // We have 3 differents states, so 2 transitions between states.
+        super.transitions = new GrammarTransition[LdapStatesEnum.LAST_UNBIND_REQUEST_STATE][256];
+
+        //============================================================================================
+        // protocolOp : UnBind Request
+        //============================================================================================
+        // LdapMessage ::= ... UnBindRequest ...
+        // UnbindRequest ::= [APPLICATION 2] NULL (Length)
+        super.transitions[LdapStatesEnum.UNBIND_REQUEST_TAG][LdapConstants.UNBIND_REQUEST_TAG]    = new GrammarTransition(
+                LdapStatesEnum.UNBIND_REQUEST_TAG, LdapStatesEnum.UNBIND_REQUEST_VALUE, null );
+
+        // LdapMessage ::= ... UnBindRequest ...
+        // UnbindRequest ::= [APPLICATION 2] NULL (Value)
+        // We have to check that the length is null (the Value is empty). This is the end of this grammar.
+        // We also have to allocate a UnBindRequest
+        super.transitions[LdapStatesEnum.UNBIND_REQUEST_VALUE][LdapConstants.UNBIND_REQUEST_TAG] = new GrammarTransition(
+                LdapStatesEnum.UNBIND_REQUEST_VALUE, LdapStatesEnum.GRAMMAR_END,
+                new GrammarAction( "Init UnBindRequest" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        LdapMessageContainer ldapMessageContainer = ( LdapMessageContainer )
+                            container;
+                        LdapMessage      ldapMessage          =
+                            ldapMessageContainer.getLdapMessage();
+
+                        // Now, we can allocate the UnBindRequest Object
+                        UnBindRequest unBindRequest = new UnBindRequest();
+
+                        // As this is a new Constructed object, we have to init its length
+                        TLV tlv            = ldapMessageContainer.getCurrentTLV();
+                        int expectedLength = tlv.getLength().getLength();
+                        
+                        // If the length is not null, this is an error.
+                        if (expectedLength != 0)
+                        {
+                            throw new DecoderException("The length of a UnBindRequest must be null");
+                        }
+
+                        unBindRequest.setParent( ldapMessage );
+
+                        // And we associate it to the ldapMessage Object
+                        ldapMessage.setProtocolOP( unBindRequest );
+                    }
+                } );
+    }
+}

Added: directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapDN.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapDN.java?rev=234264&view=auto
==============================================================================
--- directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapDN.java (added)
+++ directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapDN.java Sun Aug 21 09:53:27 2005
@@ -0,0 +1,119 @@
+/*
+ *   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 org.apache.asn1new.DecoderException;
+import org.apache.asn1new.util.StringUtils;
+
+/**
+ * This class parses a DN. 
+ * 
+ * The DN MUST respect this BNF grammar (as of RFC2253, par. 3, and RFC1779, fig. 1) <br>
+ * 
+ * <p>
+ *-    &lt;distinguishedName&gt;      ::= &lt;name&gt; | e <br>
+ *-    &lt;name&gt;                   ::= &lt;name-component&gt; &lt;name-components&gt; <br>
+ *-    &lt;name-components&gt;        ::= &lt;spaces&gt; &lt;separator&gt; &lt;spaces&gt; &lt;name-component&gt; &lt;name-components&gt; | e <br>
+ *-    &lt;name-component&gt;         ::= &lt;attributeType&gt; &lt;spaces&gt; '=' &lt;spaces&gt; &lt;attributeValue&gt; &lt;attributeTypeAndValues&gt; <br>
+ *-    &lt;attributeTypeAndValues&gt; ::= &lt;spaces&gt; '+' &lt;spaces&gt; &lt;attributeType&gt; &lt;spaces&gt; '=' &lt;spaces&gt; &lt;attributeValue&gt; &lt;attributeTypeAndValues&gt; | e <br>
+ *-    &lt;attributeType&gt;          ::= [a-zA-Z] &lt;keychars&gt; | &lt;oidPrefix&gt; [0-9] &lt;digits&gt; &lt;oids&gt; | [0-9] &lt;digits&gt; &lt;oids&gt; <br>
+ *-    &lt;keychars&gt;               ::= [a-zA-Z] &lt;keychars&gt; | [0-9] &lt;keychars&gt; | '-' &lt;keychars&gt; | e <br>
+ *-    &lt;oidPrefix&gt;              ::= 'OID.' | 'oid.' | e <br>
+ *-    &lt;oids&gt;                   ::= '.' [0-9] &lt;digits&gt; &lt;oids&gt; | e <br>
+ *-    &lt;attributeValue&gt;         ::= &lt;pairs-or-strings&gt; | '#' &lt;hexstring&gt; |'"' &lt;quotechar-or-pairs&gt; '"' <br>
+ *-    &lt;pairs-or-strings&gt;       ::= '\' &lt;pairchar&gt; &lt;pairs-or-strings&gt; | &lt;stringchar&gt; &lt;pairs-or-strings&gt; | e <br>
+ *-    &lt;quotechar-or-pairs&gt;     ::= &lt;quotechar&gt; &lt;quotechar-or-pairs&gt; | '\' &lt;pairchar&gt; &lt;quotechar-or-pairs&gt; | e <br>
+ *-    &lt;pairchar&gt;               ::= ',' | '=' | '+' | '&lt;' | '&gt;' | '#' | ';' | '\' | '"' | [0-9a-fA-F] [0-9a-fA-F]  <br>
+ *-    &lt;hexstring&gt;              ::= [0-9a-fA-F] [0-9a-fA-F] &lt;hexpairs&gt; <br>
+ *-    &lt;hexpairs&gt;               ::= [0-9a-fA-F] [0-9a-fA-F] &lt;hexpairs&gt; | e <br>
+ *-    &lt;digits&gt;                 ::= [0-9] &lt;digits&gt; | e <br>
+ *-    &lt;stringchar&gt;             ::= [0x00-0xFF] - [,=+&lt;&gt;#;\"\n\r] <br>
+ *-    &lt;quotechar&gt;              ::= [0x00-0xFF] - [\"] <br>
+ *-    &lt;separator&gt;              ::= ',' | ';' <br>
+ *-    &lt;spaces&gt;                 ::= ' ' &lt;spaces&gt; | e <br>
+ * </p>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapDN extends RelativeLdapDN
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** A null LdapDN */
+    public transient static final LdapDN EMPTY_STRING = new LdapDN();
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Construct an empty LdapDN object
+     */
+    public LdapDN()
+    {
+        super(0, false);
+    }
+    
+    /**
+     * Parse a buffer and checks that it is a valid DN <br>
+     * <p>
+     * &lt;distinguishedName&gt;     ::= &lt;name&gt; | e <br>
+     * &lt;name&gt;                ::= &lt;name-component&gt; &lt;name-components&gt; <br>
+     * &lt;name-components&gt;    ::= &lt;spaces&gt; &lt;separator&gt; &lt;spaces&gt; &lt;name-component&gt; &lt;name-components&gt; | e <br>
+     * </p>
+     * 
+     * @param bytes The byte buffer that contains the DN
+     * @exception A DecoderException is thrown if the buffer does not contains a valid DN.
+     */
+    public LdapDN( byte[] bytes ) throws DecoderException
+    {
+
+        if ( bytes == null || bytes.length == 0)
+        {
+            return;
+        }
+        
+        int pos = 0;
+
+        // <name>             ::= <name-component> <name-components>
+        // <name-components> ::= <spaces> <separator> <spaces> <name-component> <name-components> | e
+        if ( ( pos = parseNameComponent( bytes, pos ) ) != -1 )
+        {
+
+            do
+            {
+
+                if ( ( StringUtils.isCharASCII( bytes, pos, ',' ) == false ) &&
+                        ( StringUtils.isCharASCII( bytes, pos, ';' ) == false ) )
+                {
+
+                    break;
+                }
+
+                bytes[pos] = ',';
+                pos++;
+
+                pos = parseSpaces( bytes, pos );
+            }
+            while ( ( pos = parseNameComponent( bytes, pos ) ) != -1 );
+        }
+        else
+        {
+            throw new DecoderException( "Bad DN : " + new String( bytes) );
+        }
+
+        setData(bytes);
+    }
+}

Added: directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapString.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapString.java?rev=234264&view=auto
==============================================================================
--- directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapString.java (added)
+++ directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapString.java Sun Aug 21 09:53:27 2005
@@ -0,0 +1,63 @@
+/*
+ *   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 org.apache.asn1new.DecoderException;
+import org.apache.asn1new.util.MutableString;
+
+/**
+ * Decodes a LdapString, and checks that the character set used comply
+ * the ISO 10646 encoded following the UTF-8 algorithm (RFC 2044, RFC 2279)
+ * .
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapString extends MutableString
+{
+    /** A null LdapString */
+    public transient static final LdapString EMPTY_STRING = new LdapString();
+
+    /**
+     * Construct an empty LdapString
+     *
+     */
+    public LdapString()
+    {
+        super( 0, false );
+    }
+    
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Transform a byte array to a MutableString. The byte array contains
+     * an UTF-8 representation of a String
+     * 
+     * @param bytes The byte buffer that contains the LDAPSTRING
+     * @return A MutableString containing the LDAPSTRING
+     * 
+     * @throws DecoderException If the byte array does not comply with RFC 2279
+     */
+    public LdapString( byte[] bytes ) throws DecoderException
+    {
+        if ( bytes == null )
+        {
+            return;
+        }
+        
+        setData(bytes);
+    }
+}

Added: directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapURL.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapURL.java?rev=234264&view=auto
==============================================================================
--- directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapURL.java (added)
+++ directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/LdapURL.java Sun Aug 21 09:53:27 2005
@@ -0,0 +1,1105 @@
+/*
+ *   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 org.apache.asn1new.DecoderException;
+import org.apache.asn1new.util.StringUtils;
+
+import org.apache.commons.httpclient.URIException;
+import org.apache.commons.httpclient.util.URIUtil;
+
+import org.apache.ldap.common.filter.FilterParserImpl;
+
+import java.io.IOException;
+
+import java.text.ParseException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import javax.naming.directory.SearchControls;
+
+
+/**
+ * Decodes a LdapUrl, and checks that it complies with
+ * the RFC 2255. The grammar is the following :
+ * ldapurl    = scheme "://" [hostport] ["/"
+ *                   [dn ["?" [attributes] ["?" [scope]
+ *                   ["?" [filter] ["?" extensions]]]]]]
+ * scheme     = "ldap"
+ * attributes = attrdesc *("," attrdesc)
+ * scope      = "base" / "one" / "sub"
+ * dn         = LdapDN
+ * hostport   = hostport from Section 5 of RFC 1738
+ * attrdesc   = AttributeDescription from Section 4.1.5 of RFC 2251
+ * filter     = filter from Section 4 of RFC 2254
+ * extensions = extension *("," extension)
+ * extension  = ["!"] extype ["=" exvalue]
+ * extype     = token / xtoken
+ * exvalue    = LDAPString
+ * token      = oid from section 4.1 of RFC 2252
+ * xtoken     = ("X-" / "x-") token
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdapURL extends LdapString
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** A null LdapURL */
+    public static final transient LdapURL EMPTY_STRING = new LdapURL();
+
+    /** The filter parser */
+    private static FilterParserImpl filterParser = new FilterParserImpl();
+
+    //~ Instance fields ----------------------------------------------------------------------------
+
+    /** The host */
+    private String host;
+
+    /** The port */
+    private int port;
+
+    /** The DN */
+    private LdapDN dn;
+
+    /** The attributes */
+    private ArrayList attributes;
+
+    /** The scope */
+    private int scope;
+
+    /** The filter as a string*/
+    private String filter;
+
+    /** The extensions */
+    private HashMap extensions;
+
+    /** The criticals extensions */
+    private HashMap criticalExtensions;
+
+    //~ Constructors -------------------------------------------------------------------------------
+
+    /**
+     * Construct an empty LdapURL
+     *
+     */
+    public LdapURL()
+    {
+        super();
+        host               = null;
+        port               = -1;
+        dn                 = null;
+        attributes         = new ArrayList();
+        scope              = SearchControls.OBJECT_SCOPE;
+        filter             = null;
+        extensions         = new HashMap();
+        criticalExtensions = new HashMap();
+    }
+
+    /**
+     * Create a new LdapURL after having parsed it.
+     * 
+     * @param bytes The byte buffer that contains the LDAPURL
+     * @return A MutableString containing the LDAPURL
+     * 
+     * @throws DecoderException If the byte array does not comply with RFC 2255
+     */
+    public LdapURL(  byte[] bytes ) throws DecoderException
+    {
+        super(bytes);
+        host               = null;
+        port               = -1;
+        dn                 = null;
+        attributes         = new ArrayList();
+        scope              = SearchControls.OBJECT_SCOPE;
+        filter             = null;
+        extensions         = new HashMap();
+        criticalExtensions = new HashMap();
+
+        if ( ( bytes == null ) || ( bytes.length == 0 ) )
+        {
+            host = "";
+            return;
+        }
+
+        // ldapurl    = scheme "://" [hostport] ["/"
+        //                 [dn ["?" [attributes] ["?" [scope]
+        //                 ["?" [filter] ["?" extensions]]]]]]
+        // scheme     = "ldap"
+
+        int pos = 0;
+
+        // The scheme
+        if ( ( pos = StringUtils.areEquals( bytes, pos, "ldap://" ) ) == -1 )
+        {
+            throw new DecoderException( "A LdapUrl must start with \"ldap://\"" );
+        }
+
+        // The hostport
+        if ( ( pos = parseHostPort( bytes, pos ) ) == -1 )
+        {
+            throw new DecoderException( "The hostport is invalid" );
+        }
+
+        if ( pos == bytes.length )
+        {
+            return;
+        }
+
+        // An optional '/'
+        if ( StringUtils.isCharASCII( bytes, pos, '/' ) == false )
+        {
+            throw new DecoderException( "Bad character, position " + pos + ", '" + bytes[pos] +
+                "', '/' expected" );
+        }
+
+        pos++;
+
+        if ( pos == bytes.length )
+        {
+            return;
+        }
+
+        // An optional DN
+        if ( ( pos = parseDN( bytes, pos ) ) == -1 )
+        {
+            throw new DecoderException( "The DN is invalid" );
+        }
+
+        if ( pos == bytes.length )
+        {
+            return;
+        }
+
+        // Optionals attributes
+        if ( StringUtils.isCharASCII( bytes, pos, '?' ) == false )
+        {
+            throw new DecoderException( "Bad character, position " + pos + ", '" + bytes[pos] +
+                "', '?' expected" );
+        }
+
+        pos++;
+
+        if ( ( pos = parseAttributes( bytes, pos ) ) == -1 )
+        {
+            throw new DecoderException( "Attributes are invalid" );
+        }
+
+        if ( pos == bytes.length )
+        {
+            return;
+        }
+
+        // Optional scope
+        if ( StringUtils.isCharASCII( bytes, pos, '?' ) == false )
+        {
+            throw new DecoderException( "Bad character, position " + pos + ", '" + bytes[pos] +
+                "', '?' expected" );
+        }
+
+        pos++;
+
+        if ( ( pos = parseScope( bytes, pos ) ) == -1 )
+        {
+            throw new DecoderException( "Scope is invalid" );
+        }
+
+        if ( pos == bytes.length )
+        {
+            return;
+        }
+
+        // Optional filter
+        if ( StringUtils.isCharASCII( bytes, pos, '?' ) == false )
+        {
+            throw new DecoderException( "Bad character, position " + pos + ", '" + bytes[pos] +
+                "', '?' expected" );
+        }
+
+        pos++;
+
+        if ( pos == bytes.length )
+        {
+            return;
+        }
+
+        if ( ( pos = parseFilter( bytes, pos ) ) == -1 )
+        {
+            throw new DecoderException( "Filter is invalid" );
+        }
+
+        if ( pos == bytes.length )
+        {
+            return;
+        }
+
+        // Optional extensions
+        if ( StringUtils.isCharASCII( bytes, pos, '?' ) == false )
+        {
+            throw new DecoderException( "Bad character, position " + pos + ", '" + bytes[pos] +
+                "', '?' expected" );
+        }
+
+        pos++;
+
+        if ( ( pos = parseExtensions( bytes, pos ) ) == -1 )
+        {
+            throw new DecoderException( "Extensions are invalid" );
+        }
+
+        if ( pos == bytes.length )
+        {
+            return;
+        }
+        else
+        {
+            throw new DecoderException( "Invalid character at the end of the ldapUrl" );
+        }
+    }
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Parse this rule : <br>
+     * <p>
+     * &lt;host&gt; ::= &lt;hostname&gt; ':' &lt;hostnumber&gt;<br>
+     * &lt;hostname&gt;     ::= *[ &lt;domainlabel&gt; "." ] &lt;toplabel&gt;<br>
+     * &lt;domainlabel&gt;  ::= &lt;alphadigit&gt; | &lt;alphadigit&gt; *[ &lt;alphadigit&gt; | "-" ] &lt;alphadigit&gt;<br>
+     * &lt;toplabel&gt;     ::= &lt;alpha&gt; | &lt;alpha&gt; *[ &lt;alphadigit&gt; | "-" ] &lt;alphadigit&gt;<br>
+     * &lt;hostnumber&gt;   ::= &lt;digits&gt; "." &lt;digits&gt; "." &lt;digits&gt; "." &lt;digits&gt;
+     * </p>
+     * 
+     * @param bytes The buffer to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+     * 
+     * TODO check that the topLabel is valid (it must start with an alpha)
+     */
+    private int parseHost( byte[] bytes, int pos )
+    {
+
+        int     start        = pos;
+        boolean hadDot       = false;
+        boolean hadMinus     = false;
+        boolean isHostNumber = true;
+        boolean invalidIp    = false;
+        int     nbDots       = 0;
+        int[]   ipElem       = new int[4];
+
+        // The host will be followed by a '/' or a ':', or by nothing if it's
+        // the end.
+        // We will search the end of the host part, and we will check some
+        // elements.
+        if ( StringUtils.isCharASCII( bytes, pos, '-' ) )
+        {
+
+            // We can't have a '-' on first position
+            return -1;
+        }
+
+        while ( ( pos < bytes.length ) && ( bytes[pos] != ':' ) && ( bytes[pos] != '/' ) )
+        {
+
+            if ( StringUtils.isCharASCII( bytes, pos, '.' ) )
+            {
+
+                if ( ( hadMinus ) || ( hadDot ) )
+                {
+
+                    // We already had a '.' just before : this is not allowed.
+                    // Or we had a '-' before a '.' : ths is not allowed either.
+                    return -1;
+                }
+
+                // Let's check the string we had before the dot.
+                if ( isHostNumber )
+                {
+
+                    if ( nbDots < 4 )
+                    {
+
+                        // We had only digits. It may be an IP adress? Check it
+                        if ( ipElem[nbDots] > 65535 )
+                        {
+                            invalidIp = true;
+                        }
+                    }
+                }
+
+                hadDot = true;
+                nbDots++;
+                pos++;
+                continue;
+            }
+            else
+            {
+
+                if ( hadDot && StringUtils.isCharASCII( bytes, pos, '-' ) )
+                {
+
+                    // We can't have a '-' just after a '.'
+                    return -1;
+                }
+
+                hadDot = false;
+            }
+
+            if ( StringUtils.isDigit( bytes, pos ) )
+            {
+
+                if ( isHostNumber && ( nbDots < 4 ) )
+                {
+                    ipElem[nbDots] = ( ipElem[nbDots] * 10 ) + ( bytes[pos] - '0' );
+
+                    if ( ipElem[nbDots] > 65535 )
+                    {
+                        invalidIp = true;
+                    }
+                }
+
+                hadMinus = false;
+            }
+            else if ( StringUtils.isAlphaDigitMinus( bytes, pos ) )
+            {
+                isHostNumber = false;
+
+                if ( StringUtils.isCharASCII( bytes, pos, '-' ) )
+                {
+                    hadMinus = true;
+                }
+                else
+                {
+                    hadMinus = false;
+                }
+            }
+            else
+            {
+                return -1;
+            }
+
+            pos++;
+        }
+
+        if ( start == pos )
+        {
+
+            // An empty host is valid
+            return pos;
+        }
+
+        // Checks the hostNumber
+        if ( isHostNumber )
+        {
+
+            // As this is a host number, we must have 3 dots.
+            if ( nbDots != 3 )
+            {
+                return -1;
+            }
+
+            if ( invalidIp )
+            {
+                return -1;
+            }
+        }
+
+        // Check if we have a '.' or a '-' in last position
+        if ( hadDot || hadMinus )
+        {
+            return -1;
+        }
+
+        host = new String( bytes, start, pos - start );
+        return pos;
+    }
+
+    /**
+     * Parse this rule : <br>
+     * <p>
+     * &lt;port&gt; ::= &lt;digits&gt;<br>
+     * &lt;digits&gt; ::= &lt;digit&gt; &lt;digits-or-null&gt;<br> 
+     * &lt;digits-or-null&gt; ::= &lt;digit&gt; &lt;digits-or-null&gt; | e<br>
+     * &lt;digit&gt; ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 
+     * </p>
+     * 
+     * The port must be between 0 and 65535.
+     * 
+     * @param bytes The buffer to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+     */
+    private int parsePort( byte[] bytes, int pos )
+    {
+
+        if ( StringUtils.isDigit( bytes, pos ) == false )
+        {
+            return -1;
+        }
+
+        port = bytes[pos] - '0';
+
+        pos++;
+
+        while ( StringUtils.isDigit( bytes, pos ) )
+        {
+            port = ( port * 10 ) + ( bytes[pos] - '0' );
+
+            if ( port > 65535 )
+            {
+                return -1;
+            }
+
+            pos++;
+        }
+
+        return pos;
+    }
+
+    /**
+     * Parse this rule : <br>
+     * <p>
+     * &lt;hostport&gt; ::= &lt;host&gt; ':' &lt;port&gt;
+     * </p>
+     * 
+     * @param bytes The buffer to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+     */
+    private int parseHostPort( byte[] bytes, int pos )
+    {
+
+        if ( ( pos = parseHost( bytes, pos ) ) == -1 )
+        {
+            return -1;
+        }
+
+        // We may have a port.
+        if ( StringUtils.isCharASCII( bytes, pos, ':' ) )
+        {
+            pos++;
+        }
+        else
+        {
+            return pos;
+        }
+
+        // As we have a ':', we must have a valid port (between 0 and 65535).
+        if ( ( pos = parsePort( bytes, pos ) ) == -1 )
+        {
+            return -1;
+        }
+
+        return pos;
+    }
+
+    /**
+     * Parse a string and check that it complies with RFC 2253.
+     * Here, we will just call the LdapDN parser to do the job.
+     * 
+     * @param bytes The bytes array to be checked
+     * @param pos the starting position
+     * @return -1 if the bytes array does not contains a DN 
+     */
+    private int parseDN( byte[] bytes, int pos )
+    {
+
+        int end = pos;
+
+        for ( int i = pos; ( i < bytes.length ) && ( bytes[i] != '?' ); i++ )
+        {
+            end++;
+        }
+
+        try
+        {
+            dn = new LdapDN( URIUtil.decode( new String( bytes, pos, end - pos ) ).getBytes() );
+        }
+        catch ( URIException ue )
+        {
+            return -1;
+        }
+        catch ( DecoderException de )
+        {
+            return -1;
+        }
+
+        return end;
+    }
+
+    /**
+     * Parse the attributes part
+     * 
+     * @param bytes The bytes array to be checked
+     * @param pos the starting position
+     * @return -1 if the bytes array does not contains attributes 
+     */
+    private int parseAttributes( byte[] bytes, int pos )
+    {
+
+        int     start       = pos;
+        int     end         = pos;
+        HashSet hAttributes = new HashSet();
+        boolean hadComma    = false;
+
+        try
+        {
+
+            for ( int i = pos; ( i < bytes.length ) && ( bytes[i] != '?' ); i++ )
+            {
+
+                if ( StringUtils.isCharASCII( bytes, i, ',' ) )
+                {
+                    hadComma = true;
+
+                    if ( ( end - start ) == 0 )
+                    {
+
+                        // An attributes must not be null
+                        return -1;
+                    }
+                    else
+                    {
+
+                        // get the attribute. It must not be blank
+                        String attribute = new String( bytes, start, end - start ).trim();
+
+                        if ( attribute.length() == 0 )
+                        {
+                            return -1;
+                        }
+
+                        String decodedAttr = URIUtil.decode( attribute );
+
+
+                        if ( hAttributes.contains( decodedAttr ) == false )
+                        {
+                            attributes.add( decodedAttr );
+                            hAttributes.add( decodedAttr );
+                        }
+                    }
+
+                    start = i + 1;
+                }
+                else
+                {
+                    hadComma = false;
+                }
+
+                end++;
+            }
+
+            if ( hadComma )
+            {
+
+                // We are not allowed to have a comma at the end of the attributes
+                return -1;
+            }
+            else
+            {
+
+                if ( end == start )
+                {
+
+                    // We don't have any attributes. This is valid.
+                    return end;
+                }
+
+                // Store the last attribute
+                // get the attribute. It must not be blank
+                String attribute = new String( bytes, start, end - start ).trim();
+
+                if ( attribute.length() == 0 )
+                {
+                    return -1;
+                }
+
+                String decodedAttr = URIUtil.decode( attribute );
+
+
+                if ( hAttributes.contains( decodedAttr ) == false )
+                {
+                    attributes.add( decodedAttr );
+                    hAttributes.add( decodedAttr );
+                }
+            }
+
+            return end;
+        }
+        catch ( URIException ue )
+        {
+            return -1;
+        }
+    }
+
+    /**
+     * Parse the filter part. We will use the FilterParserImpl class
+     * 
+     * @param bytes The bytes array to be checked
+     * @param pos the starting position
+     * @return -1 if the bytes array does not contains a filter 
+     */
+    private int parseFilter( byte[] bytes, int pos )
+    {
+
+        int end = pos;
+
+        for ( int i = pos; ( i < bytes.length ) && ( bytes[i] != '?' ); i++ )
+        {
+            end++;
+        }
+
+        try
+        {
+            filter       = URIUtil.decode( new String( bytes, pos, end - pos ) );
+            filterParser.parse( filter );
+        }
+        catch ( URIException ue )
+        {
+            return -1;
+        }
+        catch ( IOException ioe )
+        {
+            return -1;
+        }
+        catch ( ParseException pe )
+        {
+            return -1;
+        }
+
+        return end;
+    }
+
+    /**
+     * Parse the scope part.
+     * 
+     * @param bytes The bytes array to be checked
+     * @param pos the starting position
+     * @return -1 if the bytes array does not contains a scope 
+     */
+    private int parseScope( byte[] bytes, int pos )
+    {
+
+        if ( StringUtils.isCharASCII( bytes, pos, 'b' ) ||
+                StringUtils.isCharASCII( bytes, pos, 'B' ) )
+        {
+            pos++;
+
+            if ( StringUtils.isCharASCII( bytes, pos, 'a' ) ||
+                    StringUtils.isCharASCII( bytes, pos, 'A' ) )
+            {
+                pos++;
+
+                if ( StringUtils.isCharASCII( bytes, pos, 's' ) ||
+                        StringUtils.isCharASCII( bytes, pos, 'S' ) )
+                {
+                    pos++;
+
+                    if ( StringUtils.isCharASCII( bytes, pos, 'e' ) ||
+                            StringUtils.isCharASCII( bytes, pos, 'E' ) )
+                    {
+                        pos++;
+                        scope = SearchControls.OBJECT_SCOPE;
+                        return pos;
+                    }
+                }
+            }
+        }
+        else if ( StringUtils.isCharASCII( bytes, pos, 'o' ) ||
+                StringUtils.isCharASCII( bytes, pos, 'O' ) )
+        {
+            pos++;
+
+            if ( StringUtils.isCharASCII( bytes, pos, 'n' ) ||
+                    StringUtils.isCharASCII( bytes, pos, 'N' ) )
+            {
+                pos++;
+
+                if ( StringUtils.isCharASCII( bytes, pos, 'e' ) ||
+                        StringUtils.isCharASCII( bytes, pos, 'E' ) )
+                {
+                    pos++;
+
+                    scope = SearchControls.ONELEVEL_SCOPE;
+                    return pos;
+                }
+            }
+        }
+        else if ( StringUtils.isCharASCII( bytes, pos, 's' ) ||
+                StringUtils.isCharASCII( bytes, pos, 'S' ) )
+        {
+            pos++;
+
+            if ( StringUtils.isCharASCII( bytes, pos, 'u' ) ||
+                    StringUtils.isCharASCII( bytes, pos, 'U' ) )
+            {
+                pos++;
+
+                if ( StringUtils.isCharASCII( bytes, pos, 'b' ) ||
+                        StringUtils.isCharASCII( bytes, pos, 'B' ) )
+                {
+                    pos++;
+
+                    scope = SearchControls.SUBTREE_SCOPE;
+                    return pos;
+                }
+            }
+        }
+        else if ( StringUtils.isCharASCII( bytes, pos, '?' ) )
+        {
+
+            // An empty scope. This is valid
+            return pos;
+        }
+
+        // The scope is not one of "one", "sub" or "base". It's an error
+        return -1;
+    }
+
+    /**
+     * Parse extensions and critical extensions. 
+     * 
+     * The grammar is :
+     * 
+     * extensions ::= extension [ ',' extension ]*
+     * extension  ::= [ '!' ] ( token | ( 'x-' | 'X-' ) token ) ) [ '=' exvalue ]  
+     * @param bytes The bytes array to be checked
+     * @param pos the starting position
+     * @return -1 if the bytes array does not contains valid extensions or critical extensions 
+     */
+    private int parseExtensions( byte[] bytes, int pos )
+    {
+
+        int     start          = pos;
+        boolean isCritical     = false;
+        boolean isNewExtension = true;
+        boolean hasValue       = false;
+        String  extension      = null;
+        String  value          = null;
+
+        if ( pos == bytes.length )
+        {
+            return pos;
+        }
+
+        try
+        {
+
+            for ( int i = pos; ( i < bytes.length ); i++ )
+            {
+
+                if ( StringUtils.isCharASCII( bytes, i, ',' ) )
+                {
+
+                    if ( isNewExtension )
+                    {
+
+                        // a ',' is not allowed when we have already had one
+                        // or if we just started to parse the extensions.
+                        return -1;
+                    }
+                    else
+                    {
+                        value = new String( URIUtil.decode( new String( bytes, start, i - start ) ) )
+                            .trim();
+
+                        if ( value.length() == 0 )
+                        {
+                            return -1;
+                        }
+
+                        if ( isCritical )
+                        {
+                            criticalExtensions.put( extension, value );
+                        }
+                        else
+                        {
+                            extensions.put( extension, value );
+                        }
+
+                        isNewExtension = true;
+                        hasValue       = false;
+                        isCritical     = false;
+                        start          = i + 1;
+                        extension      = null;
+                        value          = null;
+                    }
+                }
+                else if ( StringUtils.isCharASCII( bytes, i, '=' ) )
+                {
+
+                    if ( hasValue )
+                    {
+
+                        // We may have two '=' for the same extension
+                        continue;
+                    }
+
+                    // An optionnal value
+                    extension = new String( URIUtil.decode( new String( bytes, start, i - start ) ) )
+                        .trim();
+
+                    if ( extension.length() == 0 )
+                    {
+
+                        // We must have an extension
+                        return -1;
+                    }
+
+                    isNewExtension = false;
+                    hasValue       = true;
+                    start          = i + 1;
+                }
+                else if ( StringUtils.isCharASCII( bytes, i, '!' ) )
+                {
+
+                    if ( isNewExtension == false )
+                    {
+
+                        // '!' must appears first
+                        return -1;
+                    }
+
+                    isCritical = true;
+                    start++;
+                }
+            }
+
+            if ( extension == null )
+            {
+                extension = new String( URIUtil.decode(
+                            new String( bytes, start, bytes.length - start ) ) ).trim();
+            }
+            else
+            {
+                value = new String( URIUtil.decode(
+                            new String( bytes, start, bytes.length - start ) ) ).trim();
+            }
+
+            if ( isCritical )
+            {
+                criticalExtensions.put( extension, value );
+            }
+            else
+            {
+                extensions.put( extension, value );
+            }
+
+            return bytes.length;
+        }
+        catch ( URIException ue )
+        {
+            return -1;
+        }
+    }
+
+    /**
+     * Encode a String to avoid special characters
+     * 
+     * *NOTE* : this is an ugly function, just needed because the
+     * RFC 2255 is VERY unclear about the way LDAP searches are
+     * to be encoded. Some references to RFC 1738 are made,
+     * but they are really useless and inadequat.
+     *   
+     * @param string The String to encode
+     * @param doubleEncode Set if we need to encode the comma
+     * @return An encoded string
+     */
+    private String urlEncode( String string, boolean doubleEncode)
+    {
+        StringBuffer sb = new StringBuffer();
+        
+        for (int i = 0; i < string.length(); i++)
+        {
+            char c = string.charAt(i);
+            
+            switch (c)
+            {
+	            case ' ' :
+	                sb.append("%20");
+	                break;
+	                
+	            case '?' :
+	                sb.append("%3f");
+	                break;
+	                
+	            case '\\' :
+	                sb.append("%5c");
+	                break;
+	                
+	            case ',' :
+	                if (doubleEncode)
+	                {
+	                    sb.append("%2c");
+	                }
+	                else
+	                {
+	                    sb.append( c );
+	                }
+	                break;
+	                
+	            default :
+	                sb.append( c );
+            }
+        }
+        
+        return sb.toString();
+    }
+    
+    /**
+     * Get a string representation of a LdapURL.
+     * @return A LdapURL string
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer( "ldap://" );
+
+        sb.append( ( host == null ) ? "" : host );
+
+        if ( port != -1 )
+        {
+            sb.append( ':' ).append( port );
+        }
+
+        if ( dn != null )
+        {
+            sb.append( '/' ).append( urlEncode(dn.toString(), false ) );
+
+            if ( ( attributes.size() != 0 ) ||
+                    ( ( scope != SearchControls.OBJECT_SCOPE ) ||
+                        ( filter != null ) ||
+                        ( extensions.size() != 0 ) ||
+                        ( criticalExtensions.size() != 0 ) ) )
+            {
+                sb.append( '?' );
+
+                for ( int i = 0; i < attributes.size(); i++ )
+                {
+
+                    if ( i > 0 )
+                    {
+                        sb.append( ',' );
+                    }
+
+                    sb.append( urlEncode((String)attributes.get( i ), false ) );
+                }
+            }
+
+            if ( ( scope != SearchControls.OBJECT_SCOPE ) ||
+                    ( filter != null ) ||
+                    ( extensions.size() != 0 ) ||
+                    ( criticalExtensions.size() != 0 ) )
+            {
+                sb.append( '?' );
+
+                switch ( scope )
+                {
+
+                    case SearchControls.OBJECT_SCOPE :
+
+                        // This is the default value.
+                        break;
+
+                    case SearchControls.ONELEVEL_SCOPE :
+                        sb.append( "one" );
+                        break;
+
+                    case SearchControls.SUBTREE_SCOPE :
+                        sb.append( "sub" );
+                        break;
+                }
+
+                if ( ( filter != null ) ||
+                        ( ( extensions.size() != 0 ) ||
+                            ( criticalExtensions.size() != 0 ) ) )
+                {
+                    sb.append( "?" );
+
+                    if ( filter != null )
+                    {
+                        sb.append( urlEncode( filter, false ) );
+                    }
+
+                    if ( ( extensions.size() != 0 ) || ( criticalExtensions.size() != 0 ) )
+                    {
+                        sb.append( '?' );
+
+                        boolean isFirst = true;
+
+                        if ( extensions.size() != 0 )
+                        {
+
+                            Iterator keys = extensions.keySet().iterator();
+
+                            while ( keys.hasNext() )
+                            {
+
+                                if ( isFirst == false )
+                                {
+                                    sb.append( ',' );
+                                }
+                                else
+                                {
+                                    isFirst = false;
+                                }
+
+                                String key = ( String ) keys.next();
+
+                                sb.append( urlEncode( key, false ) ).append( '=' ).append( urlEncode( (String)extensions.get( key ), true ) );
+                            }
+                        }
+
+                        isFirst = true;
+
+                        if ( criticalExtensions.size() != 0 )
+                        {
+
+                            Iterator keys = criticalExtensions.keySet().iterator();
+
+                            while ( keys.hasNext() )
+                            {
+
+                                if ( isFirst == false )
+                                {
+                                    sb.append( ",!" );
+                                }
+                                else
+                                {
+                                    sb.append( '!' );
+                                    isFirst = false;
+                                }
+
+                                String key = ( String ) keys.next();
+
+                                sb.append( urlEncode( key, false ) ).append( '=' ).append( urlEncode( (String)criticalExtensions.get( key ), true ) );
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        else
+        {
+            sb.append( '/' );
+        }
+
+        return sb.toString();
+    }
+}

Added: directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/RelativeLdapDN.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/RelativeLdapDN.java?rev=234264&view=auto
==============================================================================
--- directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/RelativeLdapDN.java (added)
+++ directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/primitives/RelativeLdapDN.java Sun Aug 21 09:53:27 2005
@@ -0,0 +1,492 @@
+/*
+ *   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 org.apache.asn1new.DecoderException;
+import org.apache.asn1new.util.MutableString;
+import org.apache.asn1new.util.StringUtils;
+import org.apache.asn1new.ldap.codec.utils.DNUtils;
+
+
+/**
+ * This class parses a relative LDdapDN, which is a name-component
+ * of the LdapDN grammar 
+ * 
+ * The relative DN MUST respect this  BNF grammar (a subset of the RFC2253, par. 3, and RFC1779, fig. 1) <br>
+ * 
+ * <p>
+ *-    &lt;name-component&gt;         ::= &lt;attributeType&gt; &lt;spaces&gt; '=' &lt;spaces&gt; &lt;attributeValue&gt; &lt;attributeTypeAndValues&gt; <br>
+ *-    &lt;attributeTypeAndValues&gt; ::= &lt;spaces&gt; '+' &lt;spaces&gt; &lt;attributeType&gt; &lt;spaces&gt; '=' &lt;spaces&gt; &lt;attributeValue&gt; &lt;attributeTypeAndValues&gt; | e <br>
+ *-    &lt;attributeType&gt;          ::= [a-zA-Z] &lt;keychars&gt; | &lt;oidPrefix&gt; [0-9] &lt;digits&gt; &lt;oids&gt; | [0-9] &lt;digits&gt; &lt;oids&gt; <br>
+ *-    &lt;keychars&gt;               ::= [a-zA-Z] &lt;keychars&gt; | [0-9] &lt;keychars&gt; | '-' &lt;keychars&gt; | e <br>
+ *-    &lt;oidPrefix&gt;              ::= 'OID.' | 'oid.' | e <br>
+ *-    &lt;oids&gt;                   ::= '.' [0-9] &lt;digits&gt; &lt;oids&gt; | e <br>
+ *-    &lt;attributeValue&gt;         ::= &lt;pairs-or-strings&gt; | '#' &lt;hexstring&gt; |'"' &lt;quotechar-or-pairs&gt; '"' <br>
+ *-    &lt;pairs-or-strings&gt;       ::= '\' &lt;pairchar&gt; &lt;pairs-or-strings&gt; | &lt;stringchar&gt; &lt;pairs-or-strings&gt; | e <br>
+ *-    &lt;quotechar-or-pairs&gt;     ::= &lt;quotechar&gt; &lt;quotechar-or-pairs&gt; | '\' &lt;pairchar&gt; &lt;quotechar-or-pairs&gt; | e <br>
+ *-    &lt;pairchar&gt;               ::= ',' | '=' | '+' | '&lt;' | '&gt;' | '#' | ';' | '\' | '"' | [0-9a-fA-F] [0-9a-fA-F]  <br>
+ *-    &lt;hexstring&gt;              ::= [0-9a-fA-F] [0-9a-fA-F] &lt;hexpairs&gt; <br>
+ *-    &lt;hexpairs&gt;               ::= [0-9a-fA-F] [0-9a-fA-F] &lt;hexpairs&gt; | e <br>
+ *-    &lt;digits&gt;                 ::= [0-9] &lt;digits&gt; | e <br>
+ *-    &lt;stringchar&gt;             ::= [0x00-0xFF] - [,=+&lt;&gt;#;\"\n\r] <br>
+ *-    &lt;quotechar&gt;              ::= [0x00-0xFF] - [\"] <br>
+ *-    &lt;spaces&gt;                 ::= ' ' &lt;spaces&gt; | e <br>
+ * </p>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class RelativeLdapDN extends MutableString
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** "oid." static */
+    private static final byte[] OID_LOWER = new byte[] { 'o', 'i', 'd', '.' };
+
+    /** "OID." static */
+    private static final byte[] OID_UPPER = new byte[] { 'O', 'I', 'D', '.' };
+
+    /** A null LdapDN */
+    public transient static final RelativeLdapDN EMPTY_STRING = new RelativeLdapDN();
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Walk the buffer while the current char is a Space char
+     * <p>
+     * &lt;spaces&gt;    ::= ' ' &lt;spaces&gt; | e
+     * </p>
+     * 
+     * @param bytes The buffer to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer
+    */
+    protected static int parseSpaces( byte[] bytes, int pos )
+    {
+
+        while ( StringUtils.isCharASCII( bytes, pos, ' ' ) )
+        {
+            pos++;
+        }
+
+        return pos;
+    }
+
+    /**
+     * Parse this rule : <br>
+     * <p>
+     * &lt;attributeValue&gt;     ::= &lt;pairs-or-strings&gt; | '#' &lt;hexstring&gt; |'"' &lt;quotechar-or-pairs&gt; '"' <br>
+     * &lt;pairs-or-strings&gt;    ::= '\' &lt;pairchar&gt; &lt;pairs-or-strings&gt; | &lt;stringchar&gt; &lt;pairs-or-strings&gt; |  | e <br>
+     * &lt;quotechar-or-pairs&gt;    ::= &lt;quotechar&gt; &lt;quotechar-or-pairs&gt; | '\' &lt;pairchar&gt; &lt;quotechar-or-pairs&gt; | e <br>
+     * </p>
+     * 
+     * @param bytes The buffer to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+     */
+    protected static int parseAttributeValue( byte[] bytes, int pos )
+    {
+        if ( StringUtils.isCharASCII( bytes, pos, '#' ) )
+        {
+            pos++;
+
+            // <attributeValue> ::= '#' <hexstring>
+            if ( ( pos = DNUtils.parseHexString( bytes, pos ) ) == -1 )
+            {
+
+                return -1;
+            }
+
+            return parseSpaces( bytes, pos );
+        }
+        else if ( StringUtils.isCharASCII( bytes, 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( bytes, pos, '\\' ) )
+                {
+                    pos++;
+
+                    if ( DNUtils.isPairChar( bytes, pos ) )
+                    {
+                        pos++;
+                    }
+                    else
+                    {
+                        return -1;
+                    }
+                }
+                else if ( (nbBytes = DNUtils.isQuoteChar( bytes, pos ) ) != -1 )
+                {
+                    pos += nbBytes;
+                }
+                else
+                {
+                    break;
+                }
+            }
+
+            if ( StringUtils.isCharASCII( bytes, pos, '"' ) )
+            {
+                pos++;
+
+                return parseSpaces( bytes, pos );
+            }
+            else
+            {
+                return -1;
+            }
+        }
+        else
+        {
+            while ( true )
+            {
+                if ( StringUtils.isCharASCII( bytes, pos, '\\' ) )
+                {
+                    // '\' <pairchar> <pairs-or-strings>
+                    pos++;
+
+                    if ( DNUtils.isPairChar( bytes, pos ) == false )
+                    {
+                        return -1;
+                    }
+                    else
+                    {
+                        pos++;
+                    }
+                }
+                else
+                {
+                    int nbBytes = 0;
+                    
+                    // <stringchar> <pairs-or-strings>
+                    if ( (nbBytes = DNUtils.isStringChar( bytes, pos )) != -1)
+                    {
+                        // A special case : if we have some spaces before the '+' character,
+                        // we MUST skip them.
+                        if ( StringUtils.isCharASCII( bytes, pos, ' ') )
+                        {
+                            pos = parseSpaces( bytes, pos );
+
+                            if ( ( DNUtils.isStringChar( bytes, pos ) == -1 ) &&
+                                    ( StringUtils.isCharASCII( bytes, pos, '\\' ) == false ) )
+                            {
+                                // Ok, we are done with the stringchar.
+                                return pos;
+                            }
+                        }
+                        else
+                        {
+                            // An unicode char could be more than one byte long 
+                            pos += nbBytes;
+                        }
+                    }
+                    else
+                    {
+                        return pos;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Parse this rule : <br>
+     * <p>
+     * &lt;oidPrefix&gt; ::= 'OID.' | 'oid.' | e
+     * </p>
+     * 
+     * @param bytes The buffer to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+     */
+    protected static int parseOidPrefix( byte[] bytes, int pos )
+    {
+
+        if ( ( StringUtils.areEquals( bytes, pos, OID_LOWER ) == -1 ) &&
+                ( StringUtils.areEquals( bytes, pos, OID_UPPER ) == -1 ) )
+        {
+
+            return -1;
+        }
+        else
+        {
+            pos += 4;
+
+            return pos;
+        }
+    }
+    
+    /**
+     * Parse this rule : <br>
+     * <p>
+     * &lt;oidValue&gt; ::= [0-9] &lt;digits&gt; &lt;oids&gt; 
+     * </p>
+     * 
+     * @param bytes The buffer to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+     */
+    protected static int parseOidValue(byte[] bytes, int pos)
+    {
+        // <attributType> ::= [0-9] <digits> <oids>
+        if ( StringUtils.isDigit( bytes, pos ) == false )
+        {
+
+            // Nope... An error
+            return -1;
+        }
+        else
+        {
+
+            // Let's process an oid
+            pos++;
+
+            while ( StringUtils.isDigit( bytes, pos ) )
+            {
+                pos++;
+            }
+
+            // <oids> ::= '.' [0-9] <digits> <oids> | e
+            if ( StringUtils.isCharASCII( bytes, pos, '.' ) == false )
+            {
+
+                return pos;
+            }
+            else
+            {
+
+                do
+                {
+                    pos++;
+
+                    if ( StringUtils.isDigit( bytes, pos ) == false )
+                    {
+
+                        return -1;
+                    }
+                    else
+                    {
+                        pos++;
+
+                        while ( StringUtils.isDigit( bytes, pos ) )
+                        {
+                            pos++;
+                        }
+                    }
+                }
+                while ( StringUtils.isCharASCII( bytes, pos, '.' ) );
+
+                return pos;
+            }
+        }
+    }
+
+    /**
+     * Parse this rule : <br>
+     * <p>
+     * &lt;attributType&gt; ::= [a-zA-Z] &lt;keychars&gt; | 
+     * 							&lt;oidPrefix&gt; [0-9] &lt;digits&gt; &lt;oids&gt; | [0-9] &lt;digits&gt; &lt;oids&gt;
+     * </p>
+     * 
+     * The string *MUST* be an ASCII string, not an unicode string.
+     * 
+     * @param bytes The buffer to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+     */
+    protected static int parseAttributeType( byte[] bytes, int pos )
+    {
+
+        // <attributType> ::= [a-zA-Z] <keychars> | <oidPrefix> [0-9] <digits> <oids> | [0-9] <digits> <oids>
+    	
+        if ( StringUtils.isAlphaASCII( bytes, 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( bytes, oldPos ) ) != -1 ) 
+            {
+            	return parseOidValue(bytes, 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( bytes, pos ) )
+                {
+                    pos++;
+                }
+
+                return pos;
+            }
+        }
+        else
+        {
+
+            // An oid
+            // <attributType> ::= [0-9] <digits> <oids> 
+        	return parseOidValue(bytes, pos);
+        }
+    }
+
+    /**
+     * Parse this rule : <br>
+     * <p>
+     * &lt;attributeTypeAndValues&gt;    ::= &lt;spaces&gt; '+' &lt;spaces&gt; &lt;attributeType&gt; &lt;spaces&gt; '=' &lt;spaces&gt; &lt;attributeValue&gt; &lt;attributeTypeAndValues&gt; | e
+     * </p>
+     * 
+     * @param bytes The buffer to parse
+     * @param pos The current position in the byte buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer
+     */
+    protected static int parseAttributeTypeAndValues( byte[] bytes, int pos )
+    {
+
+        while ( true )
+        {
+            pos = parseSpaces( bytes, pos );
+
+            if ( StringUtils.isCharASCII( bytes, pos, '+' ) )
+            {
+                pos++;
+            }
+            else
+            {
+
+                // <attributeTypeAndValues> ::= e
+                return pos;
+            }
+
+            pos = parseSpaces( bytes, pos );
+
+            if ( ( pos = parseAttributeType( bytes, pos ) ) == -1 )
+            {
+
+                return -1;
+            }
+
+            pos = parseSpaces( bytes, pos );
+
+            if ( StringUtils.isCharASCII( bytes, pos, '=' ) )
+            {
+                pos++;
+            }
+            else
+            {
+
+                return -1;
+            }
+
+            pos = parseSpaces( bytes, pos );
+
+            return parseAttributeValue( bytes, pos );
+        }
+    }
+
+    /**
+     * Parse this rule : <br>
+     * <p>
+     * &lt;name-component&gt;    ::= &lt;attributeType&gt; &lt;spaces&gt; '=' &lt;spaces&gt; &lt;attributeValue&gt; &lt;attributeTypeAndValues&gt;
+     * </p>
+     * 
+     * @param bytes The buffer to parse
+     * @param pos The current position in the buffer
+     * @return The new position in the byte buffer, or -1 if the rule does not apply to the byte buffer 
+     */
+    protected static int parseNameComponent( byte[] bytes, int pos )
+    {
+
+        if ( ( pos = parseAttributeType( bytes, pos ) ) == -1 )
+        {
+
+            return -1;
+        }
+
+        pos = parseSpaces( bytes, pos );
+
+        if ( StringUtils.isCharASCII( bytes, pos, '=' ) == false )
+        {
+
+            return -1;
+        }
+        else
+        {
+            pos++;
+        }
+
+        pos = parseSpaces( bytes, pos );
+
+        if ( ( pos = parseAttributeValue( bytes, pos ) ) == -1 )
+        {
+
+            return -1;
+        }
+
+        return parseAttributeTypeAndValues( bytes, pos );
+    }
+
+    /**
+     * Construct an empty LdapDN object
+     */
+    public RelativeLdapDN(int length, boolean isStreamed)
+    {
+        super(length, isStreamed);
+    }
+    
+    /**
+     * Construct an empty LdapDN object
+     */
+    public RelativeLdapDN()
+    {
+        super(0, false);
+    }
+    
+    /**
+     * Parse a buffer and checks that it is a valid relative DN <br>
+     * 
+     * @param bytes The byte buffer that contains the relative DN
+     * @exception A DecoderException is thrown if the buffer does not contains a valid relative DN.
+     */
+    public RelativeLdapDN( byte[] bytes ) throws DecoderException
+    {
+
+        if ( bytes == null || bytes.length == 0)
+        {
+            return;
+        }
+        
+        int pos = 0;
+
+        // Parse the name component
+        if ( ( pos = parseNameComponent( bytes, pos ) ) == -1 )
+        {
+            throw new DecoderException( "Bad relative DN : " + new String( bytes) );
+        }
+        
+        setData(bytes);
+    }
+}

Added: directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/utils/DNUtils.java
URL: http://svn.apache.org/viewcvs/directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/utils/DNUtils.java?rev=234264&view=auto
==============================================================================
--- directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/utils/DNUtils.java (added)
+++ directory/shared/ldap/branches/new-codec-integration/apache2-provider/src/java/main/org/apache/asn1new/ldap/codec/utils/DNUtils.java Sun Aug 21 09:53:27 2005
@@ -0,0 +1,385 @@
+/*
+ *   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.utils;
+
+import org.apache.asn1new.util.StringUtils;
+
+/**
+ * Utility class used by the LdapDN Parser.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DNUtils
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** <safe-init-char>    ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x1F] | [0x21-0x39] | 0x3B | [0x3D-0x7F] */
+    private static final boolean[] SAFE_INIT_CHAR =
+    {
+        false, true, true, true, true, true, true, true, true, true, false, true, true, false,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, false, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, false,
+        true, false, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true
+    };
+
+    /** <safe-char>        ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x7F] */
+    private static final boolean[] SAFE_CHAR =
+    {
+        false, true, true, true, true, true, true, true, true, true, false, true, true, false,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true
+    };
+
+    /** <base64-char>    ::= 0x2B | 0x2F | [0x30-0x39] | 0x3D | [0x41-0x5A] | [0x61-0x7A] */
+    private static final boolean[] BASE64_CHAR =
+    {
+        false, false, false, false, false, false, false, false, false, false, false, false, false,
+        false, false, false, false, false, false, false, false, false, false, false, false, false,
+        false, false, false, false, false, false, false, false, false, false, false, false, false,
+        false, false, false, false, true, false, false, false, true, true, true, true, true, true,
+        true, true, true, true, true, false, false, false, true, false, false, false, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, false, false, false, false, false,
+        false, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+        true, true, true, true, true, true, true, true, true, true, true, true, false, false,
+        false, false, false
+    };
+
+    /** '"'  | '#'  | '+'  | ','  | [0-9] | ';'  | '<'  | '='  | '>'  | [A-F] | '\' | [a-f] 
+     * 0x22 | 0x23 | 0x2B | 0x2C | [0x30-0x39] | 0x3B | 0x3C | 0x3D | 0x3E | [0x41-0x46] | 0x5C | [0x61-0x66] */
+    private static final boolean[] PAIR_CHAR =
+    {
+        false, false, false, false, false, false, false, false, false, false, false, false, false,
+        false, false, false, false, false, false, false, false, false, false, false, false, false,
+        false, false, false, false, false, false, false, false, true, true, false, false, false,
+        false, false, false, false, true, true, false, false, false, true, true, true, true, true,
+        true, true, true, true, true, false, true, true, true, true, false, false, true, true,
+        true, true, true, true, false, false, false, false, false, false, false, false, false,
+        false, false, false, false, false, false, false, false, false, false, false, false, true,
+        false, false, false, false, true, true, true, true, true, true, false, false, false, false,
+        false, false, false, false, false, false, false, false, false, false, false, false, false,
+        false, false, false, false, false, false, false, false
+    };
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Walk the buffer while characters are Safe String characters :
+     *  <safe-string>    ::= <safe-init-char> <safe-chars>
+     *  <safe-init-char> ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x1F] | [0x21-0x39] | 0x3B | [0x3D-0x7F]
+     *  <safe-chars>     ::= <safe-char> <safe-chars> |
+     *  <safe-char>      ::= [0x01-0x09] | 0x0B | 0x0C | [0x0E-0x7F]
+     *
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     *
+     * @return The position of the first character which is not a Safe Char
+     */
+    public static int parseSafeString( byte[] byteArray, int index )
+    {
+        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
+                ( index >= byteArray.length ) )
+        {
+            return -1;
+        }
+        else
+        {
+            byte c = byteArray[index];
+
+            if ( ( c > 127 ) || ( SAFE_INIT_CHAR[c] == false ) )
+            {
+                return -1;
+            }
+
+            index++;
+
+            while ( index < byteArray.length )
+            {
+                c = byteArray[index];
+
+                if ( ( c > 127 ) || ( SAFE_CHAR[c] == false ) )
+                {
+                    break;
+                }
+
+                index++;
+            }
+
+            return index;
+        }
+    }
+
+    /**
+     * Walk the buffer while characters are Alpha characters :
+     *  <alpha>    ::= [0x41-0x5A] | [0x61-0x7A]
+     * 
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     *
+     * @return The position of the first character which is not an Alpha Char
+     */
+    public static int parseAlphaASCII( byte[] byteArray, int index )
+    {
+        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
+                ( index >= byteArray.length ) )
+        {
+            return -1;
+        }
+        else
+        {
+            byte c = byteArray[index++];
+
+            if ( ( c > 127 ) || ( StringUtils.ALPHA[c] == false ) )
+            {
+                return -1;
+            }
+            else
+            {
+                return index;
+            }
+        }
+    }
+
+    /**
+     * Check if the current character is a Pair Char
+     *  <pairchar>    ::= ',' | '=' | '+' | '<' | '>' | '#' | ';' | '\' | '"' | [0-9a-fA-F] [0-9a-fA-F]
+     *  
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     *
+     * @return <code>true</code> if the current character is a Pair Char
+     */
+    public static boolean isPairChar( byte[] byteArray, int index )
+    {
+        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
+                ( index >= byteArray.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            byte c = byteArray[index];
+
+            if ( ( c > 127 ) || ( PAIR_CHAR[c] == false ) )
+            {
+                return false;
+            }
+            else
+            {
+                if ( StringUtils.isHex( byteArray, index++ ) )
+                {
+                    return StringUtils.isHex( byteArray, index );
+                }
+                else
+                {
+                    return true;
+                }
+            }
+        }
+    }
+
+    /**
+     * Check if the current character is a String Char.
+     * Chars are Unicode, not ASCII.
+     *  <stringchar>    ::= [0x00-0xFFFF] - [,=+<>#;\"\n\r]
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     *
+     * @return The current char if it is a String Char, or '#' (this is
+     * simpler than throwing an exception :)
+     */
+    public static int isStringChar( byte[] byteArray, int index )
+    {
+        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
+                ( index >= byteArray.length ) )
+        {
+            return -1;
+        }
+        else
+        {
+            byte c = byteArray[index];
+
+            if ( ( c == 0x0A ) ||
+                    ( c == 0x0D ) ||
+                    ( c == '"' ) ||
+                    ( c == '#' ) ||
+                    ( c == '+' ) ||
+                    ( c == ',' ) ||
+                    ( c == ';' ) ||
+                    ( c == '<' ) ||
+                    ( c == '=' ) ||
+                    ( c == '>' ) )
+            {
+                return -1;
+            }
+            else
+            {
+                return StringUtils.countBytesPerChar(byteArray, index);
+            }
+        }
+    }
+
+    /**
+     * Check if the current character is a Quote Char
+     * We are testing Unicode chars
+     *  <quotechar>    ::= [0x00-0xFFFF] - [\"]
+     * 
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     *
+     * @return <code>true</code> if the current character is a Quote Char
+     */
+    public static int isQuoteChar( byte[] byteArray, int index )
+    {
+        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
+                ( index >= byteArray.length ) )
+        {
+            return -1;
+        }
+        else
+        {
+            byte c = byteArray[index];
+
+            if ( ( c == '\\' ) || ( c == '"' ) )
+            {
+                return -1;
+            }
+            else
+            {
+                return StringUtils.countBytesPerChar(byteArray, index);
+            }
+        }
+    }
+
+    /**
+     * Parse an hex pair
+     *   <hexpair>    ::= <hex> <hex>
+     *
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     *
+     * @return The new position, -1 if the buffer does not contain an HexPair, -2 if the
+     * buffer contains an hex byte but not two.
+     */
+    public static int parseHexPair( byte[] byteArray, int index )
+    {
+        if ( StringUtils.isHex( byteArray, index ) )
+        {
+            if ( StringUtils.isHex( byteArray, index + 1 ) )
+            {
+                return index + 2;
+            }
+            else
+            {
+                return -2;
+            }
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+    /**
+     * Parse an hex string, which is a list of hex pairs
+     *  <hexstring>    ::= <hexpair> <hexpairs>
+     *  <hexpairs>    ::= <hexpair> <hexpairs> | e
+     *
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     *
+     * @return Return the first position which is not an hex pair, or -1 if there is no
+     * hexpair at the beginning or if an hexpair is invalid (if we have only one hex instead of 2)
+     */
+    public static int parseHexString( byte[] byteArray, int index )
+    {
+        int result = parseHexPair( byteArray, index );
+
+        if ( result < 0 )
+        {
+            return -1;
+        }
+        else
+        {
+            index += 2;
+        }
+
+        while ( ( result = parseHexPair( byteArray, index ) ) >= 0 )
+        {
+            index += 2;
+        }
+
+        return ( ( result == -2 ) ? -1 : index );
+    }
+
+    /**
+     * Walk the buffer while characters are Base64 characters : 
+     *     <base64-string>      ::= <base64-char> <base64-chars>
+     *  <base64-chars>       ::= <base64-char> <base64-chars> |
+     *  <base64-char>        ::= 0x2B | 0x2F | [0x30-0x39] | 0x3D | [0x41-0x5A] | [0x61-0x7A]
+     *
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     *
+     * @return The position of the first character which is not a Base64 Char
+     */
+    public static int parseBase64String( byte[] byteArray, int index )
+    {
+        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
+                ( index >= byteArray.length ) )
+        {
+            return -1;
+        }
+        else
+        {
+            byte c = byteArray[index];
+
+            if ( ( c > 127 ) || ( BASE64_CHAR[c] == false ) )
+            {
+                return -1;
+            }
+
+            index++;
+
+            while ( index < byteArray.length )
+            {
+                c = byteArray[index];
+
+                if ( ( c > 127 ) || ( BASE64_CHAR[c] == false ) )
+                {
+                    break;
+                }
+
+                index++;
+            }
+
+            return index;
+        }
+    }
+
+}



Mime
View raw message