001/*
002 * Copyright 2017-2019 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2017-2019 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 java.math.BigInteger;
026
027import com.unboundid.util.Debug;
028import com.unboundid.util.NotMutable;
029import com.unboundid.util.ThreadSafety;
030import com.unboundid.util.ThreadSafetyLevel;
031
032import static com.unboundid.asn1.ASN1Messages.*;
033
034
035
036/**
037 * This class provides an ASN.1 integer element that is backed by a Java
038 * {@code BigInteger} and whose value can be represented as an integer of any
039 * magnitude.  For an ASN.1 integer implementation that is backed by a signed
040 * 32-bit {@code int}, see {@link ASN1Integer}.  For an implementation that is
041 * backed by a signed 64-bit {@code long}, see {@link ASN1Long}.
042 */
043@NotMutable()
044@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
045public final class ASN1BigInteger
046       extends ASN1Element
047{
048  /**
049   * The serial version UID for this serializable class.
050   */
051  private static final long serialVersionUID = 2631806934961821260L;
052
053
054
055  // The BigInteger value for this element.
056  private final BigInteger value;
057
058
059
060  /**
061   * Creates a new ASN.1 big integer element with the default BER type and the
062   * provided value.
063   *
064   * @param  value  The value to use for this element.  It must not be
065   *                {@code null}.
066   */
067  public ASN1BigInteger(final BigInteger value)
068  {
069    this(ASN1Constants.UNIVERSAL_INTEGER_TYPE, value);
070  }
071
072
073
074  /**
075   * Creates a new ASN.1 big integer element with the specified BER type and the
076   * provided value.
077   *
078   * @param  type   The BER type to use for this element.
079   * @param  value  The value to use for this element.  It must not be
080   *                {@code null}.
081   */
082  public ASN1BigInteger(final byte type, final BigInteger value)
083  {
084    super(type, value.toByteArray());
085
086    this.value = value;
087  }
088
089
090
091  /**
092   * Creates a new ASN.1 big integer element with the specified BER type and the
093   * provided value.
094   *
095   * @param  type             The BER type to use for this element.
096   * @param  bigIntegerValue  The value to use for this element.  It must not be
097   *                          {@code null}.
098   * @param  berValue         The encoded BER value for this element.  It must
099   *                          not be {@code null} or empty.
100   */
101  private ASN1BigInteger(final byte type, final BigInteger bigIntegerValue,
102                         final byte[] berValue)
103  {
104    super(type, berValue);
105    value = bigIntegerValue;
106  }
107
108
109
110  /**
111   * Creates a new ASN.1 big integer element with the default BER type and the
112   * provided long value.
113   *
114   * @param  value  The int value to use for this element.
115   */
116  public ASN1BigInteger(final long value)
117  {
118    this(ASN1Constants.UNIVERSAL_INTEGER_TYPE, BigInteger.valueOf(value));
119  }
120
121
122
123  /**
124   * Creates a new ASN.1 big integer element with the specified BER type and the
125   * provided long value.
126   *
127   * @param  type   The BER type to use for this element.
128   * @param  value  The int value to use for this element.
129   */
130  public ASN1BigInteger(final byte type, final long value)
131  {
132    this(type, BigInteger.valueOf(value));
133  }
134
135
136
137  /**
138   * Retrieves the value for this element as a Java {@code BigInteger}.
139   *
140   * @return  The value for this element as a Java {@code BigInteger}.
141   */
142  public BigInteger getBigIntegerValue()
143  {
144    return value;
145  }
146
147
148
149  /**
150   * Decodes the contents of the provided byte array as a big integer element.
151   *
152   * @param  elementBytes  The byte array to decode as an ASN.1 big integer
153   *                       element.
154   *
155   * @return  The decoded ASN.1 big integer element.
156   *
157   * @throws  ASN1Exception  If the provided array cannot be decoded as a big
158   *                         integer element.
159   */
160  public static ASN1BigInteger decodeAsBigInteger(final byte[] elementBytes)
161         throws ASN1Exception
162  {
163    try
164    {
165      int valueStartPos = 2;
166      int length = (elementBytes[1] & 0x7F);
167      if (length != elementBytes[1])
168      {
169        final int numLengthBytes = length;
170
171        length = 0;
172        for (int i=0; i < numLengthBytes; i++)
173        {
174          length <<= 8;
175          length |= (elementBytes[valueStartPos++] & 0xFF);
176        }
177      }
178
179      if ((elementBytes.length - valueStartPos) != length)
180      {
181        throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length,
182                                     (elementBytes.length - valueStartPos)));
183      }
184
185      if (length == 0)
186      {
187        throw new ASN1Exception(ERR_BIG_INTEGER_DECODE_EMPTY_VALUE.get());
188      }
189
190      final byte[] elementValue = new byte[length];
191      System.arraycopy(elementBytes, valueStartPos, elementValue, 0, length);
192
193      final BigInteger bigIntegerValue = new BigInteger(elementValue);
194      return new ASN1BigInteger(elementBytes[0], bigIntegerValue, elementValue);
195    }
196    catch (final ASN1Exception ae)
197    {
198      Debug.debugException(ae);
199      throw ae;
200    }
201    catch (final Exception e)
202    {
203      Debug.debugException(e);
204      throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e);
205    }
206  }
207
208
209
210  /**
211   * Decodes the provided ASN.1 element as a big integer element.
212   *
213   * @param  element  The ASN.1 element to be decoded.
214   *
215   * @return  The decoded ASN.1 big integer element.
216   *
217   * @throws  ASN1Exception  If the provided element cannot be decoded as a big
218   *                         integer element.
219   */
220  public static ASN1BigInteger decodeAsBigInteger(final ASN1Element element)
221         throws ASN1Exception
222  {
223    final byte[] value = element.getValue();
224    if (value.length == 0)
225    {
226      throw new ASN1Exception(ERR_BIG_INTEGER_DECODE_EMPTY_VALUE.get());
227    }
228
229    return new ASN1BigInteger(element.getType(), new BigInteger(value), value);
230  }
231
232
233
234  /**
235   * {@inheritDoc}
236   */
237  @Override()
238  public void toString(final StringBuilder buffer)
239  {
240    buffer.append(value);
241  }
242}