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