directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From elecha...@apache.org
Subject svn commit: r291711 - in /directory/asn1/trunk/ber-new/src: java/main/org/apache/asn1new/ber/ java/main/org/apache/asn1new/util/ test/org/apache/asn1new/util/
Date Mon, 26 Sep 2005 18:56:54 GMT
Author: elecharny
Date: Mon Sep 26 11:56:41 2005
New Revision: 291711

URL: http://svn.apache.org/viewcvs?rev=291711&view=rev
Log:
Merged with the asn1-NameComponent branch

Removed:
    directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/util/BooleanDecoder.java
Modified:
    directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/ber/Asn1Decoder.java
    directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/util/MutableString.java
    directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/util/StringUtils.java
    directory/asn1/trunk/ber-new/src/test/org/apache/asn1new/util/MutableStringTest.java
    directory/asn1/trunk/ber-new/src/test/org/apache/asn1new/util/StringUtilsTest.java

Modified: directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/ber/Asn1Decoder.java
URL: http://svn.apache.org/viewcvs/directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/ber/Asn1Decoder.java?rev=291711&r1=291710&r2=291711&view=diff
==============================================================================
--- directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/ber/Asn1Decoder.java (original)
+++ directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/ber/Asn1Decoder.java Mon Sep 26 11:56:41 2005
@@ -98,66 +98,69 @@
     private boolean treatTagStartState( ByteBuffer stream, IAsn1Container container )
         throws DecoderException
     {
+
         if ( stream.hasRemaining() )
         {
+
             byte octet = stream.get();
-    
+
             TLV tlv = new TLV();
             Tag tag = tlv.getTag();
-    
+
+            tag.setSize( 1 );
             tag.setPrimitive( ( octet & Tag.CONSTRUCTED_FLAG ) == 0 );
             tag.setTypeClass( Tag.TYPE_CLASS[( octet & Tag.TYPE_CLASS_MASK ) >>> 6] );
-    
+
             int value = octet & Tag.SHORT_MASK;
-    
+
             if ( value == Tag.SHORT_MASK )
             {
-                // It's a tag wich value is above 31
+
                 // we have to check the typeClass. UNIVERSAL class is not
                 // allowed with this value.
                 if ( tag.isUniversal() )
                 {
                     throw new DecoderException( "Universal tag 31 is reserved" );
                 }
-    
+
                 // we will have more than one byte to encode the value
                 // The tag is encoded on [2 - 6 bytes], its value
-                // is contained in the 7 lower bits of the bytes following
+                // is container in the 7 lower bits of the bytes following
                 // the first byte.
                 container.setState( TLVStateEnum.TAG_STATE_PENDING );
                 tag.setId( 0 );
                 tag.addByte( octet );
-                tag.setSize( 0 );
             }
             else
             {
                 // It's a tag wich value is below 30 (31 is not allowed
-                // as it signals a multi-bytes value). The tag's length is 1 byte
-                tag.setSize( 1 );
-    
+                // as it signals a multi-bytes value. Everything is done.
+
                 // We have to check for reserved tags if typeClass is UNIVERSAL
                 if ( tag.isUniversal() )
                 {
+
                     if ( ( value == UniversalTag.RESERVED_14 ) || ( value == UniversalTag.RESERVED_15 ) )
                     {
                         throw new DecoderException( "Universal tag " + value + " is reserved" );
                     }
                 }
-    
+
                 tag.setId( value );
                 tag.addByte( octet );
-    
+
                 // The tag has been completed, we have to decode the Length
                 container.setState( TLVStateEnum.TAG_STATE_END );
             }
-    
+
             // Store the current TLV in the container.
             container.setCurrentTLV( tlv );
-            
+
             return MORE;
         }
         else
         {
+
             // The stream has been exhausted
             return END;
         }
@@ -179,35 +182,40 @@
     private boolean treatTagPendingState( ByteBuffer stream, IAsn1Container container )
         throws DecoderException
     {
+
         if ( stream.hasRemaining() )
         {
+
             Tag  tag    = container.getCurrentTLV().getTag();
             byte octet = stream.get();
-    
+
             if ( tag.getSize() >= Tag.MAX_TAG_BYTES )
             {
                 container.setState( TLVStateEnum.TAG_STATE_OVERFLOW );
                 log.error( "Tag label Overflow" );
                 throw new DecoderException( "Tag label overflow" );
             }
-    
+
             byte val = ( byte ) ( octet & Tag.LONG_MASK );
-    
+
             tag.setId( ( tag.getId() << 7 ) | val );
             tag.incTagSize();
-    
+
             if ( val == octet )
             {
+
                 // The Tag is completed, so let's decode the Length
                 container.setState( TLVStateEnum.LENGTH_STATE_START );
             }
-            
+
             return MORE;
         }
         else
         {
+
             return END;
         }
+
     }
 
     /**
@@ -219,26 +227,25 @@
         StringBuffer sb = new StringBuffer();
         TLV current = container.getCurrentTLV();
         
-        sb.append( "TLV" ).
-        	append( StringUtils.dumpByte( current.getTag().getTagBytes()[0] ) ).
-        	append( "(" ).
-        	append( current.getExpectedLength() ).
-        	append( ")" );
+        sb.append("TLV").
+        	append(StringUtils.dumpByte(current.getTag().getTagBytes()[0])).
+        	append("(").
+        	append(current.getExpectedLength()).
+        	append(")");
         
         current = current.getParent();
         
         while (current != null)
         {
-            sb.append( "-TLV" ).
-        		append( StringUtils.dumpByte( current.getTag().getTagBytes()[0] ) ).
-        		append( "(" ).
-        		append( current.getExpectedLength() ).
-        		append( ")" );
-            
+            sb.append("-TLV").
+        		append(StringUtils.dumpByte(current.getTag().getTagBytes()[0])).
+        		append("(").
+        		append(current.getExpectedLength()).
+        		append(")");
             current = current.getParent();
         }
         
-        log.debug( "TLV Tree : " + sb.toString() );
+        log.debug("TLV Tree : " + sb.toString());
     }
     
     /**
@@ -247,11 +254,11 @@
      */
     private boolean isTLVDecoded( IAsn1Container container )
     {
-        TLV currentTLV = container.getCurrentTLV();
+        TLV current = container.getCurrentTLV();
         
-        TLV parent = currentTLV.getParent();
+        TLV parent = current.getParent();
         
-        while ( parent != null )
+        while (parent != null)
         {
         	if (parent.getExpectedLength() != 0)
         	{
@@ -261,15 +268,15 @@
         	parent = parent.getParent();
         }
         
-        Value value = currentTLV.getValue();
+        Value value = current.getValue();
         
-        if ( ( value != null ) && ( value.getData() != null ) )
+        if ( (value != null) && (value.getData() != null) )
         {
-            return ( currentTLV.getExpectedLength() == value.getData().length );
+            return (current.getExpectedLength() == value.getData().length);
         } 
         else
         {
-            return currentTLV.getExpectedLength() == 0;
+            return current.getExpectedLength() == 0;
         }
     }
     
@@ -286,20 +293,18 @@
     private void treatTagEndState( IAsn1Container container )
         throws DecoderException
     {
-        TLV currentTlv = container.getCurrentTLV(); 
 
         if ( DEBUG )
         {
-            Tag tag = currentTlv.getTag();
+            Tag tag = container.getCurrentTLV().getTag();
             log.debug( tag.toString() + " has been decoded" );
         }
         
-        // Create a link between the current TLV with its parent, if any.
-        currentTlv.setParent( container.getParentTLV() );
+        // Create a link between the current TLV with its parent
+        container.getCurrentTLV().setParent(container.getParentTLV());
         
         // After having decoded a tag, we have to execute the action
         // which controls if this tag is allowed and well formed.
-        // TODO : this is totally useless.
         container.getGrammar().executeAction( container );
 
         // Switch to the next state, which is the Length decoding
@@ -322,37 +327,39 @@
     private boolean treatLengthStartState( ByteBuffer stream, IAsn1Container container )
         throws DecoderException
     {
+
         if ( stream.hasRemaining() )
         {
+
             byte octet = stream.get();
-    
+
             Length length = container.getCurrentTLV().getLength();
-    
+
             if ( ( octet & Length.LENGTH_LONG_FORM ) == 0 )
             {
-    
+
                 // We don't have a long form. The Length of the Value part is
                 // given by this byte.
                 length.setLength( octet );
                 length.setExpectedLength( 0 );
                 length.setCurrentLength( 0 );
                 length.setSize( 1 );
-    
+
                 container.setState( TLVStateEnum.LENGTH_STATE_END );
             }
             else if ( ( octet & Length.LENGTH_EXTENSION_RESERVED ) !=
                     Length.LENGTH_EXTENSION_RESERVED )
             {
-    
+
                 int expectedLength = octet & Length.SHORT_MASK;
-    
+
                 if ( expectedLength > 4 )
                 {
                     log.error( "Overflow : can't have more than 4 bytes long length" );
                     throw new DecoderException(
                         "Overflow : can't have more than 4 bytes long length" );
                 }
-    
+
                 length.setExpectedLength( expectedLength );
                 length.setCurrentLength( 0 );
                 length.setLength( 0 );
@@ -369,6 +376,7 @@
         }
         else
         {
+
             return END;
         }
     }
@@ -389,31 +397,34 @@
     private boolean treatLengthPendingState( ByteBuffer stream, IAsn1Container container )
         throws DecoderException
     {
-        if (stream.hasRemaining() )
+
+        if ( stream.hasRemaining() )
         {
+
             Length length = container.getCurrentTLV().getLength();
-    
+
             while ( length.getCurrentLength() < length.getExpectedLength() )
             {
-    
+
                 byte octet = stream.get();
-    
+
                 if ( DEBUG )
                 {
                     log.debug( "  current byte : " + StringUtils.dumpByte( octet ) );
                 }
-    
+
                 length.incCurrentLength();
                 length.incSize();
                 length.setLength( ( length.getLength() << 8 ) | (octet & 0x00FF));
             }
-    
+
             container.setState( TLVStateEnum.LENGTH_STATE_END );
-            
+
             return MORE;
         }
         else
         {
+
             return END;
         }
     }
@@ -460,7 +471,7 @@
         throws DecoderException
     {
         TLV tlv = container.getCurrentTLV();
-        int length = tlv.getLength().getLength();
+        Length length = tlv.getLength();
 
         // We will check the length here. What we must control is
         // that the enclosing constructed TLV expected length is not
@@ -469,19 +480,19 @@
         
         if ( DEBUG )
         {
-            log.debug( getParentLength( parentTLV ) );
+            log.debug(getParentLength(parentTLV));
         }
         
-        if ( parentTLV == null ) 
+        if (parentTLV == null) 
         {
             // This is the first TLV, so we can't check anything. We will
             // just store this TLV as the root of the PDU
-            tlv.setExpectedLength( length );
-            container.setParentTLV( tlv );
+            tlv.setExpectedLength(length.getLength());
+            container.setParentTLV(tlv);
             
             if ( DEBUG )
             {
-                log.debug( "Root TLV[" + length + "]" );
+                log.debug("Root TLV[" + tlv.getLength().getLength() + "]");
             }
         }
         else
@@ -491,46 +502,46 @@
             int expectedLength = parentTLV.getExpectedLength();
             int currentLength = tlv.getSize();
             
-            if ( expectedLength < currentLength )
+            if (expectedLength < currentLength)
             {
                 // The expected length is lower than the Value length of the
                 // current TLV. This is an error...
-                log.error( "tlv[" + expectedLength + ", " + currentLength + "]" );
-                throw new DecoderException( "The current Value length is above the expected length" );
+                log.error("tlv[" + expectedLength + ", " + currentLength + "]");
+                throw new DecoderException("The current Value length is above the expected length");
             }
             
-            if ( expectedLength == currentLength )
+            if (expectedLength == currentLength)
             {
+                parentTLV.setExpectedLength(0);
+
                 // deal with the particular case where expected length equal
                 // the current length, which means that the parentTLV has been
                 // completed. 
-                // The parent length must be reset.
-                parentTLV.setExpectedLength( 0 );
-                tlv.setExpectedLength( length );
-
-                // Check the current length, and also check that the current TLV 
-                // is a constructed one.
+                // We also have to check that the current TLV is a constructed
+                // one. 
                 // In this case, we have to switch from this parent TLV
                 // to the parent's parent TLV.
-                if ( ( length != 0 ) && ( tlv.getTag().isConstructed() ) )
+                if (tlv.getTag().isConstructed())
                 {
                     // It's a constructed TLV. We will set it's parent to the 
                     // parentTLV, and it will become the new parent TLV, after
-                    // having set the new expected length
-                    tlv.setParent( parentTLV ) ;
-                    container.setParentTLV( tlv );
+                    // having set the new expected length.
+                    tlv.setParent(parentTLV);
+                    tlv.setExpectedLength(tlv.getLength().getLength());
+                    container.setParentTLV(tlv);
                 }
                 else
                 {
-                    // We have to unstack the parentTLV until we 
-                    // find one which length is not null. It will
-                    // become the container parentTLV.
-                    while ( parentTLV != null )
+                    tlv.setExpectedLength(tlv.getLength().getLength());
+                    // It's over, the parent TLV has been completed.
+                    // Go back to the parent's parent TLV until we find
+                    // a tlv which is not complete.
+                    while (parentTLV != null)
                     {
                         if ( parentTLV.getExpectedLength() != 0 )
                         {
-                            // Ok, we have an incomplete parent. we will
-                            // stop the recursion rigth here
+                            // ok, we have an incomplete parent. we will
+                            // stop the recursion right here
                             break;
                         }
                         else
@@ -538,41 +549,41 @@
                             parentTLV = parentTLV.getParent();
                         }
                     }
-
-                    // The parent might be null.
-                    container.setParentTLV( parentTLV ) ;
+                    
+                    container.setParentTLV(parentTLV);
                 }
             }
             else
             {
 	            // Renew the expected Length.
-	            parentTLV.setExpectedLength( expectedLength - currentLength) ;
-                tlv.setExpectedLength( length );
+	            parentTLV.setExpectedLength(expectedLength - currentLength);
+                tlv.setExpectedLength(tlv.getLength().getLength());
 	            
-	            if ( tlv.getTag().isConstructed() )
+	            if (tlv.getTag().isConstructed())
 	            {
-	                // We have a constructed tag, so we must change the 
-                    // container parentTLV. The current container parentTLV 
-                    // will be store in the current TLV.
-                    tlv.setParent( parentTLV );
-                    tlv.setExpectedLength( length );
-                    container.setParentTLV( tlv );
+	                // We have a constructed tag, so we must switch the parentTLV
+                    tlv.setParent(parentTLV);
+                    tlv.setExpectedLength(tlv.getLength().getLength());
+                    container.setParentTLV(tlv);
 	            }
             }
+            
         }
 
         if ( DEBUG )
         {
-            log.debug( tlv.getLength().toString() + " has been decoded" );
+            log.debug( length.toString() + " has been decoded" );
         }
 
-        if ( length == 0 )
+        if ( length.getLength() == 0 )
         {
+
             // The length is 0, so we can't expect a value.
             container.setState( TLVStateEnum.TLV_STATE_DONE );
         }
         else
         {
+
             // Go ahead and decode the value part
             container.setState( TLVStateEnum.VALUE_STATE_START );
         }
@@ -595,13 +606,13 @@
     private boolean treatValueStartState( ByteBuffer stream, IAsn1Container container )
         throws DecoderException
     {
+
         TLV currentTlv = container.getCurrentTLV();
-        Value value = currentTlv.getValue();
 
         if ( currentTlv.getTag().isConstructed() )
         {
             container.setState( TLVStateEnum.TLV_STATE_DONE );
-            
+
             return MORE;
         }
         else
@@ -609,20 +620,21 @@
 
             int length  = currentTlv.getLength().getLength();
             int nbBytes = stream.remaining();
-            value.init( length );
 
             if ( nbBytes < length )
             {
-                value.setData( stream );
+                currentTlv.getValue().init( length );
+                currentTlv.getValue().setData( stream );
                 container.setState( TLVStateEnum.VALUE_STATE_PENDING );
-                
+
                 return END;
             }
             else
             {
-                stream.get( value.getData(), 0, length );
+                currentTlv.getValue().init( length );
+                stream.get( currentTlv.getValue().getData(), 0, length );
                 container.setState( TLVStateEnum.TLV_STATE_DONE );
-                
+
                 return MORE;
             }
         }
@@ -646,17 +658,16 @@
     {
 
         TLV currentTlv    = container.getCurrentTLV();
-        Value value       = currentTlv.getValue();
 
         int length        = currentTlv.getLength().getLength();
-        int currentLength = value.getCurrentLength();
+        int currentLength = currentTlv.getValue().getCurrentLength();
         int nbBytes       = stream.remaining();
 
         if ( ( currentLength + nbBytes ) < length )
         {
-            value.addData( stream );
+            currentTlv.getValue().addData( stream );
             container.setState( TLVStateEnum.VALUE_STATE_PENDING );
-            
+
             return END;
         }
         else
@@ -665,9 +676,9 @@
             int    remaining = length - currentLength;
             byte[] data      = new byte[remaining];
             stream.get( data, 0, remaining );
-            value.addData( data );
+            currentTlv.getValue().addData( data );
             container.setState( TLVStateEnum.TLV_STATE_DONE );
-            
+
             return MORE;
         }
     }
@@ -722,8 +733,10 @@
     */
     private String stateToString( int state )
     {
+
         switch ( state )
         {
+
             case TLVStateEnum.TAG_STATE_START :
                 return "TAG_STATE_START";
 
@@ -771,7 +784,7 @@
      * 
      * @throws DecoderException Thrown if anything went wrong!
      */
-    public void decode( ByteBuffer stream, IAsn1Container container ) throws DecoderException
+    public void decode( ByteBuffer stream, IAsn1Container container ) throws org.apache.asn1.codec.DecoderException
     {
 
         /* We have to deal with the current state. This is an
@@ -783,7 +796,7 @@
          * all information to track back this case, and punish the guilty !
          */
 
-        // boolean hasRemaining = stream.hasRemaining();
+        boolean hasRemaining = stream.hasRemaining();
 
         if ( DEBUG )
         {
@@ -792,8 +805,6 @@
             log.debug( ">>>------------------------------------------" );
         }
 
-        boolean hasRemaining = stream.hasRemaining();
-        
         while ( hasRemaining )
         {
 
@@ -815,6 +826,7 @@
 
             switch ( container.getState() )
             {
+
                 case TLVStateEnum.TAG_STATE_START :
                     hasRemaining = treatTagStartState( stream, container );
 
@@ -860,7 +872,7 @@
                     break;
 
                 case TLVStateEnum.VALUE_STATE_END :
-                    hasRemaining = stream.hasRemaining();
+                	hasRemaining = stream.hasRemaining();
 
                     // Nothing to do. We will never reach this state
                     break;
@@ -878,22 +890,25 @@
                         log.warn("The PDU has been fully decoded but there are still bytes in the buffer.");
                     }
                     
-                    if ( DEBUG )
-                    {
-                        log.debug( "<<<------------------------------------------" );
-                        log.debug( "<-- Stop decoding : " + container.getCurrentTLV().toString() );
-                        log.debug( "<<<==========================================" );
-                    }
+                    hasRemaining = false;
                     
-                    return;
+                    break;
             }
         }
 
         if ( DEBUG )
         {
             log.debug( "<<<------------------------------------------" );
-            log.debug( "  no more byte to decode in the stream");
-            log.debug( "<-- End decoding : " + container.getCurrentTLV().toString() );
+            
+            if ( container.getState() == TLVStateEnum.PDU_DECODED )
+            {
+                log.debug( "<-- Stop decoding : " + container.getCurrentTLV().toString() );
+            }
+            else
+            {
+                log.debug( "<-- End decoding : " + container.getCurrentTLV().toString() );
+            }
+            
             log.debug( "<<<==========================================" );
         }
         

Modified: directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/util/MutableString.java
URL: http://svn.apache.org/viewcvs/directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/util/MutableString.java?rev=291711&r1=291710&r2=291711&view=diff
==============================================================================
--- directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/util/MutableString.java (original)
+++ directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/util/MutableString.java Mon Sep 26 11:56:41 2005
@@ -19,8 +19,7 @@
 import java.io.UnsupportedEncodingException;
 
 /**
- * A Mutable version of the String class. This mutable String can be
- * stored in a pool.
+ * A Mutable version of the String class. It stores only UTF-8 Strings.
  * 
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
@@ -54,9 +53,9 @@
     /**
      * Creates a MutableString.
      */
-    public MutableString(String string)
+    public MutableString(String string) throws UnsupportedEncodingException
     {
-        this( string.getBytes() );
+        this( string.getBytes( "UTF-8" ) );
     }
     
     /**
@@ -84,7 +83,7 @@
      * is coded in Unicode, so the bytes *MUST* be valid ! 
      * @param bytes The value to store.
      */
-    public MutableString(byte[] bytes)
+    public MutableString(byte[] bytes) throws UnsupportedEncodingException
     {
         setData( bytes );
     }
@@ -95,20 +94,34 @@
      * 
      * @param bytes The string to store
      */
-    public void setData(byte[] bytes)
+    public void setData(byte[] bytes) throws UnsupportedEncodingException
     {
         data = bytes;
         length = bytes.length;
         int charLength = StringUtils.countChars(bytes);
         
+        if ( charLength == StringUtils.BAD_CHAR_ENCODING )
+        {
+            throw new UnsupportedEncodingException( "Bad UTF-8 encoding" );
+        }
+        
         string = new char[charLength];
         
+        StringUtils.decodeUTF8( string, bytes );
+    }
+    
+    /**
+     * Store the char[] as a byte[]. The bye[] is supposed to be large enough to store the result.
+     * 
+     * @param string The char[] to transform
+     */
+    private void setData( char[] string )
+    {
         int pos = 0;
         
-        for ( int i = 0; i < charLength; i++ )
+        for ( int i = 0; i < string.length; i++ )
         {
-            string[i] = StringUtils.bytesToChar(bytes, pos);
-            pos += StringUtils.countBytesPerChar(bytes, pos); 
+            pos = StringUtils.charToBytes( string[i], data, pos );
         }
     }
     
@@ -130,24 +143,175 @@
     }
 
     /**
+     * Trim the String to suppress leading and trailing spaces, if any.
+     * 
+     * @return The new trimmed MutableString
+     */
+    public MutableString trim() throws UnsupportedEncodingException
+    {
+        int start = 0;
+        int end = length - 1;
+        
+        while ( (start < length ) && ( string[start] == ' ' ) )
+        {
+            start++;
+        }
+        
+        if ( start == length )
+        {
+            return EMPTY_STRING;
+        }
+        
+        while ( ( end > 0 ) && ( string[end] == ' ' ) )
+        {
+            end --;
+        }
+        
+        if ( end == -1 )
+        {
+            return EMPTY_STRING;
+        }
+        
+        if ( ( start == 0 ) && (end == length - 1) )
+        {
+            // Special case : we don't have any leading and trailing space.
+            // We can avoid creating a MutableString, then.
+            return this;
+        }
+        
+        int newLength = end - start + 1;
+        byte[] newData = new byte[ newLength ];
+        
+        System.arraycopy(data, start, newData, 0, newLength );
+        
+        MutableString newString = new MutableString( newData );
+        
+        return newString;
+    }
+    
+    /**
+     * Trim the String to suppress leading spaces, if any.
+     * 
+     * @return The new trimmed MutableString
+     */
+    public MutableString trimLeft() throws UnsupportedEncodingException
+    {
+        int start = 0;
+        
+        while ( (start < length ) && ( string[start] == ' ' ) )
+        {
+            start++;
+        }
+        
+        if (start == 0)
+        {
+            // Special case : we don't have any leading space.
+            // We can avoid creating a MutableString, then.
+            return this;
+        }
+        
+        if ( start == length )
+        {
+            return EMPTY_STRING;
+        }
+        
+        int newLength = length - start;
+        byte[] newData = new byte[ newLength ];
+        
+        System.arraycopy(data, start, newData, 0, newLength );
+        
+        MutableString newString = new MutableString( newData );
+        
+        return newString;
+    }
+    
+    /**
+     * Trim the String to suppress trailing spaces, if any.
+     * 
+     * @return The new trimmed MutableString
+     */
+    public MutableString trimRight() throws UnsupportedEncodingException
+    {
+        int end = length - 1;
+        
+        while ( ( end > 0 ) && ( string[end] == ' ' ) )
+        {
+            end --;
+        }
+        
+        if ( end == length - 1 )
+        {
+            // Special case : we don't have any trailing space.
+            // We can avoid creating a MutableString, then.
+            return this;
+        }
+        
+        if ( end == -1 )
+        {
+            return EMPTY_STRING;
+        }
+        
+        int newLength = end + 1;
+        byte[] newData = new byte[ newLength ];
+        
+        System.arraycopy(data, 0, newData, 0, newLength );
+        
+        MutableString newString = new MutableString( newData );
+        
+        return newString;
+    }
+    
+    /**
+     *  Converts all of the characters in this String to upper case.
+     */
+    public void toUpperCase()
+    {
+        for ( int i = 0; i < length; i++ )
+        {
+            if ( Character.isLowerCase( string[i] ) )
+            {
+                string[i] = Character.toUpperCase( string[i] );
+            }
+        }
+        
+        setData( string );
+    }
+    
+    /**
+     *  Converts all of the characters in this String to lower case.
+     */
+    public void toLowerCase()
+    {
+        for ( int i = 0; i < length; i++ )
+        {
+            if ( Character.isUpperCase( string[i] ) )
+            {
+                string[i] = Character.toLowerCase( string[i] );
+            }
+        }
+
+        setData( string );
+    }
+    
+    /**
      * Return a native String representation of the MutableString.
      */
     public String toString()
     {
-    	if ( length == 0 )
-    	{
-    		return "";
-    	}
-    	else
-    	{
-    		try
-    		{
-    			return new String(data, 0, length, "UTF8");
-    		}
-    		catch (UnsupportedEncodingException uee)
-    		{
-    			return "";
-    		}
-    	}
+        if ( length == 0 )
+        {
+            return "";
+        }
+        else
+        {
+            try
+            {
+                return new String(data, 0, length, "UTF8");
+            }
+            catch (UnsupportedEncodingException uee)
+            {
+                return "";
+            }
+        }
     }
 }

Modified: directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/util/StringUtils.java
URL: http://svn.apache.org/viewcvs/directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/util/StringUtils.java?rev=291711&r1=291710&r2=291711&view=diff
==============================================================================
--- directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/util/StringUtils.java (original)
+++ directory/asn1/trunk/ber-new/src/java/main/org/apache/asn1new/util/StringUtils.java Mon Sep 26 11:56:41 2005
@@ -16,6 +16,8 @@
  */
 package org.apache.asn1new.util;
 
+import java.io.UnsupportedEncodingException;
+
 /**
  * Little helper class. Nothing that should stay here, but I need those 
  * to debug.
@@ -47,6 +49,22 @@
     private static int UTF8_SIX_BYTES_MASK = 0x00FE;
     private static int UTF8_SIX_BYTES = 0x00FC;
     
+    private static int CHAR_ONE_BYTE_MASK    = 0xFFFFFF80;
+    private static int CHAR_ONE_BYTE         = ~CHAR_ONE_BYTE_MASK;
+    
+    private static int CHAR_TWO_BYTES_MASK   = 0xFFFFF800;
+    
+    private static int CHAR_THREE_BYTES_MASK = 0xFFFF0000;
+    
+    private static int CHAR_FOUR_BYTES_MASK  = 0xFFE00000;
+    
+    private static int CHAR_FIVE_BYTES_MASK  = 0xFC000000;
+    
+    private static int CHAR_SIX_BYTES_MASK   = 0x80000000;
+    
+    /** A constant for a bad UTF-8 encoding */
+    public static final int BAD_CHAR_ENCODING = -1;
+    
     /** <alpha>    ::= [0x41-0x5A] | [0x61-0x7A] */
     public static final boolean[] ALPHA =
     {
@@ -141,17 +159,6 @@
     }
     
     /**
-     * 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
@@ -161,154 +168,318 @@
      * 
      * TODO : Should stop after the third byte, as a char is only 2 bytes long.
      */
-    public static int countBytesPerChar(byte[] bytes, int pos)
+    public static int countBytesPerChar(byte[] bytes, int pos) throws UnsupportedEncodingException
     {
         if ((bytes[pos] & UTF8_MULTI_BYTES_MASK) == 0)
         {
             return 1;
-        } else if ((bytes[pos] & UTF8_TWO_BYTES_MASK) == UTF8_TWO_BYTES)
-    	{
+        } 
+        else if ((bytes[pos] & UTF8_TWO_BYTES_MASK) == UTF8_TWO_BYTES)
+        {
             return 2;
-    	}
-    	else if ((bytes[pos] & UTF8_THREE_BYTES_MASK) == UTF8_THREE_BYTES)
-    	{
-    	    return 3;
-    	}
-    	else if ((bytes[pos] & UTF8_FOUR_BYTES_MASK) == UTF8_FOUR_BYTES)
-    	{
-    	    return 4;
-    	}
-    	else if ((bytes[pos] & UTF8_FIVE_BYTES_MASK) == UTF8_FIVE_BYTES)
-    	{
-    	    return 5;
-    	}
-    	else if ((bytes[pos] & UTF8_SIX_BYTES_MASK) == UTF8_SIX_BYTES)
-    	{
-    	    return 6;
+        }
+        else if ((bytes[pos] & UTF8_THREE_BYTES_MASK) == UTF8_THREE_BYTES)
+        {
+            return 3;
+        }
+        else if ((bytes[pos] & UTF8_FOUR_BYTES_MASK) == UTF8_FOUR_BYTES)
+        {
+            return 4;
+        }
+        else if ((bytes[pos] & UTF8_FIVE_BYTES_MASK) == UTF8_FIVE_BYTES)
+        {
+            return 5;
+        }
+        else if ((bytes[pos] & UTF8_SIX_BYTES_MASK) == UTF8_SIX_BYTES)
+        {
+            return 6;
         } 
-    	else
-    	{
-    	    return -1;
-    	}
+        else
+        {
+            throw new UnsupportedEncodingException( "Cannot encode a character" );
+        }
+    }
+    
+    /**
+     * Return the Unicode char which is coded in the bytes at the given position. 
+     * This method suppose that the UTF-8 byte array is 3 bytes long, no more.
+     *  
+     * @param bytes The byte[] representation of an Unicode string. 
+     * @param pos The current position to start decoding the char
+     * @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) throws UnsupportedEncodingException
+    {
+        if ( ( bytes[pos] & UTF8_MULTI_BYTES_MASK ) == 0)
+        {
+            return (char)bytes[pos];
+        }
+        else
+        {
+            if ( ( ( bytes[pos] & UTF8_TWO_BYTES_MASK ) == UTF8_TWO_BYTES ) &&
+                 ( ( bytes[pos +1 ] & UTF8_TWO_BYTES ) == UTF8_MULTI_BYTES_MASK ) )
+            {
+                // 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 ) &&
+                      ( ( bytes[pos + 1] & UTF8_TWO_BYTES ) == UTF8_MULTI_BYTES_MASK ) &&
+                      ( ( bytes[pos + 2] & UTF8_TWO_BYTES ) == UTF8_MULTI_BYTES_MASK ) )
+            {
+                // 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
+            {
+                throw new UnsupportedEncodingException( "Bad UTF-8 encoding" );
+            }
+        }
     }
     
     /**
      * Return the Unicode char which is coded in the bytes at the given position. 
-     * @param bytes The byte[] represntation of an Unicode string. 
+     * This method suppose that the UTF-8 byte array is 3 bytes long, no more.
+     *  
+     * @param bytes The byte[] representation 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)
+    public static void bytesToTwoChars(byte[] bytes, int pos, char[] chars ) throws UnsupportedEncodingException
+    {
+        int value = 0;
+        
+        if ( ( bytes[pos] & UTF8_FOUR_BYTES_MASK ) == UTF8_FOUR_BYTES )
+        {
+            value = 
+                    // 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 ) && 
+                ( ( bytes[pos + 1] & UTF8_TWO_BYTES ) == UTF8_MULTI_BYTES_MASK ) )
+        {
+            // Five bytes char
+            value =
+                    // 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 ) &&
+                ( ( bytes[pos + 1] & UTF8_TWO_BYTES ) == UTF8_MULTI_BYTES_MASK ) &&
+                ( ( bytes[pos + 2] & UTF8_TWO_BYTES ) == UTF8_MULTI_BYTES_MASK ) )
+        {
+            // Six bytes char
+            value =
+                    // 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
+        {
+            throw new UnsupportedEncodingException( "Bad UTF-8 encoding" );
+        }
+
+        // Compute the surrogates, decrementing the value by the number
+        // of chars encoded on one char (65536). The new value will then
+        // be 20 bits long max.
+        value -= 0x10000;
+        
+        // The lower value is 10 bits long
+        int lowValue = value & 0x03FF;
+        
+        // The higher value is 10 bits long
+        int highValue = value >> 10;
+        
+        chars[0] = (char)( 0xD800 & highValue );
+        chars[1] = (char)( 0xDC00 & lowValue );
+    }
+    
+    public static void decodeUTF8( char[] chars, byte[] bytes ) throws UnsupportedEncodingException
     {
-    	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;
-    		}
-    	}
+        int pos = 0;
+        char[] twoChars = new char[2];
+        int nbBytes = 0;
+        
+        for ( int i = 0; i < bytes.length; i+= nbBytes )
+        {
+            nbBytes = countBytesPerChar( bytes, i );
+            
+            if ( nbBytes < 4 )
+            {
+                chars[pos] = bytesToChar( bytes, i );
+                pos++;
+            }
+            else
+            {
+                bytesToTwoChars( bytes, i, twoChars );
+                chars[pos++] = twoChars[0];
+                chars[pos++] = twoChars[1];
+            }
+        }
+        
+    }
+    
+    /**
+     * Return the bytes that hold an Unicode char.
+     * 
+     * The result is stored in the given byte[], starting at position pos.
+     * If the byte[] is not large enough to store the result, a runtime
+     * exception will be generated. It is the caller responsability to
+     * provide a byte[] that can store up to 6 bytes.
+     *
+     * @param car The character to be decoded
+     * @param bytes The byte[] where to store the result 
+     * @param pos The position where to store the result in the byte[] 
+     * @return The current position in the byte[].
+     * 
+     * TODO : Should stop after the third byte, as a char is only 2 bytes long.
+     */
+    public static int charToBytes(char car, byte[] bytes, int pos)
+    {
+        if ( ( car & CHAR_ONE_BYTE_MASK ) == 0 )
+        {
+            bytes[ pos++ ] = (byte)( car & CHAR_ONE_BYTE );
+            return pos;
+        }
+        else
+        {
+            if ( ( car & CHAR_TWO_BYTES_MASK ) == 0 )
+            {
+                // Two bytes char
+                // 0000-0xxx yyzz-zzzz -> 110x xxyy
+                bytes[ pos++ ] = (byte)( 0x00C0 | ( ( car & 0x07C0 ) >> 6 ) );
+                // 0000-0xxx yyzz-zzzz -> 10zz zzzz
+                bytes[ pos++ ] = (byte)( 0x0080 | ( car & 0x003F ) ); 
+
+                return pos;
+            }
+            else if ( ( car & CHAR_THREE_BYTES_MASK ) == 0 )
+            {
+                // Three bytes char
+                // tttt-0000-0000-0000 -> 1110-tttt
+                bytes[ pos++ ] = (byte)( 0x00E0 | ( ( car & 0xF000 ) >> 12 ) );
+                // 0000-xxxx-yy00-0000 -> 10xx-xxyy
+                bytes[ pos++ ] = (byte)( 0x0080 | ( ( car & 0x0FC0 ) >> 6 ) ); 
+                // 0000-0000-00zz-zzzz -> 10zz zzzz
+                bytes[ pos++ ] = (byte)( 0x0080 | ( car & 0x003F ) ); 
+
+                return pos;
+            }
+            else if ( ( car & CHAR_FOUR_BYTES_MASK ) == 0 )
+            {
+                // Four bytes char
+                // 000t-tt00 0000-0000 0000-0000 -> 1111-0ttt
+                bytes[ pos++ ] = (byte)( 0x00F8 | ( ( car & 0x1C0000 ) >> 18 ) );
+                // 0000-00uu vvvv-0000 0000-0000 -> 10uu-vvvv
+                bytes[ pos++ ] = (byte)( 0x0080 | ( ( car & 0x3F000 ) >> 12 ) ); 
+                // 0000-0000 0000-xxxx yy00-0000 -> 10xx xxyy
+                bytes[ pos++ ] = (byte)( 0x0080 | ( car & 0xFC0 ) >> 6); 
+                // 0000-0000 0000-0000 00zz-zzzz -> 10zz zzzz
+                bytes[ pos++ ] = (byte)( 0x0080 | ( car & 0x3F ) ); 
+
+                return pos;
+            }
+            else if ( ( car & CHAR_FIVE_BYTES_MASK ) == 0 )
+            {
+                // Five bytes char
+                // 0000-00tt 0000-0000 0000-0000 0000-0000 -> 1111-10tt
+                bytes[ pos++ ] = (byte)( 0x00FC | ( ( car & 0x03000000 ) >> 24 ) );
+                // 0000-0000 uuuu-uu00 0000-0000 0000-0000 -> 10uu-uuuu
+                bytes[ pos++ ] = (byte)( 0x0080 | ( ( car & 0xFC0000 ) >> 18 ) ); 
+                // 0000-0000 0000-00vv wwww-0000 0000-0000 -> 10vv wwww
+                bytes[ pos++ ] = (byte)( 0x0080 | ( car & 0x3F000 ) >> 12); 
+                // 0000-0000 0000-0000 0000-xxxx yy00-0000 -> 10xx xxyy
+                bytes[ pos++ ] = (byte)( 0x0080 | ( car & 0xFC0 ) >> 6); 
+                // 0000-0000 0000-0000 0000-0000 00zz-zzzz -> 10zz zzzz
+                bytes[ pos++ ] = (byte)( 0x0080 | ( car & 0x3F ) ); 
+
+                return pos;
+            }
+            else if ( ( car & CHAR_SIX_BYTES_MASK ) == 0 )
+            {
+                // Six bytes char
+                // 0s00-0000 0000-0000 0000-0000 0000-0000 -> 1111-110s
+                bytes[ pos++ ] = (byte)( 0x00FC | ( ( car & 0x40000000 ) >> 30 ) );
+                // 00tt-tttt 0000-0000 0000-0000 0000-0000 -> 10tt-tttt
+                bytes[ pos++ ] = (byte)( 0x0080 | ( ( car & 0x3F000000 ) >> 24 ) ); 
+                // 0000-0000 uuuu-uu00 0000-0000 0000-0000 -> 10uu uuuu
+                bytes[ pos++ ] = (byte)( 0x0080 | ( car & 0xFC0000 ) >> 18); 
+                // 0000-0000 0000-00vv wwww-0000 0000-0000 -> 10vv wwww
+                bytes[ pos++ ] = (byte)( 0x0080 | ( car & 0x3F000 ) >> 12); 
+                // 0000-0000 0000-0000 0000-xxxx yy00-0000 -> 10xx xxyy
+                bytes[ pos++ ] = (byte)( 0x0080 | ( car & 0xFC0 ) >> 6); 
+                // 0000-0000 0000-0000 0000-0000 00zz-zzzz -> 10zz zzzz
+                bytes[ pos++ ] = (byte)( 0x0080 | ( car & 0x3F ) ); 
+
+                return pos;
+            } 
+            else
+            {
+                return -1;
+            }
+        }
     }
     
     /**
@@ -316,15 +487,26 @@
      * @param bytes The byte array to decode
      * @return The number of char in the byte array
      */
-    public static int countChars(byte[] bytes)
+    public static int countChars(byte[] bytes) throws UnsupportedEncodingException
     {
         int nbChars = 0;
         int currentPos = 0;
         
         while (currentPos < bytes.length)
         {
-            currentPos += countBytesPerChar(bytes, currentPos);
-            nbChars ++;
+            int nbBytes = countBytesPerChar(bytes, currentPos);
+            
+            currentPos += nbBytes;
+
+            if ( currentPos > bytes.length )
+            {
+                throw new UnsupportedEncodingException( "Byte array too short to be decoded" );
+            }
+            
+            
+            // Ig the number of bytes necessary to encode a character is
+            // above 3, we will need two UTF-16 chars
+            nbChars += ( nbBytes > 3 ? 2 : 1 );
         }
 
         return nbChars;
@@ -339,18 +521,49 @@
      *
      * @return <code>true</code> if the buffer contains the text.
      */
-    public static int areEquals( byte[] byteArray, int index, String text )
+    public static int areEquals( char[] chars, int index, String text )
     {
-        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( byteArray.length <= index ) ||
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( chars.length <= index ) ||
                 ( index < 0 ) || ( text == null ) )
         {
             return -1;
         }
         else
         {
-            byte[] data = text.getBytes();
+            char[] data = text.toCharArray();
 
-            return areEquals( byteArray, index, data );
+            return areEquals( chars, index, data );
+        }
+    }
+
+    /**
+     * 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[] bytes, int index, String text )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( bytes.length <= index ) ||
+                ( index < 0 ) || ( text == null ) )
+        {
+            return -1;
+        }
+        else
+        {
+            try
+            {
+                byte[] data = text.getBytes( "UTF-8" );
+
+                return areEquals( bytes, index, data );
+            }
+            catch ( UnsupportedEncodingException uee )
+            {
+                return -1;
+            }
         }
     }
 
@@ -428,26 +641,48 @@
 
     /**
      * Test if the current character is equal to a specific character.
+     * 
+     *
+     * @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( char[] chars, int index, char car )
+    {
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( index < 0 ) ||
+                ( index >= chars.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( chars[index] == car ) ? true : false );
+        }
+    }
+
+    /**
+     * 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 )
+    public static boolean isCharASCII( byte[] bytes, int index, char car )
     {
-        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
-                ( index >= byteArray.length ) )
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) ||
+                ( index >= bytes.length ) )
         {
             return false;
         }
         else
         {
-            return ( ( byteArray[index] == car ) ? true : false );
+            return ( ( bytes[index] == car ) ? true : false );
         }
     }
 
@@ -460,16 +695,47 @@
      *
      * @return <code>true</code> if the current character is a Hex Char
      */
-    public static boolean isHex( byte[] byteArray, int index )
+    public static boolean isHex( char[] chars, int index )
     {
-        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
-                ( index >= byteArray.length ) )
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( index < 0 ) ||
+                ( index >= chars.length ) )
         {
             return false;
         }
         else
         {
-            byte c = byteArray[index];
+            char c = chars[index];
+
+            if ( ( c > 127 ) || ( StringUtils.HEX[c] == false ) )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+    /**
+     * 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[] bytes, int index )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) ||
+                ( index >= bytes.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            byte c = bytes[index];
 
             if ( ( c > 127 ) || ( StringUtils.HEX[c] == false ) )
             {
@@ -490,15 +756,35 @@
      *
      * @return <code>true</code> if the current character is a Digit
      */
-    public static boolean isDigit( byte[] byteArray )
+    public static boolean isDigit( char[] chars )
     {
-        if ( ( byteArray == null ) || ( byteArray.length == 0 ) )
+        if ( ( chars == null ) || ( chars.length == 0 ) )
         {
             return false;
         }
         else
         {
-            return ( ( ( byteArray[0] > 127 ) || ! StringUtils.DIGIT[byteArray[0]] ) ? false : true );
+            return ( ( ( chars[0] > 127 ) || ! StringUtils.DIGIT[chars[0]] ) ? false : true );
+        }
+    }
+
+    /**
+     * Test if the current character is a digit
+     * <digit>    ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * @param bytes The buffer which contains the data
+     *
+     * @return <code>true</code> if the current character is a Digit
+     */
+    public static boolean isDigit( byte[] bytes )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( ( bytes[0] > 127 ) || ! StringUtils.DIGIT[bytes[0]] ) ? false : true );
         }
     }
 
