001 /* 002 * Copyright 2007-2016 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005 /* 006 * Copyright (C) 2008-2016 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 }