001/* 002 * Copyright 2007-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2019 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.asn1; 022 023 024 025import com.unboundid.util.Debug; 026import com.unboundid.util.NotMutable; 027import com.unboundid.util.ThreadSafety; 028import com.unboundid.util.ThreadSafetyLevel; 029 030import static com.unboundid.asn1.ASN1Messages.*; 031 032 033 034/** 035 * This class provides an ASN.1 integer element that is backed by a Java 036 * {@code int}, which is a signed 32-bit value and can represent any integer 037 * between -2147483648 and 2147483647. If you need support for integer values 038 * in the signed 64-bit range, see the {@link ASN1Long} class as an alternative. 039 * If you need support for integer values of arbitrary size, see 040 * {@link ASN1BigInteger}. 041 */ 042@NotMutable() 043@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 044public final class ASN1Integer 045 extends ASN1Element 046{ 047 /** 048 * The serial version UID for this serializable class. 049 */ 050 private static final long serialVersionUID = -733929804601994372L; 051 052 053 054 // The int value for this element. 055 private final int intValue; 056 057 058 059 /** 060 * Creates a new ASN.1 integer element with the default BER type and the 061 * provided int value. 062 * 063 * @param intValue The int value to use for this element. 064 */ 065 public ASN1Integer(final int intValue) 066 { 067 super(ASN1Constants.UNIVERSAL_INTEGER_TYPE, encodeIntValue(intValue)); 068 069 this.intValue = intValue; 070 } 071 072 073 074 /** 075 * Creates a new ASN.1 integer element with the specified BER type and the 076 * provided int value. 077 * 078 * @param type The BER type to use for this element. 079 * @param intValue The int value to use for this element. 080 */ 081 public ASN1Integer(final byte type, final int intValue) 082 { 083 super(type, encodeIntValue(intValue)); 084 085 this.intValue = intValue; 086 } 087 088 089 090 /** 091 * Creates a new ASN.1 integer element with the specified BER type and the 092 * provided int and pre-encoded values. 093 * 094 * @param type The BER type to use for this element. 095 * @param intValue The int value to use for this element. 096 * @param value The pre-encoded value to use for this element. 097 */ 098 private ASN1Integer(final byte type, final int intValue, final byte[] value) 099 { 100 super(type, value); 101 102 this.intValue = intValue; 103 } 104 105 106 107 /** 108 * Encodes the provided int value to a byte array suitable for use as the 109 * value of an integer element. 110 * 111 * @param intValue The int value to be encoded. 112 * 113 * @return A byte array containing the encoded value. 114 */ 115 static byte[] encodeIntValue(final int intValue) 116 { 117 if (intValue < 0) 118 { 119 if ((intValue & 0xFFFF_FF80) == 0xFFFF_FF80) 120 { 121 return new byte[] 122 { 123 (byte) (intValue & 0xFF) 124 }; 125 } 126 else if ((intValue & 0xFFFF_8000) == 0xFFFF_8000) 127 { 128 return new byte[] 129 { 130 (byte) ((intValue >> 8) & 0xFF), 131 (byte) (intValue & 0xFF) 132 }; 133 } 134 else if ((intValue & 0xFF80_0000) == 0xFF80_0000) 135 { 136 return new byte[] 137 { 138 (byte) ((intValue >> 16) & 0xFF), 139 (byte) ((intValue >> 8) & 0xFF), 140 (byte) (intValue & 0xFF) 141 }; 142 } 143 else 144 { 145 return new byte[] 146 { 147 (byte) ((intValue >> 24) & 0xFF), 148 (byte) ((intValue >> 16) & 0xFF), 149 (byte) ((intValue >> 8) & 0xFF), 150 (byte) (intValue & 0xFF) 151 }; 152 } 153 } 154 else 155 { 156 if ((intValue & 0x0000_007F) == intValue) 157 { 158 return new byte[] 159 { 160 (byte) (intValue & 0x7F) 161 }; 162 } 163 else if ((intValue & 0x0000_7FFF) == intValue) 164 { 165 return new byte[] 166 { 167 (byte) ((intValue >> 8) & 0x7F), 168 (byte) (intValue & 0xFF) 169 }; 170 } 171 else if ((intValue & 0x007F_FFFF) == intValue) 172 { 173 return new byte[] 174 { 175 (byte) ((intValue >> 16) & 0x7F), 176 (byte) ((intValue >> 8) & 0xFF), 177 (byte) (intValue & 0xFF) 178 }; 179 } 180 else 181 { 182 return new byte[] 183 { 184 (byte) ((intValue >> 24) & 0x7F), 185 (byte) ((intValue >> 16) & 0xFF), 186 (byte) ((intValue >> 8) & 0xFF), 187 (byte) (intValue & 0xFF) 188 }; 189 } 190 } 191 } 192 193 194 195 /** 196 * Retrieves the int value for this element. 197 * 198 * @return The int value for this element. 199 */ 200 public int intValue() 201 { 202 return intValue; 203 } 204 205 206 207 /** 208 * Decodes the contents of the provided byte array as an integer element. 209 * 210 * @param elementBytes The byte array to decode as an ASN.1 integer element. 211 * 212 * @return The decoded ASN.1 integer element. 213 * 214 * @throws ASN1Exception If the provided array cannot be decoded as an 215 * integer element. 216 */ 217 public static ASN1Integer decodeAsInteger(final byte[] elementBytes) 218 throws ASN1Exception 219 { 220 try 221 { 222 int valueStartPos = 2; 223 int length = (elementBytes[1] & 0x7F); 224 if (length != elementBytes[1]) 225 { 226 final int numLengthBytes = length; 227 228 length = 0; 229 for (int i=0; i < numLengthBytes; i++) 230 { 231 length <<= 8; 232 length |= (elementBytes[valueStartPos++] & 0xFF); 233 } 234 } 235 236 if ((elementBytes.length - valueStartPos) != length) 237 { 238 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length, 239 (elementBytes.length - valueStartPos))); 240 } 241 242 final byte[] value = new byte[length]; 243 System.arraycopy(elementBytes, valueStartPos, value, 0, length); 244 245 int intValue; 246 switch (value.length) 247 { 248 case 1: 249 intValue = (value[0] & 0xFF); 250 if ((value[0] & 0x80) != 0x00) 251 { 252 intValue |= 0xFFFF_FF00; 253 } 254 break; 255 256 case 2: 257 intValue = ((value[0] & 0xFF) << 8) | (value[1] & 0xFF); 258 if ((value[0] & 0x80) != 0x00) 259 { 260 intValue |= 0xFFFF_0000; 261 } 262 break; 263 264 case 3: 265 intValue = ((value[0] & 0xFF) << 16) | ((value[1] & 0xFF) << 8) | 266 (value[2] & 0xFF); 267 if ((value[0] & 0x80) != 0x00) 268 { 269 intValue |= 0xFF00_0000; 270 } 271 break; 272 273 case 4: 274 intValue = ((value[0] & 0xFF) << 24) | ((value[1] & 0xFF) << 16) | 275 ((value[2] & 0xFF) << 8) | (value[3] & 0xFF); 276 break; 277 278 default: 279 throw new ASN1Exception(ERR_ENUMERATED_INVALID_LENGTH.get( 280 value.length)); 281 } 282 283 return new ASN1Integer(elementBytes[0], intValue, value); 284 } 285 catch (final ASN1Exception ae) 286 { 287 Debug.debugException(ae); 288 throw ae; 289 } 290 catch (final Exception e) 291 { 292 Debug.debugException(e); 293 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e); 294 } 295 } 296 297 298 299 /** 300 * Decodes the provided ASN.1 element as an integer element. 301 * 302 * @param element The ASN.1 element to be decoded. 303 * 304 * @return The decoded ASN.1 integer element. 305 * 306 * @throws ASN1Exception If the provided element cannot be decoded as an 307 * integer element. 308 */ 309 public static ASN1Integer decodeAsInteger(final ASN1Element element) 310 throws ASN1Exception 311 { 312 int intValue; 313 final byte[] value = element.getValue(); 314 switch (value.length) 315 { 316 case 1: 317 intValue = (value[0] & 0xFF); 318 if ((value[0] & 0x80) != 0x00) 319 { 320 intValue |= 0xFFFF_FF00; 321 } 322 break; 323 324 case 2: 325 intValue = ((value[0] & 0xFF) << 8) | (value[1] & 0xFF); 326 if ((value[0] & 0x80) != 0x00) 327 { 328 intValue |= 0xFFFF_0000; 329 } 330 break; 331 332 case 3: 333 intValue = ((value[0] & 0xFF) << 16) | ((value[1] & 0xFF) << 8) | 334 (value[2] & 0xFF); 335 if ((value[0] & 0x80) != 0x00) 336 { 337 intValue |= 0xFF00_0000; 338 } 339 break; 340 341 case 4: 342 intValue = ((value[0] & 0xFF) << 24) | ((value[1] & 0xFF) << 16) | 343 ((value[2] & 0xFF) << 8) | (value[3] & 0xFF); 344 break; 345 346 default: 347 throw new ASN1Exception(ERR_INTEGER_INVALID_LENGTH.get(value.length)); 348 } 349 350 return new ASN1Integer(element.getType(), intValue, value); 351 } 352 353 354 355 /** 356 * {@inheritDoc} 357 */ 358 @Override() 359 public void toString(final StringBuilder buffer) 360 { 361 buffer.append(intValue); 362 } 363}