View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.directory.api.asn1.ber.tlv;
21  
22  
23  import org.apache.directory.api.i18n.I18n;
24  import org.apache.directory.api.util.Strings;
25  
26  
27  /**
28   * Parse and decode an Integer value.
29   *
30   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
31   */
32  public final class IntegerDecoder
33  {
34      /** A mask used to get only the necessary bytes */
35      private static final int[] MASK = new int[]
36          { 0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF };
37  
38  
39      private IntegerDecoder()
40      {
41      }
42  
43  
44      /**
45       * Parse a byte buffer and send back an integer, controlling that this number
46       * is in a specified interval.
47       *
48       * @param value The Value containing the byte[] to parse
49       * @param min Lowest value allowed, included
50       * @param max Highest value allowed, included
51       * @return An integer
52       * @throws IntegerDecoderException Thrown if the byte[] does not contains an integer
53       */
54      public static int parse( BerValue value, int min, int max ) throws IntegerDecoderException
55      {
56          int result = parseInt( value );
57  
58          if ( ( result >= min ) && ( result <= max ) )
59          {
60              return result;
61          }
62          else
63          {
64              throw new IntegerDecoderException( I18n.err( I18n.ERR_00038_VALUE_NOT_IN_RANGE, min, max ) );
65          }
66      }
67  
68  
69      /**
70       * Parse a byte buffer and send back an integer
71       *
72       * @param value The byte buffer to parse
73       * @return An integer
74       * @throws IntegerDecoderException Thrown if the byte stream does not contains an integer
75       */
76      public static int parse( BerValue value ) throws IntegerDecoderException
77      {
78          return parseInt( value );
79      }
80  
81  
82      /**
83       * Helper method used to parse the integer. We don't check any minimal or maximal
84       * bound.
85       * An BER encoded int can be either positive or negative. It uses the minimum
86       * number of byts necessary to encode the value. The high order bit gives the
87       * sign of the integer : if it's 1, then it's a negative value, otherwise it's
88       * a positive value. Integer with a high order bit set to 1 but prefixed by a 0x00
89       * are positive. If the integer is negative, then the 2 complement value is
90       * stored<br>
91       * Here are a few samples :
92       * <ul>
93       * <li>0x02 0x01 0x00 : integer 0</li>
94       * <li>0x02 0x01 0x01 : integer 1</li>
95       * <li>0x02 0x01 0x7F : integer 127</li>
96       * <li>0x02 0x01 0x80 : integer -128</li>
97       * <li>0x02 0x01 0x81 : integer -127</li>
98       * <li>0x02 0x01 0xFF : integer -1</li>
99       * <li>0x02 0x02 0x00 0x80 : integer 128</li>
100      * <li>0x02 0x02 0x00 0x81 : integer 129</li>
101      * <li>0x02 0x02 0x00 0xFF : integer 255</li>
102      * </ul>
103      * and so on...
104      */
105     private static int parseInt( BerValue value ) throws IntegerDecoderException
106     {
107         int result = 0;
108 
109         byte[] bytes = value.getData();
110 
111         if ( Strings.isEmpty( bytes ) )
112         {
113             throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
114         }
115 
116         boolean positive = true;
117 
118         switch ( bytes.length )
119         {
120             case 5:
121                 if ( bytes[0] == 0x00 )
122                 {
123                     if ( ( bytes[1] & ( byte ) 0x80 ) != ( byte ) 0x80 )
124                     {
125                         throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
126                     }
127 
128                     result = bytes[1] & 0x00FF;
129                     result = ( result << 8 ) | ( bytes[2] & 0x00FF );
130                     result = ( result << 8 ) | ( bytes[3] & 0x00FF );
131                     result = ( result << 8 ) | ( bytes[4] & 0x00FF );
132                 }
133                 else
134                 {
135                     throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
136                 }
137 
138                 break;
139 
140             case 4:
141                 if ( bytes[0] == 0x00 )
142                 {
143                     result = bytes[1] & 0x00FF;
144                 }
145                 else
146                 {
147                     result = bytes[0] & 0x00FF;
148 
149                     if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
150                     {
151                         positive = false;
152                     }
153 
154                     result = ( result << 8 ) | ( bytes[1] & 0x00FF );
155                 }
156 
157                 result = ( result << 8 ) | ( bytes[2] & 0x00FF );
158                 result = ( result << 8 ) | ( bytes[3] & 0x00FF );
159 
160                 break;
161 
162             case 3:
163                 if ( bytes[0] == 0x00 )
164                 {
165                     result = bytes[1] & 0x00FF;
166                 }
167                 else
168                 {
169                     result = bytes[0] & 0x00FF;
170 
171                     if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
172                     {
173                         positive = false;
174                     }
175 
176                     result = ( result << 8 ) | ( bytes[1] & 0x00FF );
177                 }
178 
179                 result = ( result << 8 ) | ( bytes[2] & 0x00FF );
180 
181                 break;
182 
183             case 2:
184                 if ( bytes[0] == 0x00 )
185                 {
186                     result = bytes[1] & 0x00FF;
187                 }
188                 else
189                 {
190                     result = bytes[0] & 0x00FF;
191 
192                     if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
193                     {
194                         positive = false;
195                     }
196 
197                     result = ( result << 8 ) | ( bytes[1] & 0x00FF );
198                 }
199 
200                 break;
201 
202             case 1:
203                 result = ( result << 8 ) | ( bytes[0] & 0x00FF );
204 
205                 if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
206                 {
207                     positive = false;
208                 }
209 
210                 break;
211 
212             default:
213                 throw new IntegerDecoderException( I18n.err( I18n.ERR_00037_ABOVE_4_BYTES_INTEGER ) );
214         }
215 
216         if ( !positive )
217         {
218             result = -( ( ( ~result ) + 1 ) & MASK[bytes.length - 1] );
219         }
220 
221         return result;
222     }
223 }