@@ -506,21 +792,52 @@
      * Test if the current character is an Alpha character :
      *  <alpha>    ::= [0x41-0x5A] | [0x61-0x7A]
      * 
-     * @param byteArray The buffer which contains the data
+     * @param chars 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 )
+    public static boolean isAlphaASCII( char[] chars, int index )
     {
-        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
-                ( index >= byteArray.length ) )
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( index < 0 ) ||
+                ( index >= chars.length ) )
         {
             return false;
         }
         else
         {
-            byte c = byteArray[index++];
+            char c = chars[index++];
+
+            if ( ( c > 127 ) || ( StringUtils.ALPHA[c] == false ) )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
+
+    /**
+     * Test if the current character is an Alpha character :
+     *  <alpha>    ::= [0x41-0x5A] | [0x61-0x7A]
+     * 
+     * @param chars 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[] bytes, int index )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) ||
+                ( index >= bytes.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            byte c = bytes[index++];
 
             if ( ( c > 127 ) || ( StringUtils.ALPHA[c] == false ) )
             {
@@ -542,16 +859,38 @@
      *
      * @return <code>true</code> if the current character is a Digit
      */
-    public static boolean isDigit( byte[] byteArray, int index )
+    public static boolean isDigit( char[] chars, int index )
+    {
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( index < 0 ) ||
+                ( index >= chars.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            return ( ( ( chars[index] > 127 ) || ! StringUtils.DIGIT[chars[index]] ) ? false : true );
+        }
+    }
+
+    /**
+     * Test if the current character is a digit
+     * <digit>    ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
+     *
+     * @param bytes 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[] bytes, int index )
     {
-        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
-                ( index >= byteArray.length ) )
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) ||
+                ( index >= bytes.length ) )
         {
             return false;
         }
         else
         {
-            return ( ( ( byteArray[index] > 127 ) || ! StringUtils.DIGIT[byteArray[index]] ) ? false : true );
+            return ( ( ( bytes[index] > 127 ) || ! StringUtils.DIGIT[bytes[index]] ) ? false : true );
         }
     }
 
@@ -564,16 +903,16 @@
      *
      * @return The position of the next character, if the current one is a CHAR.
      */
-    public static boolean isAlphaDigitMinus( byte[] byteArray, int index )
+    public static boolean isAlphaDigitMinus( char[] chars, int index )
     {
-        if ( ( byteArray == null ) || ( byteArray.length == 0 ) || ( index < 0 ) ||
-                ( index >= byteArray.length ) )
+        if ( ( chars == null ) || ( chars.length == 0 ) || ( index < 0 ) ||
+                ( index >= chars.length ) )
         {
             return false;
         }
         else
         {
-            byte c = byteArray[index++];
+            char c = chars[index++];
 
             if ( ( c > 127 ) || ( StringUtils.CHAR[c] == false ) )
             {
@@ -585,6 +924,333 @@
             }
         }
     }
+    
+    /**
+     * 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[] bytes, int index )
+    {
+        if ( ( bytes == null ) || ( bytes.length == 0 ) || ( index < 0 ) ||
+                ( index >= bytes.length ) )
+        {
+            return false;
+        }
+        else
+        {
+            byte c = bytes[index++];
 
+            if ( ( c > 127 ) || ( StringUtils.CHAR[c] == false ) )
+            {
+                return false;
+            }
+            else
+            {
+                return true;
+            }
+        }
+    }
     
+    // The following methods are taken from org.apache.commons.lang.StringUtils
+    
+    /**
+     * The empty String <code>""</code>.
+     * @since 2.0
+     */
+    public static final String EMPTY = "";
+
+    // Empty checks
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Checks if a String is empty ("") or null.</p>
+     *
+     * <pre>
+     * StringUtils.isEmpty(null)      = true
+     * StringUtils.isEmpty("")        = true
+     * StringUtils.isEmpty(" ")       = false
+     * StringUtils.isEmpty("bob")     = false
+     * StringUtils.isEmpty("  bob  ") = false
+     * </pre>
+     *
+     * <p>NOTE: This method changed in Lang version 2.0.
+     * It no longer trims the String.
+     * That functionality is available in isBlank().</p>
+     *
+     * @param str  the String to check, may be null
+     * @return <code>true</code> if the String is empty or null
+     */
+    public static boolean isEmpty(String str) {
+        return str == null || str.length() == 0;
+    }
+
+    /**
+     * <p>Checks if a String is not empty ("") and not null.</p>
+     *
+     * <pre>
+     * StringUtils.isNotEmpty(null)      = false
+     * StringUtils.isNotEmpty("")        = false
+     * StringUtils.isNotEmpty(" ")       = true
+     * StringUtils.isNotEmpty("bob")     = true
+     * StringUtils.isNotEmpty("  bob  ") = true
+     * </pre>
+     *
+     * @param str  the String to check, may be null
+     * @return <code>true</code> if the String is not empty and not null
+     */
+    public static boolean isNotEmpty(String str) {
+        return str != null && str.length() > 0;
+    }
+
+    /**
+     * <p>Removes spaces (char &lt;= 32) from both start and
+     * ends of this String, handling <code>null</code> by returning
+     * <code>null</code>.</p>
+     *
+     * Trim removes start and end characters &lt;= 32.
+     *
+     * <pre>
+     * StringUtils.trim(null)          = null
+     * StringUtils.trim("")            = ""
+     * StringUtils.trim("     ")       = ""
+     * StringUtils.trim("abc")         = "abc"
+     * StringUtils.trim("    abc    ") = "abc"
+     * </pre>
+     *
+     * @param str  the String to be trimmed, may be null
+     * @return the trimmed string, <code>null</code> if null String input
+     */
+    public static String trim(String str) {
+        if ( isEmpty( str ) )
+        {
+            return str;
+        }
+        
+        char[] array = str.toCharArray();
+        int start = 0;
+        int end = array.length;
+        
+        while ( ( start < end ) && ( array[start] == ' ' ) )
+        {
+            start++;
+        }
+        
+        while ( ( end > start ) && ( array[end - 1] == ' ' ) )
+        {
+            end--;
+        }
+        
+        return new String( array, start, ( end - start ) );
+    }
+
+    /**
+     * <p>Removes spaces (char &lt;= 32) from start
+     * of this String, handling <code>null</code> by returning
+     * <code>null</code>.</p>
+     *
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     * StringUtils.trim(null)          = null
+     * StringUtils.trim("")            = ""
+     * StringUtils.trim("     ")       = ""
+     * StringUtils.trim("abc")         = "abc"
+     * StringUtils.trim("    abc    ") = "abc    "
+     * </pre>
+     *
+     * @param str  the String to be trimmed, may be null
+     * @return the trimmed string, <code>null</code> if null String input
+     */
+    public static String trimLeft( String str ) {
+        if ( isEmpty( str ) )
+        {
+            return str;
+        }
+        
+        char[] array = str.toCharArray();
+        int end = array.length;
+        
+        while ( ( end > 0 ) && ( array[end - 1] == ' ' ) )
+        {
+            end--;
+        }
+        
+        return new String( array, 0, end );
+    }
+
+    /**
+     * <p>Removes spaces (char &lt;= 32) from end
+     * of this String, handling <code>null</code> by returning
+     * <code>null</code>.</p>
+     *
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     * StringUtils.trim(null)          = null
+     * StringUtils.trim("")            = ""
+     * StringUtils.trim("     ")       = ""
+     * StringUtils.trim("abc")         = "abc"
+     * StringUtils.trim("    abc    ") = "    abc"
+     * </pre>
+     *
+     * @param str  the String to be trimmed, may be null
+     * @return the trimmed string, <code>null</code> if null String input
+     */
+    public static String trimRight( String str ) {
+        if ( isEmpty( str ) )
+        {
+            return str;
+        }
+        
+        char[] array = str.toCharArray();
+        int start = 0;
+        int end = array.length;
+        
+        while ( ( start < end ) && ( array[start] == ' ' ) )
+        {
+            start++;
+        }
+        
+        return new String( array, start, ( end - start ) );
+    }
+
+    /**
+     * <p>Removes spaces (char &lt;= 32) from start
+     * of this array, handling <code>null</code> by returning
+     * <code>null</code>.</p>
+     *
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     * StringUtils.trim(null)          = null
+     * StringUtils.trim("")            = ""
+     * StringUtils.trim("     ")       = ""
+     * StringUtils.trim("abc")         = "abc"
+     * StringUtils.trim("    abc    ") = "abc    "
+     * </pre>
+     *
+     * @param chars  the chars array to be trimmed, may be null
+     * @return the position of the first char which is not a space,
+     * or the last position of the array.
+     */
+    public static int trimLeft( char[] chars, int pos ) {
+        if ( chars == null )
+        {
+            return pos;
+        }
+        
+        while ( ( pos < chars.length ) && ( chars[pos] == ' ' ) )
+        {
+            pos++;
+        }
+        
+        return pos;
+    }
+
+    /**
+     * <p>Removes spaces (char &lt;= 32) from start
+     * of this array, handling <code>null</code> by returning
+     * <code>null</code>.</p>
+     *
+     * Trim removes start characters &lt;= 32.
+     *
+     * <pre>
+     * StringUtils.trim(null)          = null
+     * StringUtils.trim("")            = ""
+     * StringUtils.trim("     ")       = ""
+     * StringUtils.trim("abc")         = "abc"
+     * StringUtils.trim("    abc    ") = "abc    "
+     * </pre>
+     *
+     * @param bytes  the byte array to be trimmed, may be null
+     * @return the position of the first byte which is not a space,
+     * or the last position of the array.
+     */
+    public static int trimLeft( byte[] bytes, int pos ) {
+        if ( bytes == null )
+        {
+            return pos;
+        }
+        
+        while ( ( pos < bytes.length ) && ( bytes[pos] == ' ' ) )
+        {
+            pos++;
+        }
+        
+        return pos;
+    }
+
+    // Case conversion
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Converts a String to upper case as per {@link String#toUpperCase()}.</p>
+     *
+     * <p>A <code>null</code> input String returns <code>null</code>.</p>
+     *
+     * <pre>
+     * StringUtils.upperCase(null)  = null
+     * StringUtils.upperCase("")    = ""
+     * StringUtils.upperCase("aBc") = "ABC"
+     * </pre>
+     *
+     * @param str  the String to upper case, may be null
+     * @return the upper cased String, <code>null</code> if null String input
+     */
+    public static String upperCase(String str) {
+        if (str == null) {
+            return null;
+        }
+        return str.toUpperCase();
+    }
+
+    /**
+     * <p>Converts a String to lower case as per {@link String#toLowerCase()}.</p>
+     *
+     * <p>A <code>null</code> input String returns <code>null</code>.</p>
+     *
+     * <pre>
+     * StringUtils.lowerCase(null)  = null
+     * StringUtils.lowerCase("")    = ""
+     * StringUtils.lowerCase("aBc") = "abc"
+     * </pre>
+     *
+     * @param str  the String to lower case, may be null
+     * @return the lower cased String, <code>null</code> if null String input
+     */
+    public static String lowerCase(String str) {
+        if (str == null) {
+            return null;
+        }
+        return str.toLowerCase();
+    }
+
+    // Equals
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Compares two Strings, returning <code>true</code> if they are equal.</p>
+     *
+     * <p><code>null</code>s are handled without exceptions. Two <code>null</code>
+     * references are considered to be equal. The comparison is case sensitive.</p>
+     *
+     * <pre>
+     * StringUtils.equals(null, null)   = true
+     * StringUtils.equals(null, "abc")  = false
+     * StringUtils.equals("abc", null)  = false
+     * StringUtils.equals("abc", "abc") = true
+     * StringUtils.equals("abc", "ABC") = false
+     * </pre>
+     *
+     * @see java.lang.String#equals(Object)
+     * @param str1  the first String, may be null
+     * @param str2  the second String, may be null
+     * @return <code>true</code> if the Strings are equal, case sensitive, or
+     *  both <code>null</code>
+     */
+    public static boolean equals(String str1, String str2) {
+        return str1 == null ? str2 == null : str1.equals(str2);
+    }
 }

Modified: directory/asn1/trunk/ber-new/src/test/org/apache/asn1new/util/MutableStringTest.java
URL: http://svn.apache.org/viewcvs/directory/asn1/trunk/ber-new/src/test/org/apache/asn1new/util/MutableStringTest.java?rev=291711&r1=291710&r2=291711&view=diff
==============================================================================
--- directory/asn1/trunk/ber-new/src/test/org/apache/asn1new/util/MutableStringTest.java (original)
+++ directory/asn1/trunk/ber-new/src/test/org/apache/asn1new/util/MutableStringTest.java Mon Sep 26 11:56:41 2005
@@ -16,6 +16,8 @@
  */
 package org.apache.asn1new.util;
 
+import java.io.UnsupportedEncodingException;
+
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
@@ -30,20 +32,112 @@
      Assert.assertEquals("", s);   
     }
 
