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      /**
40       * Parse a byte buffer and send back an integer, controlling that this number
41       * is in a specified interval.
42       *
43       * @param value The Value containing the byte[] to parse
44       * @param min Lowest value allowed, included
45       * @param max Highest value allowed, included
46       * @return An integer
47       * @throws IntegerDecoderException Thrown if the byte[] does not contains an integer
48       */
49      public static int parse( BerValue value, int min, int max ) throws IntegerDecoderException
50      {
51          int result = parseInt( value );
52  
53          if ( ( result >= min ) && ( result <= max ) )
54          {
55              return result;
56          }
57          else
58          {
59              throw new IntegerDecoderException( I18n.err( I18n.ERR_00038_VALUE_NOT_IN_RANGE, min, max ) );
60          }
61      }
62  
63  
64      /**
65       * Parse a byte buffer and send back an integer
66       *
67       * @param value The byte buffer to parse
68       * @return An integer
69       * @throws IntegerDecoderException Thrown if the byte stream does not contains an integer
70       */
71      public static int parse( BerValue value ) throws IntegerDecoderException
72      {
73          return parseInt( value );
74      }
75  
76  
77      /**
78       * Helper method used to parse the integer. We don't check any minimal or maximal
79       * bound.
80       * An BER encoded int can be either positive or negative. It uses the minimum
81       * number of byts necessary to encode the value. The high order bit gives the
82       * sign of the integer : if it's 1, then it's a negative value, otherwise it's
83       * a positive value. Integer with a high order bit set to 1 but prefixed by a 0x00
84       * are positive. If the integer is negative, then the 2 complement value is
85       * stored<br/>
86       * Here are a few samples :
87       * <ul>
88       * <li>0x02 0x01 0x00 : integer 0</li>
89       * <li>0x02 0x01 0x01 : integer 1</li>
90       * <li>0x02 0x01 0x7F : integer 127</li>
91       * <li>0x02 0x01 0x80 : integer -128</li>
92       * <li>0x02 0x01 0x81 : integer -127</li>
93       * <li>0x02 0x01 0xFF : integer -1</li>
94       * <li>0x02 0x02 0x00 0x80 : integer 128</li>
95       * <li>0x02 0x02 0x00 0x81 : integer 129</li>
96       * <li>0x02 0x02 0x00 0xFF : integer 255</li>
97       * </ul>
98       * and so on...
99       */
100     private static int parseInt( BerValue value ) throws IntegerDecoderException
101     {
102         int result = 0;
103 
104         byte[] bytes = value.getData();
105 
106         if ( Strings.isEmpty( bytes ) )
107         {
108             throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
109         }
110 
111         boolean positive = true;
112 
113         switch ( bytes.length )
114         {
115             case 5:
116                 if ( bytes[0] == 0x00 )
117                 {
118                     if ( ( bytes[1] & ( byte ) 0x80 ) != ( byte ) 0x80 )
119                     {
120                         throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
121                     }
122 
123                     result = bytes[1] & 0x00FF;
124                     result = ( result << 8 ) | ( bytes[2] & 0x00FF );
125                     result = ( result << 8 ) | ( bytes[3] & 0x00FF );
126                     result = ( result << 8 ) | ( bytes[4] & 0x00FF );
127                 }
128                 else
129                 {
130                     throw new IntegerDecoderException( I18n.err( I18n.ERR_00036_0_BYTES_LONG_INTEGER ) );
131                 }
132 
133                 break;
134 
135             case 4:
136                 if ( bytes[0] == 0x00 )
137                 {
138                     result = bytes[1] & 0x00FF;
139                 }
140                 else
141                 {
142                     result = bytes[0] & 0x00FF;
143 
144                     if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
145                     {
146                         positive = false;
147                     }
148 
149                     result = ( result << 8 ) | ( bytes[1] & 0x00FF );
150                 }
151 
152                 result = ( result << 8 ) | ( bytes[2] & 0x00FF );
153                 result = ( result << 8 ) | ( bytes[3] & 0x00FF );
154 
155                 break;
156 
157             case 3:
158                 if ( bytes[0] == 0x00 )
159                 {
160                     result = bytes[1] & 0x00FF;
161                 }
162                 else
163                 {
164                     result = bytes[0] & 0x00FF;
165 
166                     if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
167                     {
168                         positive = false;
169                     }
170 
171                     result = ( result << 8 ) | ( bytes[1] & 0x00FF );
172                 }
173 
174                 result = ( result << 8 ) | ( bytes[2] & 0x00FF );
175 
176                 break;
177 
178             case 2:
179                 if ( bytes[0] == 0x00 )
180                 {
181                     result = bytes[1] & 0x00FF;
182                 }
183                 else
184                 {
185                     result = bytes[0] & 0x00FF;
186 
187                     if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
188                     {
189                         positive = false;
190                     }
191 
192                     result = ( result << 8 ) | ( bytes[1] & 0x00FF );
193                 }
194 
195                 break;
196 
197             case 1:
198                 result = ( result << 8 ) | ( bytes[0] & 0x00FF );
199 
200                 if ( ( bytes[0] & ( byte ) 0x80 ) == ( byte ) 0x80 )
201                 {
202                     positive = false;
203                 }
204 
205                 break;
206 
207             default:
208                 throw new IntegerDecoderException( I18n.err( I18n.ERR_00037_ABOVE_4_BYTES_INTEGER ) );
209         }
210 
211         if ( !positive )
212         {
213             result = -( ( ( ~result ) + 1 ) & MASK[bytes.length - 1] );
214         }
215 
216         return result;
217     }
218 }