001/*
002 * Copyright 2007-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2014 UnboundID Corp.
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, whose value may be represented
037 * as an integer with up to a 32-bit representation.
038 */
039@NotMutable()
040@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
041public final class ASN1Integer
042       extends ASN1Element
043{
044  /**
045   * The serial version UID for this serializable class.
046   */
047  private static final long serialVersionUID = -733929804601994372L;
048
049
050
051  // The int value for this element.
052  private final int intValue;
053
054
055
056  /**
057   * Creates a new ASN.1 integer element with the default BER type and the
058   * provided int value.
059   *
060   * @param  intValue  The int value to use for this element.
061   */
062  public ASN1Integer(final int intValue)
063  {
064    super(UNIVERSAL_INTEGER_TYPE, encodeIntValue(intValue));
065
066    this.intValue = intValue;
067  }
068
069
070
071  /**
072   * Creates a new ASN.1 integer element with the specified BER type and the
073   * provided int value.
074   *
075   * @param  type      The BER type to use for this element.
076   * @param  intValue  The int value to use for this element.
077   */
078  public ASN1Integer(final byte type, final int intValue)
079  {
080    super(type, encodeIntValue(intValue));
081
082    this.intValue = intValue;
083  }
084
085
086
087  /**
088   * Creates a new ASN.1 integer element with the specified BER type and the
089   * provided int and pre-encoded values.
090   *
091   * @param  type      The BER type to use for this element.
092   * @param  intValue  The int value to use for this element.
093   * @param  value     The pre-encoded value to use for this element.
094   */
095  private ASN1Integer(final byte type, final int intValue, final byte[] value)
096  {
097    super(type, value);
098
099    this.intValue = intValue;
100  }
101
102
103
104  /**
105   * Encodes the provided int value to a byte array suitable for use as the
106   * value of an integer element.
107   *
108   * @param  intValue  The int value to be encoded.
109   *
110   * @return  A byte array containing the encoded value.
111   */
112  static byte[] encodeIntValue(final int intValue)
113  {
114    if (intValue < 0)
115    {
116      if ((intValue & 0xFFFFFF80) == 0xFFFFFF80)
117      {
118        return new byte[]
119        {
120          (byte) (intValue & 0xFF)
121        };
122      }
123      else if ((intValue & 0xFFFF8000) == 0xFFFF8000)
124      {
125        return new byte[]
126        {
127          (byte) ((intValue >> 8) & 0xFF),
128          (byte) (intValue & 0xFF)
129        };
130      }
131      else if ((intValue & 0xFF800000) == 0xFF800000)
132      {
133        return new byte[]
134        {
135          (byte) ((intValue >> 16) & 0xFF),
136          (byte) ((intValue >> 8) & 0xFF),
137          (byte) (intValue & 0xFF)
138        };
139      }
140      else
141      {
142        return new byte[]
143        {
144          (byte) ((intValue >> 24) & 0xFF),
145          (byte) ((intValue >> 16) & 0xFF),
146          (byte) ((intValue >> 8) & 0xFF),
147          (byte) (intValue & 0xFF)
148        };
149      }
150    }
151    else
152    {
153      if ((intValue & 0x0000007F) == intValue)
154      {
155        return new byte[]
156        {
157          (byte) (intValue & 0x7F)
158        };
159      }
160      else if ((intValue & 0x00007FFF) == intValue)
161      {
162        return new byte[]
163        {
164          (byte) ((intValue >> 8) & 0x7F),
165          (byte) (intValue & 0xFF)
166        };
167      }
168      else if ((intValue & 0x007FFFFF) == intValue)
169      {
170        return new byte[]
171        {
172          (byte) ((intValue >> 16) & 0x7F),
173          (byte) ((intValue >> 8) & 0xFF),
174          (byte) (intValue & 0xFF)
175        };
176      }
177      else
178      {
179        return new byte[]
180        {
181          (byte) ((intValue >> 24) & 0x7F),
182          (byte) ((intValue >> 16) & 0xFF),
183          (byte) ((intValue >> 8) & 0xFF),
184          (byte) (intValue & 0xFF)
185        };
186      }
187    }
188  }
189
190
191
192  /**
193   * Retrieves the int value for this element.
194   *
195   * @return  The int value for this element.
196   */
197  public int intValue()
198  {
199    return intValue;
200  }
201
202
203
204  /**
205   * Decodes the contents of the provided byte array as an integer element.
206   *
207   * @param  elementBytes  The byte array to decode as an ASN.1 integer element.
208   *
209   * @return  The decoded ASN.1 integer element.
210   *
211   * @throws  ASN1Exception  If the provided array cannot be decoded as an
212   *                         integer element.
213   */
214  public static ASN1Integer decodeAsInteger(final byte[] elementBytes)
215         throws ASN1Exception
216  {
217    try
218    {
219      int valueStartPos = 2;
220      int length = (elementBytes[1] & 0x7F);
221      if (length != elementBytes[1])
222      {
223        final int numLengthBytes = length;
224
225        length = 0;
226        for (int i=0; i < numLengthBytes; i++)
227        {
228          length <<= 8;
229          length |= (elementBytes[valueStartPos++] & 0xFF);
230        }
231      }
232
233      if ((elementBytes.length - valueStartPos) != length)
234      {
235        throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length,
236                                     (elementBytes.length - valueStartPos)));
237      }
238
239      final byte[] value = new byte[length];
240      System.arraycopy(elementBytes, valueStartPos, value, 0, length);
241
242      int intValue;
243      switch (value.length)
244      {
245        case 1:
246          intValue = (value[0] & 0xFF);
247          if ((value[0] & 0x80) != 0x00)
248          {
249            intValue |= 0xFFFFFF00;
250          }
251          break;
252
253        case 2:
254          intValue = ((value[0] & 0xFF) << 8) | (value[1] & 0xFF);
255          if ((value[0] & 0x80) != 0x00)
256          {
257            intValue |= 0xFFFF0000;
258          }
259          break;
260
261        case 3:
262          intValue = ((value[0] & 0xFF) << 16) | ((value[1] & 0xFF) << 8) |
263                     (value[2] & 0xFF);
264          if ((value[0] & 0x80) != 0x00)
265          {
266            intValue |= 0xFF000000;
267          }
268          break;
269
270        case 4:
271          intValue = ((value[0] & 0xFF) << 24) | ((value[1] & 0xFF) << 16) |
272                     ((value[2] & 0xFF) << 8) | (value[3] & 0xFF);
273          break;
274
275        default:
276          throw new ASN1Exception(ERR_ENUMERATED_INVALID_LENGTH.get(
277                                       value.length));
278      }
279
280      return new ASN1Integer(elementBytes[0], intValue, value);
281    }
282    catch (final ASN1Exception ae)
283    {
284      debugException(ae);
285      throw ae;
286    }
287    catch (final Exception e)
288    {
289      debugException(e);
290      throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e);
291    }
292  }
293
294
295
296  /**
297   * Decodes the provided ASN.1 element as an integer element.
298   *
299   * @param  element  The ASN.1 element to be decoded.
300   *
301   * @return  The decoded ASN.1 integer element.
302   *
303   * @throws  ASN1Exception  If the provided element cannot be decoded as an
304   *                         integer element.
305   */
306  public static ASN1Integer decodeAsInteger(final ASN1Element element)
307         throws ASN1Exception
308  {
309    int intValue;
310    final byte[] value = element.getValue();
311    switch (value.length)
312    {
313      case 1:
314        intValue = (value[0] & 0xFF);
315        if ((value[0] & 0x80) != 0x00)
316        {
317          intValue |= 0xFFFFFF00;
318        }
319        break;
320
321      case 2:
322        intValue = ((value[0] & 0xFF) << 8) | (value[1] & 0xFF);
323        if ((value[0] & 0x80) != 0x00)
324        {
325          intValue |= 0xFFFF0000;
326        }
327        break;
328
329      case 3:
330        intValue = ((value[0] & 0xFF) << 16) | ((value[1] & 0xFF) << 8) |
331                   (value[2] & 0xFF);
332        if ((value[0] & 0x80) != 0x00)
333        {
334          intValue |= 0xFF000000;
335        }
336        break;
337
338      case 4:
339        intValue = ((value[0] & 0xFF) << 24) | ((value[1] & 0xFF) << 16) |
340                   ((value[2] & 0xFF) << 8) | (value[3] & 0xFF);
341        break;
342
343      default:
344        throw new ASN1Exception(ERR_INTEGER_INVALID_LENGTH.get(value.length));
345    }
346
347    return new ASN1Integer(element.getType(), intValue, value);
348  }
349
350
351
352  /**
353   * Appends a string representation of this ASN.1 element to the provided
354   * buffer.
355   *
356   * @param  buffer  The buffer to which to append the information.
357   */
358  @Override()
359  public void toString(final StringBuilder buffer)
360  {
361    buffer.append(intValue);
362  }
363}