001/* 002 * Copyright 2007-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2007-2020 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2008-2020 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.asn1; 037 038 039 040import com.unboundid.util.Debug; 041import com.unboundid.util.NotMutable; 042import com.unboundid.util.ThreadSafety; 043import com.unboundid.util.ThreadSafetyLevel; 044 045import static com.unboundid.asn1.ASN1Messages.*; 046 047 048 049/** 050 * This class provides an ASN.1 enumerated element. Enumerated elements are 051 * very similar to integer elements, and the only real difference between them 052 * is that the individual values of an enumerated element have a symbolic 053 * significance (i.e., each value is associated with a particular meaning), 054 * although this does not impact its encoding other than through the use of a 055 * different default BER type. 056 */ 057@NotMutable() 058@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 059public final class ASN1Enumerated 060 extends ASN1Element 061{ 062 /** 063 * The serial version UID for this serializable class. 064 */ 065 private static final long serialVersionUID = -5915912036130847725L; 066 067 068 069 // The int value for this element. 070 private final int intValue; 071 072 073 074 /** 075 * Creates a new ASN.1 enumerated element with the default BER type and the 076 * provided int value. 077 * 078 * @param intValue The int value to use for this element. 079 */ 080 public ASN1Enumerated(final int intValue) 081 { 082 super(ASN1Constants.UNIVERSAL_ENUMERATED_TYPE, 083 ASN1Integer.encodeIntValue(intValue)); 084 085 this.intValue = intValue; 086 } 087 088 089 090 /** 091 * Creates a new ASN.1 enumerated element with the specified BER type and the 092 * provided int value. 093 * 094 * @param type The BER type to use for this element. 095 * @param intValue The int value to use for this element. 096 */ 097 public ASN1Enumerated(final byte type, final int intValue) 098 { 099 super(type, ASN1Integer.encodeIntValue(intValue)); 100 101 this.intValue = intValue; 102 } 103 104 105 106 /** 107 * Creates a new ASN.1 enumerated element with the specified BER type and the 108 * provided int and pre-encoded values. 109 * 110 * @param type The BER type to use for this element. 111 * @param intValue The int value to use for this element. 112 * @param value The pre-encoded value to use for this element. 113 */ 114 private ASN1Enumerated(final byte type, final int intValue, 115 final byte[] value) 116 { 117 super(type, value); 118 119 this.intValue = intValue; 120 } 121 122 123 124 /** 125 * Retrieves the int value for this element. 126 * 127 * @return The int value for this element. 128 */ 129 public int intValue() 130 { 131 return intValue; 132 } 133 134 135 136 /** 137 * Decodes the contents of the provided byte array as an enumerated element. 138 * 139 * @param elementBytes The byte array to decode as an ASN.1 enumerated 140 * element. 141 * 142 * @return The decoded ASN.1 enumerated element. 143 * 144 * @throws ASN1Exception If the provided array cannot be decoded as an 145 * enumerated element. 146 */ 147 public static ASN1Enumerated decodeAsEnumerated(final byte[] elementBytes) 148 throws ASN1Exception 149 { 150 try 151 { 152 int valueStartPos = 2; 153 int length = (elementBytes[1] & 0x7F); 154 if (length != elementBytes[1]) 155 { 156 final int numLengthBytes = length; 157 158 length = 0; 159 for (int i=0; i < numLengthBytes; i++) 160 { 161 length <<= 8; 162 length |= (elementBytes[valueStartPos++] & 0xFF); 163 } 164 } 165 166 if ((elementBytes.length - valueStartPos) != length) 167 { 168 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length, 169 (elementBytes.length - valueStartPos))); 170 } 171 172 final byte[] value = new byte[length]; 173 System.arraycopy(elementBytes, valueStartPos, value, 0, length); 174 175 int intValue; 176 switch (value.length) 177 { 178 case 1: 179 intValue = (value[0] & 0xFF); 180 if ((value[0] & 0x80) != 0x00) 181 { 182 intValue |= 0xFFFF_FF00; 183 } 184 break; 185 186 case 2: 187 intValue = ((value[0] & 0xFF) << 8) | (value[1] & 0xFF); 188 if ((value[0] & 0x80) != 0x00) 189 { 190 intValue |= 0xFFFF_0000; 191 } 192 break; 193 194 case 3: 195 intValue = ((value[0] & 0xFF) << 16) | ((value[1] & 0xFF) << 8) | 196 (value[2] & 0xFF); 197 if ((value[0] & 0x80) != 0x00) 198 { 199 intValue |= 0xFF00_0000; 200 } 201 break; 202 203 case 4: 204 intValue = ((value[0] & 0xFF) << 24) | ((value[1] & 0xFF) << 16) | 205 ((value[2] & 0xFF) << 8) | (value[3] & 0xFF); 206 break; 207 208 default: 209 throw new ASN1Exception(ERR_ENUMERATED_INVALID_LENGTH.get( 210 value.length)); 211 } 212 213 return new ASN1Enumerated(elementBytes[0], intValue, value); 214 } 215 catch (final ASN1Exception ae) 216 { 217 Debug.debugException(ae); 218 throw ae; 219 } 220 catch (final Exception e) 221 { 222 Debug.debugException(e); 223 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e); 224 } 225 } 226 227 228 229 /** 230 * Decodes the provided ASN.1 element as an enumerated element. 231 * 232 * @param element The ASN.1 element to be decoded. 233 * 234 * @return The decoded ASN.1 enumerated element. 235 * 236 * @throws ASN1Exception If the provided element cannot be decoded as an 237 * enumerated element. 238 */ 239 public static ASN1Enumerated decodeAsEnumerated(final ASN1Element element) 240 throws ASN1Exception 241 { 242 int intValue; 243 final byte[] value = element.getValue(); 244 switch (value.length) 245 { 246 case 1: 247 intValue = (value[0] & 0xFF); 248 if ((value[0] & 0x80) != 0x00) 249 { 250 intValue |= 0xFFFF_FF00; 251 } 252 break; 253 254 case 2: 255 intValue = ((value[0] & 0xFF) << 8) | (value[1] & 0xFF); 256 if ((value[0] & 0x80) != 0x00) 257 { 258 intValue |= 0xFFFF_0000; 259 } 260 break; 261 262 case 3: 263 intValue = ((value[0] & 0xFF) << 16) | ((value[1] & 0xFF) << 8) | 264 (value[2] & 0xFF); 265 if ((value[0] & 0x80) != 0x00) 266 { 267 intValue |= 0xFF00_0000; 268 } 269 break; 270 271 case 4: 272 intValue = ((value[0] & 0xFF) << 24) | ((value[1] & 0xFF) << 16) | 273 ((value[2] & 0xFF) << 8) | (value[3] & 0xFF); 274 break; 275 276 default: 277 throw new ASN1Exception(ERR_ENUMERATED_INVALID_LENGTH.get( 278 value.length)); 279 } 280 281 return new ASN1Enumerated(element.getType(), intValue, value); 282 } 283 284 285 286 /** 287 * {@inheritDoc} 288 */ 289 @Override() 290 public void toString(final StringBuilder buffer) 291 { 292 buffer.append(intValue); 293 } 294}