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/08/21 20:51:13 UTC

svn commit: r234315 [2/2] - in /directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new: ber/containers/ ber/grammar/ ber/tlv/ primitives/ util/

Added: directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/BitString.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/BitString.java?rev=234315&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/BitString.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/BitString.java Sun Aug 21 11:51:02 2005
@@ -0,0 +1,298 @@
+/*
+ *   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.primitives;
+
+import org.apache.asn1new.DecoderException;
+
+
+/**
+ * Implement the Bit String primitive type.
+ * 
+ * A BitString is internally stored as an array of int. 
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class BitString
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** A null MutableString */
+    public static final BitString EMPTY_STRING = new BitString();
+
+    /** A flag to mark the OctetString as Streamed (for OctetString larger than 1024 chars) */
+    // TODO implement the streaming...
+    public static final boolean STREAMED = true;
+
+    /** The default length of an BitString */
+    private static final int DEFAULT_LENGTH = 8;
+
+    //~ Instance fields ----------------------------------------------------------------------------
+
+    /** The number of unused ints */
+    private int nbUnusedBits;
+
+    /** Tells if the OctetString is streamed or not */
+    private boolean isStreamed;
+
+    /** The string is stored in a byte array */
+    private byte[] bytes;
+
+    /** Actual length of the byte array */
+    private int nbBytes;
+
+    /** Actual length of the bit string */
+    private int nbBits;
+
+    //~ Constructors -------------------------------------------------------------------------------
+
+    /**
+     * Creates a BitString, with a default length.
+     */
+    public BitString()
+    {
+        bytes        = new byte[DEFAULT_LENGTH];
+        nbBytes      = 0;
+        isStreamed   = false;
+        nbUnusedBits = 0;
+        nbBits       = 0;
+    }
+
+    /**
+     * Creates a BitString with a specific length (length is the number
+     * of bytes).
+     *
+     * @param length The BitString length (it's a number of bits)
+    */
+    public BitString(  int length )
+    {
+        nbBits = length;
+
+        // As we store values in bytes, we must divide the length by 8
+        nbBytes      = ( length / 8 ) + ( ( ( length % 8 ) != 0 ) ? 1 : 0 );
+
+        nbUnusedBits = length % 8;
+
+        if ( nbBytes > DEFAULT_LENGTH )
+        {
+
+            // TODO : implement the streaming
+            isStreamed = true;
+            bytes      = new byte[nbBytes];
+        }
+        else
+        {
+            isStreamed = false;
+            bytes      = new byte[nbBytes];
+        }
+    }
+
+    /**
+     * Creates a streamed BitString with a specific length.
+     * Actually, it's just a simple BitString.
+     * TODO Implement streaming.
+     * 
+     * @param length The BitString length, in number of bits 
+     * @param isStreamed Tells if the BitString must be streamed or not 
+    */
+    public BitString(  int length, boolean isStreamed )
+    {
+        nbBits          = length;
+        this.isStreamed = isStreamed;
+        nbBytes         = ( length / 8 ) + ( ( ( length % 8 ) != 0 ) ? 1 : 0 );
+
+        nbUnusedBits    = length % 8;
+
+        if ( isStreamed )
+        {
+
+            // TODO : implement the streaming
+            bytes = new byte[nbBytes];
+        }
+        else
+        {
+            bytes = new byte[nbBytes];
+        }
+    }
+
+    /**
+     * Creates a BitString with a value.  
+     * 
+     * @param bytes The value to store. The first byte contains the number 
+     * of unused bits
+     */
+    public BitString(  byte[] bytes )
+    {
+        nbBytes = bytes.length - 1;
+
+        if ( nbBytes > DEFAULT_LENGTH )
+        {
+            isStreamed = true;
+
+            // It will be a streamed OctetString.
+            // TODO : implement the streaming
+            bytes = new byte[nbBytes];
+        }
+        else
+        {
+            isStreamed = false;
+
+            bytes      = new byte[nbBytes];
+        }
+
+        setBytes( bytes, nbBytes );
+    }
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Set the value into the bytes.
+     * @param bytes The bytes to copy
+     * @param nbBytes Number of bytes to copy
+    */
+    private void setBytes( byte[] bytes, int nbBytes )
+    {
+
+        // The first byte contains the number of unused ints
+        nbUnusedBits = bytes[0] & 0x07;
+        nbBits       = ( nbBytes * 8 ) - nbUnusedBits;
+
+        // We have to transfer the data from bytes to ints
+        for ( int i = 0; i < nbBytes; i++ )
+        {
+            this.bytes[i] = bytes[i + 1];
+        }
+    }
+
+    /**
+     * Set a new BitString in the BitString. It will replace the old BitString,
+     * and reset the current length with the new one.
+     * 
+     * @param bytes The string to store
+     */
+    public void setData( byte[] bytes )
+    {
+
+        if ( ( bytes == null ) || ( bytes.length == 0 ) )
+        {
+            nbBits = -1;
+            return;
+        }
+
+        int nbBytes = bytes.length - 1;
+
+        if ( ( nbBytes > DEFAULT_LENGTH ) && ( bytes.length < nbBytes ) )
+        {
+
+            // The current size is too small.
+            // We have to allocate more space
+            // TODO : implement the streaming
+            bytes = new byte[nbBytes];
+        }
+
+        setBytes( bytes, nbBytes );
+    }
+    
+    /**
+     * Get the representation of a BitString
+     * @return A byte array which represent the BitString
+     */
+    public byte[] getData()
+    {
+        return bytes;
+    }
+
+    /**
+     * Get the number of unused bits 
+     * @return A byte which represent the number of unused bits
+     */
+    public byte getUnusedBits()
+    {
+        return (byte)nbUnusedBits;
+    }
+
+    /**
+     * Get the bit stored into the BitString at a specific position? The position start at 0,
+     * which is on the left :
+     * With '1001 000x', where x is an unused bit, 
+     *       ^ ^    ^^ 
+     *       | |    ||
+     *       | |    |+---- getBit(7) -> DecoderException
+     *       | |    +----- getBit(6) = 0
+     *       | +---------- getBit(2) = 0
+     *       +------------ getBit(0) = 1 
+     * @param pos The position of the requested bit.
+     * @return <code>true</code> if the bit is set, <code>false</code> otherwise
+     */
+    public boolean getBit( int pos ) throws DecoderException
+    {
+
+        if ( pos > nbBits )
+        {
+            throw new DecoderException(
+                "Cannot get a bit at position " + pos + " when the BitString contains only " +
+                nbBits + " ints" );
+        }
+
+        int posInt    = pos / 8;
+
+        int bitNumber = 7 - ( pos % 8 );
+        int res       = bytes[posInt] & ( 1 << bitNumber );
+        return res != 0;
+    }
+
+    /**
+     * Return a native String representation of the BitString.
+     * @return A String representing the BitString
+    */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        try
+        {
+
+            for ( int i = 0; i < nbBits; i++ )
+            {
+
+                if ( getBit( i ) )
+                {
+                    sb.append( '1' );
+                }
+                else
+                {
+                    sb.append( '0' );
+                }
+            }
+        }
+        catch ( DecoderException de )
+        {
+            return "Invalid BitString";
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Tells if the OctetString is streamed or not
+     * @return <code>true</code> if the OctetString is streamed.
+     */
+    public boolean isStreamed()
+    {
+        return isStreamed;
+    }
+}

