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