001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.directory.api.asn1.ber.tlv;
021
022
023import org.apache.directory.api.i18n.I18n;
024import org.apache.directory.api.util.Strings;
025
026
027/**
028 * Parse and decode an Integer value.
029 *
030 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
031 */
032public final class IntegerDecoder
033{
034    /** A mask used to get only the necessary bytes */
035    private static final int[] MASK = new int[]
036        { 0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF };
037
038
039    /**
040     * Parse a byte buffer and send back an integer, controlling that this number
041     * is in a specified interval.
042     *
043     * @param value The Value containing the byte[] to parse
044     * @param min Lowest value allowed, included
045     * @param max Highest value allowed, included
046     * @return An integer
047     * @throws IntegerDecoderException Thrown if the byte[] does not contains an integer
048     */
049    public static int parse( BerValue value, int min, int max ) throws IntegerDecoderException
050    {
051        int result = parseInt( value );
052
053        if ( ( result >= min ) && ( result <= max ) )
054        {
055            return result;
056        }
057        else
058        {
059            throw new IntegerDecoderException( I18n.err( I18n.ERR_00038_VALUE_NOT_IN_RANGE, min, max ) );
060        }
061    }
062
063
064    /**
065     * Parse a byte buffer and send back an integer
066     *
067     * @param value The byte buffer to parse
068     * @return An integer
069     * @throws IntegerDecoderException Thrown if the byte stream does not contains an integer
070     */
071    public static int parse( BerValue value ) throws IntegerDecoderException
072    {
073        return parseInt( value );
074    }
075
076
077    /**
078     * Helper method used to parse the integer. We don't check any minimal or maximal
079     * bound.
080     * An BER encoded int can be either positive or negative. It uses the minimum
081     * number of byts necessary to encode the value. The high order bit gives the
082     * sign of the integer : if it's 1, then it's a negative value, otherwise it's
083     * a positive value. Integer with a high order bit set to 1 but prefixed by a 0x00
084     * are positive. If the integer is negative, then the 2 complement value is
085     * stored<br/>
086     * Here are a few samples :
087     * <ul>
088     * <li>0x02 0x01 0x00 : integer 0</li>
089     * <li>0x02 0x01 0x01 : integer 1</li>
090     * <li>0x02 0x01 0x7F : integer 127</li>
091     * <li>0x02 0x01 0x80 : integer -128</li>
092     * <li>0x02 0x01 0x81 : integer -127</li>
093     * <li>0x02 0x01 0xFF : integer -1</li>
094     * <li>0x02 0x02 0x00 0x80 : integer 128</li>
095     * <li>0x02 0x02 0x00 0x81 : integer 129</li>
096     * <li>0x02 0x02 0x00 0xFF : integer 255</li>
097     * </ul>
098     * and so on...
099     */
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}