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 integer elements that may need to hold values greater than will 042 * fit in the scope of a Java <CODE>int</CODE> structure. 043 * <BR><BR> 044 * Note that the difference between the <CODE>ASN1Integer</CODE> and 045 * <CODE>ASN1Long</CODE> classes is purely artificial. The ASN.1 specification 046 * does not define any size limits for integer values, but the 047 * <CODE>ASN1Integer</CODE> class uses an <CODE>int</CODE> data type behind the 048 * scenes and therefore is only capable of representing values up to 049 * 2<SUP>31</SUP> - 1 (a little over two billion). This class uses a 050 * <CODE>long</CODE> data type behind the scenes and therefore is capable of 051 * holding much larger values. Because of the need to deal with larger values, 052 * this class may have a small performance disadvantage over the 053 * <CODE>ASN1Integer</CODE> class and therefore that class should be used for 054 * cases in which there is no danger of overflowing an <CODE>int</CODE> value. 055 */ 056 @org.opends.server.types.PublicAPI( 057 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED, 058 mayInstantiate=true, 059 mayExtend=false, 060 mayInvoke=true) 061 public final class ASN1Long 062 extends ASN1Element 063 { 064 /** 065 * The serial version identifier required to satisfy the compiler because this 066 * class implements the <CODE>java.io.Serializable</CODE> interface. This 067 * value was generated using the <CODE>serialver</CODE> command-line utility 068 * included with the Java SDK. 069 */ 070 private static final long serialVersionUID = -6015600344725970947L; 071 072 073 074 // The long value for this element. 075 private long longValue; 076 077 078 079 080 /** 081 * Creates a new ASN.1 long element with the default type and the provided 082 * value. 083 * 084 * @param longValue The value for this ASN.1 long element. 085 */ 086 public ASN1Long (long longValue) 087 { 088 super(UNIVERSAL_INTEGER_TYPE, encodeLongValue(longValue)); 089 090 091 this.longValue = longValue; 092 } 093 094 095 096 /** 097 * Creates a new ASN.1 long element with the specified type and value. 098 * 099 * @param type The BER type for this ASN.1 long element. 100 * @param longValue The value for this ASN.1 long element. 101 */ 102 public ASN1Long(byte type, long longValue) 103 { 104 super(type, encodeLongValue(longValue)); 105 106 107 this.longValue = longValue; 108 } 109 110 111 112 /** 113 * Creates a new ASN.1 long element with the specified type and value. 114 * 115 * @param type The BER type for this ASN.1 long element. 116 * @param value The encoded value for this ASN.1 long element. 117 * @param longValue The long value for this ASN.1 long element. 118 */ 119 private ASN1Long(byte type, byte[] value, long longValue) 120 { 121 super(type, value); 122 123 124 this.longValue = longValue; 125 } 126 127 128 129 /** 130 * Retrieves the long value for this ASN.1 long element. 131 * 132 * @return The long value for this ASN.1 long element. 133 */ 134 public long longValue() 135 { 136 return longValue; 137 } 138 139 140 141 /** 142 * Specifies the long value for this ASN.1 long element. 143 * 144 * @param longValue The long value for this ASN.1 long element. 145 */ 146 public void setValue(long longValue) 147 { 148 this.longValue = longValue; 149 setValueInternal(encodeLongValue(longValue)); 150 } 151 152 153 154 /** 155 * Specifies the value for this ASN.1 long element. 156 * 157 * @param value The encoded value for this ASN.1 long element. 158 * 159 * @throws ASN1Exception If the provided array is null or is not between one 160 * and four bytes in length. 161 */ 162 public void setValue(byte[] value) 163 throws ASN1Exception 164 { 165 if (value == null) 166 { 167 Message message = ERR_ASN1_INTEGER_SET_VALUE_NULL.get(); 168 throw new ASN1Exception(message); 169 } 170 171 if ((value.length < 1) || (value.length > 8)) 172 { 173 Message message = 174 ERR_ASN1_LONG_SET_VALUE_INVALID_LENGTH.get(value.length); 175 throw new ASN1Exception(message); 176 } 177 178 longValue = 0; 179 for (byte b : value) 180 { 181 longValue = (longValue << 8) | (b & 0xFF); 182 } 183 184 setValueInternal(value); 185 } 186 187 188 189 /** 190 * Decodes the provided ASN.1 element as a long element. 191 * 192 * @param element The ASN.1 element to decode as a long element. 193 * 194 * @return The decoded ASN.1 long element. 195 * 196 * @throws ASN1Exception If the provided ASN.1 element cannot be decoded as 197 * a long element. 198 */ 199 public static ASN1Long decodeAsLong(ASN1Element element) 200 throws ASN1Exception 201 { 202 if (element == null) 203 { 204 Message message = ERR_ASN1_INTEGER_DECODE_ELEMENT_NULL.get(); 205 throw new ASN1Exception(message); 206 } 207 208 byte[] value = element.value(); 209 if ((value.length < 1) || (value.length > 8)) 210 { 211 Message message = 212 ERR_ASN1_LONG_DECODE_ELEMENT_INVALID_LENGTH.get(value.length); 213 throw new ASN1Exception(message); 214 } 215 216 long longValue = 0; 217 for (byte b : value) 218 { 219 longValue = (longValue << 8) | (b & 0xFF); 220 } 221 222 return new ASN1Long(element.getType(), value, longValue); 223 } 224 225 226 227 /** 228 * Decodes the provided byte array as an ASN.1 long element. 229 * 230 * @param encodedElement The byte array to decode as an ASN.1 long element. 231 * 232 * @return The decoded ASN.1 long element. 233 * 234 * @throws ASN1Exception If the provided byte array cannot be decoded as an 235 * ASN.1 long element. 236 */ 237 public static ASN1Long decodeAsLong(byte[] encodedElement) 238 throws ASN1Exception 239 { 240 // First make sure that the array is not null and long enough to contain 241 // a valid ASN.1 long element. 242 if (encodedElement == null) 243 { 244 Message message = ERR_ASN1_INTEGER_DECODE_ARRAY_NULL.get(); 245 throw new ASN1Exception(message); 246 } 247 248 if (encodedElement.length < 3) 249 { 250 Message message = 251 ERR_ASN1_INTEGER_SHORT_ELEMENT.get(encodedElement.length); 252 throw new ASN1Exception(message); 253 } 254 255 256 // Next, decode the length. This allows multi-byte lengths with up to four 257 // bytes used to indicate how many bytes are in the length. 258 byte type = encodedElement[0]; 259 int length = (encodedElement[1] & 0x7F); 260 int valueStartPos = 2; 261 if (length != encodedElement[1]) 262 { 263 int numLengthBytes = length; 264 if (numLengthBytes > 4) 265 { 266 Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes); 267 throw new ASN1Exception(message); 268 } 269 else if (encodedElement.length < (2 + numLengthBytes)) 270 { 271 Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes); 272 throw new ASN1Exception(message); 273 } 274 275 length = 0x00; 276 valueStartPos = 2 + numLengthBytes; 277 for (int i=0; i < numLengthBytes; i++) 278 { 279 length = (length << 8) | (encodedElement[i+2] & 0xFF); 280 } 281 } 282 283 284 // Make sure that the number of bytes left is equal to the number of bytes 285 // in the value. 286 if ((encodedElement.length - valueStartPos) != length) 287 { 288 Message message = ERR_ASN1_LENGTH_MISMATCH.get( 289 length, (encodedElement.length - valueStartPos)); 290 throw new ASN1Exception(message); 291 } 292 293 294 // Make sure that the decoded length is between 1 and 8 bytes. 295 if ((length < 1) || (length > 8)) 296 { 297 Message message = ERR_ASN1_LONG_DECODE_ARRAY_INVALID_LENGTH.get(length); 298 throw new ASN1Exception(message); 299 } 300 301 302 // Copy the value and construct the element to return. 303 byte[] value = new byte[length]; 304 System.arraycopy(encodedElement, valueStartPos, value, 0, length); 305 306 long longValue = 0; 307 for (byte b : value) 308 { 309 longValue = (longValue << 8) | (b & 0xFF); 310 } 311 312 return new ASN1Long(type, value, longValue); 313 } 314 315 316 317 /** 318 * Appends a string representation of this ASN.1 integer element to the 319 * provided buffer. 320 * 321 * @param buffer The buffer to which the information should be appended. 322 */ 323 public void toString(StringBuilder buffer) 324 { 325 buffer.append("ASN1Long(type="); 326 buffer.append(byteToHex(getType())); 327 buffer.append(", value="); 328 buffer.append(longValue); 329 buffer.append(")"); 330 } 331 332 333 334 /** 335 * Appends a string representation of this protocol element to the provided 336 * buffer. 337 * 338 * @param buffer The buffer into which the string representation should be 339 * written. 340 * @param indent The number of spaces that should be used to indent the 341 * resulting string representation. 342 */ 343 public void toString(StringBuilder buffer, int indent) 344 { 345 StringBuilder indentBuf = new StringBuilder(indent); 346 for (int i=0 ; i < indent; i++) 347 { 348 indentBuf.append(' '); 349 } 350 351 buffer.append(indentBuf); 352 buffer.append("ASN.1 Long"); 353 buffer.append(EOL); 354 355 buffer.append(indentBuf); 356 buffer.append(" BER Type: "); 357 buffer.append(byteToHex(getType())); 358 buffer.append(EOL); 359 360 buffer.append(indentBuf); 361 buffer.append(" Value: "); 362 buffer.append(longValue); 363 buffer.append(" ("); 364 buffer.append(bytesToHex(value())); 365 buffer.append(")"); 366 buffer.append(EOL); 367 } 368 } 369