001/* 002 * Copyright 2008-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 long}, which is a signed 64-bit value and can represent any integer 037 * between -9223372036854775808 and 9223372036854775807. If you need support 038 * for integer values of arbitrary size, see the {@link ASN1BigInteger} class as 039 * an alternative. 040 */ 041@NotMutable() 042@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 043public final class ASN1Long 044 extends ASN1Element 045{ 046 /** 047 * The serial version UID for this serializable class. 048 */ 049 private static final long serialVersionUID = -3445506299288414013L; 050 051 052 053 // The long value for this element. 054 private final long longValue; 055 056 057 058 /** 059 * Creates a new ASN.1 long element with the default BER type and the 060 * provided long value. 061 * 062 * @param longValue The long value to use for this element. 063 */ 064 public ASN1Long(final long longValue) 065 { 066 super(ASN1Constants.UNIVERSAL_INTEGER_TYPE, encodeLongValue(longValue)); 067 068 this.longValue = longValue; 069 } 070 071 072 073 /** 074 * Creates a new ASN.1 long element with the specified BER type and the 075 * provided long value. 076 * 077 * @param type The BER type to use for this element. 078 * @param longValue The long value to use for this element. 079 */ 080 public ASN1Long(final byte type, final long longValue) 081 { 082 super(type, encodeLongValue(longValue)); 083 084 this.longValue = longValue; 085 } 086 087 088 089 /** 090 * Creates a new ASN.1 long element with the specified BER type and the 091 * provided long and pre-encoded values. 092 * 093 * @param type The BER type to use for this element. 094 * @param longValue The long value to use for this element. 095 * @param value The pre-encoded value to use for this element. 096 */ 097 private ASN1Long(final byte type, final long longValue, final byte[] value) 098 { 099 super(type, value); 100 101 this.longValue = longValue; 102 } 103 104 105 106 /** 107 * Encodes the provided long value to a byte array suitable for use as the 108 * value of a long element. 109 * 110 * @param longValue The long value to be encoded. 111 * 112 * @return A byte array containing the encoded value. 113 */ 114 static byte[] encodeLongValue(final long longValue) 115 { 116 if (longValue < 0) 117 { 118 if ((longValue & 0xFFFF_FFFF_FFFF_FF80L) == 0xFFFF_FFFF_FFFF_FF80L) 119 { 120 return new byte[] 121 { 122 (byte) (longValue & 0xFFL) 123 }; 124 } 125 else if ((longValue & 0xFFFF_FFFF_FFFF_8000L) == 0xFFFF_FFFF_FFFF_8000L) 126 { 127 return new byte[] 128 { 129 (byte) ((longValue >> 8) & 0xFFL), 130 (byte) (longValue & 0xFFL) 131 }; 132 } 133 else if ((longValue & 0xFFFF_FFFF_FF80_0000L) == 0xFFFF_FFFF_FF80_0000L) 134 { 135 return new byte[] 136 { 137 (byte) ((longValue >> 16) & 0xFFL), 138 (byte) ((longValue >> 8) & 0xFFL), 139 (byte) (longValue & 0xFFL) 140 }; 141 } 142 else if ((longValue & 0xFFFF_FFFF_8000_0000L) == 0xFFFF_FFFF_8000_0000L) 143 { 144 return new byte[] 145 { 146 (byte) ((longValue >> 24) & 0xFFL), 147 (byte) ((longValue >> 16) & 0xFFL), 148 (byte) ((longValue >> 8) & 0xFFL), 149 (byte) (longValue & 0xFFL) 150 }; 151 } 152 else if ((longValue & 0xFFFF_FF80_0000_0000L) == 0xFFFF_FF80_0000_0000L) 153 { 154 return new byte[] 155 { 156 (byte) ((longValue >> 32) & 0xFFL), 157 (byte) ((longValue >> 24) & 0xFFL), 158 (byte) ((longValue >> 16) & 0xFFL), 159 (byte) ((longValue >> 8) & 0xFFL), 160 (byte) (longValue & 0xFFL) 161 }; 162 } 163 else if ((longValue & 0xFFFF_8000_0000_0000L) == 0xFFFF_8000_0000_0000L) 164 { 165 return new byte[] 166 { 167 (byte) ((longValue >> 40) & 0xFFL), 168 (byte) ((longValue >> 32) & 0xFFL), 169 (byte) ((longValue >> 24) & 0xFFL), 170 (byte) ((longValue >> 16) & 0xFFL), 171 (byte) ((longValue >> 8) & 0xFFL), 172 (byte) (longValue & 0xFFL) 173 }; 174 } 175 else if ((longValue & 0xFF80_0000_0000_0000L) == 0xFF80_0000_0000_0000L) 176 { 177 return new byte[] 178 { 179 (byte) ((longValue >> 48) & 0xFFL), 180 (byte) ((longValue >> 40) & 0xFFL), 181 (byte) ((longValue >> 32) & 0xFFL), 182 (byte) ((longValue >> 24) & 0xFFL), 183 (byte) ((longValue >> 16) & 0xFFL), 184 (byte) ((longValue >> 8) & 0xFFL), 185 (byte) (longValue & 0xFFL) 186 }; 187 } 188 else 189 { 190 return new byte[] 191 { 192 (byte) ((longValue >> 56) & 0xFFL), 193 (byte) ((longValue >> 48) & 0xFFL), 194 (byte) ((longValue >> 40) & 0xFFL), 195 (byte) ((longValue >> 32) & 0xFFL), 196 (byte) ((longValue >> 24) & 0xFFL), 197 (byte) ((longValue >> 16) & 0xFFL), 198 (byte) ((longValue >> 8) & 0xFFL), 199 (byte) (longValue & 0xFFL) 200 }; 201 } 202 } 203 else 204 { 205 if ((longValue & 0x0000_0000_0000_007FL) == longValue) 206 { 207 return new byte[] 208 { 209 (byte) (longValue & 0x7FL) 210 }; 211 } 212 else if ((longValue & 0x0000_0000_0000_7FFFL) == longValue) 213 { 214 return new byte[] 215 { 216 (byte) ((longValue >> 8) & 0x7FL), 217 (byte) (longValue & 0xFFL) 218 }; 219 } 220 else if ((longValue & 0x0000_0000_007F_FFFFL) == longValue) 221 { 222 return new byte[] 223 { 224 (byte) ((longValue >> 16) & 0x7FL), 225 (byte) ((longValue >> 8) & 0xFFL), 226 (byte) (longValue & 0xFFL) 227 }; 228 } 229 else if ((longValue & 0x0000_0000_7FFF_FFFFL) == longValue) 230 { 231 return new byte[] 232 { 233 (byte) ((longValue >> 24) & 0x7FL), 234 (byte) ((longValue >> 16) & 0xFFL), 235 (byte) ((longValue >> 8) & 0xFFL), 236 (byte) (longValue & 0xFFL) 237 }; 238 } 239 else if ((longValue & 0x0000_007F_FFFF_FFFFL) == longValue) 240 { 241 return new byte[] 242 { 243 (byte) ((longValue >> 32) & 0x7FL), 244 (byte) ((longValue >> 24) & 0xFFL), 245 (byte) ((longValue >> 16) & 0xFFL), 246 (byte) ((longValue >> 8) & 0xFFL), 247 (byte) (longValue & 0xFFL) 248 }; 249 } 250 else if ((longValue & 0x0000_7FFF_FFFF_FFFFL) == longValue) 251 { 252 return new byte[] 253 { 254 (byte) ((longValue >> 40) & 0x7FL), 255 (byte) ((longValue >> 32) & 0xFFL), 256 (byte) ((longValue >> 24) & 0xFFL), 257 (byte) ((longValue >> 16) & 0xFFL), 258 (byte) ((longValue >> 8) & 0xFFL), 259 (byte) (longValue & 0xFFL) 260 }; 261 } 262 else if ((longValue & 0x007F_FFFF_FFFF_FFFFL) == longValue) 263 { 264 return new byte[] 265 { 266 (byte) ((longValue >> 48) & 0x7FL), 267 (byte) ((longValue >> 40) & 0xFFL), 268 (byte) ((longValue >> 32) & 0xFFL), 269 (byte) ((longValue >> 24) & 0xFFL), 270 (byte) ((longValue >> 16) & 0xFFL), 271 (byte) ((longValue >> 8) & 0xFFL), 272 (byte) (longValue & 0xFFL) 273 }; 274 } 275 else 276 { 277 return new byte[] 278 { 279 (byte) ((longValue >> 56) & 0x7FL), 280 (byte) ((longValue >> 48) & 0xFFL), 281 (byte) ((longValue >> 40) & 0xFFL), 282 (byte) ((longValue >> 32) & 0xFFL), 283 (byte) ((longValue >> 24) & 0xFFL), 284 (byte) ((longValue >> 16) & 0xFFL), 285 (byte) ((longValue >> 8) & 0xFFL), 286 (byte) (longValue & 0xFFL) 287 }; 288 } 289 } 290 } 291 292 293 294 /** 295 * Retrieves the long value for this element. 296 * 297 * @return The long value for this element. 298 */ 299 public long longValue() 300 { 301 return longValue; 302 } 303 304 305 306 /** 307 * Decodes the contents of the provided byte array as a long element. 308 * 309 * @param elementBytes The byte array to decode as an ASN.1 long element. 310 * 311 * @return The decoded ASN.1 long element. 312 * 313 * @throws ASN1Exception If the provided array cannot be decoded as a long 314 * element. 315 */ 316 public static ASN1Long decodeAsLong(final byte[] elementBytes) 317 throws ASN1Exception 318 { 319 try 320 { 321 int valueStartPos = 2; 322 int length = (elementBytes[1] & 0x7F); 323 if (length != elementBytes[1]) 324 { 325 final int numLengthBytes = length; 326 327 length = 0; 328 for (int i=0; i < numLengthBytes; i++) 329 { 330 length <<= 8; 331 length |= (elementBytes[valueStartPos++] & 0xFF); 332 } 333 } 334 335 if ((elementBytes.length - valueStartPos) != length) 336 { 337 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length, 338 (elementBytes.length - valueStartPos))); 339 } 340 341 final byte[] value = new byte[length]; 342 System.arraycopy(elementBytes, valueStartPos, value, 0, length); 343 344 long longValue; 345 switch (value.length) 346 { 347 case 1: 348 longValue = (value[0] & 0xFFL); 349 if ((value[0] & 0x80L) != 0x00L) 350 { 351 longValue |= 0xFFFF_FFFF_FFFF_FF00L; 352 } 353 break; 354 355 case 2: 356 longValue = ((value[0] & 0xFFL) << 8) | (value[1] & 0xFFL); 357 if ((value[0] & 0x80L) != 0x00L) 358 { 359 longValue |= 0xFFFF_FFFF_FFFF_0000L; 360 } 361 break; 362 363 case 3: 364 longValue = ((value[0] & 0xFFL) << 16) | ((value[1] & 0xFFL) << 8) | 365 (value[2] & 0xFFL); 366 if ((value[0] & 0x80L) != 0x00L) 367 { 368 longValue |= 0xFFFF_FFFF_FF00_0000L; 369 } 370 break; 371 372 case 4: 373 longValue = ((value[0] & 0xFFL) << 24) | ((value[1] & 0xFFL) << 16) | 374 ((value[2] & 0xFFL) << 8) | (value[3] & 0xFFL); 375 if ((value[0] & 0x80L) != 0x00L) 376 { 377 longValue |= 0xFFFF_FFFF_0000_0000L; 378 } 379 break; 380 381 case 5: 382 longValue = ((value[0] & 0xFFL) << 32) | ((value[1] & 0xFFL) << 24) | 383 ((value[2] & 0xFFL) << 16) | ((value[3] & 0xFFL) << 8) | 384 (value[4] & 0xFFL); 385 if ((value[0] & 0x80L) != 0x00L) 386 { 387 longValue |= 0xFFFF_FF00_0000_0000L; 388 } 389 break; 390 391 case 6: 392 longValue = ((value[0] & 0xFFL) << 40) | ((value[1] & 0xFFL) << 32) | 393 ((value[2] & 0xFFL) << 24) | ((value[3] & 0xFFL) << 16) | 394 ((value[4] & 0xFFL) << 8) | (value[5] & 0xFFL); 395 if ((value[0] & 0x80L) != 0x00L) 396 { 397 longValue |= 0xFFFF_0000_0000_0000L; 398 } 399 break; 400 401 case 7: 402 longValue = ((value[0] & 0xFFL) << 48) | ((value[1] & 0xFFL) << 40) | 403 ((value[2] & 0xFFL) << 32) | ((value[3] & 0xFFL) << 24) | 404 ((value[4] & 0xFFL) << 16) | ((value[5] & 0xFFL) << 8) | 405 (value[6] & 0xFFL); 406 if ((value[0] & 0x80L) != 0x00L) 407 { 408 longValue |= 0xFF00_0000_0000_0000L; 409 } 410 break; 411 412 case 8: 413 longValue = ((value[0] & 0xFFL) << 56) | ((value[1] & 0xFFL) << 48) | 414 ((value[2] & 0xFFL) << 40) | ((value[3] & 0xFFL) << 32) | 415 ((value[4] & 0xFFL) << 24) | ((value[5] & 0xFFL) << 16) | 416 ((value[6] & 0xFFL) << 8) | (value[7] & 0xFFL); 417 break; 418 419 default: 420 throw new ASN1Exception(ERR_LONG_INVALID_LENGTH.get(value.length)); 421 } 422 423 return new ASN1Long(elementBytes[0], longValue, value); 424 } 425 catch (final ASN1Exception ae) 426 { 427 Debug.debugException(ae); 428 throw ae; 429 } 430 catch (final Exception e) 431 { 432 Debug.debugException(e); 433 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e); 434 } 435 } 436 437 438 439 /** 440 * Decodes the provided ASN.1 element as a long element. 441 * 442 * @param element The ASN.1 element to be decoded. 443 * 444 * @return The decoded ASN.1 long element. 445 * 446 * @throws ASN1Exception If the provided element cannot be decoded as a long 447 * element. 448 */ 449 public static ASN1Long decodeAsLong(final ASN1Element element) 450 throws ASN1Exception 451 { 452 long longValue; 453 final byte[] value = element.getValue(); 454 switch (value.length) 455 { 456 case 1: 457 longValue = (value[0] & 0xFFL); 458 if ((value[0] & 0x80L) != 0x00L) 459 { 460 longValue |= 0xFFFF_FFFF_FFFF_FF00L; 461 } 462 break; 463 464 case 2: 465 longValue = ((value[0] & 0xFFL) << 8) | (value[1] & 0xFFL); 466 if ((value[0] & 0x80L) != 0x00L) 467 { 468 longValue |= 0xFFFF_FFFF_FFFF_0000L; 469 } 470 break; 471 472 case 3: 473 longValue = ((value[0] & 0xFFL) << 16) | ((value[1] & 0xFFL) << 8) | 474 (value[2] & 0xFFL); 475 if ((value[0] & 0x80L) != 0x00L) 476 { 477 longValue |= 0xFFFF_FFFF_FF00_0000L; 478 } 479 break; 480 481 case 4: 482 longValue = ((value[0] & 0xFFL) << 24) | ((value[1] & 0xFFL) << 16) | 483 ((value[2] & 0xFFL) << 8) | (value[3] & 0xFFL); 484 if ((value[0] & 0x80L) != 0x00L) 485 { 486 longValue |= 0xFFFF_FFFF_0000_0000L; 487 } 488 break; 489 490 case 5: 491 longValue = ((value[0] & 0xFFL) << 32) | ((value[1] & 0xFFL) << 24) | 492 ((value[2] & 0xFFL) << 16) | ((value[3] & 0xFFL) << 8) | 493 (value[4] & 0xFFL); 494 if ((value[0] & 0x80L) != 0x00L) 495 { 496 longValue |= 0xFFFF_FF00_0000_0000L; 497 } 498 break; 499 500 case 6: 501 longValue = ((value[0] & 0xFFL) << 40) | ((value[1] & 0xFFL) << 32) | 502 ((value[2] & 0xFFL) << 24) | ((value[3] & 0xFFL) << 16) | 503 ((value[4] & 0xFFL) << 8) | (value[5] & 0xFFL); 504 if ((value[0] & 0x80L) != 0x00L) 505 { 506 longValue |= 0xFFFF_0000_0000_0000L; 507 } 508 break; 509 510 case 7: 511 longValue = ((value[0] & 0xFFL) << 48) | ((value[1] & 0xFFL) << 40) | 512 ((value[2] & 0xFFL) << 32) | ((value[3] & 0xFFL) << 24) | 513 ((value[4] & 0xFFL) << 16) | ((value[5] & 0xFFL) << 8) | 514 (value[6] & 0xFFL); 515 if ((value[0] & 0x80L) != 0x00L) 516 { 517 longValue |= 0xFF00_0000_0000_0000L; 518 } 519 break; 520 521 case 8: 522 longValue = ((value[0] & 0xFFL) << 56) | ((value[1] & 0xFFL) << 48) | 523 ((value[2] & 0xFFL) << 40) | ((value[3] & 0xFFL) << 32) | 524 ((value[4] & 0xFFL) << 24) | ((value[5] & 0xFFL) << 16) | 525 ((value[6] & 0xFFL) << 8) | (value[7] & 0xFFL); 526 break; 527 528 default: 529 throw new ASN1Exception(ERR_LONG_INVALID_LENGTH.get(value.length)); 530 } 531 532 return new ASN1Long(element.getType(), longValue, value); 533 } 534 535 536 537 /** 538 * {@inheritDoc} 539 */ 540 @Override() 541 public void toString(final StringBuilder buffer) 542 { 543 buffer.append(longValue); 544 } 545}