Added: directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/OID.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/OID.java?rev=234315&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/OID.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/OID.java Sun Aug 21 11:51:02 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.primitives;
+
+import org.apache.asn1new.DecoderException;
+
+
+/**
+ * This class implement an OID (Object Identifier).
+ * 
+ * An OID is encoded as a list of bytes representing integers. 
+ * 
+ * An OID has a numeric representation where number are separated with dots :
+ * SPNEGO Oid = 1.3.6.1.5.5.2
+ * 
+ * Translating from a byte list to a dot separated list of number follows the rules :
+ * - the first number is in [0..2]
+ * - the second number is in [0..39] if the first number is 0 or 1
+ * - the first byte has a value equal to : number 1 * 40 + number two
+ * - the upper bit of a byte is set if the next byte is a part of the number
+ * 
+ * For instance, the SPNEGO Oid (1.3.6.1.5.5.2) will be encoded : 
+ * 1.3 -> 0x2B (1*40 + 3 = 43 = 0x2B) 
+ * .6  -> 0x06 
+ * .1  -> 0x01 
+ * .5  -> 0x05 
+ * .5  -> 0x05 
+ * .2  -> 0x02 
+ * 
+ * The Kerberos V5 Oid (1.2.840.48018.1.2.2)  will be encoded :
+ * 1.2   -> 0x2A (1*40 + 2 = 42 = 0x2A) 
+ * 840   -> 0x86 0x48 (840 = 6 * 128 + 72 = (0x06 | 0x80) 0x48 = 0x86 0x48
+ * 48018 -> 0x82 0xF7 0x12 (2 * 128 * 128 + 119 * 128 + 18 = (0x02 | 0x80) (0x77 | 0x80) 0x12
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OID
+{
+    //~ Instance fields ----------------------------------------------------------------------------
+
+    /** The OID as a array of int */
+    private int[] oidValues;
+
+    //~ Constructors -------------------------------------------------------------------------------
+
+    /**
+     * Creates a new OID object.
+     */
+    public OID()
+    {
+
+        // We should not create this kind of object directly, it must
+        // be created through the factory.
+    }
+
+    /**
+     * Create a new OID object from a byte array
+     * @param oid
+     */
+    public OID( byte[] oid ) throws DecoderException
+    {
+        setOID(oid);
+    }
+
+    /**
+     * Create a new OID object from a String
+     * @param oid The String which is supposed to be an OID
+     */
+    public OID( String oid ) throws DecoderException
+    {
+        setOID( oid );
+    }
+
+    //~ Methods ------------------------------------------------------------------------------------
+    /**
+     * Set the OID. It will be translated from a byte array to an internal representation.
+     * @param oid The bytes containing the OID
+     */
+    public void setOID( byte[] oid ) throws DecoderException
+    {
+
+        if ( oid == null )
+        {
+            throw new DecoderException( "Null OID" );
+        }
+
+        if ( oid.length < 1 )
+        {
+            throw new DecoderException( "Invalid OID : " + oid );
+        }
+
+        // First, we have to calculate the number of int to allocate
+        int nbValues = 1;
+
+        int pos      = 0;
+
+        while ( pos < oid.length )
+        {
+
+            if ( oid[pos] >= 0 )
+            {
+                nbValues++;
+            }
+
+            pos++;
+        }
+
+        oidValues = new int[nbValues];
+
+        nbValues  = 0;
+        pos       = 0;
+
+        int accumulator = 0;
+
+
+        if ( ( oid[0] < 0 ) || ( oid[0] >= 80 ) )
+        {
+            oidValues[nbValues++] = 2;
+
+            while ( pos < oid.length )
+            {
+
+                if ( oid[pos] >= 0 )
+                {
+                    oidValues[nbValues++] = ( ( accumulator << 7 ) + oid[pos] ) - 80;
+                    accumulator           = 0;
+                    pos++;
+                    break;
+                }
+                else
+                {
+                    accumulator = ( accumulator << 7 ) + ( oid[pos] & 0x007F );
+                }
+
+                pos++;
+            }
+        }
+        else if ( oid[0] < 40 )
+        {
+            oidValues[nbValues++] = 0;
+            oidValues[nbValues++] = oid[pos++]; // itu-t
+        }
+        else // oid[0] is < 80
+        {
+            oidValues[nbValues++] = 1;
+            oidValues[nbValues++] = oid[pos++] - 40; // iso
+        }
+
+        while ( pos < oid.length )
+        {
+
+            if ( oid[pos] >= 0 )
+            {
+                oidValues[nbValues++] = ( accumulator << 7 ) + oid[pos];
+                accumulator           = 0;
+            }
+            else
+            {
+                accumulator = ( accumulator << 7 ) + ( oid[pos] & 0x007F );
+            }
+
+            pos++;
+        }
+    }
+
+    /**
+     * Set the OID. It will be translated from a String to an internal representation.
+     * The syntax will be controled in respect with this rule :
+     *  OID = ( [ '0' | '1' ] '.' [ 0 .. 39 ] | '2' '.' int) ( '.' int )* 
+     * @param oid The String containing the OID
+     */
+    public void setOID( String oid ) throws DecoderException
+    {
+
+        if ( ( oid == null ) || ( oid.length() == 0 ) )
+        {
+            throw new DecoderException( "Null OID" );
+        }
+
+        int     nbInts  = 1;
+        byte[]  bytes   = oid.getBytes();
+        boolean dotSeen = false;
+
+        // Count the number of int to allocate.
+        for ( int i = 0; i < bytes.length; i++ )
+        {
+
+            if ( bytes[i] == '.' )
+            {
+
+                if ( dotSeen )
+                {
+
+                    // Two dots, that's an error !
+                    throw new DecoderException( "Invalid OID : " + oid );
+                }
+
+                nbInts++;
+                dotSeen = true;
+            }
+            else
+            {
+                dotSeen = false;
+            }
+        }
+
+        // We must have at least 2 ints
+        if ( nbInts < 2 )
+        {
+            throw new DecoderException( "Invalid OID : " + oid );
+        }
+
+        oidValues = new int[nbInts];
+
+        int pos    = 0;
+        int intPos = 0;
+        
+        // This flag is used to forbid a second value above 39 if the 
+        // first value is 0 or 1 (itu_t or iso arcs)
+        boolean ituOrIso = false;
+
+        // The first value
+        switch ( bytes[pos] )
+        {
+
+            case '0' : // itu-t
+            case '1' : // iso
+                ituOrIso = true;
+                // fallthrough
+                
+            case '2' : // joint-iso-itu-t
+                oidValues[intPos++] = bytes[pos++] - '0';
+                break;
+
+            default : // error, this value is not allowed
+                throw new DecoderException( "Invalid OID : " + oid );
+        }
+
+        // We must have a dot
+        if ( bytes[pos++] != '.' )
+        {
+            throw new DecoderException( "Invalid OID : " + oid );
+        }
+
+        dotSeen = true;
+
+        int value = 0;
+
+        for ( int i = pos; i < bytes.length; i++ )
+        {
+
+            if ( bytes[i] == '.' )
+            {
+
+                if ( dotSeen )
+                {
+
+                    // Two dots, that's an error !
+                    throw new DecoderException( "Invalid OID : " + oid );
+                }
+
+                if (ituOrIso && value > 39)
+                {
+                    throw new DecoderException( "Invalid OID : " + oid );
+                }
+                else
+                {
+                    ituOrIso = false;
+                }
+                
+                nbInts++;
+                dotSeen             = true;
+                oidValues[intPos++] = value;
+                value               = 0;
+            }
+            else if ( ( bytes[i] >= 0x30 ) && ( bytes[i] <= 0x39 ) )
+            {
+                dotSeen = false;
+                value   = ( ( value * 10 ) + bytes[i] ) - '0';
+                
+            }
+            else
+            {
+
+                // We don't have a number, this is an error
+                throw new DecoderException( "Invalid OID : " + oid );
+            }
+        }
+
+        oidValues[intPos++] = value;
+    }
+
+    /**
+     * Get an array of int from the OID
+     * @return An array of int representing the OID
+     */
+    public int[] getOIDValues()
+    {
+        return oidValues;
+    }
+
+    /**
+     * Get the number of bytes necessary to store the OID
+     * @return An int representing the length of the OID
+     */
+    public int getOIDLength()
+    {
+        int value = oidValues[0] * 40 + oidValues[1];
+        int nbBytes = 0;
+
+        if (value < 128)
+        {
+            nbBytes = 1;
+        } 
+        else if (value < 16384)
+        {
+            nbBytes = 2;
+        }
+        else if (value < 2097152)
+        {
+            nbBytes = 3;
+        }
+        else if (value < 268435456)
+        {
+            nbBytes = 4;
+        }
+        else 
+        {
+            nbBytes = 5;
+        }
+
+        for (int i = 2; i < oidValues.length; i++ )
+        {
+            value = oidValues[i];
+            
+            if (value < 128)
+            {
+                nbBytes += 1;
+            } 
+            else if (value < 16384)
+            {
+                nbBytes += 2;
+            }
+            else if (value < 2097152)
+            {
+                nbBytes += 3;
+            }
+            else if (value < 268435456)
+            {
+                nbBytes += 4;
+            }
+            else 
+            {
+                nbBytes += 5;
+            }
+        }
+        
+        return nbBytes;
+    }
+
+    /**
+     * Get an array of bytes from the OID
+     * @return An array of int representing the OID
+     */
+    public byte[] getOID()
+    {
+        int value = oidValues[0] * 40 + oidValues[1];
+        int firstValues = value;
+        
+        byte[] bytes = new byte[getOIDLength()];
+        int pos = 0;
+        
+        if (oidValues[0] < 2)
+        {
+            bytes[pos++] = (byte)(oidValues[0] * 40 + oidValues[1]);
+        } 
+        else
+        {
+            if (firstValues < 128)
+            {
+                bytes[pos++] = (byte)(firstValues);
+            } 
+            else if (firstValues < 16384)
+            {
+                bytes[pos++] = (byte)( ( firstValues >> 7 ) | 0x0080 );
+                bytes[pos++] = (byte)( firstValues & 0x007F);
+            }
+            else if (value < 2097152)
+            {
+                bytes[pos++] = (byte)( ( firstValues >> 14 ) | 0x0080);
+                bytes[pos++] = (byte)( ( ( firstValues >> 7 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( firstValues & 0x007F);
+            }
+            else if (value < 268435456)
+            {
+                bytes[pos++] = (byte)( ( firstValues >> 21 ) | 0x0080);
+                bytes[pos++] = (byte)( ( ( firstValues >> 14 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( ( ( firstValues >> 7 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( firstValues & 0x007F);
+            }
+            else 
+            {
+                bytes[pos++] = (byte)( ( firstValues >> 28 ) | 0x0080);
+                bytes[pos++] = (byte)( ( ( firstValues >> 21 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( ( ( firstValues >> 14 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( ( ( firstValues >> 7 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( firstValues & 0x007F);
+            }
+        }
+        
+        for (int i = 2; i < oidValues.length; i++ )
+        {
+            value = oidValues[i];
+            
+            if (value < 128)
+            {
+                bytes[pos++] = (byte)(value);
+            } 
+            else if (value < 16384)
+            {
+                bytes[pos++] = (byte)( ( value >> 7 ) | 0x0080 );
+                bytes[pos++] = (byte)( value & 0x007F);
+            }
+            else if (value < 2097152)
+            {
+                bytes[pos++] = (byte)( ( value >> 14 ) | 0x0080);
+                bytes[pos++] = (byte)( ( ( value >> 7 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( value & 0x007F);
+            }
+            else if (value < 268435456)
+            {
+                bytes[pos++] = (byte)( ( value >> 21 ) | 0x0080);
+                bytes[pos++] = (byte)( ( ( value >> 14 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( ( ( value >> 7 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( value & 0x007F);
+            }
+            else 
+            {
+                bytes[pos++] = (byte)( ( value >> 28 ) | 0x0080);
+                bytes[pos++] = (byte)( ( ( value >> 21 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( ( ( value >> 14 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( ( ( value >> 7 ) & 0x007F) | 0x0080);
+                bytes[pos++] = (byte)( value & 0x007F);
+            }
+        }
+        
+        return bytes;
+    }
+
+    /**
+     * Get the OID as a String
+     * @return A String representing the OID
+     */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+        
+        if (oidValues != null)
+        {
+	        sb.append( oidValues[0] );
+	
+	        for ( int i = 1; i < oidValues.length; i++ )
+	        {
+	            sb.append( '.' ).append( oidValues[i] );
+	        }
+        }
+
+        return sb.toString();
+    }
+}

Added: directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/OctetString.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/OctetString.java?rev=234315&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/OctetString.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/primitives/OctetString.java Sun Aug 21 11:51:02 2005
@@ -0,0 +1,221 @@
+/*
+ *   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.primitives;
+
+import org.apache.asn1new.util.StringUtils;
+
+
+/**
+ * Implement the Octet String primitive type.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class OctetString
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** A null OctetString */
+    public static final OctetString EMPTY_STRING = new OctetString(0);
+
+    /** A flag to mark the OctetString as Streamed (for OctetString larger than 1024 chars) */
+    // TODO implement the streaming...
+    public static final boolean STREAMED = true;
+
+    /** The default length of an octet string */
+    private static final int DEFAULT_LENGTH = 1024;
+
+    //~ Instance fields ----------------------------------------------------------------------------
+
+    /** Tells if the OctetString is streamed or not */
+    private boolean isStreamed;
+
+    /** The string is stored in a byte array */
+    private byte[] bytes;
+
+    /** Actual length of the string */
+    private int length;
+
+    //~ Constructors -------------------------------------------------------------------------------
+
+    /**
+     * Creates a OctetString with a specific length.
+     * @param length The OctetString length
+    */
+    public OctetString(  int length )
+    {
+        this.length = length;
+
+        if ( length > DEFAULT_LENGTH )
+        {
+
+            // TODO : implement the streaming
+            isStreamed = true;
+            bytes      = new byte[length];
+        }
+        else
+        {
+            isStreamed = false;
+            bytes      = new byte[length];
+        }
+    }
+
+    /**
+     * Creates a streamed OctetString with a specific length.
+     * Actually, it's just a simple OctetString.
+     * TODO Implement streaming.
+     * @param length The OctetString length 
+     * @param isStreamed Tells if the OctetString must be streamed or not 
+    */
+    public OctetString(  int length, boolean isStreamed )
+    {
+        this.isStreamed = isStreamed;
+        this.length     = length;
+
+        if ( isStreamed )
+        {
+
+            // TODO : implement the streaming
+            bytes = new byte[length];
+        }
+        else
+        {
+            bytes = new byte[length];
+
+        }
+    }
+
+    /**
+     * Creates a OctetString with a value.  
+     * 
+     * @param bytes The value to store.
+     */
+    public OctetString(  byte[] bytes )
+    {
+        length = bytes.length;
+
+        if ( length > DEFAULT_LENGTH )
+        {
+            isStreamed = true;
+
+            // It will be a streamed OctetString.
+            // TODO : implement the streaming
+            this.bytes = new byte[length];
+
+            // We have to copy the data, because the parameter
+            // is not a copy.
+            System.arraycopy( bytes, 0, this.bytes, 0, length );
+        }
+        else
+        {
+            isStreamed = false;
+
+            this.bytes = new byte[length];
+
+            // We have to copy the data, because the parameter
+            // is not a copy.
+            System.arraycopy( bytes, 0, this.bytes, 0, length );
+        }
+    }
+
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Set a new octetString in the OctetString. It will replace the old OctetString,
+     * and reset the current length with the new one.
+     * 
+     * @param bytes The string to store
+     */
+    public void setData( byte[] bytes )
+    {
+        length = bytes.length;
+
+        if ( length > DEFAULT_LENGTH )
+        {
+
+            if ( this.bytes.length < length )
+            {
+
+                // The current size is too small.
+                // We have to allocate more space
+                // It will be a streamed OctetString.
+                // TODO : implement the streaming
+                this.bytes = new byte[length];
+            }
+
+            // We have to copy the data, because the parameter
+            // is not a copy.
+            System.arraycopy( bytes, 0, this.bytes, 0, length );
+        }
+        else
+        {
+
+            // We have to copy the data, because the parameter
+            // is not a copy.
+            System.arraycopy( bytes, 0, this.bytes, 0, length );
+        }
+    }
+
+    /**
+     * Get the data stored into the OctetString
+     * @return A byte array
+     */
+    public byte[] getValue()
+    {
+        return bytes;
+    }
+
+    /**
+     * Return a native String representation of the OctetString.
+     * @return A string representing the OctetString
+    */
+    public String toString()
+    {
+
+        StringBuffer sb = new StringBuffer();
+
+        for ( int i = 0; i < length; i++ )
+        {
+            if ( ( bytes[i] < 32 ) || ( bytes[i] > 127 ) ) 
+            {
+                sb.append( StringUtils.dumpByte( bytes[i] ) );
+            }
+            else
+            {
+                sb.append( (char)bytes[i] );
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Tells if the OctetString is streamed or not
+     * @return <code>true</code> if the OctetString is streamed.
+     */
+    public boolean isStreamed()
+    {
+        return isStreamed;
+    }
+    
+    /**
+     * @return Returns the length.
+     */
+    public int getLength() 
+    {
+        return length;
+    }
+}

Added: directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/IntegerDecoder.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/IntegerDecoder.java?rev=234315&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/IntegerDecoder.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/IntegerDecoder.java Sun Aug 21 11:51:02 2005
@@ -0,0 +1,85 @@
+/*
+ *   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.util;
+
+import org.apache.asn1new.DecoderException;
+import org.apache.asn1new.ber.tlv.Value;
+
+
+/**
+ * Parse and decode an Integer value.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class IntegerDecoder
+{
+    //~ Methods ------------------------------------------------------------------------------------
+
+    /**
+     * Parse a byte buffer and send back an integer, controling
+     * that this number is in a specified interval.
+     * @param value The byte buffer to parse
+     * @param min Lowest value allowed, included
+     * @param max Highest value allowed, included
+     *
+     * @return An integer
+     *
+     * @throws DecoderException Thrown if the byte stream does not contains an integer
+     */
+    public static int parse( Value value, int min, int max ) throws DecoderException
+    {
+
+        int    result = 0;
+
+        byte[] bytes  = value.getData();
+
+        if ( bytes.length > 4 )
+        {
+            throw new DecoderException(
+                "The value is more than 4 bytes long. This is not allowed for an integer" );
+        }
+
+        for ( int i = 0; ( i < bytes.length ) && ( i < 5 ); i++ )
+        {
+            result = ( result << 8 ) | ( bytes[i] & 0x00FF );
+        }
+
+        if ( ( result >= min ) && ( result <= max ) )
+        {
+
+            return result;
+        }
+        else
+        {
+            throw new DecoderException( "The value is not in the range [" + min + ", " + max + "]" );
+        }
+    }
+    
+    /**
+     * Parse a byte buffer and send back an integer 
+     *
+     * @param value The byte buffer to parse
+     *
+     * @return An integer
+     *
+     * @throws DecoderException Thrown if the byte stream does not contains an integer
+     */
+    public static int parse( Value value ) throws DecoderException
+    {
+    	return parse( value, Integer.MIN_VALUE, Integer.MAX_VALUE ); 
+    }
+}

Added: directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/MutableString.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/MutableString.java?rev=234315&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/MutableString.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/MutableString.java Sun Aug 21 11:51:02 2005
@@ -0,0 +1,137 @@
+/*
+ *   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.util;
+
+/**
+ * A Mutable version of the String class. This mutable String can be
+ * stored in a pool.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MutableString {
+    /** The string is stored in a char array */
+    private char[] string;
+    
+    /** We also store the byte array for performance sake */
+    private byte[] data;
+    
+    /** Actual length of the string. Be aware that it's a number of bytes,
+     * not a number of chars ! */
+    private int length;
+    
+    /** A null MutableString */
+    public transient static final MutableString EMPTY_STRING = new MutableString();
+    
+    /** A flag to mark the MutableString as Streamed (for string larger than 1024 chars) */
+    // TODO implement the streaming...
+    public transient static final boolean STREAMED = true;
+    
+    /**
+     * Creates a MutableString.
+     */
+    public MutableString()
+    {
+        string = null;
+        length = 0;
+    }
+    
+    /**
+     * Creates a MutableString.
+     */
+    public MutableString(String string)
+    {
+        this( string.getBytes() );
+    }
+    
+    /**
+     * Creates a MutableString with a specific length.
+     */
+    public MutableString(int length)
+    {
+        string = new char[length];
+        this.length = length;
+    }
+    
+    /**
+     * Creates a streamed MutableString with a specific length.
+     * Actually, it's just a simple MutableString.
+     * TODO Implement streaming.
+     */
+    public MutableString(int length, boolean isStreamed)
+    {
+        string = new char[length];
+        this.length = length;
+    }
+    
+    /**
+     * Creates a MutableString with a value. The stored string
+     * is coded in Unicode, so the bytes *MUST* be valid ! 
+     * @param bytes The value to store.
+     */
+    public MutableString(byte[] bytes)
+    {
+        setData( bytes );
+    }
+    
+    /**
+     * Set a new string in the MutableString. It will replace the old string,
+     * and reset the current length with the new one.
+     * 
+     * @param bytes The string to store
+     */
+    public void setData(byte[] bytes)
+    {
+        data = bytes;
+        length = bytes.length;
+        int charLength = StringUtils.countChars(bytes);
+        
+        string = new char[charLength];
+        
+        int pos = 0;
+        
+        for ( int i = 0; i < charLength; i++ )
+        {
+            string[i] = StringUtils.bytesToChar(bytes, pos);
+            pos += StringUtils.countBytesPerChar(bytes, pos); 
+        }
+    }
+    
+    /**
+     * @return Returns the length, as a number of bytes, not a number
+     * of chars.
+     */
+    public int getLength() 
+    {
+        return length;
+    }
+
+    /**
+     * @return Returns the data.
+     */
+    public byte[] getData()
+    {
+        return data;
+    }
+
+    /**
+     * Return a native String representation of the MutableString.
+     */
+    public String toString()
+    {
+        return length == 0 ? "" : new String(data, 0, length);
+    }
+}

Added: directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/StringUtils.java
URL: http://svn.apache.org/viewcvs/directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/StringUtils.java?rev=234315&view=auto
==============================================================================
--- directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/StringUtils.java (added)
+++ directory/asn1/branches/asn1-new-ber/ber-new/src/java/main/org/apache/asn1new/util/StringUtils.java Sun Aug 21 11:51:02 2005
@@ -0,0 +1,590 @@
+/*
+ *   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.util;
+
+/**
+ * Little helper class. Nothing that should stay here, but I need those 
+ * to debug.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class StringUtils
+{
+    //~ Static fields/initializers -----------------------------------------------------------------
+
+    /** Hex chars */
+    private static final byte[] HEX_CHAR =
+        new byte[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+    
+    private static int UTF8_MULTI_BYTES_MASK = 0x0080;
+    
+    private static int UTF8_TWO_BYTES_MASK = 0x00E0;
+    private static int UTF8_TWO_BYTES = 0x00C0;
+    
+    private static int UTF8_THREE_BYTES_MASK = 0x00F0;
+    private static int UTF8_THREE_BYTES = 0x00E0;
+
+    private static int UTF8_FOUR_BYTES_MASK = 0x00F8;
+    private static int UTF8_FOUR_BYTES = 0x00F0;
+    
+    private static int UTF8_FIVE_BYTES_MASK = 0x00FC;
+    private static int UTF8_FIVE_BYTES = 0x00F8;
+
+    private static int UTF8_SIX_BYTES_MASK = 0x00FE;
+    private static int UTF8_SIX_BYTES = 0x00FC;
+    
+    /** <alpha>    ::= [0x41-0x5A] | [0x61-0x7A] */
+    public static final boolean[] ALPHA =
+    {
+        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, false, false, false, false, false, false, false, false, false,
+        false, false, false, false, false, false, false, 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, 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
+    };
+
+    /** <alpha> | <digit> | '-' */
+    public static final boolean[] 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, false, false, true, false, false, true, true, true, true, true,
+        true, true, true, true, true, false, 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,
+        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' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' */
+    public static final boolean[] DIGIT =
+    {
+        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, false, false, false, false, false, true, true, true, true,
+        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, 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, false, false,
+    };
+
+    /** <hex>    ::= [0x30-0x39] | [0x41-0x46] | [0x61-0x66] */
+    private static final boolean[] HEX =
+    {
+        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, false, false, false, false, false, true, true, true, true,
+        true, true, true, true, true, true, false, false, false, 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, 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 ------------------------------------------------------------------------------------
+
+    /**
+     * Helper function that dump a byte in hex form
+     * 
+     * @param octet The byte to dump
+     * @return A string representation of the byte
+     */
+    public static String dumpByte( byte octet )
+    {
+        return new String(
+                new byte[] { '0', 'x', HEX_CHAR[( octet & 0x00F0 ) >> 4], HEX_CHAR[octet & 0x000F] } );
+    }
+    
+    /**
+     * Helper function that dump an array of bytes in hex form
+     * 
+     * @param octet The bytes array to dump
+     * @return A string representation of the array of bytes
+     */
+    public static String dumpBytes( byte[] buffer )
+    {
+        StringBuffer sb = new StringBuffer();
+        
+        for (int i = 0; i < buffer.length ; i++)
+        {
+            sb.append("0x").append((char)(HEX_CHAR[( buffer[i] & 0x00F0 ) >> 4])).append((char)(HEX_CHAR[buffer[i] & 0x000F])).append(" ");
+        }
+        
+        return sb.toString();
+    }
+    
+    /**
+     * Return the Unicode char which is coded in the bytes at position 0.
+     * 
+     * @param bytes The byte[] represntation of an Unicode string. 
+     * @return The first char found.
+     */
+    public static char bytesToChar(byte[] bytes)
+    {
+        return bytesToChar(bytes, 0);
+    }
+
+    /**
+     * Count the number of bytes needed to return an Unicode char. This
+     * can be from 1 to 6. 
+     * @param bytes The bytes to read
+     * @param pos Position to start counting. It must be a valid start of a 
+     * encoded char !
+     * @return The number of bytes to create a char, or -1 if the encoding is wrong.
+     * 
+     * TODO : Should stop after the third byte, as a char is only 2 bytes long.
+     */
+    public static int countBytesPerChar(byte[] bytes, int pos)
+    {
+        if ((bytes[0] & UTF8_MULTI_BYTES_MASK) == 0)
+        {
+            return 1;
+        } else if ((bytes[0] & UTF8_TWO_BYTES_MASK) == UTF8_TWO_BYTES)
+    	{
+            return 2;
+    	}
+    	else if ((bytes[0] & UTF8_THREE_BYTES_MASK) == UTF8_THREE_BYTES)
+    	{
+    	    return 3;
+    	}
+    	else if ((bytes[0] & UTF8_FOUR_BYTES_MASK) == UTF8_FOUR_BYTES)
+    	{
+    	    return 4;
+    	}
+    	else if ((bytes[0] & UTF8_FIVE_BYTES_MASK) == UTF8_FIVE_BYTES)
+    	{
+    	    return 5;
+    	}
+    	else if ((bytes[0] & UTF8_SIX_BYTES_MASK) == UTF8_SIX_BYTES)
+    	{
+    	    return 6;
+        } 
+    	else
+    	{
+    	    return -1;
+    	}
+    }
+    
+    /**
+     * Return the Unicode char which is coded in the bytes at the given position. 
+     * @param bytes The byte[] represntation of an Unicode string. 
+     * @param pos The current position to start decoding the char
+     * @return The char found.
+     * @return The decoded char, or -1 if no char can be decoded
+     * 
+     * TODO : Should stop after the third byte, as a char is only 2 bytes long.
+     */
+    public static char bytesToChar(byte[] bytes, int pos)
+    {
+    	if ((bytes[pos] & UTF8_MULTI_BYTES_MASK) == 0)
+		{
+    		return (char)bytes[pos];
+		}
+    	else
+    	{
+    		if ((bytes[pos] & UTF8_TWO_BYTES_MASK) == UTF8_TWO_BYTES)
+    		{
+    			// Two bytes char
+    			return (char)( 
+    					( ( bytes[pos] & 0x1C ) << 6 ) + 	// 110x-xxyy 10zz-zzzz -> 0000-0xxx 0000-0000
+    					( ( bytes[pos] & 0x03 ) << 6 ) + 	// 110x-xxyy 10zz-zzzz -> 0000-0000 yy00-0000
+						( bytes[pos + 1] & 0x3F ) 		   	// 110x-xxyy 10zz-zzzz -> 0000-0000 00zz-zzzz
+						); 								//                     -> 0000-0xxx yyzz-zzzz (07FF)
+    		}
+    		else if ((bytes[pos] & UTF8_THREE_BYTES_MASK) == UTF8_THREE_BYTES)
+    		{
+    			// Three bytes char
+    			return (char)( 
+    					// 1110-tttt 10xx-xxyy 10zz-zzzz -> tttt-0000-0000-0000
+    					( ( bytes[pos] & 0x0F) << 12 ) + 	
+						// 1110-tttt 10xx-xxyy 10zz-zzzz -> 0000-xxxx-0000-0000
+    					( ( bytes[pos + 1] & 0x3C) << 6 ) + 	
+						// 1110-tttt 10xx-xxyy 10zz-zzzz -> 0000-0000-yy00-0000
+    					( ( bytes[pos + 1] & 0x03) << 6 ) + 	
+						// 1110-tttt 10xx-xxyy 10zz-zzzz -> 0000-0000-00zz-zzzz
+						( bytes[pos + 2] & 0x3F )				
+						//                               -> tttt-xxxx yyzz-zzzz (FF FF)
+						);   							 
+    		}
+    		else if ((bytes[pos] & UTF8_FOUR_BYTES_MASK) == UTF8_FOUR_BYTES)
+    		{
+    			// Four bytes char
+    			return (char)(
+    					// 1111-0ttt 10uu-vvvv 10xx-xxyy 10zz-zzzz -> 000t-tt00 0000-0000 0000-0000
+    					( ( bytes[pos] & 0x07) << 18 ) +
+						// 1111-0ttt 10uu-vvvv 10xx-xxyy 10zz-zzzz -> 0000-00uu 0000-0000 0000-0000
+    					( ( bytes[pos + 1] & 0x30) << 16 ) + 
+						// 1111-0ttt 10uu-vvvv 10xx-xxyy 10zz-zzzz -> 0000-0000 vvvv-0000 0000-0000
+    					( ( bytes[pos + 1] & 0x0F) << 12 ) + 
+						// 1111-0ttt 10uu-vvvv 10xx-xxyy 10zz-zzzz -> 0000-0000 0000-xxxx 0000-0000
+    					( ( bytes[pos + 2] & 0x3C) << 6 ) + 
+						// 1111-0ttt 10uu-vvvv 10xx-xxyy 10zz-zzzz -> 0000-0000 0000-0000 yy00-0000
+    					( ( bytes[pos + 2] & 0x03) << 6 ) +
+						// 1111-0ttt 10uu-vvvv 10xx-xxyy 10zz-zzzz -> 0000-0000 0000-0000 00zz-zzzz
+						( bytes[pos + 3] & 0x3F )
+						//                                         -> 000t-ttuu vvvv-xxxx yyzz-zzzz (1FFFFF)
+						);   
+    		}
+    		else if ((bytes[pos] & UTF8_FIVE_BYTES_MASK) == UTF8_FIVE_BYTES)
+    		{
+    			// Five bytes char
+    			return (char)( 
+    					// 1111-10tt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz -> 0000-00tt 0000-0000 0000-0000 0000-0000
+    					( ( bytes[pos] & 0x03) << 24 ) + 
+    					// 1111-10tt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz -> 0000-0000 uuuu-uu00 0000-0000 0000-0000
+    					( ( bytes[pos + 1] & 0x3F) << 18 ) + 
+    					// 1111-10tt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz -> 0000-0000 0000-00vv 0000-0000 0000-0000
+    					( ( bytes[pos + 2] & 0x30) << 12 ) + 
+    					// 1111-10tt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz -> 0000-0000 0000-0000 wwww-0000 0000-0000
+    					( ( bytes[pos + 2] & 0x0F) << 12 ) + 
+    					// 1111-10tt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz -> 0000-0000 0000-0000 0000-xxxx 0000-0000
+    					( ( bytes[pos + 3] & 0x3C) << 6 ) + 
+    					// 1111-10tt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz -> 0000-0000 0000-0000 0000-0000 yy00-0000
+    					( ( bytes[pos + 3] & 0x03) << 6 ) + 
+						// 1111-10tt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz -> 0000-0000 0000-0000 0000-0000 00zz-zzzz
+						( bytes[pos + 4] & 0x3F )
+						// -> 0000-00tt uuuu-uuvv wwww-xxxx yyzz-zzzz (03 FF FF FF)
+						);   
+    		}
+    		else if ((bytes[pos] & UTF8_FIVE_BYTES_MASK) == UTF8_FIVE_BYTES)
+    		{
+    			// Six bytes char
+    			return (char)( 
+    			        // 1111-110s 10tt-tttt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz ->
+    			        // 0s00-0000 0000-0000 0000-0000 0000-0000
+    					( ( bytes[pos] & 0x01) << 30 ) + 
+    			        // 1111-110s 10tt-tttt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz ->
+    			        // 00tt-tttt 0000-0000 0000-0000 0000-0000
+    					( ( bytes[pos + 1] & 0x3F) << 24 ) + 
+    			        // 1111-110s 10tt-tttt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz ->
+    			        // 0000-0000 uuuu-uu00 0000-0000 0000-0000
+    					( ( bytes[pos + 2] & 0x3F) << 18 ) + 
+    			        // 1111-110s 10tt-tttt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz ->
+    			        // 0000-0000 0000-00vv 0000-0000 0000-0000
+    					( ( bytes[pos + 3] & 0x30) << 12 ) + 
+    			        // 1111-110s 10tt-tttt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz ->
+    			        // 0000-0000 0000-0000 wwww-0000 0000-0000
+    					( ( bytes[pos + 3] & 0x0F) << 12 ) + 
+    			        // 1111-110s 10tt-tttt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz ->
+    					// 0000-0000 0000-0000 0000-xxxx 0000-0000
+    					( ( bytes[pos + 4] & 0x3C) << 6 ) + 
+    			        // 1111-110s 10tt-tttt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz ->
+    					// 0000-0000 0000-0000 0000-0000 yy00-0000
+    					( ( bytes[pos + 4] & 0x03) << 6 ) + 
+    			        // 1111-110s 10tt-tttt 10uu-uuuu 10vv-wwww 10xx-xxyy 10zz-zzzz ->
+    					// 0000-0000 0000-0000 0000-0000 00zz-zzzz
+						( bytes[pos + 5] & 0x3F )
+    			        // -> 0stt-tttt uuuu-uuvv wwww-xxxx yyzz-zzzz (7F FF FF FF)
+						);   
+    		} 
+    		else
+    		{
+    		    return (char)-1;
+    		}
+    	}
+    }
+    
+    /**
+     * Count the number of chars included in the given byte[].  
+     * @param bytes The byte array to decode
+     * @return The number of char in the byte array
+     */
+    public static int countChars(byte[] bytes)
+    {
+        int nbChars = 0;
+        int currentPos = 0;
+        
+        while (currentPos < bytes.length)
+        {
+            currentPos += countBytesPerChar(bytes, currentPos);
+            nbChars ++;
+        }
+
+        return nbChars;
+    }
+    
+    /**
+     * Check if a text is present at the current position in a buffer.
+     *
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     * @param text The text we want to check
+     *
+     * @return <code>true</code> if the buffer contains the text.
+     */
+    public static int areEquals( byte[] byteArray, int index, String text )
+    {
+        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( byteArray.length <= index ) ||
+                ( index < 0 ) || ( text == null ) )
+        {
+            return -1;
+        }
+        else
+        {
+            byte[] data = text.getBytes();
+
+            return areEquals( byteArray, index, data );
+        }
+    }
+
+    /**
+     * Check if a text is present at the current position in a buffer.
+     *
+     * @param charArray The buffer which contains the data
+     * @param index Current position in the buffer
+     * @param charArray2 The text we want to check
+     *
+     * @return <code>true</code> if the buffer contains the text.
+     */
+    public static int areEquals( char[] charArray, int index, char[] charArray2 )
+    {
+
+        if ( ( charArray == null ) ||
+                ( charArray.length == 0 ) ||
+                ( charArray.length <= index ) ||
+                ( index < 0 ) ||
+                ( charArray2 == null ) ||
+                ( charArray2.length == 0 ) ||
+                ( charArray2.length > ( charArray.length + index ) ) )
+        {
+            return -1;
+        }
+        else
+        {
+            for ( int i = 0; i < charArray2.length; i++ )
+            {
+                if ( charArray[index++] != charArray2[i] )
+                {
+                    return -1;
+                }
+            }
+
+            return index;
+        }
+    }
+
+    /**
+     * Check if a text is present at the current position in a buffer.
+     *
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     * @param byteArray2 The text we want to check
+     *
+     * @return <code>true</code> if the buffer contains the text.
+     */
+    public static int areEquals( byte[] byteArray, int index, byte[] byteArray2 )
+    {
+
+        if ( ( byteArray == null ) ||
+                ( byteArray.length == 0 ) ||
+                ( byteArray.length <= index ) ||
+                ( index < 0 ) ||
+                ( byteArray2 == null ) ||
+                ( byteArray2.length == 0 ) ||
+                ( byteArray2.length > ( byteArray.length + index ) ) )
+        {
+            return -1;
+        }
+        else
+        {
+            for ( int i = 0; i < byteArray2.length; i++ )
+            {
+                if ( byteArray[index++] != byteArray2[i] )
+                {
+                    return -1;
+                }
+            }
+
+            return index;
+        }
+    }
+
+    /**
+     * Test if the current character is equal to a specific character.
+     * This function works only for character between 0 and 127, as it
+     * does compare a byte and a char (which is 16 bits wide)
+     * 
+     *
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     * @param car The character we want to compare with the current buffer position
+     *
+     * @return <code>true</code> if the current character equals the given character.
+     */
+    public static boolean isCharASCII( byte[] byteArray, int index, char car )
+    {
+        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
+                ( index >= byteArray.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( byteArray[index] == car ) ? true : false );
+        }
+    }
+
+    /**
+     * Check if the current character is an Hex Char
+     *  <hex>    ::= [0x30-0x39] | [0x41-0x46] | [0x61-0x66]
+     * 
+     * @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 Hex Char
+     */
+    public static boolean isHex( 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 ) || ( StringUtils.HEX[c] == false ) )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+    /**
+     * Test if the current character is a digit
+     * <digit>    ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * @param byteArray The buffer which contains the data
+     *
+     * @return <code>true</code> if the current character is a Digit
+     */
+    public static boolean isDigit( byte[] byteArray )
+    {
+        if ( ( byteArray == null ) || ( byteArray.length == 0 ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( ( byteArray[0] > 127 ) || ! StringUtils.DIGIT[byteArray[0]] ) ? false : true );
+        }
+    }
+
+    /**
+     * Test if the current character is an Alpha character :
+     *  <alpha>    ::= [0x41-0x5A] | [0x61-0x7A]
+     * 
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     *
+     * @return <code>true</code> if the current character is an Alpha character
+     */
+    public static boolean isAlphaASCII( 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 ) || ( StringUtils.ALPHA[c] == false ) )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+    /**
+     * Test if the current character is a digit
+     * <digit>    ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * @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 Digit
+     */
+    public static boolean isDigit( byte[] byteArray, int index )
+    {
+        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
+                ( index >= byteArray.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( ( byteArray[index] > 127 ) || ! StringUtils.DIGIT[byteArray[index]] ) ? false : true );
+        }
+    }
+
+    /**
+     * Check if the current character is an 7 bits ASCII CHAR (between 0 and 127).
+     *   <char>    ::= <alpha> | <digit> | '-'
+     *
+     * @param byteArray The buffer which contains the data
+     * @param index Current position in the buffer
+     *
+     * @return The position of the next character, if the current one is a CHAR.
+     */
+    public static boolean isAlphaDigitMinus( 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 ) || ( StringUtils.CHAR[c] == false ) )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+    
+}