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 2013/04/26 00:55:32 UTC

svn commit: r1476001 - in /directory/shared/trunk/asn1/ber/src: main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java

Author: elecharny
Date: Thu Apr 25 22:55:31 2013
New Revision: 1476001

URL: http://svn.apache.org/r1476001
Log:
Fixed the Integer BER decoding : when the value starts with 0x00, it may be a positive value with a high order bit set to 1

Modified:
    directory/shared/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java
    directory/shared/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java

Modified: directory/shared/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java?rev=1476001&r1=1476000&r2=1476001&view=diff
==============================================================================
--- directory/shared/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java (original)
+++ directory/shared/trunk/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/IntegerDecoder.java Thu Apr 25 22:55:31 2013
@@ -72,11 +72,30 @@ public final class IntegerDecoder
     {
         return parseInt( value );
     }
-    
-    
+
+
     /**
      * Helper method used to parse the integer. We don't check any minimal or maximal
      * bound.
+     * An BER encoded int can be either positive or negative. It uses the minimum
+     * number of byts necessary to encode the value. The high order bit gives the
+     * sign of the integer : if it's 1, then it's a negative value, otherwise it's
+     * a positive value. Integer with a high order bit set to 1 but prefixed by a 0x00
+     * are positive. If the integer is negative, then the 2 complement value is
+     * stored<br/>
+     * Here are a few samples :
+     * <ul>
+     * <li>0x02 0x01 0x00 : integer 0</li>
+     * <li>0x02 0x01 0x01 : integer 1</li>
+     * <li>0x02 0x01 0x7F : integer 127</li>
+     * <li>0x02 0x01 0x80 : integer -128</li>
+     * <li>0x02 0x01 0x81 : integer -127</li>
+     * <li>0x02 0x01 0xFF : integer -1</li>
+     * <li>0x02 0x02 0x00 0x80 : integer 128</li>
+     * <li>0x02 0x02 0x00 0x81 : integer 129</li>
+     * <li>0x02 0x02 0x00 0xFF : integer 255</li>
+     * </ul>
+     * and so on...
      */
     private static int parseInt( BerValue value ) throws IntegerDecoderException
     {
@@ -89,21 +108,111 @@ public final class IntegerDecoder
             throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
         }
 
-        if ( bytes.length > 4 )
-        {
-            throw new IntegerDecoderException( I18n.err( I18n.ERR_00037_ABOVE_4_BYTES_INTEGER ) );
-        }
+        boolean positive = true;
 
-        for ( int i = 0; ( i < bytes.length ); i++ )
+        switch ( bytes.length )
         {
-            result = ( result << 8 ) | ( bytes[i] & 0x00FF );
+            case 5:
+                if ( bytes[0] == 0x00 )
+                {
+                    if ( ( bytes[1] & ( byte ) 0x80 ) != ( byte ) 0x80 )
+                    {
+                        throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
+                    }
+
+                    result = bytes[1] & 0x00FF;
+                    result = ( result << 8 ) | ( bytes[2] & 0x00FF );
+                    result = ( result << 8 ) | ( bytes[3] & 0x00FF );
+                    result = ( result << 8 ) | ( bytes[4] & 0x00FF );
+                }
+                else
+                {
+                    throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
+                }
+
+                break;
+
+            case 4:
+                if ( bytes[0] == 0x00 )
+                {
+                    result = bytes[1] & 0x00FF;
+                }
+                else
+                {
+                    result = bytes[0] & 0x00FF;
+
+                    if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+                    {
+                        positive = false;
+                    }
+
+                    result = ( result << 8 ) | ( bytes[1] & 0x00FF );
+                }
+
+                result = ( result << 8 ) | ( bytes[2] & 0x00FF );
+                result = ( result << 8 ) | ( bytes[3] & 0x00FF );
+
+                break;
+
+            case 3:
+                if ( bytes[0] == 0x00 )
+                {
+                    result = bytes[1] & 0x00FF;
+                }
+                else
+                {
+                    result = bytes[0] & 0x00FF;
+
+                    if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+                    {
+                        positive = false;
+                    }
+
+                    result = ( result << 8 ) | ( bytes[1] & 0x00FF );
+                }
+
+                result = ( result << 8 ) | ( bytes[2] & 0x00FF );
+
+                break;
+
+            case 2:
+                if ( bytes[0] == 0x00 )
+                {
+                    result = bytes[1] & 0x00FF;
+                }
+                else
+                {
+                    result = bytes[0] & 0x00FF;
+
+                    if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+                    {
+                        positive = false;
+                    }
+
+                    result = ( result << 8 ) | ( bytes[1] & 0x00FF );
+                }
+
+                break;
+
+            case 1:
+                result = ( result << 8 ) | ( bytes[0] & 0x00FF );
+
+                if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
+                {
+                    positive = false;
+                }
+
+                break;
+
+            default:
+                throw new IntegerDecoderException( I18n.err( I18n.ERR_00037_ABOVE_4_BYTES_INTEGER ) );
         }
 
