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}