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