001    /*
002     * Copyright 2007-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2016 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.asn1;
022    
023    
024    
025    import java.io.InputStream;
026    import java.io.IOException;
027    import java.io.OutputStream;
028    import java.io.Serializable;
029    import java.util.Arrays;
030    
031    import com.unboundid.util.ByteStringBuffer;
032    import com.unboundid.util.NotExtensible;
033    import com.unboundid.util.NotMutable;
034    import com.unboundid.util.ThreadSafety;
035    import com.unboundid.util.ThreadSafetyLevel;
036    
037    import static com.unboundid.asn1.ASN1Constants.*;
038    import static com.unboundid.asn1.ASN1Messages.*;
039    import static com.unboundid.util.Debug.*;
040    import static com.unboundid.util.StaticUtils.*;
041    
042    
043    
044    /**
045     * This class defines a generic ASN.1 BER element, which has a type and value.
046     * It provides a framework for encoding and decoding BER elements, both as
047     * generic elements and more specific subtypes.
048     */
049    @NotExtensible()
050    @NotMutable()
051    @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
052    public class ASN1Element
053           implements Serializable
054    {
055      /**
056       * The serial version UID for this serializable class.
057       */
058      private static final long serialVersionUID = -1871166128693521335L;
059    
060    
061    
062      // The BER type for this element.
063      private final byte type;
064    
065      // The encoded value for this element.
066      private final byte[] value;
067    
068      // The cached hashCode for this element.
069      private int hashCode = -1;
070    
071      // The number of bytes contained in the value.
072      private final int valueLength;
073    
074      // The offset within the value array at which the value begins.
075      private final int valueOffset;
076    
077    
078    
079      /**
080       * Creates a new ASN.1 BER element with the specified type and no value.
081       *
082       * @param  type  The BER type for this element.
083       */
084      public ASN1Element(final byte type)
085      {
086        this.type   = type;
087        value       = NO_VALUE;
088        valueOffset = 0;
089        valueLength = 0;
090      }
091    
092    
093    
094      /**
095       * Creates a new ASN1 BER element with the specified type and value.
096       *
097       * @param  type   The BER type for this element.
098       * @param  value  The encoded value for this element.
099       */
100      public ASN1Element(final byte type, final byte[] value)
101      {
102        this.type = type;
103    
104        if (value == null)
105        {
106          this.value = NO_VALUE;
107        }
108        else
109        {
110          this.value = value;
111        }
112    
113        valueOffset = 0;
114        valueLength = this.value.length;
115      }
116    
117    
118    
119      /**
120       * Creates a new ASN1 BER element with the specified type and value.
121       *
122       * @param  type    The BER type for this element.
123       * @param  value   The array containing the encoded value for this element.
124       *                 It must not be {@code null}.
125       * @param  offset  The offset within the array at which the value begins.
126       * @param  length  The number of bytes contained in the value.
127       */
128      public ASN1Element(final byte type, final byte[] value, final int offset,
129                         final int length)
130      {
131        this.type  = type;
132        this.value = value;
133    
134        valueOffset = offset;
135        valueLength = length;
136      }
137    
138    
139    
140      /**
141       * Retrieves the BER type for this element.
142       *
143       * @return  The BER type for this element.
144       */
145      public final byte getType()
146      {
147        return type;
148      }
149    
150    
151    
152      /**
153       * Retrieves the array containing the value.  The returned array may be
154       * larger than the actual value, so it must be used in conjunction with the
155       * values returned by the {@link #getValueOffset} and {@link #getValueLength}
156       * methods.
157       *
158       * @return  The array containing the value.
159       */
160      byte[] getValueArray()
161      {
162        return value;
163      }
164    
165    
166    
167      /**
168       * Retrieves the position in the value array at which the value actually
169       * begins.
170       *
171       * @return  The position in the value array at which the value actually
172       *          begins.
173       */
174      int getValueOffset()
175      {
176        return valueOffset;
177      }
178    
179    
180    
181      /**
182       * Retrieves the number of bytes contained in the value.
183       *
184       * @return  The number of bytes contained in the value.
185       */
186      public int getValueLength()
187      {
188        return valueLength;
189      }
190    
191    
192    
193      /**
194       * Retrieves the encoded value for this element.
195       *
196       * @return  The encoded value for this element.
197       */
198      public byte[] getValue()
199      {
200        if ((valueOffset == 0) && (valueLength == value.length))
201        {
202          return value;
203        }
204        else
205        {
206          final byte[] returnValue = new byte[valueLength];
207          System.arraycopy(value, valueOffset, returnValue, 0, valueLength);
208          return returnValue;
209        }
210      }
211    
212    
213    
214      /**
215       * Encodes this ASN.1 element to a byte array.
216       *
217       * @return  A byte array containing the encoded representation of this ASN.1
218       *          element.
219       */
220      public final byte[] encode()
221      {
222        final byte[] valueArray = getValueArray();
223        final int    length     = getValueLength();
224        final int    offset     = getValueOffset();
225    
226        if (length == 0)
227        {
228          return new byte[] { type, 0x00 };
229        }
230    
231        final byte[] lengthBytes  = encodeLength(length);
232        final byte[] elementBytes = new byte[1 + lengthBytes.length + length];
233    
234        elementBytes[0] = type;
235        System.arraycopy(lengthBytes, 0, elementBytes, 1, lengthBytes.length);
236        System.arraycopy(valueArray, offset, elementBytes, 1+lengthBytes.length,
237             length);
238    
239        return elementBytes;
240      }
241    
242    
243    
244      /**
245       * Encodes the provided length to the given buffer.
246       *
247       * @param  length  The length to be encoded.
248       * @param  buffer  The buffer to which the length should be appended.
249       */
250      static void encodeLengthTo(final int length, final ByteStringBuffer buffer)
251      {
252        if ((length & 0x7F) == length)
253        {
254          buffer.append((byte) length);
255        }
256        else if ((length & 0xFF) == length)
257        {
258          buffer.append((byte) 0x81);
259          buffer.append((byte) (length & 0xFF));
260        }
261        else if ((length & 0xFFFF) == length)
262        {
263          buffer.append((byte) 0x82);
264          buffer.append((byte) ((length >> 8) & 0xFF));
265          buffer.append((byte) (length & 0xFF));
266        }
267        else if ((length & 0xFFFFFF) == length)
268        {
269          buffer.append((byte) 0x83);
270          buffer.append((byte) ((length >> 16) & 0xFF));
271          buffer.append((byte) ((length >> 8) & 0xFF));
272          buffer.append((byte) (length & 0xFF));
273        }
274        else
275        {
276          buffer.append((byte) 0x84);
277          buffer.append((byte) ((length >> 24) & 0xFF));
278          buffer.append((byte) ((length >> 16) & 0xFF));
279          buffer.append((byte) ((length >> 8) & 0xFF));
280          buffer.append((byte) (length & 0xFF));
281        }
282      }
283    
284    
285    
286      /**
287       * Appends an encoded representation of this ASN.1 element to the provided
288       * buffer.
289       *
290       * @param  buffer  The buffer to which the encoded representation should be
291       *                 appended.
292       */
293      public void encodeTo(final ByteStringBuffer buffer)
294      {
295        final byte[] valueArray = getValueArray();
296        final int    length     = getValueLength();
297        final int    offset     = getValueOffset();
298    
299        buffer.append(type);
300        if (length == 0)
301        {
302          buffer.append((byte) 0x00);
303        }
304        else
305        {
306          encodeLengthTo(length, buffer);
307          buffer.append(valueArray, offset, length);
308        }
309      }
310    
311    
312    
313      /**
314       * Encodes the provided length to a byte array.
315       *
316       * @param  length  The length to be encoded.
317       *
318       * @return  A byte array containing the encoded length.
319       */
320      public static byte[] encodeLength(final int length)
321      {
322        switch (length)
323        {
324          case 0:  return LENGTH_0;
325          case 1:  return LENGTH_1;
326          case 2:  return LENGTH_2;
327          case 3:  return LENGTH_3;
328          case 4:  return LENGTH_4;
329          case 5:  return LENGTH_5;
330          case 6:  return LENGTH_6;
331          case 7:  return LENGTH_7;
332          case 8:  return LENGTH_8;
333          case 9:  return LENGTH_9;
334          case 10:  return LENGTH_10;
335          case 11:  return LENGTH_11;
336          case 12:  return LENGTH_12;
337          case 13:  return LENGTH_13;
338          case 14:  return LENGTH_14;
339          case 15:  return LENGTH_15;
340          case 16:  return LENGTH_16;
341          case 17:  return LENGTH_17;
342          case 18:  return LENGTH_18;
343          case 19:  return LENGTH_19;
344          case 20:  return LENGTH_20;
345          case 21:  return LENGTH_21;
346          case 22:  return LENGTH_22;
347          case 23:  return LENGTH_23;
348          case 24:  return LENGTH_24;
349          case 25:  return LENGTH_25;
350          case 26:  return LENGTH_26;
351          case 27:  return LENGTH_27;
352          case 28:  return LENGTH_28;
353          case 29:  return LENGTH_29;
354          case 30:  return LENGTH_30;
355          case 31:  return LENGTH_31;
356          case 32:  return LENGTH_32;
357          case 33:  return LENGTH_33;
358          case 34:  return LENGTH_34;
359          case 35:  return LENGTH_35;
360          case 36:  return LENGTH_36;
361          case 37:  return LENGTH_37;
362          case 38:  return LENGTH_38;
363          case 39:  return LENGTH_39;
364          case 40:  return LENGTH_40;
365          case 41:  return LENGTH_41;
366          case 42:  return LENGTH_42;
367          case 43:  return LENGTH_43;
368          case 44:  return LENGTH_44;
369          case 45:  return LENGTH_45;
370          case 46:  return LENGTH_46;
371          case 47:  return LENGTH_47;
372          case 48:  return LENGTH_48;
373          case 49:  return LENGTH_49;
374          case 50:  return LENGTH_50;
375          case 51:  return LENGTH_51;
376          case 52:  return LENGTH_52;
377          case 53:  return LENGTH_53;
378          case 54:  return LENGTH_54;
379          case 55:  return LENGTH_55;
380          case 56:  return LENGTH_56;
381          case 57:  return LENGTH_57;
382          case 58:  return LENGTH_58;
383          case 59:  return LENGTH_59;
384          case 60:  return LENGTH_60;
385          case 61:  return LENGTH_61;
386          case 62:  return LENGTH_62;
387          case 63:  return LENGTH_63;
388          case 64:  return LENGTH_64;
389          case 65:  return LENGTH_65;
390          case 66:  return LENGTH_66;
391          case 67:  return LENGTH_67;
392          case 68:  return LENGTH_68;
393          case 69:  return LENGTH_69;
394          case 70:  return LENGTH_70;
395          case 71:  return LENGTH_71;
396          case 72:  return LENGTH_72;
397          case 73:  return LENGTH_73;
398          case 74:  return LENGTH_74;
399          case 75:  return LENGTH_75;
400          case 76:  return LENGTH_76;
401          case 77:  return LENGTH_77;
402          case 78:  return LENGTH_78;
403          case 79:  return LENGTH_79;
404          case 80:  return LENGTH_80;
405          case 81:  return LENGTH_81;
406          case 82:  return LENGTH_82;
407          case 83:  return LENGTH_83;
408          case 84:  return LENGTH_84;
409          case 85:  return LENGTH_85;
410          case 86:  return LENGTH_86;
411          case 87:  return LENGTH_87;
412          case 88:  return LENGTH_88;
413          case 89:  return LENGTH_89;
414          case 90:  return LENGTH_90;
415          case 91:  return LENGTH_91;
416          case 92:  return LENGTH_92;
417          case 93:  return LENGTH_93;
418          case 94:  return LENGTH_94;
419          case 95:  return LENGTH_95;
420          case 96:  return LENGTH_96;
421          case 97:  return LENGTH_97;
422          case 98:  return LENGTH_98;
423          case 99:  return LENGTH_99;
424          case 100:  return LENGTH_100;
425          case 101:  return LENGTH_101;
426          case 102:  return LENGTH_102;
427          case 103:  return LENGTH_103;
428          case 104:  return LENGTH_104;
429          case 105:  return LENGTH_105;
430          case 106:  return LENGTH_106;
431          case 107:  return LENGTH_107;
432          case 108:  return LENGTH_108;
433          case 109:  return LENGTH_109;
434          case 110:  return LENGTH_110;
435          case 111:  return LENGTH_111;
436          case 112:  return LENGTH_112;
437          case 113:  return LENGTH_113;
438          case 114:  return LENGTH_114;
439          case 115:  return LENGTH_115;
440          case 116:  return LENGTH_116;
441          case 117:  return LENGTH_117;
442          case 118:  return LENGTH_118;
443          case 119:  return LENGTH_119;
444          case 120:  return LENGTH_120;
445          case 121:  return LENGTH_121;
446          case 122:  return LENGTH_122;
447          case 123:  return LENGTH_123;
448          case 124:  return LENGTH_124;
449          case 125:  return LENGTH_125;
450          case 126:  return LENGTH_126;
451          case 127:  return LENGTH_127;
452        }
453    
454        if ((length & 0x000000FF) == length)
455        {
456          return new byte[]
457          {
458            (byte) 0x81,
459            (byte) (length & 0xFF)
460          };
461        }
462        else if ((length & 0x0000FFFF) == length)
463        {
464          return new byte[]
465          {
466            (byte) 0x82,
467            (byte) ((length >> 8) & 0xFF),
468            (byte) (length & 0xFF)
469          };
470        }
471        else if ((length & 0x00FFFFFF) == length)
472        {
473          return new byte[]
474          {
475            (byte) 0x83,
476            (byte) ((length >> 16) & 0xFF),
477            (byte) ((length >> 8) & 0xFF),
478            (byte) (length & 0xFF)
479          };
480        }
481        else
482        {
483          return new byte[]
484          {
485            (byte) 0x84,
486            (byte) ((length >> 24) & 0xFF),
487            (byte) ((length >> 16) & 0xFF),
488            (byte) ((length >> 8) & 0xFF),
489            (byte) (length & 0xFF)
490          };
491        }
492      }
493    
494    
495    
496      /**
497       * Decodes the content in the provided byte array as an ASN.1 element.
498       *
499       * @param  elementBytes  The byte array containing the data to decode.
500       *
501       * @return  The decoded ASN.1 BER element.
502       *
503       * @throws  ASN1Exception  If the provided byte array does not represent a
504       *                         valid ASN.1 element.
505       */
506      public static ASN1Element decode(final byte[] elementBytes)
507             throws ASN1Exception
508      {
509        try
510        {
511          int valueStartPos = 2;
512          int length = (elementBytes[1] & 0x7F);
513          if (length != elementBytes[1])
514          {
515            final int numLengthBytes = length;
516    
517            length = 0;
518            for (int i=0; i < numLengthBytes; i++)
519            {
520              length <<= 8;
521              length |= (elementBytes[valueStartPos++] & 0xFF);
522            }
523          }
524    
525          if ((elementBytes.length - valueStartPos) != length)
526          {
527            throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length,
528                                         (elementBytes.length - valueStartPos)));
529          }
530    
531          final byte[] value = new byte[length];
532          System.arraycopy(elementBytes, valueStartPos, value, 0, length);
533          return new ASN1Element(elementBytes[0], value);
534        }
535        catch (final ASN1Exception ae)
536        {
537          debugException(ae);
538          throw ae;
539        }
540        catch (final Exception e)
541        {
542          debugException(e);
543          throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e);
544        }
545      }
546    
547    
548    
549      /**
550       * Decodes this ASN.1 element as a Boolean element.
551       *
552       * @return  The decoded Boolean element.
553       *
554       * @throws  ASN1Exception  If this element cannot be decoded as a Boolean
555       *                         element.
556       */
557      public final ASN1Boolean decodeAsBoolean()
558             throws ASN1Exception
559      {
560        return ASN1Boolean.decodeAsBoolean(this);
561      }
562    
563    
564    
565      /**
566       * Decodes this ASN.1 element as an enumerated element.
567       *
568       * @return  The decoded enumerated element.
569       *
570       * @throws  ASN1Exception  If this element cannot be decoded as an enumerated
571       *                         element.
572       */
573      public final ASN1Enumerated decodeAsEnumerated()
574             throws ASN1Exception
575      {
576        return ASN1Enumerated.decodeAsEnumerated(this);
577      }
578    
579    
580    
581      /**
582       * Decodes this ASN.1 element as an integer element.
583       *
584       * @return  The decoded integer element.
585       *
586       * @throws  ASN1Exception  If this element cannot be decoded as an integer
587       *                         element.
588       */
589      public final ASN1Integer decodeAsInteger()
590             throws ASN1Exception
591      {
592        return ASN1Integer.decodeAsInteger(this);
593      }
594    
595    
596    
597      /**
598       * Decodes this ASN.1 element as a long element.
599       *
600       * @return  The decoded long element.
601       *
602       * @throws  ASN1Exception  If this element cannot be decoded as a long
603       *                         element.
604       */
605      public final ASN1Long decodeAsLong()
606             throws ASN1Exception
607      {
608        return ASN1Long.decodeAsLong(this);
609      }
610    
611    
612    
613      /**
614       * Decodes this ASN.1 element as a null element.
615       *
616       * @return  The decoded null element.
617       *
618       * @throws  ASN1Exception  If this element cannot be decoded as a null
619       *                         element.
620       */
621      public final ASN1Null decodeAsNull()
622             throws ASN1Exception
623      {
624        return ASN1Null.decodeAsNull(this);
625      }
626    
627    
628    
629      /**
630       * Decodes this ASN.1 element as an octet string element.
631       *
632       * @return  The decoded octet string element.
633       */
634      public final ASN1OctetString decodeAsOctetString()
635      {
636        return ASN1OctetString.decodeAsOctetString(this);
637      }
638    
639    
640    
641      /**
642       * Decodes this ASN.1 element as a sequence element.
643       *
644       * @return  The decoded sequence element.
645       *
646       * @throws  ASN1Exception  If this element cannot be decoded as a sequence
647       *                         element.
648       */
649      public final ASN1Sequence decodeAsSequence()
650             throws ASN1Exception
651      {
652        return ASN1Sequence.decodeAsSequence(this);
653      }
654    
655    
656    
657      /**
658       * Decodes this ASN.1 element as a set element.
659       *
660       * @return  The decoded set element.
661       *
662       * @throws  ASN1Exception  If this element cannot be decoded as a set
663       *                         element.
664       */
665      public final ASN1Set decodeAsSet()
666             throws ASN1Exception
667      {
668        return ASN1Set.decodeAsSet(this);
669      }
670    
671    
672    
673      /**
674       * Reads an ASN.1 element from the provided input stream.
675       *
676       * @param  inputStream  The input stream from which to read the element.
677       *
678       * @return  The element read from the input stream, or {@code null} if the end
679       *          of the input stream is reached without reading any data.
680       *
681       * @throws  IOException  If a problem occurs while attempting to read from the
682       *                       input stream.
683       *
684       * @throws  ASN1Exception  If a problem occurs while attempting to decode the
685       *                         element.
686       */
687      public static ASN1Element readFrom(final InputStream inputStream)
688             throws IOException, ASN1Exception
689      {
690        return readFrom(inputStream, -1);
691      }
692    
693    
694    
695      /**
696       * Reads an ASN.1 element from the provided input stream.
697       *
698       * @param  inputStream  The input stream from which to read the element.
699       * @param  maxSize      The maximum value size in bytes that will be allowed.
700       *                      A value less than or equal to zero indicates that no
701       *                      maximum size should be enforced.  An attempt to read
702       *                      an element with a value larger than this will cause an
703       *                      {@code ASN1Exception} to be thrown.
704       *
705       * @return  The element read from the input stream, or {@code null} if the end
706       *          of the input stream is reached without reading any data.
707       *
708       * @throws  IOException  If a problem occurs while attempting to read from the
709       *                       input stream.
710       *
711       * @throws  ASN1Exception  If a problem occurs while attempting to decode the
712       *                         element.
713       */
714      public static ASN1Element readFrom(final InputStream inputStream,
715                                         final int maxSize)
716             throws IOException, ASN1Exception
717      {
718        final int typeInt = inputStream.read();
719        if (typeInt < 0)
720        {
721          return null;
722        }
723    
724        final byte type = (byte) typeInt;
725    
726        int length = inputStream.read();
727        if (length < 0)
728        {
729          throw new ASN1Exception(ERR_READ_END_BEFORE_FIRST_LENGTH.get());
730        }
731        else if (length > 127)
732        {
733          final int numLengthBytes = length & 0x7F;
734          length = 0;
735          if ((numLengthBytes < 1) || (numLengthBytes > 4))
736          {
737            throw new ASN1Exception(ERR_READ_LENGTH_TOO_LONG.get(numLengthBytes));
738          }
739    
740          for (int i=0; i < numLengthBytes; i++)
741          {
742            final int lengthInt = inputStream.read();
743            if (lengthInt < 0)
744            {
745              throw new ASN1Exception(ERR_READ_END_BEFORE_LENGTH_END.get());
746            }
747    
748            length <<= 8;
749            length |= (lengthInt & 0xFF);
750          }
751        }
752    
753        if ((length < 0) || ((maxSize > 0) && (length > maxSize)))
754        {
755          throw new ASN1Exception(ERR_READ_LENGTH_EXCEEDS_MAX.get(length, maxSize));
756        }
757    
758        int totalBytesRead = 0;
759        int bytesRemaining = length;
760        final byte[] value = new byte[length];
761        while (totalBytesRead < length)
762        {
763          final int bytesRead =
764               inputStream.read(value, totalBytesRead, bytesRemaining);
765          if (bytesRead < 0)
766          {
767            throw new ASN1Exception(ERR_READ_END_BEFORE_VALUE_END.get());
768          }
769    
770          totalBytesRead += bytesRead;
771          bytesRemaining -= bytesRead;
772        }
773    
774        final ASN1Element e = new ASN1Element(type, value);
775        debugASN1Read(e);
776        return e;
777      }
778    
779    
780    
781      /**
782       * Writes an encoded representation of this ASN.1 element to the provided
783       * output stream.
784       *
785       * @param  outputStream  The output stream to which the element should be
786       *                       written.
787       *
788       * @return  The total number of bytes written to the output stream.
789       *
790       * @throws  IOException  If a problem occurs while attempting to write to the
791       *                       provided output stream.
792       *
793       * @see  ASN1Writer#writeElement(ASN1Element,OutputStream)
794       */
795      public final int writeTo(final OutputStream outputStream)
796             throws IOException
797      {
798        debugASN1Write(this);
799    
800        final ByteStringBuffer buffer = new ByteStringBuffer();
801        encodeTo(buffer);
802        buffer.write(outputStream);
803        return buffer.length();
804      }
805    
806    
807    
808      /**
809       * Retrieves a hash code for this ASN.1 BER element.
810       *
811       * @return  A hash code for this ASN.1 BER element.
812       */
813      @Override()
814      public final int hashCode()
815      {
816        if (hashCode == -1)
817        {
818          int hash = 0;
819          for (final byte b : getValue())
820          {
821            hash = hash * 31 + b;
822          }
823          hashCode = hash;
824        }
825    
826        return hashCode;
827      }
828    
829    
830    
831      /**
832       * Indicates whether the provided object is equal to this ASN.1 BER element.
833       * The object will only be considered equal to this ASN.1 element if it is a
834       * non-null ASN.1 element with the same type and value as this element.
835       *
836       * @param  o  The object for which to make the determination.
837       *
838       * @return  {@code true} if the provided object is considered equal to this
839       *          ASN.1 element, or {@code false} if not.
840       */
841      @Override()
842      public final boolean equals(final Object o)
843      {
844        if (o == null)
845        {
846          return false;
847        }
848    
849        if (o == this)
850        {
851          return true;
852        }
853    
854        try
855        {
856          final ASN1Element e = (ASN1Element) o;
857          return ((type == e.getType()) && Arrays.equals(getValue(), e.getValue()));
858        }
859        catch (final Exception e)
860        {
861          debugException(e);
862          return false;
863        }
864      }
865    
866    
867    
868      /**
869       * Indicates whether the provided ASN.1 element is equal to this element,
870       * ignoring any potential difference in the BER type.
871       *
872       * @param  element  The ASN.1 BER element for which to make the determination.
873       *
874       * @return  {@code true} if the provided ASN.1 element is considered equal to
875       *          this element (ignoring type differences), or {@code false} if not.
876       */
877      public final boolean equalsIgnoreType(final ASN1Element element)
878      {
879        if (element == null)
880        {
881          return false;
882        }
883    
884        if (element == this)
885        {
886          return true;
887        }
888    
889        return Arrays.equals(getValue(), element.getValue());
890      }
891    
892    
893    
894      /**
895       * Retrieves a string representation of the value for ASN.1 element.
896       *
897       * @return  A string representation of the value for this ASN.1 element.
898       */
899      @Override()
900      public final String toString()
901      {
902        final StringBuilder buffer = new StringBuilder();
903        toString(buffer);
904        return buffer.toString();
905      }
906    
907    
908    
909      /**
910       * Appends a string representation of the value for this ASN.1 element to the
911       * provided buffer.
912       *
913       * @param  buffer  The buffer to which to append the information.
914       */
915      public void toString(final StringBuilder buffer)
916      {
917        final byte[] v = getValue();
918        buffer.append("ASN1Element(type=");
919        toHex(type, buffer);
920        buffer.append(", valueLength=");
921        buffer.append(v.length);
922        buffer.append(", valueBytes='");
923        toHex(v, buffer);
924        buffer.append("')");
925      }
926    }