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 private IntegerDecoder() 040 { 041 } 042 043 044 /** 045 * Parse a byte buffer and send back an integer, controlling that this number 046 * is in a specified interval. 047 * 048 * @param value The Value containing the byte[] to parse 049 * @param min Lowest value allowed, included 050 * @param max Highest value allowed, included 051 * @return An integer 052 * @throws IntegerDecoderException Thrown if the byte[] does not contains an integer 053 */ 054 public static int parse( BerValue value, int min, int max ) throws IntegerDecoderException 055 { 056 int result = parseInt( value ); 057 058 if ( ( result >= min ) && ( result <= max ) ) 059 { 060 return result; 061 } 062 else 063 { 064 throw new IntegerDecoderException( I18n.err( I18n.ERR_00038_VALUE_NOT_IN_RANGE, min, max ) ); 065 } 066 } 067 068 069 /** 070 * Parse a byte buffer and send back an integer 071 * 072 * @param value The byte buffer to parse 073 * @return An integer 074 * @throws IntegerDecoderException Thrown if the byte stream does not contains an integer 075 */ 076 public static int parse( BerValue value ) throws IntegerDecoderException 077 { 078 return parseInt( value ); 079 } 080 081 082 /** 083 * Helper method used to parse the integer. We don't check any minimal or maximal 084 * bound. 085 * An BER encoded int can be either positive or negative. It uses the minimum 086 * number of byts necessary to encode the value. The high order bit gives the 087 * sign of the integer : if it's 1, then it's a negative value, otherwise it's 088 * a positive value. Integer with a high order bit set to 1 but prefixed by a 0x00 089 * are positive. If the integer is negative, then the 2 complement value is 090 * stored<br> 091 * Here are a few samples : 092 * <ul> 093 * <li>0x02 0x01 0x00 : integer 0</li> 094 * <li>0x02 0x01 0x01 : integer 1</li> 095 * <li>0x02 0x01 0x7F : integer 127</li> 096 * <li>0x02 0x01 0x80 : integer -128</li> 097 * <li>0x02 0x01 0x81 : integer -127</li> 098 * <li>0x02 0x01 0xFF : integer -1</li> 099 * <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}