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