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