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