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