001    /*
002     * Copyright 2007-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2015 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 enumerated element.  Enumerated elements are
034     * very similar to integer elements, and the only real difference between them
035     * is that the individual values of an enumerated element have a symbolic
036     * significance (i.e., each value is associated with a particular meaning),
037     * although this does not impact its encoding other than through the use of a
038     * different default BER type.
039     */
040    public final class ASN1Enumerated
041           extends ASN1Element
042    {
043      /**
044       * The serial version UID for this serializable class.
045       */
046      private static final long serialVersionUID = -5915912036130847725L;
047    
048    
049    
050      // The int value for this element.
051      private final int intValue;
052    
053    
054    
055      /**
056       * Creates a new ASN.1 enumerated element with the default BER type and the
057       * provided int value.
058       *
059       * @param  intValue  The int value to use for this element.
060       */
061      public ASN1Enumerated(final int intValue)
062      {
063        super(UNIVERSAL_ENUMERATED_TYPE, ASN1Integer.encodeIntValue(intValue));
064    
065        this.intValue = intValue;
066      }
067    
068    
069    
070      /**
071       * Creates a new ASN.1 enumerated element with the specified BER type and the
072       * provided int value.
073       *
074       * @param  type      The BER type to use for this element.
075       * @param  intValue  The int value to use for this element.
076       */
077      public ASN1Enumerated(final byte type, final int intValue)
078      {
079        super(type, ASN1Integer.encodeIntValue(intValue));
080    
081        this.intValue = intValue;
082      }
083    
084    
085    
086      /**
087       * Creates a new ASN.1 enumerated element with the specified BER type and the
088       * provided int and pre-encoded values.
089       *
090       * @param  type      The BER type to use for this element.
091       * @param  intValue  The int value to use for this element.
092       * @param  value     The pre-encoded value to use for this element.
093       */
094      private ASN1Enumerated(final byte type, final int intValue,
095                             final byte[] value)
096      {
097        super(type, value);
098    
099        this.intValue = intValue;
100      }
101    
102    
103    
104      /**
105       * Retrieves the int value for this element.
106       *
107       * @return  The int value for this element.
108       */
109      public int intValue()
110      {
111        return intValue;
112      }
113    
114    
115    
116      /**
117       * Decodes the contents of the provided byte array as an enumerated element.
118       *
119       * @param  elementBytes  The byte array to decode as an ASN.1 enumerated
120       *                       element.
121       *
122       * @return  The decoded ASN.1 enumerated element.
123       *
124       * @throws  ASN1Exception  If the provided array cannot be decoded as an
125       *                         enumerated element.
126       */
127      public static ASN1Enumerated decodeAsEnumerated(final byte[] elementBytes)
128             throws ASN1Exception
129      {
130        try
131        {
132          int valueStartPos = 2;
133          int length = (elementBytes[1] & 0x7F);
134          if (length != elementBytes[1])
135          {
136            final int numLengthBytes = length;
137    
138            length = 0;
139            for (int i=0; i < numLengthBytes; i++)
140            {
141              length <<= 8;
142              length |= (elementBytes[valueStartPos++] & 0xFF);
143            }
144          }
145    
146          if ((elementBytes.length - valueStartPos) != length)
147          {
148            throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length,
149                                         (elementBytes.length - valueStartPos)));
150          }
151    
152          final byte[] value = new byte[length];
153          System.arraycopy(elementBytes, valueStartPos, value, 0, length);
154    
155          int intValue;
156          switch (value.length)
157          {
158            case 1:
159              intValue = (value[0] & 0xFF);
160              if ((value[0] & 0x80) != 0x00)
161              {
162                intValue |= 0xFFFFFF00;
163              }
164              break;
165    
166            case 2:
167              intValue = ((value[0] & 0xFF) << 8) | (value[1] & 0xFF);
168              if ((value[0] & 0x80) != 0x00)
169              {
170                intValue |= 0xFFFF0000;
171              }
172              break;
173    
174            case 3:
175              intValue = ((value[0] & 0xFF) << 16) | ((value[1] & 0xFF) << 8) |
176                         (value[2] & 0xFF);
177              if ((value[0] & 0x80) != 0x00)
178              {
179                intValue |= 0xFF000000;
180              }
181              break;
182    
183            case 4:
184              intValue = ((value[0] & 0xFF) << 24) | ((value[1] & 0xFF) << 16) |
185                         ((value[2] & 0xFF) << 8) | (value[3] & 0xFF);
186              break;
187    
188            default:
189              throw new ASN1Exception(ERR_ENUMERATED_INVALID_LENGTH.get(
190                                           value.length));
191          }
192    
193          return new ASN1Enumerated(elementBytes[0], intValue, value);
194        }
195        catch (final ASN1Exception ae)
196        {
197          debugException(ae);
198          throw ae;
199        }
200        catch (final Exception e)
201        {
202          debugException(e);
203          throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e);
204        }
205      }
206    
207    
208    
209      /**
210       * Decodes the provided ASN.1 element as an enumerated element.
211       *
212       * @param  element  The ASN.1 element to be decoded.
213       *
214       * @return  The decoded ASN.1 enumerated element.
215       *
216       * @throws  ASN1Exception  If the provided element cannot be decoded as an
217       *                         enumerated element.
218       */
219      public static ASN1Enumerated decodeAsEnumerated(final ASN1Element element)
220             throws ASN1Exception
221      {
222        int intValue;
223        final byte[] value = element.getValue();
224        switch (value.length)
225        {
226          case 1:
227            intValue = (value[0] & 0xFF);
228            if ((value[0] & 0x80) != 0x00)
229            {
230              intValue |= 0xFFFFFF00;
231            }
232            break;
233    
234          case 2:
235            intValue = ((value[0] & 0xFF) << 8) | (value[1] & 0xFF);
236            if ((value[0] & 0x80) != 0x00)
237            {
238              intValue |= 0xFFFF0000;
239            }
240            break;
241    
242          case 3:
243            intValue = ((value[0] & 0xFF) << 16) | ((value[1] & 0xFF) << 8) |
244                       (value[2] & 0xFF);
245            if ((value[0] & 0x80) != 0x00)
246            {
247              intValue |= 0xFF000000;
248            }
249            break;
250    
251          case 4:
252            intValue = ((value[0] & 0xFF) << 24) | ((value[1] & 0xFF) << 16) |
253                       ((value[2] & 0xFF) << 8) | (value[3] & 0xFF);
254            break;
255    
256          default:
257            throw new ASN1Exception(ERR_ENUMERATED_INVALID_LENGTH.get(
258                                         value.length));
259        }
260    
261        return new ASN1Enumerated(element.getType(), intValue, value);
262      }
263    
264    
265    
266      /**
267       * Appends a string representation of this ASN.1 element to the provided
268       * buffer.
269       *
270       * @param  buffer  The buffer to which to append the information.
271       */
272      @Override()
273      public void toString(final StringBuilder buffer)
274      {
275        buffer.append(intValue);
276      }
277    }