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