001/*
002 * Copyright 2007-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2014 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 */
021package com.unboundid.asn1;
022
023
024
025import java.io.InputStream;
026import java.io.IOException;
027import java.io.OutputStream;
028import java.io.Serializable;
029import java.util.Arrays;
030
031import com.unboundid.util.ByteStringBuffer;
032import com.unboundid.util.NotExtensible;
033import com.unboundid.util.NotMutable;
034import com.unboundid.util.ThreadSafety;
035import com.unboundid.util.ThreadSafetyLevel;
036
037import static com.unboundid.asn1.ASN1Constants.*;
038import static com.unboundid.asn1.ASN1Messages.*;
039import static com.unboundid.util.Debug.*;
040import 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)
052public 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}