-    public void testNormalString()
+    public void testNormalString() throws UnsupportedEncodingException
     {
-        String s = new MutableString("abcdef".getBytes()).toString();
+        String s = new MutableString( "abcdef" ).toString();
         
         Assert.assertEquals("abcdef", s);   
     }
+    
+    public void testEmptyStringTrim() throws UnsupportedEncodingException
+    {
+        MutableString ms = new MutableString( "" );
+        
+        MutableString result = ms.trim();
+        
+        Assert.assertEquals( MutableString.EMPTY_STRING, result );
+        Assert.assertEquals( "", result.toString() );
+    }
+
+    public void testStringNoTrim() throws UnsupportedEncodingException
+    {
+        MutableString ms = new MutableString( "abcd" );
+        
+        MutableString result = ms.trim();
+        
+        Assert.assertEquals( "abcd", result.toString() );
+    }
+
+    public void testStringTrimLeft() throws UnsupportedEncodingException
+    {
+        MutableString ms = new MutableString( "  abcd" );
+        
+        MutableString result = ms.trim();
+        
+        Assert.assertEquals( "abcd", result.toString() );
+    }
+
+    public void testStringTrimRightFunc() throws UnsupportedEncodingException
+    {
+        MutableString ms = new MutableString( "abcd  " );
+        
+        MutableString result = ms.trimRight();
+        
+        Assert.assertEquals( "abcd", result.toString() );
+    }
+
+    public void testStringTrimLeftFunc() throws UnsupportedEncodingException
+    {
+        MutableString ms = new MutableString( "  abcd" );
+        
+        MutableString result = ms.trimLeft();
+        
+        Assert.assertEquals( "abcd", result.toString() );
+    }
+
+    public void testStringTrimRight() throws UnsupportedEncodingException
+    {
+        MutableString ms = new MutableString( "abcd  " );
+        
+        MutableString result = ms.trim();
+        
+        Assert.assertEquals( "abcd", result.toString() );
+    }
+
+    public void testStringTrimLeftRight() throws UnsupportedEncodingException
+    {
+        MutableString ms = new MutableString( "  abcd  " );
+        
+        MutableString result = ms.trim();
+        
+        Assert.assertEquals( "abcd", result.toString() );
+    }
+
+    public void testStringTrimAll() throws UnsupportedEncodingException
+    {
+        MutableString ms = new MutableString( "     " );
+        
+        MutableString result = ms.trim();
+        
+        Assert.assertEquals( MutableString.EMPTY_STRING, result );
+        Assert.assertEquals( "", result.toString() );
+    }
+
+    public void testStringUpperCase() throws UnsupportedEncodingException
+    {
+        MutableString ms = new MutableString( "abCdEf" );
+        
+        ms.toUpperCase();
+        
+        Assert.assertEquals( "ABCDEF", ms.toString() );
+    }
+
+    public void testStringLowerCase() throws UnsupportedEncodingException
+    {
+        MutableString ms = new MutableString( "abCdEf" );
+        
+        ms.toLowerCase();
+        
+        Assert.assertEquals( "abcdef", ms.toString() );
+    }
 
     /**
      * Test a string with non ASCII chars
      *
      */
