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.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}