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