-/*    public void testNonASCIIString()
+    public void testNonASCIIString() throws UnsupportedEncodingException
     {
-        MutableString ms = new MutableString("Emmanuel Lécharny");
+        MutableString ms = new MutableString( new String( "Emmanuel Lécharny".getBytes(), "UTF-8") );
         String s = ms.toString();
         
         int msLength = ms.getLength();
@@ -52,5 +146,4 @@
         Assert.assertEquals("Emmanuel Lécharny" , s);   
         Assert.assertEquals( sLength, msLength);
     }
-*/
 }

Modified: directory/asn1/trunk/ber-new/src/test/org/apache/asn1new/util/StringUtilsTest.java
URL: http://svn.apache.org/viewcvs/directory/asn1/trunk/ber-new/src/test/org/apache/asn1new/util/StringUtilsTest.java?rev=291711&r1=291710&r2=291711&view=diff
==============================================================================
--- directory/asn1/trunk/ber-new/src/test/org/apache/asn1new/util/StringUtilsTest.java (original)
+++ directory/asn1/trunk/ber-new/src/test/org/apache/asn1new/util/StringUtilsTest.java Mon Sep 26 11:56:41 2005
@@ -16,6 +16,8 @@
  */
 package org.apache.asn1new.util;
 
+import java.io.UnsupportedEncodingException;
+
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
@@ -24,47 +26,162 @@
  */
 public class StringUtilsTest extends TestCase {
 
-	public void testOneByteChar()
-	{
-		char res = StringUtils.bytesToChar(new byte[]{0x30});
-		
-		Assert.assertEquals('0', res);
-	}
-
-	public void testOneByteChar00()
-	{
-		char res = StringUtils.bytesToChar(new byte[]{0x00});
-		
-		Assert.assertEquals(0x00, res);
-	}
-
-	public void testOneByteChar7F()
-	{
-		char res = StringUtils.bytesToChar(new byte[]{0x7F});
-		
-		Assert.assertEquals(0x7F, res);
-	}
-
-	public void testTwoBytesChar()
-	{
-		char res = StringUtils.bytesToChar(new byte[]{(byte)0xCE, (byte)0x91});
-		
-		Assert.assertEquals(0x0391, res);
-	}
-
-	public void testThreeBytesChar()
-	{
-		char res = StringUtils.bytesToChar(new byte[]{(byte)0xE2, (byte)0x89, (byte)0xA2});
-		
-		Assert.assertEquals(0x2262, res);
-	}
-
-	/*
-	public void testSixBytesChar()
-	{
-		char res = StringUtils.bytesToChar(new byte[]{(byte)0xFD, (byte)0x93, (byte)0x91, (byte)0xBA, (byte)0x95, (byte)0xA3});
-		
-		Assert.assertEquals(0x7347A563, res);
-	}
-	*/
+    public void testOneByteChar() throws UnsupportedEncodingException
+    {
+        char[] res = new char[1];
+        
+        StringUtils.decodeUTF8( res, new byte[]{0x30} );
+        
+        Assert.assertEquals('0', res[0] );
+    }
+
+    public void testOneByteChar00() throws UnsupportedEncodingException
+    {
+        char[] res = new char[1];
+
+        StringUtils.decodeUTF8( res, new byte[]{0x00} );
+        
+        Assert.assertEquals(0x00, res[0] );
+    }
+
+    public void testOneByteChar7F() throws UnsupportedEncodingException
+    {
+        char[] res = new char[1];
+
+        StringUtils.decodeUTF8( res, new byte[]{0x7F} );
+        
+        Assert.assertEquals(0x7F, res[0] );
+    }
+
+    public void testTwoBytesChar() throws UnsupportedEncodingException
+    {
+        char[] res = new char[1];
+
+        StringUtils.decodeUTF8( res, new byte[]{(byte)0xCE, (byte)0x91} );
+        
+        Assert.assertEquals(0x0391, res[0] );
+    }
+
+    public void testThreeBytesChar() throws UnsupportedEncodingException
+    {
+        char[] res = new char[1];
+
+        StringUtils.decodeUTF8( res, new byte[]{(byte)0xE2, (byte)0x89, (byte)0xA2} );
+        
+        Assert.assertEquals(0x2262, res[0] );
+    }
+
+    public void testCharOneByte() throws UnsupportedEncodingException
+    {
+        char[] res = new char[1];
+
+        byte[] bytesInit = new byte[]{0x30};
+        byte[] bytesRes = new byte[1];
+        
+        StringUtils.decodeUTF8( res, bytesInit );
+        
+        int pos = StringUtils.charToBytes( res[0], bytesRes, 0 );
+        
+        Assert.assertEquals( bytesInit[0], bytesRes[0]);
+        Assert.assertEquals( 1, pos );
+    }
+
+    public void testCharOneByte00() throws UnsupportedEncodingException
+    {
+        char[] res = new char[1];
+
+        byte[] bytesInit = new byte[]{0x00};
+        byte[] bytesRes = new byte[1];
+        StringUtils.decodeUTF8( res, bytesInit );
+        
+        int pos = StringUtils.charToBytes( res[0], bytesRes, 0 );
+        
+        Assert.assertEquals( bytesInit[0], bytesRes[0]);
+        Assert.assertEquals( 1, pos );
+    }
+
+    public void testCharOneByte7F() throws UnsupportedEncodingException
+    {
+        char[] res = new char[1];
+
+        byte[] bytesInit = new byte[]{0x7F};
+        byte[] bytesRes = new byte[1];
+        StringUtils.decodeUTF8( res, bytesInit );
+        
+        int pos = StringUtils.charToBytes( res[0], bytesRes, 0 );
+        
+        Assert.assertEquals( bytesInit[0], bytesRes[0]);
+        Assert.assertEquals( 1, pos );
+    }
+
+    public void testCharTwoBytes() throws UnsupportedEncodingException
+    {
+        char[] res = new char[1];
+
+        byte[] bytesInit = new byte[]{(byte)0xCE, (byte)0x91};
+        byte[] bytesRes = new byte[2];
+        StringUtils.decodeUTF8( res, bytesInit );
+        
+        int pos = StringUtils.charToBytes( res[0], bytesRes, 0 );
+        
+        Assert.assertEquals( bytesInit[0], bytesRes[0]);
+        Assert.assertEquals( bytesInit[1], bytesRes[1]);
+        Assert.assertEquals( 2, pos );
+    }
+
+    public void testCharThreeBytes() throws UnsupportedEncodingException
+    {
+        char[] res = new char[1];
+
+        byte[] bytesInit = new byte[]{(byte)0xE2, (byte)0x89, (byte)0xA2};
+        byte[] bytesRes = new byte[3];
+        StringUtils.decodeUTF8( res, bytesInit );
+        
+        int pos = StringUtils.charToBytes( res[0], bytesRes, 0 );
+        
+        Assert.assertEquals( bytesInit[0], bytesRes[0]);
+        Assert.assertEquals( bytesInit[1], bytesRes[1]);
+        Assert.assertEquals( bytesInit[2], bytesRes[2]);
+        Assert.assertEquals( 3, pos );
+    }
+    
+    public void testTrimNull()
+    {
+        Assert.assertEquals( null, StringUtils.trim( null ) );
+    }
+
+    public void testTrimEmpty() 
+    {
+        Assert.assertEquals( "", StringUtils.trim( "" ) );
+    }
+
+    public void testTrimOneSpace()
+    {
+        Assert.assertEquals( "", StringUtils.trim( " " ) );
+    }
+
+    public void testNoTrim()
+    {
+        Assert.assertEquals( "abcd", StringUtils.trim( "abcd" ) );
+    }
+
+    public void testTrimLeft()
+    {
+        Assert.assertEquals( "abcd", StringUtils.trim( "  abcd" ) );
+    }
+
+    public void testTrimRight()
+    {
+        Assert.assertEquals( "abcd", StringUtils.trim( "abcd  " ) );
+    }
+
+    public void testTrimFull()
+    {
+        Assert.assertEquals( "abcd", StringUtils.trim( "  abcd  " ) );
+    }
+
+    public void testTrimSpaces()
+    {
+        Assert.assertEquals( "", StringUtils.trim( "    " ) );
+    }
 }



Mime
View raw message