001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.protocols.asn1; 028 import org.opends.messages.Message; 029 030 031 032 import static org.opends.messages.ProtocolMessages.*; 033 import static org.opends.server.protocols.asn1.ASN1Constants.*; 034 import static org.opends.server.util.ServerConstants.*; 035 import static org.opends.server.util.StaticUtils.*; 036 037 038 039 /** 040 * This class defines the data structures and methods to use when interacting 041 * with ASN.1 enumerated elements. 042 */ 043 @org.opends.server.types.PublicAPI( 044 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, 045 mayInstantiate=true, 046 mayExtend=false, 047 mayInvoke=true) 048 public final class ASN1Enumerated 049 extends ASN1Element 050 { 051 /** 052 * The serial version identifier required to satisfy the compiler because this 053 * class implements the <CODE>java.io.Serializable</CODE> interface. This 054 * value was generated using the <CODE>serialver</CODE> command-line utility 055 * included with the Java SDK. 056 */ 057 private static final long serialVersionUID = -8686345111964945130L; 058 059 060 061 // The integer value for this element. 062 private int intValue; 063 064 065 066 067 /** 068 * Creates a new ASN.1 enumerated element with the default type and the 069 * provided value. 070 * 071 * @param intValue The value for this ASN.1 enumerated element. 072 */ 073 public ASN1Enumerated(int intValue) 074 { 075 super(UNIVERSAL_ENUMERATED_TYPE, encodeValue(intValue)); 076 077 078 this.intValue = intValue; 079 } 080 081 082 083 /** 084 * Creates a new ASN.1 enumerated element with the specified type and value. 085 * 086 * @param type The BER type for this ASN.1 enumerated element. 087 * @param intValue The value for this ASN.1 enumerated element. 088 */ 089 public ASN1Enumerated(byte type, int intValue) 090 { 091 super(type, encodeValue(intValue)); 092 093 094 this.intValue = intValue; 095 } 096 097 098 099 /** 100 * Creates a new ASN.1 enumerated element with the specified type and value. 101 * 102 * @param type The BER type for this ASN.1 enumerated element. 103 * @param value The encoded value for this ASN.1 enumerated element. 104 * @param intValue The int value for this ASN.1 enumerated element. 105 */ 106 private ASN1Enumerated(byte type, byte[] value, int intValue) 107 { 108 super(type, value); 109 110 111 this.intValue = intValue; 112 } 113 114 115 116 /** 117 * Retrieves the integer value for this ASN.1 enumerated element. 118 * 119 * @return The integer value for this ASN.1 enumerated element. 120 */ 121 public int intValue() 122 { 123 return intValue; 124 } 125 126 127 128 /** 129 * Specifies the integer value for this ASN.1 enumerated element. 130 * 131 * @param intValue The integer value for this ASN.1 enumerated element. 132 */ 133 public void setValue(int intValue) 134 { 135 this.intValue = intValue; 136 setValueInternal(encodeValue(intValue)); 137 } 138 139 140 141 /** 142 * Specifies the value for this ASN.1 enumerated element. 143 * 144 * @param value The encoded value for this ASN.1 enumerated element. 145 * 146 * @throws ASN1Exception If the provided array is null or is not between one 147 * and four bytes in length. 148 */ 149 public void setValue(byte[] value) 150 throws ASN1Exception 151 { 152 if (value == null) 153 { 154 Message message = ERR_ASN1_ENUMERATED_SET_VALUE_NULL.get(); 155 throw new ASN1Exception(message); 156 } 157 158 if ((value.length < 1) || (value.length > 4)) 159 { 160 Message message = 161 ERR_ASN1_ENUMERATED_SET_VALUE_INVALID_LENGTH.get(value.length); 162 throw new ASN1Exception(message); 163 } 164 165 intValue = 0; 166 for (byte b : value) 167 { 168 intValue = (intValue << 8) | (b & 0xFF); 169 } 170 171 setValueInternal(value); 172 } 173 174 175 176 /** 177 * Decodes the provided ASN.1 element as an enumerated element. 178 * 179 * @param element The ASN.1 element to decode as an enumerated element. 180 * 181 * @return The decoded ASN.1 enumerated element. 182 * 183 * @throws ASN1Exception If the provided ASN.1 element cannot be decoded as 184 * an enumerated element. 185 */ 186 public static ASN1Enumerated decodeAsEnumerated(ASN1Element element) 187 throws ASN1Exception 188 { 189 if (element == null) 190 { 191 Message message = ERR_ASN1_ENUMERATED_DECODE_ELEMENT_NULL.get(); 192 throw new ASN1Exception(message); 193 } 194 195 byte[] value = element.value(); 196 if ((value.length < 1) || (value.length > 4)) 197 { 198 Message message = 199 ERR_ASN1_ENUMERATED_DECODE_ELEMENT_INVALID_LENGTH.get(value.length); 200 throw new ASN1Exception(message); 201 } 202 203 int intValue = 0; 204 for (byte b : value) 205 { 206 intValue = (intValue << 8) | (b & 0xFF); 207 } 208 209 return new ASN1Enumerated(element.getType(), value, intValue); 210 } 211 212 213 214 /** 215 * Decodes the provided byte array as an ASN.1 enumerated element. 216 * 217 * @param encodedElement The byte array to decode as an ASN.1 enumerated 218 * element. 219 * 220 * @return The decoded ASN.1 enumerated element. 221 * 222 * @throws ASN1Exception If the provided byte array cannot be decoded as an 223 * ASN.1 enumerated element. 224 */ 225 public static ASN1Enumerated decodeAsEnumerated(byte[] encodedElement) 226 throws ASN1Exception 227 { 228 // First make sure that the array is not null and long enough to contain 229 // a valid ASN.1 enumerated element. 230 if (encodedElement == null) 231 { 232 Message message = ERR_ASN1_ENUMERATED_DECODE_ARRAY_NULL.get(); 233 throw new ASN1Exception(message); 234 } 235 236 if (encodedElement.length < 3) 237 { 238 Message message = 239 ERR_ASN1_ENUMERATED_SHORT_ELEMENT.get(encodedElement.length); 240 throw new ASN1Exception(message); 241 } 242 243 244 // Next, decode the length. This allows multi-byte lengths with up to four 245 // bytes used to indicate how many bytes are in the length. 246 byte type = encodedElement[0]; 247 int length = (encodedElement[1] & 0x7F); 248 int valueStartPos = 2; 249 if (length != encodedElement[1]) 250 { 251 int numLengthBytes = length; 252 if (numLengthBytes > 4) 253 { 254 Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes); 255 throw new ASN1Exception(message); 256 } 257 else if (encodedElement.length < (2 + numLengthBytes)) 258 { 259 Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes); 260 throw new ASN1Exception(message); 261 } 262 263 length = 0x00; 264 valueStartPos = 2 + numLengthBytes; 265 for (int i=0; i < numLengthBytes; i++) 266 { 267 length = (length << 8) | (encodedElement[i+2] & 0xFF); 268 } 269 } 270 271 272 // Make sure that the number of bytes left is equal to the number of bytes 273 // in the value. 274 if ((encodedElement.length - valueStartPos) != length) 275 { 276 Message message = ERR_ASN1_LENGTH_MISMATCH.get( 277 length, (encodedElement.length - valueStartPos)); 278 throw new ASN1Exception(message); 279 } 280 281 282 // Make sure that the decoded length is between 1 and 4 bytes. 283 if ((length < 1) || (length > 4)) 284 { 285 Message message = 286 ERR_ASN1_ENUMERATED_DECODE_ARRAY_INVALID_LENGTH.get(length); 287 throw new ASN1Exception(message); 288 } 289 290 291 // Copy the value and construct the element to return. 292 byte[] value = new byte[length]; 293 System.arraycopy(encodedElement, valueStartPos, value, 0, length); 294 295 int intValue = 0; 296 for (byte b : value) 297 { 298 intValue = (intValue << 8) | (b & 0xFF); 299 } 300 301 return new ASN1Enumerated(type, value, intValue); 302 } 303 304 305 306 /** 307 * Appends a string representation of this ASN.1 enumerated element to the 308 * provided buffer. 309 * 310 * @param buffer The buffer to which the information should be appended. 311 */ 312 public void toString(StringBuilder buffer) 313 { 314 buffer.append("ASN1Enumerated(type="); 315 buffer.append(byteToHex(getType())); 316 buffer.append(", value="); 317 buffer.append(intValue); 318 buffer.append(")"); 319 } 320 321 322 323 /** 324 * Appends a string representation of this protocol element to the provided 325 * buffer. 326 * 327 * @param buffer The buffer into which the string representation should be 328 * written. 329 * @param indent The number of spaces that should be used to indent the 330 * resulting string representation. 331 */ 332 public void toString(StringBuilder buffer, int indent) 333 { 334 StringBuilder indentBuf = new StringBuilder(indent); 335 for (int i=0 ; i < indent; i++) 336 { 337 indentBuf.append(' '); 338 } 339 340 buffer.append(indentBuf); 341 buffer.append("ASN.1 Enumerated"); 342 buffer.append(EOL); 343 344 buffer.append(indentBuf); 345 buffer.append(" BER Type: "); 346 buffer.append(byteToHex(getType())); 347 buffer.append(EOL); 348 349 buffer.append(indentBuf); 350 buffer.append(" Value: "); 351 buffer.append(intValue); 352 buffer.append(" ("); 353 buffer.append(bytesToHex(value())); 354 buffer.append(")"); 355 buffer.append(EOL); 356 } 357 } 358