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