-        if ( ( bytes[0] & 0x80 ) == 0x80 )
+        if ( !positive )
         {
             result = -( ( ( ~result ) + 1 ) & MASK[bytes.length - 1] );
         }
-        
+
         return result;
     }
 }

Modified: directory/shared/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java
URL: http://svn.apache.org/viewvc/directory/shared/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java?rev=1476001&r1=1476000&r2=1476001&view=diff
==============================================================================
--- directory/shared/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java (original)
+++ directory/shared/trunk/asn1/ber/src/test/java/org/apache/directory/api/asn1/ber/tlv/PrimitivesTest.java Thu Apr 25 22:55:31 2013
@@ -21,10 +21,8 @@ package org.apache.directory.api.asn1.be
 
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
-import org.apache.directory.api.asn1.ber.tlv.BerValue;
-import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
-import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -69,6 +67,12 @@ public class PrimitivesTest
 
         value.init( 2 );
         value.setData( new byte[]
+            { ( byte ) 0x00, ( byte ) 0xFF } ); // res = 255
+        assertEquals( 255, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
             { 0x00, 0x01 } ); // res = 1
         assertEquals( 1, IntegerDecoder.parse( value ) );
         value.reset();
@@ -97,31 +101,112 @@ public class PrimitivesTest
         assertEquals( 512, IntegerDecoder.parse( value ) );
         value.reset();
 
+        value.init( 2 );
+        value.setData( new byte[]
+            { 0x7F, ( byte ) 0xFF } ); // res = 32767
+        assertEquals( 32767, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
+            { ( byte ) 0x80, 0x00 } ); // res = -32768
+        assertEquals( -32768, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 2 );
+        value.setData( new byte[]
+            { ( byte ) 0xFF, ( byte ) 0xFF } ); // res = -65535
+        assertEquals( -1, IntegerDecoder.parse( value ) );
+        value.reset();
+
         value.init( 3 );
         value.setData( new byte[]
             { 0x00, ( byte ) 0xFF, ( byte ) 0xFF } ); // res = 65535
         assertEquals( 65535, IntegerDecoder.parse( value ) );
         value.reset();
 
+        value.init( 3 );
+        // res = 65536
+        value.setData( new byte[]
+            { 0x01, 0x00, 0x00 } );
+        assertEquals( 65536, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 3 );
+        // res = 8388607
+        value.setData( new byte[]
+            { 0x7F, ( byte ) 0xFF, ( byte ) 0xFF } );
+        assertEquals( 8388607, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 3 );
+        // res = -8388608
+        value.setData( new byte[]
+            { ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x00 } );
+        assertEquals( -8388608, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 3 );
+        // res = -1
+        value.setData( new byte[]
+            { ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+        assertEquals( -1, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 4 );
+        // res = 16777215
+        value.setData( new byte[]
+            { 0x00, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+        assertEquals( 16777215, IntegerDecoder.parse( value ) );
+        value.reset();
+
         value.init( 4 );
+        // res = 2^31 - 1 = MaxInt
         value.setData( new byte[]
-            { ( byte ) 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } ); // res
-                                                                              // =
-                                                                              // 2^31
-                                                                              // - 1
-                                                                              // =
-                                                                              // MaxInt
+            { ( byte ) 0x7F, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
         assertEquals( Integer.MAX_VALUE, IntegerDecoder.parse( value ) );
         value.reset();
 
         value.init( 4 );
+        // res = 2^31 = MinInt
+        value.setData( new byte[]
+            { ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 } );
+        assertEquals( Integer.MIN_VALUE, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 4 );
+        // res = -1
         value.setData( new byte[]
-            { ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 } ); // res
-                                                                              // =
-                                                                              // 2^31
-                                                                              // =
-                                                                              // MinInt
+            { ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+        assertEquals( -1, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        value.init( 5 );
+        // res = 2^31 = MinInt
+        value.setData( new byte[]
+            { 0x00, ( byte ) 0x80, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 } );
         assertEquals( Integer.MIN_VALUE, IntegerDecoder.parse( value ) );
         value.reset();
+
+        value.init( 5 );
+        // res = 2^31 = MinInt
+        value.setData( new byte[]
+            { 0x00, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF } );
+        assertEquals( -1, IntegerDecoder.parse( value ) );
+        value.reset();
+
+        try
+        {
+            value.init( 5 );
+            // res = 2^31 = MinInt
+            value.setData( new byte[]
+                { 0x00, ( byte ) 0x7F, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00 } ); // res
+            IntegerDecoder.parse( value );
+            fail();
+        }
+        catch ( IntegerDecoderException ide )
+        {
+            // Expected
+        }
     }
 } // end class TLVTagDecoderTest