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}