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