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 null 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 ASN1Null
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 = 8921787912269145125L;
058    
059    
060    
061      /**
062       * Creates a new ASN.1 null element with the default type.
063       */
064      public ASN1Null()
065      {
066        super(UNIVERSAL_NULL_TYPE);
067    
068      }
069    
070    
071    
072      /**
073       * Creates a new ASN.1 null element with the specified type.
074       *
075       * @param  type  The BER type to use for this ASN.1 null element.
076       */
077      public ASN1Null(byte type)
078      {
079        super(type);
080    
081      }
082    
083    
084    
085      /**
086       * Specifies the value for this ASN.1 null element.
087       *
088       * @param  value  The encoded value for this ASN.1 null element.
089       *
090       * @throws  ASN1Exception  If the provided array is not empty.
091       */
092      public void setValue(byte[] value)
093             throws ASN1Exception
094      {
095        if ((value != null) && (value.length != 0))
096        {
097          Message message =
098              ERR_ASN1_NULL_SET_VALUE_INVALID_LENGTH.get(value.length);
099          throw new ASN1Exception(message);
100        }
101      }
102    
103    
104    
105      /**
106       * Decodes the provided ASN.1 element as a null element.
107       *
108       * @param  element  The ASN.1 element to decode as a null element.
109       *
110       * @return  The decoded ASN.1 null element.
111       *
112       * @throws  ASN1Exception  If the provided ASN.1 element cannot be decoded as
113       *                         a null element.
114       */
115      public static ASN1Null decodeAsNull(ASN1Element element)
116             throws ASN1Exception
117      {
118        if (element == null)
119        {
120          Message message = ERR_ASN1_NULL_DECODE_ELEMENT_NULL.get();
121          throw new ASN1Exception(message);
122        }
123    
124        byte[] value = element.value();
125        if (value.length != 0)
126        {
127          Message message =
128              ERR_ASN1_NULL_DECODE_ELEMENT_INVALID_LENGTH.get(value.length);
129          throw new ASN1Exception(message);
130        }
131    
132        return new ASN1Null(element.getType());
133      }
134    
135    
136    
137      /**
138       * Decodes the provided byte array as an ASN.1 null element.
139       *
140       * @param  encodedElement  The byte array to decode as an ASN.1 null element.
141       *
142       * @return  The decoded ASN.1 null element.
143       *
144       * @throws  ASN1Exception  If the provided byte array cannot be decoded as an
145       *                         ASN.1 null element.
146       */
147      public static ASN1Null decodeAsNull(byte[] encodedElement)
148             throws ASN1Exception
149      {
150        // First make sure that the array is not null and long enough to contain
151        // a valid ASN.1 null element.
152        if (encodedElement == null)
153        {
154          Message message = ERR_ASN1_NULL_DECODE_ARRAY_NULL.get();
155          throw new ASN1Exception(message);
156        }
157    
158        if (encodedElement.length < 2)
159        {
160          Message message = ERR_ASN1_SHORT_ELEMENT.get(encodedElement.length);
161          throw new ASN1Exception(message);
162        }
163    
164    
165        // Next, decode the length.  This allows multi-byte lengths with up to four
166        // bytes used to indicate how many bytes are in the length.
167        byte type = encodedElement[0];
168        int length = (encodedElement[1] & 0x7F);
169        int valueStartPos = 2;
170        if (length != encodedElement[1])
171        {
172          int numLengthBytes = length;
173          if (numLengthBytes > 4)
174          {
175            Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
176            throw new ASN1Exception(message);
177          }
178          else if (encodedElement.length < (2 + numLengthBytes))
179          {
180            Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
181            throw new ASN1Exception(message);
182          }
183    
184          length = 0x00;
185          valueStartPos = 2 + numLengthBytes;
186          for (int i=0; i < numLengthBytes; i++)
187          {
188            length = (length << 8) | (encodedElement[i+2] & 0xFF);
189          }
190        }
191    
192    
193        // Make sure that the number of bytes left is equal to the number of bytes
194        // in the value.
195        if ((encodedElement.length - valueStartPos) != length)
196        {
197          Message message = ERR_ASN1_LENGTH_MISMATCH.get(
198              length, (encodedElement.length - valueStartPos));
199          throw new ASN1Exception(message);
200        }
201    
202    
203        // Make sure that the decoded length is exactly zero byte.
204        if (length != 0)
205        {
206          Message message = ERR_ASN1_NULL_DECODE_ARRAY_INVALID_LENGTH.get(length);
207          throw new ASN1Exception(message);
208        }
209    
210    
211        // Copy the value and construct the element to return.
212        return new ASN1Null(type);
213      }
214    
215    
216    
217      /**
218       * Appends a string representation of this ASN.1 null element to the provided
219       * buffer.
220       *
221       * @param  buffer  The buffer to which the information should be appended.
222       */
223      public void toString(StringBuilder buffer)
224      {
225        buffer.append("ASN1Null(type=");
226        buffer.append(byteToHex(getType()));
227        buffer.append(")");
228      }
229    
230    
231    
232      /**
233       * Appends a string representation of this protocol element to the provided
234       * buffer.
235       *
236       * @param  buffer  The buffer into which the string representation should be
237       *                 written.
238       * @param  indent  The number of spaces that should be used to indent the
239       *                 resulting string representation.
240       */
241      public void toString(StringBuilder buffer, int indent)
242      {
243        StringBuilder indentBuf = new StringBuilder(indent);
244        for (int i=0 ; i < indent; i++)
245        {
246          indentBuf.append(' ');
247        }
248    
249        buffer.append(indentBuf);
250        buffer.append("ASN.1 Null");
251        buffer.append(EOL);
252    
253        buffer.append(indentBuf);
254        buffer.append("  BER Type:  ");
255        buffer.append(byteToHex(getType()));
256        buffer.append(EOL);
257      }
258    }
259