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 org.opends.server.types.ByteString;
033    import org.opends.server.types.DebugLogLevel;
034    
035    import static org.opends.server.loggers.debug.DebugLogger.*;
036    import org.opends.server.loggers.debug.DebugTracer;
037    import static org.opends.messages.ProtocolMessages.*;
038    import static org.opends.server.protocols.asn1.ASN1Constants.*;
039    import static org.opends.server.util.ServerConstants.*;
040    import static org.opends.server.util.StaticUtils.*;
041    
042    
043    
044    /**
045     * This class defines the data structures and methods to use when interacting
046     * with ASN.1 octet string elements.
047     * <BR><BR>
048     * Note that this class also implements the <CODE>ByteString</CODE> interface,
049     * but in most cases whenever it is necessary to create an instance of a
050     * <CODE>ByteString</CODE> object, the caller should use one of the
051     * <CODE>ByteStringFactory.create</CODE> methods rather than creating an
052     * <CODE>ASN1OctetString</CODE> object directly.  In general, direct references
053     * to ASN.1 elements should be limited to cases in which ASN.1 is actually
054     * involved.
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 ASN1OctetString
062           extends ASN1Element
063           implements ByteString
064    {
065      /**
066       * The tracer object for the debug logger.
067       */
068      private static final DebugTracer TRACER = getTracer();
069    
070    
071    
072    
073      /**
074       * The serial version identifier required to satisfy the compiler because this
075       * class implements the <CODE>java.io.Serializable</CODE> interface.  This
076       * value was generated using the <CODE>serialver</CODE> command-line utility
077       * included with the Java SDK.
078       */
079      private static final long serialVersionUID = -6101268916754431502L;
080    
081    
082    
083      // The string value for this element.  It may be null due to lazy
084      // initialization.
085      private String stringValue;
086    
087    
088    
089      /**
090       * Creates a new ASN.1 octet string element with the default type and no
091       * value.
092       */
093      public ASN1OctetString()
094      {
095        super(UNIVERSAL_OCTET_STRING_TYPE);
096    
097      }
098    
099    
100    
101      /**
102       * Creates a new ASN.1 octet string element with the specified type and no
103       * value.
104       *
105       * @param  type  The BER type for this ASN.1 octet string element.
106       */
107      public ASN1OctetString(byte type)
108      {
109        super(type);
110    
111      }
112    
113    
114    
115      /**
116       * Creates a new ASN.1 octet string element with the default type and the
117       * provided value.
118       *
119       * @param  value  The value for this ASN.1 octet string element.
120       */
121      public ASN1OctetString(byte[] value)
122      {
123        super(UNIVERSAL_OCTET_STRING_TYPE, value);
124    
125    
126        this.stringValue = null;
127      }
128    
129    
130    
131      /**
132       * Creates a new ASN.1 octet string element with the default type and the
133       * provided value.
134       *
135       * @param  messageValue  The value for this ASN.1 octet string element as a
136       *                      string.
137       */
138      public ASN1OctetString(Message messageValue)
139      {
140        this(messageValue != null ? messageValue.toString() : null);
141      }
142    
143    
144    
145      /**
146       * Creates a new ASN.1 octet string element with the default type and the
147       * provided value.
148       *
149       * @param  stringValue  The value for this ASN.1 octet string element as a
150       *                      string.
151       */
152      public ASN1OctetString(String stringValue)
153      {
154        super(UNIVERSAL_OCTET_STRING_TYPE, getBytes(stringValue));
155    
156    
157        this.stringValue = stringValue;
158      }
159    
160    
161    
162      /**
163       * Creates a new ASN.1 octet string element with the specified type and the
164       * provided value.
165       *
166       * @param  type   The BER type for this ASN.1 octet string element.
167       * @param  value  The value for this ASN.1 octet string element.
168       */
169      public ASN1OctetString(byte type, byte[] value)
170      {
171        super(type, value);
172    
173    
174        this.stringValue = null;
175      }
176    
177    
178    
179      /**
180       * Creates a new ASN.1 octet string element with the specified type and the
181       * provided value.
182       *
183       * @param  type         The BER type for this ASN.1 octet string element.
184       * @param  stringValue  The value for this ASN.1 octet string element as a
185       *                      string.
186       */
187      public ASN1OctetString(byte type, String stringValue)
188      {
189        super(type, getBytes(stringValue));
190    
191    
192        this.stringValue = stringValue;
193      }
194    
195    
196    
197      /**
198       * Retrieves the string representation of the value for this ASN.1 octet
199       * string element.  The behavior of this method when the bytes are not
200       * valid in the UTF-8 charset is unspecified.  In particular the behavior for
201       * binary values is unspecified.
202       *
203       * @return  The string representation of the value for this ASN.1 octet string
204       *          element.
205       */
206      public String stringValue()
207      {
208        if (stringValue == null)
209        {
210    /*
211          // This code could be used to explicitly detect and handle binary values.
212          Charset charset = Charset.forName("UTF-8");
213          CharsetDecoder decoder = charset.newDecoder();
214          ByteBuffer bb = ByteBuffer.wrap(value());
215          try
216          {
217            CharBuffer cb = decoder.decode(bb);
218            stringValue = cb.toString();
219          }
220          catch (CharacterCodingException e)
221          {
222            // Handle binary values here.
223            return "[Binary]";
224          }
225    */
226          try
227          {
228            stringValue = new String(value(), "UTF-8");
229          }
230          catch (Exception e)
231          {
232            if (debugEnabled())
233            {
234              TRACER.debugCaught(DebugLogLevel.ERROR, e);
235            }
236    
237            stringValue = new String(value());
238          }
239        }
240    
241        return stringValue;
242      }
243    
244    
245    
246      /**
247       * Appends a string representation of the value for this ASN.1 octet string
248       * element to the provided buffer.
249       *
250       * @param  buffer  The buffer to which the string representation should be
251       *                 appended.
252       */
253      public void stringValue(StringBuilder buffer)
254      {
255        if (stringValue != null)
256        {
257          buffer.append(stringValue);
258          return;
259        }
260    
261        byte[] value  = value();
262        int    length = value.length;
263    
264        for (int i=0; i < length; i++)
265        {
266          if ((value[i] & 0x7F) == value[i])
267          {
268            buffer.append((char) value[i]);
269          }
270          else
271          {
272            String s;
273            try
274            {
275              s = new String(value, i, (length-i), "UTF-8");
276            }
277            catch (Exception e)
278            {
279              if (debugEnabled())
280              {
281                TRACER.debugCaught(DebugLogLevel.ERROR, e);
282              }
283    
284              s = new String(value, i, (length - i));
285            }
286    
287            buffer.append(s);
288            return;
289          }
290        }
291      }
292    
293    
294    
295      /**
296       * Specifies the string value for this ASN.1 octet string element.
297       *
298       * @param  stringValue  The string value for this ASN.1 octet string element.
299       */
300      public void setValue(String stringValue)
301      {
302        if (stringValue == null)
303        {
304          this.stringValue = null;
305          setValueInternal(new byte[0]);
306        }
307        else
308        {
309          this.stringValue = stringValue;
310          setValueInternal(getBytes(stringValue));
311        }
312      }
313    
314    
315    
316      /**
317       * Specifies the value for this ASN.1 octet string element.
318       *
319       * @param  value  The encoded value for this ASN.1 octet string element.
320       */
321      public void setValue(byte[] value)
322      {
323        if (value == null)
324        {
325          setValueInternal(NO_VALUE);
326        }
327        else
328        {
329          setValueInternal(value);
330        }
331    
332        stringValue = null;
333      }
334    
335    
336    
337      /**
338       * Decodes the provided ASN.1 element as an octet string element.
339       *
340       * @param  element  The ASN.1 element to decode as an octet string element.
341       *
342       * @return  The decoded ASN.1 octet string element.
343       *
344       * @throws  ASN1Exception  If the provided ASN.1 element cannot be decoded as
345       *                         an octet string element.
346       */
347      public static ASN1OctetString decodeAsOctetString(ASN1Element element)
348             throws ASN1Exception
349      {
350        if (element == null)
351        {
352          Message message = ERR_ASN1_OCTET_STRING_DECODE_ELEMENT_NULL.get();
353          throw new ASN1Exception(message);
354        }
355    
356        return new ASN1OctetString(element.getType(), element.value());
357      }
358    
359    
360    
361      /**
362       * Decodes the provided byte array as an ASN.1 octet string element.
363       *
364       * @param  encodedElement  The byte array to decode as an ASN.1 octet string
365       *                         element.
366       *
367       * @return  The decoded ASN.1 octet string element.
368       *
369       * @throws  ASN1Exception  If the provided byte array cannot be decoded as an
370       *                         ASN.1 octet string element.
371       */
372      public static ASN1OctetString decodeAsOctetString(byte[] encodedElement)
373             throws ASN1Exception
374      {
375        // First make sure that the array is not null and long enough to contain
376        // a valid ASN.1 element.
377        if (encodedElement == null)
378        {
379          Message message = ERR_ASN1_OCTET_STRING_DECODE_ARRAY_NULL.get();
380          throw new ASN1Exception(message);
381        }
382    
383        if (encodedElement.length < 2)
384        {
385          Message message = ERR_ASN1_SHORT_ELEMENT.get(encodedElement.length);
386          throw new ASN1Exception(message);
387        }
388    
389    
390        // Next, decode the length.  This allows multi-byte lengths with up to four
391        // bytes used to indicate how many bytes are in the length.
392        byte type = encodedElement[0];
393        int length = (encodedElement[1] & 0x7F);
394        int valueStartPos = 2;
395        if (length != encodedElement[1])
396        {
397          int numLengthBytes = length;
398          if (numLengthBytes > 4)
399          {
400            Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
401            throw new ASN1Exception(message);
402          }
403          else if (encodedElement.length < (2 + numLengthBytes))
404          {
405            Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
406            throw new ASN1Exception(message);
407          }
408    
409          length = 0x00;
410          valueStartPos = 2 + numLengthBytes;
411          for (int i=0; i < numLengthBytes; i++)
412          {
413            length = (length << 8) | (encodedElement[i+2] & 0xFF);
414          }
415        }
416    
417    
418        // Make sure that the number of bytes left is equal to the number of bytes
419        // in the value.
420        if ((encodedElement.length - valueStartPos) != length)
421        {
422          Message message = ERR_ASN1_LENGTH_MISMATCH.get(
423              length, (encodedElement.length - valueStartPos));
424          throw new ASN1Exception(message);
425        }
426    
427    
428        // Copy the value and construct the element to return.
429        byte[] value = new byte[length];
430        System.arraycopy(encodedElement, valueStartPos, value, 0, length);
431        return new ASN1OctetString(type, value);
432      }
433    
434    
435    
436      /**
437       * Creates a duplicate of this ASN.1 octet string.
438       *
439       * @return  A duplicate of this ASN.1 octet string.
440       */
441      public ASN1OctetString duplicate()
442      {
443        byte[] value = value();
444        int length = value.length;
445    
446        byte[] duplicateValue = new byte[length];
447        System.arraycopy(value, 0, duplicateValue, 0, length);
448    
449        return new ASN1OctetString(getType(), value);
450      }
451    
452    
453    
454      /**
455       * Appends a string representation of this ASN.1 octet string element to the
456       * provided buffer.
457       *
458       * @param  buffer  The buffer to which the information should be appended.
459       */
460      public void toString(StringBuilder buffer)
461      {
462        buffer.append(stringValue());
463      }
464    
465    
466    
467      /**
468       * Appends a string representation of this protocol element to the provided
469       * buffer.
470       *
471       * @param  buffer  The buffer into which the string representation should be
472       *                 written.
473       * @param  indent  The number of spaces that should be used to indent the
474       *                 resulting string representation.
475       */
476      public void toString(StringBuilder buffer, int indent)
477      {
478        StringBuilder indentBuf = new StringBuilder(indent);
479        for (int i=0 ; i < indent; i++)
480        {
481          indentBuf.append(' ');
482        }
483    
484        buffer.append(indentBuf);
485        buffer.append("ASN.1 Octet String");
486        buffer.append(EOL);
487    
488        buffer.append(indentBuf);
489        buffer.append("  BER Type:  ");
490        buffer.append(byteToHex(getType()));
491        buffer.append(EOL);
492    
493        byte[] value = value();
494        buffer.append(indentBuf);
495        buffer.append("  Value (");
496        buffer.append(value.length);
497        buffer.append(" bytes)");
498        buffer.append(EOL);
499    
500        byteArrayToHexPlusAscii(buffer, value, indent+2);
501      }
502    
503    
504    
505      /**
506       * Retrieves this byte string as an ASN.1 octet string.
507       *
508       * @return  An ASN.1 octet string with the value of this byte string.
509       */
510      public ASN1OctetString toASN1OctetString()
511      {
512        return this;
513      }
514    }
515