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}